讓我們爭議!
我不同意一般MVC + EF共識,保持上下文,活在整個請求是有許多原因的好事:
低性能提升 你知道如何昂貴的創建新的數據庫上下文是?好...「一個DataContext是輕量級的,不貴創建」從MSDN
是獲得國際奧委會錯誤,直到你去住 如果你設置你的IoC容器來處理的,它會顯得很好..你的背景和你錯了,你真的搞錯了。我已經兩次現在看到從IoC容器創建的大量內存泄漏並不總是正確地處理上下文。直到您的服務器在正常級別的併發用戶中開始崩潰時,您纔會意識到您已將其設置爲錯誤。它不會發生在開發中,所以做一些負載測試!
意外延遲加載 您返回最新文章的IQueryable,以便您可以在主頁上列出它們。有一天,其他人被要求顯示相應文章旁邊的評論數量。因此,他們的代碼添加一個簡單的位到View顯示,像這樣的評論了......
@foreach(var article in Model.Articles) {
<div>
<b>@article.Title</b> <span>@article.Comments.Count() comments</span>
</div>
}
外觀精緻,做工精細。但實際上,您並未在返回的數據中包含註釋,因此現在將爲循環中的每篇文章創建一個新的數據庫調用。選擇N + 1問題。 10篇文章= 11個數據庫調用。好,所以代碼是錯誤的,但這是一個容易犯的錯誤,所以它會發生。
您可以通過在數據層中關閉您的上下文來防止此問題。但是不會在article.Comments.Count()上的NullReferenceException中破解代碼嗎?是的,它會迫使你編輯圖層以獲取視圖圖層所需的數據。這是應該如何。
代碼異味 從您的視圖中擊中數據庫只是錯誤的。你知道一個IQueryable實際上並沒有實際打到數據庫,所以忘了這個對象。確保你的數據庫在離開你的數據層之前被擊中。
所以答案
您的代碼應該是這樣的
數據層(在我看來):
public List<Article> GetArticles()
{
List<Article> model;
using (var context = new MyEntities())
{
//for an example I've assumed your "MyTable" is a table of news articles
model = (from mt in context.Articles
select mt).ToList();
//data in a List<T> so the database has been hit now and data is final
}
return model;
}
控制器:
public ActionResult Index()
{
var model = new HomeViewModel(); //class with the bits needed for you view
model.Articles = _dataservice.GetArticles(); //irrelevant how _dataService was intialised
return View(model);
}
一旦你這樣做這並理解這可能喲你可以開始試驗擁有一個IoC容器句柄的上下文,但絕對不是之前。頭部我的警告 - 我已經看到兩個大規模失敗:)
但老實說,你喜歡什麼,編程很有趣,應該是一個偏好問題。我只是告訴你我的。但是無論你做什麼,都不要開始使用每個控制器或每個請求的IoC上下文,因爲「所有酷的孩子都在這樣做。」這樣做是因爲你真的關心它的好處,並瞭解它是如何正確完成的。
'model = context.MyTable.ToList()' - 'ToList()'將執行您的查詢。在你的情況下,IQueryable的確不會在上下文範圍之外工作。 – Andrei