为什么Entity Framework会尝试插入现有实体?

时间:2018-03-31 13:16:13

标签: c# entity-framework ef-code-first data-annotations navigation-properties

我正在使用Entity Framework(使用代码优先方法),并使用预期的外键和唯一键约束成功创建数据库。

我有两个模型类:

public class Foo 
{
    [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public Guid Id { get; set; }

    public Bar Bar { get; set; } 
}

public class Bar
{
    [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public Guid Id { get; set; }

    [Index(IsUnique = true), StringLength(512)]
    public string Url { get; set; }
}

这个应用程序代码:

var foo = GetData();

using (DatabaseContext db = new DatabaseContext())
{
    db.Entry(foo).State = EntityState.Added;

    if (foo.Bar != null)
    {
        var bar = await db.Bar.FirstOrDefaultAsync(x => x.Url == foo.Bar.Url);

        if (bar != null)
        {
            // When I assign an existing entity ...
            foo.Bar = bar;
        }
    }

    // ... following exception will be thrown.
    await db.SaveChangesAsync();
}
  

SqlException :无法在对象' dbo.Bar'中插入重复的键行。具有唯一索引' IX_Url'重复键值为(https://api.example.com/rest/v1.0/bar/FD6FAB72-DCE2-47DB-885A-424F3D4A70B6)。   声明已经终止。

我不明白为什么Entity Framework尝试添加导航属性Bar,即使在从同一DbContext获取并分配它之后也是如此。类似的StackOverflow问题尚未提供任何有效的解决方案。

请告诉我是否需要提供其他信息。

我是否忘记设置任何EF相关配置或类似的东西?提前谢谢!

1 个答案:

答案 0 :(得分:4)

这是因为

db.Entry(foo).State = EntityState.Added;

foo.Bar(以及未被上下文跟踪的任何引用实体)标记为Added

您应该在添加Foo实体之前解析引用的实体:

var foo = GetData();
using (DatabaseContext db = new DatabaseContext())
{
    // Resolve references
    if (foo.Bar != null)
    {
        var bar = await db.Bar.FirstOrDefaultAsync(x => x.Url == foo.Bar.Url);
        if (bar != null)
            foo.Bar = bar;
    }
    // Then add the entity
    db.Entry(foo).State = EntityState.Added;

    await db.SaveChangesAsync();
}