You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
We've found a strange behavior while unit testing some code which saves related data as shown here: Saving Related Data. The principal entity holds a list of dependents, just like in the docs example.
I have this sample code for inserting one work item along with one comment:
varworkItem=new WorkItem
{Id= Guid.NewGuid(),Title="Some work item"};// Save the workItem first
wiContext.WorkItems.Add(workItem);await wiContext.SaveChangesAsync();varcomment=new WorkItemComment
{Id= Guid.NewGuid(),Comment="Some comment"};// Add the comment to the saved comment instance
workItem.Comments.Add(comment);// State is unchangedvarworkItemState= wiContext.Entry(workItem).State;// PROBLEM: The comment has a state of Modified.varstate2= wiContext.Entry(comment).State;// Call fails with UPDATE comment instead of insertawait wiContext.SaveChangesAsync();
Odd, but okay. I then tried doing this: (simulated disconnected scenario)
varworkItem=new WorkItem
{Id= Guid.NewGuid(),Title="Some work item"};// Save the workItem first with the passed in DbContext// Like a request to an endpoint "CreateWorkItem"
wiContext.WorkItems.Add(workItem);await wiContext.SaveChangesAsync();// simulates a "disconnected scenario" where I only want to add a comment// Like a request to an endpoint "AddComment"using(varnewContext=new WorkItemDbContext()){varexistingWorkItem=await newContext.WorkItems.Include(wi => wi.Comments).FirstAsync(wi => wi.Id == workItem.Id);varcomment=new WorkItemComment
{Id= Guid.NewGuid(),Comment="SOme comment",};
existingWorkItem.Comments.Add(comment);// State is "Unchanged"varworkItemState= newContext.Entry(existingWorkItem).State;// State is "Detached"varstate2= newContext.Entry(comment).State;// Fails as wellawait newContext.SaveChangesAsync();}
In both cases I get:
Microsoft.EntityFrameworkCore.DbUpdateConcurrencyException: 'Database operation expected to affect 1 row(s) but actually affected 0 row(s). Data may have been modified or deleted since entities were loaded. See http://go.microsoft.com/fwlink/?LinkId=527962 for information on understanding and handling optimistic concurrency exceptions.'
at Microsoft.EntityFrameworkCore.Update.AffectedCountModificationCommandBatch.ThrowAggregateUpdateConcurrencyException(Int32 commandIndex, Int32 expectedRowsAffected, Int32 rowsAffected)
at Microsoft.EntityFrameworkCore.Update.AffectedCountModificationCommandBatch.<ConsumeResultSetWithoutPropagationAsync>d__6.MoveNext()
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at Microsoft.EntityFrameworkCore.Update.AffectedCountModificationCommandBatch.<ConsumeAsync>d__2.MoveNext()
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.<ExecuteAsync>d__29.MoveNext()
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.<ExecuteAsync>d__29.MoveNext()
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.<ExecuteAsync>d__8.MoveNext()
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.<ExecuteAsync>d__8.MoveNext()
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.<SaveChangesAsync>d__97.MoveNext()
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.<SaveChangesAsync>d__101.MoveNext()
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerExecutionStrategy.<ExecuteAsync>d__7`2.MoveNext()
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
at Microsoft.EntityFrameworkCore.DbContext.<SaveChangesAsync>d__54.MoveNext()
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
at EFCore31.Program.<GenerateWorkItemWithComment3>d__3.MoveNext() in C:\github\efcore-childupdate-bugrepro\src\EFCore31\Program.cs:line 137
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
at EFCore31.Program.<Main>d__0.MoveNext() in C:\github\efcore-childupdate-bugrepro\src\EFCore31\Program.cs:line 23
The only way it works (generating the new insert) is if I do this:
varworkItem=new WorkItem
{Id= Guid.NewGuid(),Title="Some work item"};varcomment=new WorkItemComment
{Id= Guid.NewGuid(),Comment="Some comment",};
workItem.Comments.Add(comment);// Add workitem to DbSet with comments
wiContext.WorkItems.Add(workItem);// WORKS: Generates two insertsawait wiContext.SaveChangesAsync();
But of course, this is not great. The real scenario is more like having case1 or case2. Case 2 is even more real because it's the same as if I had two actions in a controller which handle both cases separately. Same as explained in the docs: Adding a related entity
It contains two console apps one using EF Core 2.2.6 and the other with EF Core 3.1.1. The code is the same. The 2.2.6 version works with 3 approaches above. The 3.1.1 just works with approach case 2
Further technical details
EF Core version: 3.1.1
Database provider: Microsoft.EntityFrameworkCore.SqlServer
Target framework: NET Core 3.1
Operating system: Windows 10 1903
IDE: Visual Studio 2019 16.4.2
The text was updated successfully, but these errors were encountered:
But then I changed the PostId to be of type Guid and when I do:
varpost=new Post
{PostId= Guid.NewGuid(),Title="Hello World",Content="I wrote an app using EF Core!"};
blog.Posts.Add(post);// *** State here is Modified instead of AddedvarpostState= db.Entry(post);
We've found a strange behavior while unit testing some code which saves related data as shown here: Saving Related Data. The principal entity holds a list of dependents, just like in the docs example.
Steps to reproduce
I have this sample code for inserting one work item along with one comment:
Odd, but okay. I then tried doing this: (simulated disconnected scenario)
In both cases I get:
The only way it works (generating the new insert) is if I do this:
But of course, this is not great. The real scenario is more like having case1 or case2. Case 2 is even more real because it's the same as if I had two actions in a controller which handle both cases separately. Same as explained in the docs: Adding a related entity
The same code works on EF Core 2.2.6.
I have created a repro here: https://github.com/joaopgrassi/efcore-childupdate-bugrepro
It contains two console apps one using EF Core 2.2.6 and the other with EF Core 3.1.1. The code is the same. The 2.2.6 version works with 3 approaches above. The 3.1.1 just works with approach case 2
Further technical details
EF Core version: 3.1.1
Database provider: Microsoft.EntityFrameworkCore.SqlServer
Target framework: NET Core 3.1
Operating system: Windows 10 1903
IDE: Visual Studio 2019 16.4.2
The text was updated successfully, but these errors were encountered: