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();
}
}
使用在其塊的末尾放置上下文。 – 2013-02-10 18:48:57
我知道了,但是IQueryable應該還是在foreach範圍之內? –
2013-02-10 18:50:06
不可以。僅僅因爲您已聲明變量超出其範圍之外,處置不會延遲。 – 2013-02-10 18:58:12