Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add DependsOnId on Add Related Object API #3079

Merged
merged 6 commits into from
Nov 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/Microsoft.OData.Client/DataServiceContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2634,7 +2634,8 @@ public virtual void AddRelatedObject(object source, string sourceProperty, objec
var targetResource = new EntityDescriptor(this.model)
{
Entity = target,
State = EntityStates.Added
State = EntityStates.Added,
DButoyez marked this conversation as resolved.
Show resolved Hide resolved
DependsOnIds = new List<string> { sourceResource.ChangeOrder.ToString(CultureInfo.InvariantCulture) }
};

targetResource.SetParentForInsert(sourceResource, sourceProperty);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
//-----------------------------------------------------------------------------
// <copyright file="AsyncMethodTests.cs" company=".NET Foundation">
// Copyright (c) .NET Foundation and Contributors. All rights reserved.
// See License.txt in the project root for license information.
// </copyright>
//------------------------------------------------------------------------------

using Microsoft.AspNetCore.OData;
using Microsoft.AspNetCore.OData.Batch;
using Microsoft.AspNetCore.OData.Routing.Controllers;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.OData.Client.E2E.TestCommon;
using Microsoft.OData.Client.E2E.Tests.Batch.Server;
using Microsoft.OData.Client.E2E.Tests.Common.Server.EndToEnd;
using Microsoft.OData.Edm.Csdl;
using System.Xml;
using Xunit;

namespace Microsoft.OData.Client.E2E.Tests.Batch
{
public class AsyncMethodTests : EndToEndTestBase<AsyncMethodTests.TestsStartup>
{
private readonly Uri _baseUri;
private readonly Container _context;

public class TestsStartup : TestStartupBase
{
public override void ConfigureServices(IServiceCollection services)
{
services.ConfigureControllers(typeof(BanksController), typeof(MetadataController));
services.AddControllers().AddOData(opt => opt.Count().Filter().Expand().Select().OrderBy().SetMaxTop(null)
.AddRouteComponents("odata", CommonEndToEndEdmModel.GetEdmModel(), new DefaultODataBatchHandler()));
}
}

public AsyncMethodTests(TestWebApplicationFactory<TestsStartup> fixture)
: base(fixture)
{
_baseUri = new Uri(Client.BaseAddress, "odata/");
_context = new Container(_baseUri)
{
HttpClientFactory = HttpClientFactory
};
}

[Fact]
public async Task JsonBatchSequencingSingeChangeSetTest()
{
// Create new BankAccounts object
var bank = new Bank
{
Id = 45,
Name = "Test Bank",
Location = "KE",
BankAccounts = new List<BankAccount>()
};

// Create new BankAccount object
var bankAccount = new BankAccount
{
Id = 890,
AccountNumber = "4567890",
BankId = bank.Id,
Bank = bank
};

// Establish the relationship between BankAccounts and BankAccount
bank.BankAccounts.Add(bankAccount);

// Add the BankAccounts entity to the context
_context.AddObject("Banks", bank);

// Add the related BankAccount entity
_context.AddRelatedObject(bank, "BankAccounts", bankAccount);

// Save both entities in a single batch request using JSON
var response = await _context.SaveChangesAsync(SaveChangesOptions.BatchWithSingleChangeset | SaveChangesOptions.UseJsonBatch);
Assert.Equal(2, response.Count());

var bankResponse = response.First() as ChangeOperationResponse;
var bankAccountResponse = response.Last() as ChangeOperationResponse;

Assert.NotNull(bankResponse);
Assert.NotNull(bankAccountResponse);

Assert.Equal(201, bankResponse.StatusCode);
Assert.Equal(201, bankAccountResponse.StatusCode);
}
}

class Container : DataServiceContext
DButoyez marked this conversation as resolved.
Show resolved Hide resolved
{
public Container(Uri serviceRoot) :
base(serviceRoot, ODataProtocolVersion.V4)
{
Format.LoadServiceModel = () => CsdlReader.Parse(XmlReader.Create(new StringReader(@"
<edmx:Edmx Version=""4.0"" xmlns:edmx=""http://docs.oasis-open.org/odata/ns/edmx"">
<edmx:DataServices>
<Schema Namespace=""ODataService"" xmlns=""http://docs.oasis-open.org/odata/ns/edm"">
<EntityType Name=""Bank"">
<Key>
<PropertyRef Name=""Id"" />
</Key>
<Property Name=""Id"" Type=""Edm.Int32"" Nullable=""false"" />
<Property Name=""Name"" Type=""Edm.String"" />
<Property Name=""Location"" Type=""Edm.String"" />
<NavigationProperty Name=""BankAccounts"" Type=""Collection(ODataService.BankAccount)"" />
</EntityType>
<EntityType Name=""BankAccount"">
<Key>
<PropertyRef Name=""Id"" />
</Key>
<Property Name=""Id"" Type=""Edm.Int32"" Nullable=""false"" />
<Property Name=""AccountNumber"" Type=""Edm.String"" />
<NavigationProperty Name=""Bank"" Type=""ODataService.Bank"" />
</EntityType>
</Schema>
<Schema Namespace=""Default"" xmlns=""http://docs.oasis-open.org/odata/ns/edm"">
<EntityContainer Name=""Container"">
<EntitySet Name=""Banks"" EntityType=""ODataService.Bank"">
<NavigationPropertyBinding Path=""BankAccounts"" Target=""BankAccounts"" />
</EntitySet>
<EntitySet Name=""BankAccounts"" EntityType=""ODataService.BankAccount"">
<NavigationPropertyBinding Path=""Bank"" Target=""Banks"" />
</EntitySet>
</EntityContainer>
</Schema>
</edmx:DataServices>
</edmx:Edmx>
")));
Format.UseJson();
Banks = base.CreateQuery<Bank>("Banks");
BankAccounts = base.CreateQuery<BankAccount>("BankAccounts");
}

public DataServiceQuery<Bank> Banks { get; private set; }
public DataServiceQuery<BankAccount> BankAccounts { get; private set; }
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.OData.Formatter;
using Microsoft.AspNetCore.OData.Query;
using Microsoft.AspNetCore.OData.Routing.Controllers;
using Microsoft.OData.Client.E2E.Tests.Common.Server.EndToEnd;

namespace Microsoft.OData.Client.E2E.Tests.Batch.Server
{
public class BanksController : ODataController
{
private static CommonEndToEndDataSource _dataSource = CommonEndToEndDataSource.CreateInstance();

[EnableQuery]
[HttpGet("odata/Banks")]
public IActionResult Get()
{
var banks = _dataSource.Banks;
return Ok(banks);
}

// POST: odata/Banks
[EnableQuery]
[HttpPost("odata/Banks")]
public IActionResult Post([FromBody] Bank bank)
{
if (bank == null)
{
return BadRequest();
}
_dataSource.Banks.Add(bank);
return Created(bank);
}

// POST: /odata/$1/BankAccounts
[HttpPost]
[Route("odata/Banks({id})/BankAccounts")]
public IActionResult PostBankAccount([FromODataUri] int id , [FromBody] BankAccount bankAccount)
{
if (bankAccount == null)
{
return BadRequest();
}

var bank = _dataSource.Banks.FirstOrDefault(b => b.Id == id);
if (bank == null)
{
return NotFound();
}

bankAccount.Bank = bank;
return Created(bankAccount);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
// </copyright>
//------------------------------------------------------------------------------

using Microsoft.OData.Client.E2E.Tests.Common.Server.EndToEnd;
using Microsoft.OData.Edm;
using Microsoft.OData.ModelBuilder;

Expand Down Expand Up @@ -37,6 +38,8 @@ public static IEdmModel GetEdmModel()
builder.EntitySet<StoredPI>("StoredPIs");
builder.EntitySet<Subscription>("SubscriptionTemplates");
builder.Singleton<StoredPI>("DefaultStoredPI");
builder.EntitySet<Bank>("Banks");
DButoyez marked this conversation as resolved.
Show resolved Hide resolved
builder.EntitySet<BankAccount>("BankAccounts");

builder.EntityType<Product>()
.Action("AddAccessRight")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -396,4 +396,22 @@ public class ComplexWithAllPrimitiveTypes
public GeographyPoint? GeographyPoint { get; set; }
public GeometryPoint? GeometryPoint { get; set; }
}

[Key("Id")]
public class Bank
{
public int Id { get; set; }
public string Name { get; set; }
public string Location { get; set; }
public ICollection<BankAccount> BankAccounts { get; set; }
}

[Key("Id")]
public class BankAccount
{
public int Id { get; set; }
public string AccountNumber { get; set; }
public int BankId { get; set; }
public Bank Bank { get; set; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ private void InitializeData()
PopulatePerson_PersonMetadata();
PopulateEmployee_Manager();
PopulateSpecialEmployee_Car();
PopulateBank();
}

private void ResetData()
Expand Down Expand Up @@ -124,6 +125,31 @@ private void ResetData()
public IList<Driver>? Drivers { get; private set; }
public IList<License>? Licenses { get; private set; }
public IList<PersonMetadata>? PersonMetadata { get; private set; }
public IList<Bank>? Banks { get; private set; }
public IList<BankAccount>? BankAccounts { get; private set; }

private void PopulateBank()
{
this.Banks =
[
new (){
Id = 300,
Name = "ICM",
Location = "KE",
BankAccounts = new List<BankAccount>()
}
];

}

private void PopulateBankAccount()
{
this.AddBankAccountToBank(300, new BankAccount()
{
AccountNumber = "2002",
BankId = 300
});
}

private void PopulateAllTypesSet()
{
Expand Down Expand Up @@ -8413,6 +8439,23 @@ private void AddLoginOrderReference(string username, params int[] orderIds)
}
}

private void AddBankAccountToBank(int bankId, params BankAccount[] bankAccounts)
{
var bank = this.Banks.FirstOrDefault(b => b.Id == bankId);

if (bank != null)
{
foreach (var bankAccount in bankAccounts)
{
if (bankAccount != null)
{
bankAccount.Bank = bank;
bank.BankAccounts.Add(bankAccount);
}
}
}
}

private void AddMessageAttachmentReference(int messageId, params Guid[] attachmentIds)
{
var message = this.Messages.FirstOrDefault(m => m.MessageId == messageId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ public static IEdmModel GetEdmModel()
builder.EntitySet<License>("Licenses");
builder.EntitySet<MappedEntityType>("MappedEntityTypes");
builder.EntitySet<Car>("Cars");
builder.EntitySet<Bank>("Banks");
builder.EntitySet<BankAccount>("BankAccounts");

builder.Action("RetrieveProduct")
.Returns<int>();
Expand Down