'附加类型的实体失败…在尝试更新EF中的类并使用通用存储库时,会出现` `异常

本文关键字:存储 异常 EF 类型 实体 失败 更新 | 更新日期: 2023-09-27 17:50:00

我使用实体框架。我想加载一个实体,编辑它,并将更改保存回数据库中。但是,无论我编辑了外键属性还是简单属性,EF都会给我以下错误:

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

请注意,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
}

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

就我所知,有3个选项:

  1. 使用ViewModels和对象到对象映射。我不打算用这个,它真的很痛苦,因为o2o地图库有很多bug。
  2. 以某种方式使用reference。但我不能这样做,因为存储库是通用的。也许我应该使用反射API ?
  3. 删除所有虚拟属性。这实际上是一种选择,因为他们制造的问题比他们解决的要多。
谁能解释一下为什么会出现这个问题,最简单的解决方法是什么?

'附加类型的实体失败…在尝试更新EF中的类并使用通用存储库时,会出现` `异常

当你将一个实体的State设置为Modified时,它也会将State == EntityState.Unchanged附加到所有子实体(由导航属性引用的实体)。如果你的上下文已经有具有相同键的实体,它将抛出该错误。

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

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

编辑

还可以弄清楚为什么上下文首先会有多个具有相同键的子实体。