让我们有些争议!
我不同意一般的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>
}
看起来不错,运行也正常。但是实际上您没有包含返回数据中的评论,因此现在每篇文章都会进行新的数据库调用。SELECT N+1 问题。10篇文章=11个数据库调用。好吧,代码是错误的,但这是一个容易犯的错误,所以会发生。
您可以通过在数据层关闭上下文来防止这种情况发生。但文章.Comments.Count()会不会出现NullReferenceException呢?是的,它会强制您编辑Data层以获得View层所需的数据。这就是应该的做法。
代码异味
从View中访问数据库就有些不对劲了。您知道IQueryable实际上还没有访问数据库吗?所以忘掉那个对象。确保在离开数据层之前访问您的数据库。
所以答案是
我的意见是,您的代码应该像这样:
DataLayer:
public List<Article> GetArticles()
{
List<Article> model;
using (var context = new MyEntities())
{
model = (from mt in context.Articles
select mt).ToList();
}
return model;
}
控制器:
public ActionResult Index()
{
var model = new HomeViewModel();
model.Articles = _dataservice.GetArticles();
return View(model);
}
一旦你已经完成并理解了这个,也许你可以开始尝试使用一个IoC容器来处理上下文,但绝对不要在此之前。请听取我的警告-我见过两个大规模失败的案例 :)
但坦白说,做你想做的,编程是有趣的,并且应该是个人喜好的问题。我只是告诉你我的看法。但无论你做什么,不要因为"所有酷酷的孩子都在用它"而开始每个控制器或请求一个IoC上下文。要做到这点,是因为你真正关心它的好处,并理解如何正确地使用它。
model = context.MyTable.ToList()
-ToList()
会执行你的查询。在你的情况下,IQueryable确实不能在上下文范围之外工作。 - Andrei