2013-02-10 53 views
0

我一直在努力弄清楚爲什麼這段代碼在foreach循環之前放置dbcontext。任何線索將不勝感激。謝謝!爲什麼在foreach循環之前放置dbcontext

[TestMethod] 
    public void CreatePostAddComment() 
    { 
     IQueryable<Post> thePost; 
     using (var _context = new BlogRepository()) 
     { 
      _context.AddPost(GetTestPost()); 
      var retrivePost = _context.GetPostByName("TestPost1"); 
      thePost = retrivePost; 
     } 

     foreach (var post in thePost) 
     { 
      using (var _dbContext = new BlogRepository()) 
      { 
       _dbContext.AddComment(GetTestComment(post)); 
      } 

     } 
    } 
+1

使用在其塊的末尾放置上下文。 – 2013-02-10 18:48:57

+0

我知道了,但是IQueryable 應該還是在foreach範圍之內? – 2013-02-10 18:50:06

+0

不可以。僅僅因爲您已聲明變量超出其範圍之外,處置不會延遲。 – 2013-02-10 18:58:12

回答

2

using語句,其實是語法糖就相當於: -

[TestMethod] 
public void CreatePostAddComment() 
{ 
    IQueryable<Post> thePost; 
    { 
     var _context = new BlogRepository(); 
     _context.AddPost(GetTestPost()); 
     var retrivePost = _context.GetPostByName("TestPost1"); 
     thePost = retrivePost; 
     _context.Dispose(); 
     //Note, using is much better, because Dipose is called 
     //even if there is an exception. 
    } 

    foreach (var post in thePost) 
    { 
     using (var _dbContext = new BlogRepository()) 
     { 
      _dbContext.AddComment(GetTestComment(post)); 
     } 

    } 
} 

但是也有你的代碼的幾個關鍵問題,只有第一個是語境處理完畢異常。

關於上下文被處理的第一個問題是因爲只有在枚舉實際的IQueryable(在本例中爲foreach)時纔會調用EF查詢。換句話說,IQueryable沒有做任何工作,而且很懶惰。當foreach實際上需要IQueryable去獲取它的信息時,上下文已經被處理了。

其次,你不能在你剛剛得到的姿勢上工作,因爲你正在使用另一個上下文。 EF會抱怨帖子對象仍然附着在舊的上下文中。這個問題將突出更一般的模式。只要你的「工作單位」,你應該保持你的背景。一般來說,在調用DbContext.SaveChanges()之後進行處理。

這導致我到你的第三個錯誤。你沒有調用DbContext.SaveChanges()。這段代碼沒有什麼會發生。您不會寫入數據庫,EF驗證不會運行,除非內存即將超出範圍,否則不會發生任何事情。

最後你的測試方法產生的副作用(假設它會成功保存)。這將導致痛苦點進一步下降。解決此問題的一種方法是在測試之前開始事務,並在測試之後回滾。

我知道MbUnit會爲你做事務邏輯,如果你想沿着這條路走下去的話。

所以總結起來,這是我會做什麼......假設我理解你正在試圖achieve-

從文體點我恨CRUD方法是什麼。像GetPostByName這樣的方法,當你有Linq的時候。我使用它的問題包括更多的代碼維護(如果您更改爲nHibernate,則需要重新實現GetPostByName)。其次,接下來你會發現你需要一個GetPostByDescript,然後一個GetPostById,然後一個GetPostByDescriptionOrName ...等等等等。帶有像ThePost這樣的名字,我假設你是在一個實例之後......

[Rollback] 
[TestMethod] 
public void CreatePostAddComment() 
{ 

    using(var _context = new BlogRepository()) 
    { 
     _context.AddPost(GetTestPost()); 
     _context.SaveChanges(); 
     var thePost = _context.Posts.First(x => x.Name =="TestPost1"); 
     _dbContext.AddComment(GetTestComment(post)); 
     _context.SaveChanges(); 
    } 
} 
+0

感謝您的信息。從我的例子中唯一不同的是,GetPostByName和GetTestComment在存儲庫中的相應方法中調用了保存更改。 – 2013-02-10 19:05:38

+0

我會高度建議不要讓SaveChanges在像GetTestPost和GetPostByName這樣的域代碼內調用。它將永遠將你與EntityFramework聯繫起來。您的域代碼應該與存儲庫的實現無關。如果要測試域代碼,則可以將存儲庫更改爲列表。 另外,實施存儲庫模式。 – Aron 2013-02-10 19:14:09