尝试将EF5与通用存储库模式结合使用,并使用ninject进行依赖关系注入,并在尝试使用带有edmx的存储过程将实体更新到数据库时遇到问题。
我在DbContextRepository.cs中的更新是:
public override void Update(T entity) { if (entity == null) throw new ArgumentException("Cannot add a null entity."); var entry = _context.Entry<T>(entity); if (entry.State == EntityState.Detached) { _context.Set<T>().Attach(entity); entry.State = EntityState.Modified; } }
从我的AddressService.cs返回到我的存储库,我有:
public int Save(vw_address address) { if (address.address_pk == 0) { _repo.Insert(address); } else { _repo.Update(address); } _repo.SaveChanges(); return address.address_pk; }
当它遇到Attach和EntityState.Modified时,它会吐出错误:
具有相同键的对象已存在于ObjectStateManager中。 ObjectStateManager无法使用相同的键跟踪多个对象。
我浏览了堆栈中和Internet上的许多建议,但没有提出任何解决方案。任何变通办法将不胜感激。
谢谢!
编辑 :使用原始答案Find代替Local.SingleOrDefault。它与@Juan的Save方法结合使用,但是可能导致对数据库的不必要查询,并且else部分可能从未执行(执行else部分会导致异常,因为Find已查询数据库并且未找到实体,因此无法更新该实体) 。感谢@BenSwayne找到问题。
Find
Local.SingleOrDefault
Save
else
您必须检查上下文是否已跟踪具有相同键的实体,并修改该实体而不是附加当前实体:
public override void Update(T entity) where T : IEntity { if (entity == null) { throw new ArgumentException("Cannot add a null entity."); } var entry = _context.Entry<T>(entity); if (entry.State == EntityState.Detached) { var set = _context.Set<T>(); T attachedEntity = set.Local.SingleOrDefault(e => e.Id == entity.Id); // You need to have access to key if (attachedEntity != null) { var attachedEntry = _context.Entry(attachedEntity); attachedEntry.CurrentValues.SetValues(entity); } else { entry.State = EntityState.Modified; // This should attach entity } } }
如您所见,主要问题是SingleOrDefault方法需要知道查找实体的键。您可以创建暴露密钥的简单界面(IEntity在我的示例中),并在要处理的所有实体中实现它。
SingleOrDefault
IEntity