当尝试通过实体框架更新数据库对象时,对象已经存在错误
本文关键字:对象 错误 存在 数据库 更新 框架 实体 | 更新日期: 2023-09-27 18:08:45
我正在使用以下方法尝试使用实体框架更新对象:
public static void UpdateItem(Item updatedObject) {
using (var context = new DbContext())
{
context.MyObjectsPropertys.Attach(updatedObject);
context.Entry(updatedObject).State = EntityState.Modified;
context.SaveChanges();
}
}
我得到一个错误的附加:
An object with the same key already exists in the ObjectStateManager. The ObjectStateManager cannot track multiple objects with the same key.
如果我试图将Attach调用更改为Add调用(具有相同键的对象已经存在objectstatemanager),我得到:
Cannot insert duplicate key in object 'database.Table'. The duplicate key value is (AttributeValue). The statement has been terminated.
我发现了很多关于这个错误的问题,但是没有一个答案适用于我的情况:
我也试着删除"附加"语句,只是按照错误中使用相同键DbContext的多个对象所建议的状态更改,但这也不起作用。
对我来说最令人沮丧的是,这是成功更新解决方案中其他内容的完全相同的语句序列。
您必须检查上下文是否已经跟踪了具有相同键的实体,并修改该实体,而不是附加当前实体:
var trackedEntity = context.MyObjectsPropertys.Find(updatedObject.Id);
context.Entry(trackedEntity).CurrentValues.SetValues(updatedObject);
context.Entry(trackedEntity).State = EntityState.Modified;
context.SaveChanges();
您必须检索相同的对象,并且从那时起,所检索的对象被DataContext对象跟踪。添加键肯定会报错,因为键显然存在于字典中。
我认为您可以使用context.ChangeTracker.Entries()
检索本地实体,然后查找相同的键,如果存在
我是这样处理的:
public virtual void Update(TEntity entityToUpdate)
{
if (_db.Entry(entityToUpdate).State == EntityState.Added)
return; // just been added leave state as added
try
{
_dbSet.Attach(entityToUpdate);
}
catch (InvalidOperationException ex)
{
var trackedEntity = _dbSet.Find(GetKeyValues(entityToUpdate));
if (trackedEntity == null)
throw;
if (_db.Entry(trackedEntity).State != EntityState.Unchanged)
throw;
_db.Entry(trackedEntity).State = EntityState.Detached;
_dbSet.Attach(entityToUpdate);
}
_db.Entry(entityToUpdate).State = EntityState.Modified;
}
public object[] GetKeyValues(TEntity entity)
{
var objectContextAdapter = ((IObjectContextAdapter)_db);
var name = typeof(TEntity).Name;
var entityKey = objectContextAdapter.ObjectContext.CreateEntityKey(name, entity);
var result = entityKey.EntityKeyValues.Select(kv => kv.Value).ToArray();
return result;
}