使用DI但获取:IEntityChangeTracker的多个实例不能引用实体对象

时间:2014-09-18 20:52:05

标签: c# asp.net-mvc entity-framework inversion-of-control

我在这个问题上所审查的问题都没有使用IOC,而我却不明白为什么我会收到此错误。据我了解,如果我只有一个上下文实例,我不应该收到这个错误。这是我的设置的细分版本。

我正试图这样做:

var product = new Product();
product.ShortText = "something";
foreach (var category in _categoryService.Get().Take(5).ToList())
    product.Categories.Add(category);
_productService.Update(product);
_productService.SaveChanges();

我的_productService

public class ProductService : IProductService
{
    private readonly IRepository<Product> _productRepository;

    public ProductService(IRepository<Product> productRepository)
    {
        _productRepository = productRepository;
    }

    //Code removed for brevity
}

_categoryService_productService几乎相同。

IRepository是这样的:

public class EfRepository<T> : IRepository<T> where T : BaseEntity
{
    private readonly IDbContext _context;
    private IDbSet<T> _entities;

    public EfRepository(IDbContext context)
    {
        _context = context;
    }

    protected virtual IDbSet<T> Entities
    {
        get { return _entities ?? (_entities = _context.Set<T>()); }
    }

    public IQueryable<T> Table
    {
        get { return Entities; }
    }

    public void Update(T entity)
    {
        Entities.AddOrUpdate(m => m.Id, entity);
    }
}

我按照请求注册我的上下文:

builder.RegisterType<CcDataContext>().As<IDbContext>().InstancePerRequest();

考虑到这一点,我看到它的方式,_productService_categoryService应该有相同的上下文实例,所以我很困惑为什么我得到错误。

修改

这是我的背景:

public class CcDataContext : DbContext, IDbContext
{
    static CcDataContext()
    {
        Database.SetInitializer<CcDataContext>(null);
    }

    public CcDataContext()
        : base("CcDataContext") //String.Format("Name={0}", CcConfig.Get("ConnectionStringName")))
    {
    }

    public DbSet<Website> Websites { get; set; }
    public DbSet<Store> Stores { get; set; }
    public DbSet<StoreView> StoreViews { get; set; }
    public DbSet<Customer> Customers { get; set; }
    public DbSet<CustomerAddress> CustomerAddresses { get; set; }
    public DbSet<CustomerContact> CustomerContacts { get; set; }
    public DbSet<CustomerRole> CustomerRoles { get; set; }
    public DbSet<RolePermission> PermissionRoles { get; set; }
    public DbSet<Product> Products { get; set; }
    public DbSet<Category> Categories { get; set; }


    public IDbSet<T> Set<T>() where T : BaseEntity
    {
        return base.Set<T>();
    }
}

2 个答案:

答案 0 :(得分:0)

这与您的DI容器没有任何关系。该错误意味着在您的上下文中的某个位置,您创建了两个DbSet属性,这两个属性都指向同一个实体。

自ASP.NET身份出现以来,最常见的原因是个人尝试添加自己的DbSet<ApplicationUser>属性,当IdentityDbContext<ApplicationUser>已经有一个属性时,应用程序的上下文继承。

不确定这是否是您的问题,因为您还没有指定您正在使用或发布上下文内容的MVC版本。但是,这应该足以让你研究这个问题。

答案 1 :(得分:0)

我找到了原因。这是我在_categoryService上执行的缓存。我的Get()方法如下所示:

public IEnumerable<Category> Get()
{
    return _cacheManager.Get(CcCacheCategoryAll, () => (_categoryRepository.Table.AsEnumerable()));
}

基本上,因为我没有将我的实体从它们被缓存时所处的上下文中分离出来,然后我在稍后的请求中获得缓存版本,并且它们没有相同的上下文。因此,尽管DI不是故障,但这是因为实体之间的上下文不匹配。