我正在使用实体框架。我想加载一个实体,编辑它,然后将更改保存回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种选择:
ViewModels
和对象到对象的映射。我不会选择这个,因为o2o映射库有很多错误,所以真的很痛苦。reference
。但我无法做到这一点,因为存储库是通用的。也许我应该使用反射API?任何人都可以解释为什么会出现这个问题,以及解决问题的最简单方法是什么?
答案 0 :(得分:4)
当您将实体的State
设置为Modified
时,它还会将所有子项(导航属性引用的实体)与State == EntityState.Unchanged
相关联。如果您的上下文已经包含具有相同键的实体,则会引发该错误。
如果您希望忽略这些实体,我可以想到几个选项:
Update
内创建新的数据上下文,并且不要担心子实体,因为EntityState.Unchanged
,当您致电SaveChanges
时,他们会被忽略。如果您使用某种存储库模式,这可能没有意义。null
State = EntityState.Modified
的导航属性
State = EntityState.Modified
后,对于您要忽略的子实体,请设置State = EntityState.Detached
修改强>
最好弄清楚为什么上下文最终将会有多个具有相同密钥的子实体。