让我们有争议!
我不同意 MVC + EF 的普遍共识,即在整个请求中保持上下文处于活动状态是一件好事,原因有很多:
低性能提升
你知道创建一个新的数据库上下文是多么昂贵吗?嗯......“ DataContext 是轻量级的,创建起来并不昂贵”,来自MSDN
弄错 IoC,它看起来会很好.. 直到你上线
如果你设置你的 IoC 容器来为你处理你的上下文并且你弄错了,你真的弄错了。我现在已经两次看到由 IoC 容器创建的大量内存泄漏,并不总是正确地处理上下文。在您的服务器在正常级别的并发用户期间开始崩溃之前,您不会意识到自己设置错误。它不会在开发中发生,所以做一些负载测试!
意外延迟加载
您返回最近文章的 IQueryable,以便您可以在主页上列出它们。有一天,其他人被要求在相应文章旁边显示评论数量。所以他们在视图中添加了一些简单的代码来显示评论计数,就像这样......
@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 上下文。这样做是因为您真正关心它的好处并了解它是如何正确完成的。