Cannot update the 1-m property out of DbContext
See original GitHub issueI found an issue that EF Core cannot update an entity with a 1-m property if we update it out of DbContext, for example, I have two models Group
and GroupItem
, the Group
has a set of GroupItems
and every GroupItem
belongs to one Group
. In this case, if we updated a Group
’s GroupItems
out of DbContext, then DbContext cannot save the changes.
Attempted to update or delete an entity that does not exist in the store.
I think the exception means my GroupItem
use a compiste key and which is changed so that EF Core cannot find any entity in the database, however, EF Core should support this situation as the code has a exact purpose, It’s obvious in below code that I want to update the Group(G-001)'s Items to value-1
and value-4
.
// EFCoreTest.csproj
//<Project Sdk = "Microsoft.NET.Sdk" >
// <PropertyGroup>
// <TargetFramework>netcoreapp2.0</TargetFramework>
// <IsPackable>false</IsPackable>
// </PropertyGroup>
// <ItemGroup>
// <PackageReference Include = "Microsoft.EntityFrameworkCore" Version="2.0.0" />
// <PackageReference Include = "Microsoft.EntityFrameworkCore.InMemory" Version="2.0.0" />
// <PackageReference Include = "Microsoft.EntityFrameworkCore.Sqlite" Version="2.0.0" />
// <PackageReference Include = "Microsoft.Extensions.Logging.Debug" Version="2.0.0" />
// <PackageReference Include = "Microsoft.NET.Test.Sdk" Version="15.3.0" />
// <PackageReference Include = "xunit" Version="2.3.0" />
// <PackageReference Include = "xunit.runner.visualstudio" Version="2.3.0" />
// </ItemGroup>
//</Project>
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Xunit;
namespace EFCoreTest
{
internal class Group
{
public string Id { get; set; }
public string Name { get; set; }
public List<GroupItem> Items { get; set; }
}
internal class GroupItem
{
public string GroupId { get; set; }
public string ItemValue { get; set; }
}
internal class EfContext : DbContext
{
public EfContext(DbContextOptions options) : base(options) { }
public DbSet<Group> Groups { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<GroupItem>().HasKey(x => new { x.GroupId, x.ItemValue });
modelBuilder.Entity<Group>().HasKey(x => x.Id);
modelBuilder.Entity<Group>().HasMany(x => x.Items).WithOne().HasForeignKey(t => t.GroupId).IsRequired();
}
}
internal static class MockContext
{
private static readonly ILoggerFactory DebugLogFactory = new LoggerFactory().AddDebug();
public static EfContext UseInMemory(string databaseName = null)
{
var options = new DbContextOptionsBuilder<EfContext>()
.UseInMemoryDatabase(databaseName ?? Guid.NewGuid().ToString())
.UseLoggerFactory(DebugLogFactory)
.Options;
return new EfContext(options);
}
}
public class UnitTest
{
[Fact]
public async Task UpdateOutOfContextTest()
{
var group = new Group
{
Id = "G-001",
Name = "group name",
Items = new List<GroupItem> {
new GroupItem{ GroupId="G-001", ItemValue="value-1"},
new GroupItem{ GroupId="G-001", ItemValue="value-2"},
new GroupItem{ GroupId="G-001", ItemValue="value-3"}
}
};
using (var ctx = MockContext.UseInMemory("UpdateTest"))
{
ctx.Groups.Add(group);
await ctx.SaveChangesAsync();
}
// Update out of DbContext scope
group.Name = "group name updated";
group.Items = new List<GroupItem> {
new GroupItem{ GroupId="G-001", ItemValue="value-1"},
new GroupItem{ GroupId="G-001", ItemValue="value-4"}
};
using (var ctx = MockContext.UseInMemory("UpdateTest"))
{
ctx.Groups.Update(group);
await ctx.SaveChangesAsync(); // Throw the exception below
var g = await ctx.Groups.Include(x => x.Items).SingleAsync(x => x.Id == "G-001");
Assert.Equal("group name updated", g.Name);
Assert.Equal(new[] { "value-1", "value-4" }, g.Items.Select(x => x.ItemValue).ToArray());
}
}
}
}
Message: Microsoft.EntityFrameworkCore.DbUpdateConcurrencyException :
Attempted to update or delete an entity that does not exist in the store.
Test Name: EFCoreTest.UnitTest.UpdateOutOfContextTest
Test FullName: EFCoreTest.UnitTest.UpdateOutOfContextTest
Test Source: C:\Codes\Learn2017\EFCoreTest\UnitTest.cs : line 77
Test Outcome: Failed
Test Duration: 0:00:00.156
Result StackTrace:
at Microsoft.EntityFrameworkCore.Storage.Internal.InMemoryTable`1.Update(IUpdateEntry entry)
at Microsoft.EntityFrameworkCore.Storage.Internal.InMemoryStore.ExecuteTransaction(IEnumerable`1 entries, IDiagnosticsLogger`1 updateLogger)
at Microsoft.EntityFrameworkCore.Storage.Internal.InMemoryDatabase.SaveChangesAsync(IReadOnlyList`1 entries, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.<SaveChangesAsync>d__61.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
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__59.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
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__48.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
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 EFCoreTest.UnitTest.<UpdateOutOfContextTest>d__0.MoveNext() in C:\Codes\Learn2017\EFCoreTest\UnitTest.cs:line 103
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
Result Message: Microsoft.EntityFrameworkCore.DbUpdateConcurrencyException : Attempted to update or delete an entity that does not exist in the store.
Further technical details
EF Core version: 2.0 Database Provider: Microsoft.EntityFrameworkCore.InMemory Operating system: Windows 10 Pro N 1709 IDE: Visual Studio Community 2017 Version 15.4.1
Issue Analytics
- State:
- Created 6 years ago
- Comments:10 (1 by maintainers)
In my case I was getting the exception discussed in this thread (first result in Google search) and I fixed it by changing this:
to this:
Which I am totally OK with. 😁
Sometimes
Attempted to update or delete an entity that does not exist in the store.
exception is raised when your DB scheme is not up to date. Make sure the database scheme is consistent with your entities.