更改跟踪器不会为新插入的实体分配正确的后续ID

时间:2017-09-02 22:10:50

标签: c# entity-framework asp.net-core .net-core entity-framework-core

我从webapi模板创建了一个新的.NET Core项目,并添加了一个模型类:

public class Todo {
    public int Id { get; set; }
    public string Name { get; set; }
}

我的上下文类:

public SoContext: DbContext {
    public SoContext(DbContextOptions<SoContext> options) { base(options); }
    public DbSet<Todo> Todos { get; set; }
}

我已经注册了这样的上下文:

public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContext<SoContext>(opt => opt.UseInMemoryDatabase("SO"));
    services.AddMvc();
}

我以为我会像这样播种上下文:

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!
}

它可以正常工作......但是然后在我的请求处理程序中,或者直接在Configure之后,当我运行它时:

context.Todos.Add(new Todo() { Name = "non-seed" });
context.SaveChanges(); // Uh - oh

我明白了:

  

无法跟踪实体类型“Todo”的实例,因为已经跟踪了具有键值的另一个实例。附加现有实体时,请确保仅附加一个具有给定键值的实体实例。

我看到更改跟踪器的方式应该已经考虑将2的ID分配给non-seed Todo,不是吗?为什么不是这样呢?

我尝试使用Attach而不是使用密钥为实体添加,即使它没有任何意义,并且确定它没有任何区别。

Here's a GitHub repository that demonstrates the problem

1 个答案:

答案 0 :(得分:2)

我在comment in the GitHub repository for EntityFrameworkCore中找到了这个问题的答案。

  

当使用数据库生成的密钥与应用程序选择的密钥同时,应用程序有责任不选择与数据库生成的密钥冲突的密钥。

这意味着,目前,数据库是使用缺少密钥的实体播种的(因此需要使用导航属性而不是ID来设置任何关系)或使用原始SQL并让FE接收已经播种的数据库(谢谢@Nicolaus - 虽然这不适用于内存我认为。)

  

我们可以使内存数据库中的密钥生成器变得更加智能,因此请将其打开以进行分类讨论,但我认为即使我们决定这样做,也可能是低优先级。