更新时间:2023-01-26 19:27:35
strong>编辑:使用原始答案查找
而不是 Local.SingleOrDefault
。它与@ Juan的 Save
方法结合使用,但可能会导致对数据库的不必要的查询,而 else
部分可能从未执行(执行else部分将导致异常,因为Find已经查询了数据库,并没有找到该实体,因此无法更新)。感谢@BenSwayne找到问题。
您必须检查具有相同密钥的实体是否已被上下文跟踪并修改该实体,而不是附加当前的实体:
public override void Update(T entity)其中T:IEntity {
if(entity == null){
throw new ArgumentException(Can not 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); //你需要访问key
if(attachedEntity!= null){
var attachEntry = _context.Entry(attachedEntity);
attachedEntry.CurrentValues.SetValues(entity);
} else {
entry.State = EntityState.Modified; //这应该附加实体
}
}
}
正如你可以看到的主要问题是 SingleOrDefault
方法需要知道找到实体的关键。您可以创建简单的界面,在我的示例中显示密钥( IEntity
),并在您想要处理的所有实体中实现。
Using EF5 with a generic Repository Pattern and ninject for dependency injenction and running into an issue when trying to update an entity to the database utilizing stored procs with my edmx.
my update in DbContextRepository.cs is:
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;
}
}
From my AddressService.cs which goes back to my repository I have:
public int Save(vw_address address)
{
if (address.address_pk == 0)
{
_repo.Insert(address);
}
else
{
_repo.Update(address);
}
_repo.SaveChanges();
return address.address_pk;
}
When it hits the Attach and EntityState.Modified it pukes with the error:
An object with the same key already exists in the ObjectStateManager. The ObjectStateManager cannot track multiple objects with the same key.
I have looked through many of the suggestions in stack and on the Internet and not coming up with anything that resolves it. Any work arounds would be appreciated.
Thanks!
Edit: Original answer used Find
instead of Local.SingleOrDefault
. It worked in combination with @Juan's Save
method but it could cause unnecessary queries to database and else
part was probably never executed (executing the else part would cause exception because Find already queried the database and hadn't found the entity so it could not be updated). Thanks to @BenSwayne for finding the issue.
You must check if an entity with the same key is already tracked by the context and modify that entity instead of attaching the current one:
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
}
}
}
As you can see the main issue is that SingleOrDefault
method needs to know the key to find the entity. You can create simple interface exposing the key (IEntity
in my example) and implement it in all your entities you want to process this way.
具有相同键的对象已经存在于ObjectStateManager。该ObjectStateManager不能用相同的密钥跟踪多个对象
。具有相同键的一个目的已经存在于ObjectStateManagerObjectStateManager不能与相同的密钥跟踪多个对象
ObjectStateManager中已经存在具有相同密钥的对象。 ObjectStateManager无法跟踪具有相同键的多个对象
ObjectStateManager中已经存在具有相同密钥的对象。 ObjectStateManager无法跟踪具有相同键的多个对象
ObjectStateManager 中已存在具有相同键的对象.ObjectStateManager 无法跟踪具有相同键的多个对象