`在尝试更新EF中的类和通用存储库时,附加类型的实体失败...`异常

时间:2015-05-20 06:10:58

标签: c# entity-framework ef-code-first entity-framework-6

我正在使用实体框架。我想加载一个实体,编辑它,然后将更改保存回DB中。但无论我是否编辑了外键属性或简单属性,EF都会给我以下错误:

  

附加类型' ClassX'的实体失败,因为同一类型的另一个实体已具有相同的主键值。使用'附加'方法或将实体的状态设置为“未更改”#39;或者'修改'如果图中的任何实体具有冲突的键值。这可能是因为某些实体是新的并且尚未收到数据库生成的键值。在这种情况下,请使用'添加'方法或“添加”#39;实体状态跟踪图形,然后将非新实体的状态设置为“未更改”。或者'修改'酌情。

请注意,ClassX不是我尝试更新的类的直接虚拟属性,而是在我的类具有导航属性的某些其他类中的虚拟属性他们。

我已阅读some related个问题。但我并没有真正理解我应该如何将它们应用到我自己的问题上,因为我使用的是下面发布的通用存储库。

public class GenericRepository<T>  where T : class
{
    private EFDbContext context = new EFDbContext();
    public IEnumerable<T> GetAll()
    {
        return context.Set<T>();
    }
    public void Insert(T entity)
    {
        context.Set<T>().Add(entity);
        context.SaveChanges();
    }
    public void Update(T entity)
    {
        context.Entry(entity).State = System.Data.Entity.EntityState.Modified;
        context.SaveChanges();
    }
 //removed for brevity
}

我遇到了与虚拟属性相关的another problem,我被建议使用ViewModels和对象到对象的映射。

据我所知,有3种选择:

  1. 使用ViewModels和对象到对象的映射。我不会选择这个,因为o2o映射库有很多错误,所以真的很痛苦。
  2. 以某种方式使用reference。但我无法做到这一点,因为存储库是通用的。也许我应该使用反射API?
  3. 删除所有虚拟属性。这实际上是一种选择,因为他们创造的问题比他们解决的更多。
  4. 任何人都可以解释为什么会出现这个问题,以及解决问题的最简单方法是什么?

1 个答案:

答案 0 :(得分:4)

当您将实体的State设置为Modified时,它还会将所有子项(导航属性引用的实体)与State == EntityState.Unchanged相关联。如果您的上下文已经包含具有相同键的实体,则会引发该错误。

如果您希望忽略这些实体,我可以想到几个选项:

  1. Update内创建新的数据上下文,并且不要担心子实体,因为EntityState.Unchanged,当您致电SaveChanges时,他们会被忽略。如果您使用某种存储库模式,这可能没有意义。
  2. 在设置null
  3. 之前,浏览您不想附加并设置为State = EntityState.Modified的导航属性
  4. 设置State = EntityState.Modified后,对于您要忽略的子实体,请设置State = EntityState.Detached
  5. 修改

    最好弄清楚为什么上下文最终将会有多个具有相同密钥的子实体。