2014-10-01 64 views
2

由于“IEntityChangeTracker的多个实例无法引用实体对象,因此我正遇到InvalidOperationException异常”。在EntityFrameWorkRepository.Create()的第一行。找不到引用实体框架实体的对象

我知道这是由于有多个数据库上下文,但在这种情况下,我有点失落,因为代码没有明显的第二个上下文,因为所有数据库访问都通过一个指定的对象,其唯一目的是管理数据库上下文。这是因为所讨论的Web应用程序具有相当的交互性,所以用户不断创建必须保存在数据库中的新对象。这是由于前面的设计使用了锁定和单个上下文的问题,因此代码被重构并且工作,除了所讨论的方法之外。

EF类:

public class EntityFrameWorkRepository<TKey, TEntity> : IDisposable, IRepository<TKey,TEntity> where TEntity: class 
{ 
    private readonly IDbContext _context; 
    private IDbSet<TEntity> _entities; 

    public EntityFrameWorkRepository() 
    { 
     _context = new ApplicationDbContext(); 
    } 

    private IDbSet<TEntity> Entities 
    { 
     get { return _entities ?? (_entities = _context.Set<TEntity>()); } 
    } 

    public void Create(TEntity entity) 
    { 
     Entities.Add(entity); 
     _context.SaveChanges(); 
    } 

    public void Dispose() 
    { 
     _context.Dispose(); 
    } 
} 

用于所有数据库访问服务对象:

public class Service : IService 
{ 
    public const string Persistance = "Persist"; 
    public const int CacheTaskSeconds = 300; //Check every 5 minutes 
    public const double IdleMinutes = 30.0; 

    private readonly IKvpRepository<int, SimulationCollection> _simulationCollectionAppStateRepository; 
    private readonly UserManager<ApplicationUser> _userManager; 

    public Service(IKvpRepository<int, SimulationCollection> simulationCollectionAppStateRepository) 
    { 
     _userManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationDbContext())); 
     AddTaskToCache(Persistance, CacheTaskSeconds); 
    } 

    public SimulationCollection CreateCollection(Guid userId, string name, string description) 
    { 
     using (var _simulationCollectionEFRepository = new EntityFrameWorkRepository<int, SimulationCollectionEntity>()) 
     { 
      var applicationUser = _userManager.FindById(userId.ToString()); 
      if (applicationUser == null) 
       throw new ArgumentOutOfRangeException("ApplicationUser matching userId doesn't exist"); 
      var collectionEntity = new SimulationCollectionEntity(applicationUser, name, description); 
      _simulationCollectionEFRepository.Create(collectionEntity); 
      return collection; 
     } 
    } 
} 

我试图添加到数据库中的对象:

public class SimulationCollectionEntity 
{ 
    [Key] 
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)] 
    public virtual int Id { get; set; } 
    public string Name { get; set; } 
    public virtual ApplicationUser User { get; set; } 
    public DateTime DateCreated { get; set; } 
    public string Description { get; set; } 

    [ForeignKey("SimulationCollectionEntityId")] 
    public virtual ICollection<SimulationEntity> Simulations { get; set; } 

    [Obsolete("Only needed for serialization and materialization", true)] 
    public SimulationCollectionEntity() {} 

    public SimulationCollectionEntity(ApplicationUser currentUser, string name, string description) 
    { 
     User = currentUser; 
     Name = name; 
     Description = description; 
     DateCreated = DateTime.Now; 
    } 
} 

有没有一种简单的方法来查看给定的对象可能被附加到哪些上下文hed to?我已经检查过,看看collectionEntity是否附加到_userManager,因为它有一个dbContext,但它的状态是分离的。 EF可能希望我以不同于我的方式添加对象吗?我怀疑SimulationCollectionEntity中的属性可能会给我带来麻烦,但我是实体框架的新手,我不确定。我是否应该换一种不同的设计,而不是像this

回答

1

您可能想要考虑一个工作单元,例如一个上下文在多个存储库之间共享的方法。这个post的接受答案就是一个很好的例子。我看过ContextPerRequest解决方案,就像你的例子中的解决方案,但我从来没有为它们疯狂过。理想情况下,您需要一个短期生活环境,例如添加发票和两个发票项目 - 一个工作单元。然后,您可以将整个操作包装在TransactionScope中,并使其成功或失败。

+0

我使用链接的解决方案解决了这个问题,谢谢!我从userManager中删除了上下文,并简单地在每次请求时创建userManager。出于好奇,就我所知,所有的缓存都是通过上下文来完成的,你不想因为这个原因而试图坚持它们吗? – CalumMcCall 2014-10-02 10:46:30

+1

这是一个原因,在很长的上下文环境中,您可以想象到上下文中内存中数据库中的所有内容,但dbContext是一个非常轻的权重对象,所以当您需要时无需旋转它并在完成后处置它。您可以放心,底层的sql连接将被释放并释放回池中。我也认为这会让你更多地考虑你的代码,并且将它结构化得更好一些,我见过的最慢的mvc视图涉及到一个ContextPerRequest和一个延迟加载的集合,导致了每个项目的数据库调用。 – 2014-10-02 17:48:45