使用带有通用存储库模式的EF5和9对象进行依赖约束,并在试图使用我的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;
}当它命中附加和EntityState.Modified时,它会发出错误:
-- ObjectStateManager中已经存在具有相同键的对象。ObjectStateManager无法用相同的键跟踪多个对象。
我在堆栈和互联网上查阅了许多建议,但没有想出任何解决办法。任何工作都将不胜感激。
谢谢!
发布于 2012-09-25 17:03:15
编辑:最初的答案使用Find而不是Local.SingleOrDefault。它与@Juan的Save方法结合使用,但它可能会导致对数据库的不必要查询,并且可能从未执行过else部件(执行never部件将导致异常,因为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 key
if (attachedEntity != null) {
var attachedEntry = _context.Entry(attachedEntity);
attachedEntry.CurrentValues.SetValues(entity);
} else {
entry.State = EntityState.Modified; // This should attach entity
}
}
} 如您所见,主要问题是SingleOrDefault方法需要知道查找实体的键。您可以创建公开密钥的简单接口(在我的示例中是IEntity),并在您希望以这种方式处理的所有实体中实现它。
发布于 2014-02-28 12:22:30
我不想通过添加接口或属性来污染自动生成的EF类。因此,这确实有点来自上述的一些答案(所以功劳归于Ladislav )。这为我提供了一个简单的解决方案。
我向update方法添加了一个func,该方法找到了实体的整数键。
public void Update(TEntity entity, Func<TEntity, int> getKey)
{
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.Find.(getKey(entity));
if (attachedEntity != null) {
var attachedEntry = _context.Entry(attachedEntity);
attachedEntry.CurrentValues.SetValues(entity);
} else {
entry.State = EntityState.Modified; // This should attach entity
}
}
} 然后当你调用你的代码时,你可以使用..。
repository.Update(entity, key => key.myId);发布于 2013-02-20 07:18:01
您实际上可以通过反射返回Id,参见下面的示例:
var entry = _dbContext.Entry<T>(entity);
// Retreive the Id through reflection
var pkey = _dbset.Create().GetType().GetProperty("Id").GetValue(entity);
if (entry.State == EntityState.Detached)
{
var set = _dbContext.Set<T>();
T attachedEntity = set.Find(pkey); // access the key
if (attachedEntity != null)
{
var attachedEntry = _dbContext.Entry(attachedEntity);
attachedEntry.CurrentValues.SetValues(entity);
}
else
{
entry.State = EntityState.Modified; // attach the entity
}
}https://stackoverflow.com/questions/12585664
复制相似问题