Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/333.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# ObjectStateManager中已存在具有相同密钥的对象。ObjectStateManager无法跟踪具有相同密钥的多个对象_C#_Entity Framework_Ninject_Repository Pattern_Entity Framework 5 - Fatal编程技术网

C# ObjectStateManager中已存在具有相同密钥的对象。ObjectStateManager无法跟踪具有相同密钥的多个对象

C# ObjectStateManager中已存在具有相同密钥的对象。ObjectStateManager无法跟踪具有相同密钥的多个对象,c#,entity-framework,ninject,repository-pattern,entity-framework-5,C#,Entity Framework,Ninject,Repository Pattern,Entity Framework 5,使用带有通用存储库模式的EF5和用于依赖项插入的ninject,并在尝试使用my edmx的存储过程将实体更新到数据库时遇到问题 我在DbContextRepository.cs中的更新是: public override void Update(T entity) { if (entity == null) throw new ArgumentException("Cannot add a null entity."); var entry = _contex

使用带有通用存储库模式的EF5和用于依赖项插入的ninject,并在尝试使用my 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;
    }
}
当它点击Attach和EntityState.Modified时,它会吐出以下错误:

ObjectStateManager中已存在具有相同密钥的对象。ObjectStateManager无法使用同一密钥跟踪多个对象。

我浏览了stack和Internet上的许多建议,但没有找到任何解决方法。任何解决办法都将不胜感激


谢谢

编辑:使用原始答案
查找
,而不是
本地。单一或默认
。它与@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 key

        if (attachedEntity != null) {
            var attachedEntry = _context.Entry(attachedEntity);
            attachedEntry.CurrentValues.SetValues(entity);
        } else {
            entry.State = EntityState.Modified; // This should attach entity
        }
    }
}  
公共覆盖无效更新(T实体),其中T:entity{
if(实体==null){
抛出新ArgumentException(“无法添加空实体”);
}
var entry=_context.entry(实体);
if(entry.State==EntityState.Detached){
var set=_context.set();
T attachedEntity=set.Local.SingleOrDefault(e=>e.Id==entity.Id);//您需要有权访问密钥
如果(附件身份!=null){
var attachedEntry=_context.Entry(attachedEntity);
attachedEntry.CurrentValues.SetValues(实体);
}否则{
entry.State=EntityState.Modified;//这应该附加实体
}
}
}  

正如您所看到的,主要问题是
SingleOrDefault
方法需要知道查找实体的键。您可以创建一个简单的接口来公开密钥(在我的示例中为
IEntity
),并在您希望以这种方式处理的所有实体中实现它。

上述答案可能是EF 4.1+。对于使用4.0的用户,请尝试这个简单的方法…虽然没有真正测试过,但确实附加并保存了我的更改

    public void UpdateRiskInsight(RiskInsight item)
    {
        if (item == null)
        {
            throw new ArgumentException("Cannot add a null entity.");
        }

        if (item.RiskInsightID == Guid.Empty)
        {
            _db.RiskInsights.AddObject(item);
        }
        else
        {
            item.EntityKey = new System.Data.EntityKey("GRC9Entities.RiskInsights", "RiskInsightID", item.RiskInsightID);
            var entry = _db.GetObjectByKey(item.EntityKey) as RiskInsight;
            if (entry != null)
            {
                _db.ApplyCurrentValues<RiskInsight>("GRC9Entities.RiskInsights", item);
            }

        }

        _db.SaveChanges();

    }
public void UpdateRiskInsight(风险洞察项目)
{
如果(项==null)
{
抛出新ArgumentException(“无法添加空实体”);
}
if(item.RiskInsightID==Guid.Empty)
{
_db.RiskInsights.AddObject(项目);
}
其他的
{
item.EntityKey=新的System.Data.EntityKey(“GRC9Entities.RiskInsights”、“RiskInsightID”、item.RiskInsightID);
var entry=_db.GetObjectByKey(item.EntityKey)作为RiskInsight;
if(条目!=null)
{
_db.ApplyCurrentValue(“GRC9Entities.RiskInsights”,项目);
}
}
_db.SaveChanges();
}

您可以通过反射实际检索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
            }
        }
var entry=\u dbContext.entry(实体);
//通过反射检索Id
var pkey=_dbset.Create().GetType().GetProperty(“Id”).GetValue(实体);
if(entry.State==EntityState.Detached)
{
var set=_dbContext.set();
T attachedEntity=set.Find(pkey);//访问密钥
如果(附件身份!=null)
{
var attachedEntry=_dbContext.Entry(attachedEntity);
attachedEntry.CurrentValues.SetValues(实体);
}
其他的
{
entry.State=EntityState.Modified;//附加实体
}
}
@您应该这样做:

**请注意,YourDb应该是从DbContext派生的类

public abstract class YourRepoBase<T> where T : class
{
    private YourDb _dbContext;
    private readonly DbSet<T> _dbset;

    public virtual void Update(T entity)
    {
        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
           }
       }
    }
公共抽象类yourrepbase其中T:class
{
私有YourDb_dbContext;
私有只读数据库集_DbSet;
公共虚拟无效更新(T实体)
{
var entry=_dbContext.entry(实体);
//通过反射检索Id
var pkey=_dbset.Create().GetType().GetProperty(“Id”).GetValue(实体);
if(entry.State==EntityState.Detached)
{
var set=_dbContext.set();
T attachedEntity=set.Find(pkey);//访问密钥
如果(附件身份!=null)
{
var attachedEntry=_dbContext.Entry(attachedEntity);
attachedEntry.CurrentValues.SetValues(实体);
}
其他的
{
entry.State=EntityState.Modified;//附加实体
}
}
}

}没有反射,如果不想使用接口,可以使用功能委托在数据库中查找实体。 这是上面更新的示例

private void Update<T>(T entity, Func<ObservableCollection<T>, T> locatorMap) where T : class
{
    var entry = Context.Entry(entity);
    if (entry.State == EntityState.Detached)
    {
        var set = Context.Set<T>();
        T attachedEntity = locatorMap(set.Local); 

        if (attachedEntity != null)
        {
            var attachedEntry = Context.Entry(attachedEntity);
            attachedEntry.CurrentValues.SetValues(entity);
        }
        else
        {
            entry.State = EntityState.Modified; // This should attach entity
        }
    }
}

我不想通过添加接口或属性来污染我自动生成的EF类。因此,这实际上是从上面的一些答案中得到的一点(因此归功于Ladislav Mrnka)。这为我提供了一个简单的解决方案

我在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
        }
    }
}  

如果您将上下文设置为AsNoTracking(),这将停止aspmvc跟踪内存中实体的更改(这是您在web上想要的)

我建议您在

上阅读更多关于这方面的内容,另一个解决方案(基于@Sergey的答案)可能是:

private void Update<T>(T entity, Func<T, bool> predicate) where T : class
{
    var entry = Context.Entry(entity);
    if (entry.State == EntityState.Detached)
    {
        var set = Context.Set<T>();
        T attachedEntity = set.Local.SingleOrDefault(predicate); 
        if (attachedEntity != null)
        {
            var attachedEntry = Context.Entry(attachedEntity);
            attachedEntry.CurrentValues.SetValues(entity);
        }
        else
        {
            entry.State = EntityState.Modified; // This should attach entity
        }
    }
}

您可能忘记安装对象
fBLL=newfornecedorbll()在algun place中

分离找到的实体(请参见解决方案中的
AttacheIdentity
)并重新连接修改后的实体对我来说效果很好

这背后的原因是
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);
_dbContext.Products.AsNoTracking().Find(id);  
private void Update<T>(T entity, Func<T, bool> predicate) where T : class
{
    var entry = Context.Entry(entity);
    if (entry.State == EntityState.Detached)
    {
        var set = Context.Set<T>();
        T attachedEntity = set.Local.SingleOrDefault(predicate); 
        if (attachedEntity != null)
        {
            var attachedEntry = Context.Entry(attachedEntity);
            attachedEntry.CurrentValues.SetValues(entity);
        }
        else
        {
            entry.State = EntityState.Modified; // This should attach entity
        }
    }
}
Update(EntitytoUpdate, key => key.Id == id)
var set = this.Set<T>();
if (this.Entry(entity).State == EntityState.Detached)
{
    var attached = set.Find(id);
    if (attached != null) { this.Entry(attached).State = EntityState.Detached; }
    this.Attach(entity);
}

set.Update(entity);