“ObjectStateManager 中已存在具有相同键的对象...”将实体状态设置为已修改时引发异常

Posted

技术标签:

【中文标题】“ObjectStateManager 中已存在具有相同键的对象...”将实体状态设置为已修改时引发异常【英文标题】:"An object with the same key already exists in the ObjectStateManager..." exception is thrown when setting an entity state to modified 【发布时间】:2011-11-05 11:41:28 【问题描述】:

我按照一些示例(包括“Pro ASP.NET MVC 3”和“Professional ASP.NET MVC 3”等书籍)使用 EF 4.1 创建简单的 ASP.NET MVC 3 应用程序(因为我是这些应用程序的新手技术)。

我正在使用以下存储库(控制器的所有操作方法都使用它的单个实例)来访问数据库:

public class ProductRepository : IProductRepository
    
        private readonly EFDbContext _context = new EFDbContext();

        #region Implementation of IProductRepository       

       ....

        public void SaveProduct(Product product)
                    
            if (product.ProductId == 0)
            
                _context.Products.Add(product);
            
            else
            
                _context.Entry(product).State = EntityState.Modified;

            

            _context.SaveChanges();
        

....

此存储库执行更新,如我使用的示例所示。

产品类别:

public class Product
           
        public int ProductId  get; set;        
        public string Name  get; set;       
        public string Description  get; set;      
        public decimal Price  get; set; 
        public string Category  get; set; 

在更新产品的情况下,我收到异常“ObjectStateManager 中已存在具有相同键的对象。ObjectStateManager 无法跟踪具有相同键的多个对象”

我知道这里已经讨论过类似的问题,但我的问题有点不同:

为什么这段代码取自示例不起作用(尽管它看起来非常简单明了)?我可能做错了什么或错过了什么。

【问题讨论】:

我在使用 Visual Studio 为您设置的默认脚手架时遇到了同样的错误,我无法弄清楚。 【参考方案1】:

在寻找解决方案数小时后,我找到了一个经过足够阅读后似乎合适的解决方案。

修复在这里:

An object with the same key already exists in the ObjectStateManager. The ObjectStateManager cannot track multiple objects with the same key

基本上,从上下文中获取记录并调用:

var currentProduct = _context.Products.Find(product.ProductId);    
_context.Entry(currentProduct).CurrentValues.SetValues(product);

这似乎是个坏主意,而且我在以前的工作中一直讨厌 EF,但根据 Ladislav Mrnka(他显然回答了 *** 上所有与 EF 相关的问题)在这篇文章中的说法:

Entity Framework and Connection Pooling

EF 将在内部存储对实体的请求,因此理想情况下,它已经存在并且不会对数据库进行额外的回调。

问题的根本原因似乎是,一旦从上下文中获取产品,上下文就会跟踪它,这就是造成所有麻烦的原因。因此,将您的更改重新合并是唯一的方法。

希望对您有所帮助。

【讨论】:

为避免这种跟踪,AsNoTracking() 可能会有所帮助。【参考方案2】:

第一次保存项目时,您似乎没有更新 product.ProductId。这意味着当您再次保存该项目时,它会再次将其添加到上下文中,因此会出现错误。

由于 Id 将由数据库添加(我假设它是自动生成的 Id),因此您需要将产品数据读回客户端。

【讨论】:

【参考方案3】:

从泛型的角度来看,这是我最近解决相同问题的方法:

    public TEntity Update(TEntity model, bool persist)
    
        if (model == null)
        
            throw new ArgumentException("Cannot update a null entity.");
        

        var updateModel = Get(model.Id);

        if (updateModel == null)
        
            return model;   
        

        this.context.Entry<TEntity>(updateModel).CurrentValues.SetValues(model);

        this.Save(persist);

        return model;
    

【讨论】:

以上是关于“ObjectStateManager 中已存在具有相同键的对象...”将实体状态设置为已修改时引发异常的主要内容,如果未能解决你的问题,请参考以下文章