ObjectStateManager中已经存在具有相同密钥的对象。 ObjectStateManager无法跟踪具有相同键的多个对象 [英] An object with the same key already exists in the ObjectStateManager. The ObjectStateManager cannot track multiple objects with the same key

查看:112
本文介绍了ObjectStateManager中已经存在具有相同密钥的对象。 ObjectStateManager无法跟踪具有相同键的多个对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

使用EF5与通用存储库模式和ninject进行依赖注册,并在使用存储过程与我的edmx更新实体到数据库时遇到问题。



我在DbContextRepository.cs中的更新是:

  public override void更新(T实体)
{
if(entity == null)
throw new ArgumentException(Can not add a null entity);

var entry = _context.Entry< T>(entity);

if(entry.State == EntityState.Detached)
{
_context.Set< T>()。
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时,会显示错误: / p>

ObjectStateManager中已经存在具有相同键的对象。 ObjectStateManager无法跟踪具有相同键的多个对象。



我已经看到了堆栈和互联网上的许多建议,没有提出任何东西解决它。



谢谢!

解决方案

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无法跟踪具有相同键的多个对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆