2014-10-01 69 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