I have created a new .NET Core project from the webapi
template and added a model class:
public class Todo {
public int Id { get; set; }
public string Name { get; set; }
}
My context class:
public SoContext: DbContext {
public SoContext(DbContextOptions<SoContext> options) { base(options); }
public DbSet<Todo> Todos { get; set; }
}
I have registered the context like this:
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<SoContext>(opt => opt.UseInMemoryDatabase("SO"));
services.AddMvc();
}
I thought I'd seed the context like this:
public void Configure(IApplicationBuilder app, IHostingEnvironment env, SoContext context)
{
app.UseMvc();
context.Todos.Add(new Todo() { Id = 1, Name = "1" });
context.SaveChanges(); // This works okay!
}
And it works okay… But then in my request handler, or even directly after in Configure
, when I run this:
context.Todos.Add(new Todo() { Name = "non-seed" });
context.SaveChanges(); // Uh - oh
I get:
The instance of entity type 'Todo' cannot be tracked because another instance with the key value is already being tracked. When attaching existing entities, ensure that only one entity instance with a given key value is attached.
The way I see it the change tracker should have figured out to assign the ID of 2
to the non-seed
Todo
, no? Why isn't it so?
I tried to use Attach
instead of add for the entity with the key, even though it doesn't make any sense, and sure enough it made no difference.
UPDATE: This now works in .NET Core 3.0! You can see a showcase here.
I got an answer to this question in a comment in the GitHub repository for EntityFrameworkCore
.
When using database-generated keys at the same time as keys chosen by the application it is the responsibility of the application to not choose keys that collide with those generated by the database.
This means that at the moment, either the database is seeded with entities lacking keys (so any relationships need to be set up using navigation properties rather than the IDs) or using raw SQL and letting FE pick up on an already seeded database (thanks, @Nicolaus - although this won't work for in-memory I think).
We could make the key generator in the in-memory database smarter, so leaving this open to discuss in triage, but I think even if we decide to do so, it will likely be low priority.