“一个实体对象不能被多个 IEntityChangeTracker 实例引用”

Posted

技术标签:

【中文标题】“一个实体对象不能被多个 IEntityChangeTracker 实例引用”【英文标题】:"An entity object cannot be referenced by multiple instances of IEntityChangeTracker" 【发布时间】:2011-11-01 10:32:30 【问题描述】:

我有 3 个数据库表:Vendors、Regions 和 VendorRegions:

Vendors
-------------------
VendorID (PK)
Name

Regions
-------------------
RegionID (PK)
Name

VendorRegions
-------------------
VendorID (PK)
RegionID (PK)

在我创建供应商的页面上,我在复选框列表中列出了每个区域。对于检查的每个区域,我想将 VendorID 和 RegionID 添加到 VendorRegions 表中。

我正在使用实体框架、C# 和 MVC 3。

这是我的控制器代码:

public class VendorsController : Controller

    readonly IVendorsRepository _vendorsRepository;
    readonly IRegionsRepository _regionsRepository;

    public VendorsController()
    
        _vendorsRepository = new SqlVendorsRepository();
        _regionsRepository = new SqlRegionsRepository();
    

    [HttpPost]
    public ActionResult Create(VendorViewModel viewModel, string[] Regions)
    
        var vendor = new Vendor();
        TryUpdateModel(vendor);

        if (ModelState.IsValid)
        
            vendor.Regions.Clear();
            foreach (var regionId in Regions)
            
                vendor.Regions.Add(_regionsRepository.GetRegion(Int32.Parse(regionId)));
            

            _vendorsRepository.SaveVendor(vendor);
            return RedirectToAction("Index");
        

        return View(viewModel);     // validation error, so redisplay same view
    

这是我的供应商存储库代码:

public class SqlVendorsRepository : IVendorsRepository

    private readonly MyDBEntities _entities;

    public SqlVendorsRepository()
                
        _entities = new MyDBEntities();
    


    public void SaveVendor(Vendor vendor)
    
        // If it's a new vendor, just attach it to the DataContext
        if (vendor.VendorID == 0)
            _entities.Vendors.Context.AddObject("Vendors", vendor); // ERROR HERE
        else if (vendor.EntityState == EntityState.Detached)
        
            // We're updating an existing vendor, but it's not attached to this data context, so attach it and detect the changes
            _entities.Vendors.Context.Attach(vendor);
            _entities.Vendors.Context.Refresh(System.Data.Objects.RefreshMode.ClientWins, vendor);
        
        _entities.Vendors.Context.SaveChanges();
    

当我尝试在_entities.Vendors.Context.AddObject("Vendors", vendor); 保存我的供应商时发生错误。以防万一,这是我的 Regions 存储库代码:

public class SqlRegionsRepository : IRegionsRepository

    private readonly MyDBEntities _entities;

    public SqlRegionsRepository()
                
        _entities = new MyDBEntities();
    


    public IQueryable<Region> Regions
    
        get  return _entities.Regions.AsQueryable(); 
    


    public Region GetRegion(int id)
    
        return Regions.FirstOrDefault(st => st.RegionID == id);
    

这似乎是一件简单的事情,但我不知道如何克服这个错误。有什么想法吗?

【问题讨论】:

【参考方案1】:

您有两个不同的存储库,每个存储库都有一个单独的数据上下文 - 这是根本问题 - 您的数据上下文应该由所有存储库共享,即您可以通过构造函数注入来注入它:

MyDBEntities entities = new MyDBEntities();
_vendorsRepository = new SqlVendorsRepository(entities);
_regionsRepository = new SqlRegionsRepository(entities);

【讨论】:

你有机会举一个基本的例子吗?【参考方案2】:

当我有一个缓存层正在缓存查找实体并从缓存中检索它们时,我遇到了同样的错误。缓存的实体是代理实体,并且仍然具有对最初检索它们的 DBContext 的引用。

这种情况的主要症状是带有查找引用的域实体的第一次保存工作正常,但随后的保存失败。

我希望这对某人有所帮助,因为这个问题让我的生活中断了 2 天。

【讨论】:

我知道这已经很长时间了,但这听起来像是我正在经历的事情,我不确定解决它的最佳方法。我在我的存储库上使用缓存,第二个更新是加载缓存的记录并尝试使用它的更改更新数据库但失败。你做了什么来解决的?我想保留我的缓存层,我认为这是处理存储库缓存的正确方法。 我用EF已经快一年了,但我会尽力回答。您的缓存不应该在您的回购中。 EF 中的实体是填充在内存中的对象,每个上下文仅从数据库中获取一次。所以它实际上已经是一个缓存。因此,如果您在上下文中调用 SaveChanges(),则需要在更新之前再次检索实体的“新”副本。实体如何更新?使用 api 或视图模型或其他类型的 DTO?如果是这样,那么如果确实有必要,您可能会从某些缓存中受益,但是您将需要处理缓存失效。 另外,如果您正在检索关闭 trackchanges 的实体,您可能会发现这很有用:***.com/a/36684660/230428

以上是关于“一个实体对象不能被多个 IEntityChangeTracker 实例引用”的主要内容,如果未能解决你的问题,请参考以下文章