:使用原始答案Find代替Local.SingleOrDefault。它与@Juan的Save方法结合使用,但是可能导致对数据库的不必要查询,并且else部分可能从未执行(执行else部分会导致异常,因为Find已查询数据库并且未找到实体,因此无法更新该实体)。感谢@BenSwayne找到问题。
您必须检查上下文是否已跟踪具有相同键的实体,并修改该实体而不是附加当前实体:
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 keyif (attachedEntity != null) { var attachedEntry = _context.Entry(attachedEntity); attachedEntry.CurrentValues.SetValues(entity);} else { entry.State = EntityState.Modified; // This should attach entity} }}
如您所见,主要问题是SingleOrDefault方法需要知道查找实体的键。您可以创建暴露密钥的简单界面(IEntity在我的示例中),并在要处理的所有实体中实现它。
解决方法尝试将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上的许多建议,但没有提出任何解决方案。任何变通办法将不胜感激。
谢谢!