我从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
而不是使用密钥为实体添加,即使它没有任何意义,并且确定它没有任何区别。
答案 0 :(得分:2)
我在comment in the GitHub repository for EntityFrameworkCore
中找到了这个问题的答案。
当使用数据库生成的密钥与应用程序选择的密钥同时,应用程序有责任不选择与数据库生成的密钥冲突的密钥。
这意味着,目前,数据库是使用缺少密钥的实体播种的(因此需要使用导航属性而不是ID来设置任何关系)或使用原始SQL并让FE接收已经播种的数据库(谢谢@Nicolaus - 虽然这不适用于内存我认为。)
我们可以使内存数据库中的密钥生成器变得更加智能,因此请将其打开以进行分类讨论,但我认为即使我们决定这样做,也可能是低优先级。