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

Fixing when to add DependsOnIds. Fixes #3150 #3153

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
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
5 changes: 5 additions & 0 deletions src/Microsoft.OData.Client/BaseSaveResult.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1047,6 +1047,7 @@ private static void HandleResponsePost(LinkDescriptor linkDescriptor)
Error.ThrowBatchUnexpectedContent(InternalError.LinkNotAddedState);
}

linkDescriptor.DependsOnIds = null;
linkDescriptor.State = EntityStates.Unchanged;
}

Expand Down Expand Up @@ -1226,6 +1227,7 @@ private void HandleResponsePost(EntityDescriptor entityDescriptor, string etag)
{
entityDescriptor.ETag = etag;
entityDescriptor.State = EntityStates.Unchanged;
entityDescriptor.DependsOnIds = null;
entityDescriptor.PropertiesToSerialize.Clear();
}

Expand Down Expand Up @@ -1297,6 +1299,7 @@ private void HandleResponsePut(Descriptor descriptor, HeaderCollection responseH
Debug.Assert(entityDescriptor.State == EntityStates.Modified, "descriptor.State == EntityStates.Modified");
entityDescriptor.ETag = etag;
entityDescriptor.State = EntityStates.Unchanged;
entityDescriptor.DependsOnIds = null;
entityDescriptor.PropertiesToSerialize.Clear();
}
}
Expand All @@ -1306,6 +1309,7 @@ private void HandleResponsePut(Descriptor descriptor, HeaderCollection responseH
if ((EntityStates.Added == descriptor.State) || (EntityStates.Modified == descriptor.State))
{
descriptor.State = EntityStates.Unchanged;
descriptor.DependsOnIds = null;
}
else if (EntityStates.Detached != descriptor.State)
{ // this link may have been previously detached by a detaching entity
Expand All @@ -1317,6 +1321,7 @@ private void HandleResponsePut(Descriptor descriptor, HeaderCollection responseH
Debug.Assert(descriptor.DescriptorKind == DescriptorKind.NamedStream, "it must be named stream");
Debug.Assert(descriptor.State == EntityStates.Modified, "named stream must only be in modified state");
descriptor.State = EntityStates.Unchanged;
descriptor.DependsOnIds = null;

StreamDescriptor streamDescriptor = (StreamDescriptor)descriptor;

Expand Down
20 changes: 17 additions & 3 deletions src/Microsoft.OData.Client/DataServiceContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2491,6 +2491,11 @@ public virtual void SetLink(object source, string sourceProperty, object target)
if (relation == null)
{
relation = new LinkDescriptor(source, sourceProperty, target, this.model);
EntityDescriptor sourceResource = this.entityTracker.GetEntityDescriptor(source);
if (sourceResource.State == EntityStates.Added)
{
relation.DependsOnIds = new List<string> { sourceResource.ChangeOrder.ToString(CultureInfo.InvariantCulture) };
}
this.entityTracker.AddLink(relation);
}

Expand Down Expand Up @@ -2633,10 +2638,14 @@ public virtual void AddRelatedObject(object source, string sourceProperty, objec
var targetResource = new EntityDescriptor(this.model)
{
Entity = target,
State = EntityStates.Added,
DependsOnIds = new List<string> { sourceResource.ChangeOrder.ToString(CultureInfo.InvariantCulture) }
State = EntityStates.Added
};

if (sourceResource.State == EntityStates.Added)
{
targetResource.DependsOnIds = new List<string> { sourceResource.ChangeOrder.ToString(CultureInfo.InvariantCulture) };
}

targetResource.SetParentForInsert(sourceResource, sourceProperty);

this.EntityTracker.AddEntityDescriptor(targetResource);
Expand Down Expand Up @@ -2884,8 +2893,12 @@ public virtual void UpdateRelatedObject(object source, string sourceProperty, ob
{
Entity = target,
State = EntityStates.Modified,
EditLink = sourceResource.GetNestedResourceInfo(this.baseUriResolver, property)
EditLink = sourceResource.GetNestedResourceInfo(this.baseUriResolver, property)
};
if (sourceResource.State == EntityStates.Added)
{
targetResource.DependsOnIds = new List<string> { sourceResource.ChangeOrder.ToString(CultureInfo.InvariantCulture) };
}

targetResource.SetParentForUpdate(sourceResource, sourceProperty);
this.EntityTracker.AddEntityDescriptor(targetResource);
Expand Down Expand Up @@ -4313,6 +4326,7 @@ private void SetStateToUnchanged(object entity)
}

descriptor.State = EntityStates.Unchanged;
descriptor.DependsOnIds = null;
}

/// <summary>
Expand Down
1 change: 1 addition & 0 deletions src/Microsoft.OData.Client/ObjectMaterializerLog.cs
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@ internal void ApplyToContext()
{
// we should always reset descriptor's state to Unchanged (old v1 behavior)
descriptor.State = EntityStates.Unchanged;
descriptor.DependsOnIds = null;
descriptor.PropertiesToSerialize.Clear();
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public class TestsStartup : TestStartupBase
{
public override void ConfigureServices(IServiceCollection services)
{
services.ConfigureControllers(typeof(BanksController), typeof(MetadataController));
services.ConfigureControllers(typeof(BanksController), typeof(BankAccountsController), typeof(MetadataController));
services.AddControllers().AddOData(opt => opt.Count().Filter().Expand().Select().OrderBy().SetMaxTop(null)
.AddRouteComponents("odata", CommonEndToEndEdmModel.GetEdmModel(), new DefaultODataBatchHandler()));
}
Expand Down Expand Up @@ -86,6 +86,98 @@ public async Task JsonBatchSequencingSingeChangeSetTest()
Assert.Equal(201, bankResponse.StatusCode);
Assert.Equal(201, bankAccountResponse.StatusCode);
}

[Fact]
// Validating regression reported here: https://github.com/OData/odata.net/issues/3150
public async Task BatchSequencingSingleChangeSetWithRelatedAlone()
{
// Create new Bank object
var bank = new Bank
{
Id = 45,
Name = "Test Bank",
Location = "KE",
BankAccounts = new List<BankAccount>()
};

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

// Save bank
var response = await _context.SaveChangesAsync();
Assert.Equal(1, response.Count());

var bankResponse = response.First() as ChangeOperationResponse;
Assert.NotNull(bankResponse);
Assert.Equal(201, bankResponse.StatusCode);

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

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

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

// Save bankAccount in a single batch request.
response = await _context.SaveChangesAsync(SaveChangesOptions.BatchWithSingleChangeset);
Assert.Equal(1, response.Count());

var bankAccountResponse = response.Last() as ChangeOperationResponse;
Assert.NotNull(bankAccountResponse);
Assert.Equal(201, bankAccountResponse.StatusCode);
}

[Fact]
public async Task JsonBatchSequencingSingeChangeSetTest_SetLink()
{
// 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,
};

// Add the Bank and Account entities to the context
_context.AddObject("Banks", bank);
_context.AddObject("BankAccounts", bankAccount);

// Set the link from BankAccount to Bank entity
_context.SetLink(bankAccount, "Bank", bank);

// Save both entities in a single batch request using JSON
var response = await _context.SaveChangesAsync(SaveChangesOptions.BatchWithSingleChangeset | SaveChangesOptions.UseJsonBatch);
Assert.Equal(3, response.Count()); // We get 2 POST's and a PUT for the link

var bankResponse = response.ElementAt(0) as ChangeOperationResponse;
var bankAccountResponse = response.ElementAt(1) as ChangeOperationResponse;
var bankAccountBankResponse = response.ElementAt(2) as ChangeOperationResponse;

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

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

class Container : DataServiceContext
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
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;
using System;
using System.Collections.Generic;
using System.Data.Common;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Microsoft.OData.Client.E2E.Tests.Batch.Server
{
internal class BankAccountsController : ODataController
{
// POST: odata/Banks
[EnableQuery]
[HttpPost("odata/BankAccounts")]
public IActionResult Post([FromBody] BankAccount bankAccount)
{
if (bankAccount == null)
{
return BadRequest();
}
BanksController._dataSource.BankAccounts.Add(bankAccount);
return Created(bankAccount);
}

// PUT: /odata/$1/Bank
[EnableQuery]
[HttpPut("odata/BankAccounts({id})/Bank/$ref")]
public IActionResult PutBankAccountBank([FromODataUri] int id, [FromBody] Bank bank)
{
if (bank == null)
{
return BadRequest();
}
BankAccount bankAccount = BanksController._dataSource.BankAccounts.First();
bankAccount.Bank = bank;
return Updated(bankAccount);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ namespace Microsoft.OData.Client.E2E.Tests.Batch.Server
{
public class BanksController : ODataController
{
private static CommonEndToEndDataSource _dataSource = CommonEndToEndDataSource.CreateInstance();
internal static CommonEndToEndDataSource _dataSource = CommonEndToEndDataSource.CreateInstance();

[EnableQuery]
[HttpGet("odata/Banks")]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ private void PopulateBank()
}
];

this.BankAccounts = new List<BankAccount>();
}

private void PopulateBankAccount()
Expand Down