尝试使用通用存储库更新 EF 中的类时出现“附加类型的实体失败...”异常

Akb*_*ari 2 c# entity-framework ef-code-first entity-framework-6

我正在使用实体框架。我想加载一个实体,对其进行编辑,然后将更改保存回数据库中。但无论我编辑的是外键属性还是简单属性,EF 都会给出以下错误:

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

请注意,这ClassX不是我要更新的类的直接虚拟属性,而是我的类具有导航属性的其他一些类中的虚拟属性。

我读过一些 相关问题。但我真的不知道应该如何将它们应用到我自己的问题上,因为我使用的是下面发布的通用存储库。

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
}
Run Code Online (Sandbox Code Playgroud)

我遇到了另一个与虚拟属性相关的问题,建议我使用ViewModels对象到对象映射。

据我所知,有3个选择:

  1. 使用ViewModels对象到对象的映射。我不会选择这个,这真的很痛苦,因为 O2O 映射库有很多错误。
  2. 以某种方式使用reference. 但我不能这样做,因为存储库是通用的。也许我应该使用反射 API 来实现这一点?
  3. 删除所有虚拟属性。这实际上是一种选择,因为他们制造的问题比解决的问题还要多。

谁能解释一下为什么会出现这个问题以及解决它的最简单方法是什么?

jjj*_*jjj 5

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

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

  1. 在 中创建一个新的数据上下文Update,并且不用担心子实体EntityState.Unchanged,因为当您调用 时SaveChanges,它们将被忽略。如果您使用某种存储库模式,这可能没有意义。
  2. null在设置之前检查您不想附加和设置的导航属性State = EntityState.Modified
  3. 设置后State = EntityState.Modified,对于要忽略的子实体,设置State = EntityState.Detached

编辑

首先弄清楚为什么上下文最终会出现多个具有相同键的子实体也很好。