关于实体框架上下文生命周期的问题 [英] Questions about Entity Framework Context Lifetime

查看:128
本文介绍了关于实体框架上下文生命周期的问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

关于ASP.NET MVC应用程序中实体框架上下文的期望生命周期,我有一些疑问。考虑以下控制器操作:



pre> public ActionResult Index()
{
IEnumerable&MyTable>模型;

using(var context = new MyEntities())
{
model = context.MyTable;
}

return View(model);
}

上面的代码将无法正常工作,因为实体框架上下文已经不再视图呈现页面的范围。其他人如何构建上述代码?

解决方案

让我们有争议!



我不同意一般的MVC + EF共识,在整个请求中保持上下文是一件好事,原因有很多:



低性能增长
您知道创建新数据库上下文的成本是多少?嗯... DataContext是轻量级的,创建并不昂贵,这是来自 MSDN



获取IoC错误,看起来很好..直到你活着
如果你设置你的IoC容器来处理你的上下文,你错了,你真的错了。我已经有两次现在看到从IoC容器创建的大量内存泄漏并不总是正确地处理上下文。您将不会意识到您的设置错误,直到您的服务器在正常级别的并发用户中开始崩溃。在开发中不会发生,所以做一些加载测试!



意外的懒惰加载
您返回最近的IQueryable文章,以便您可以在您的主页上列出。有一天有人要求他们显示相应文章旁边的评论数量。所以他们添加一个简单的代码到视图来显示这样的注释计数...

  @foreach(Model.Articles中的var article){
< div>
< b> @ article.Title< / b> < span> @ article.Comments.Count()注释< / span>
< / div>
}

看起来不错,工作正常。但实际上您没有在返回的数据中包含注释,所以现在这将为循环中的每篇文章创建一个新的数据库调用。 SELECT N + 1问题。 10个文章= 11个数据库调用。好的,所以代码是错误的,但这是一个容易的错误,所以会发生。



你可以通过在你的数据层关闭你的上下文来防止这种情况。但是不会在article.Comments.Count()上使用NullReferenceException代码中断?是的,它将强制您编辑数据图层以获取View层所需的数据。这是应该是如何。



代码气味
从您的View中点击数据库有点错误。你知道一个IQueryable没有真正打到数据库,所以忘了那个对象。



所以答案



你的代码应该是(在我看来)这样



DataLayer:

 code> public List< Article> GetArticles()
{
列表<文章>模型;

使用(var context = new MyEntities())
{
//一个例子我假设你的MyTable是一个新闻文章表
model =(from mt in context.Articles
select mt).ToList();
//列表中的数据< T>所以数据库已经被打了,数据是最终的
}

返回模型;
}

控制器:

  public ActionResult Index()
{
var model = new HomeViewModel(); //所需的位,你需要查看
model.Articles = _dataservice.GetArticles(); //不相干如何_dataService被初始化
return View(model);
}

一旦你这样做了,明白这一点,那么也许你可以开始尝试一个IoC容器句柄上下文,但绝对不是之前的。发出警告 - 我看到两个大规模的故障:)



但老实说,做你喜欢的,编程很有趣,应该是一个偏好的问题。我只是告诉你我的但是无论你做什么,不要开始使用控制器或每个请求的IoC上下文,因为所有酷的孩子都在做。这样做是因为你真的非常关心它的好处,并且了解它的做法是否正确。


I have some questions about the desired lifetime of an Entity Framework context in an ASP.NET MVC application. Isn't it best to keep the context alive for the shortest time possible?

Consider the following controller action:

public ActionResult Index()
{
    IEnumerable<MyTable> model;

    using (var context = new MyEntities())
    {
        model = context.MyTable;
    }

    return View(model);
}

The code above won't work because the Entity Framework context has gone out of scope while the view renders the page. How would others structure the code above?

解决方案

Let's get controversial!

I disagree with the general MVC + EF consensus that keeping a context alive throughout the entire request is a good thing for a number of reasons:

Low performance increase Do you know how expensive creating a new database context is? Well... "A DataContext is lightweight and is not expensive to create" that's from MSDN

Get the IoC wrong and it'll seem fine.. until you go live If you set up your IoC container to dispose of your context for you and you get it wrong, you really really get it wrong. I've twice now seen massive memory leaks created from an IoC container not always disposing of a context correctly. You won't realise you've set it up wrong until your servers start crumbling during normal levels of concurrent users. It won't happen in development so do some load tests!

Accidental lazy loading You return an IQueryable of your most recent articles so that you can list them on your homepage. One day someone else is asked to show the number of comments next to the respective article. So they add a simple bit of code to the View to show the comment count like so...

@foreach(var article in Model.Articles) {
    <div>
        <b>@article.Title</b> <span>@article.Comments.Count() comments</span>
    </div>
}

Looks fine, works fine. But actually you didn't include the comments in your returned data so now this will make a new database call for each article in the loop. SELECT N+1 issue. 10 article = 11 database calls. Okay so the code is wrong but it is an easy mistake to make so it will happen.

You can prevent this by shutting your context down in you data layer. But won't the code break with a NullReferenceException on the article.Comments.Count() ? Yes it will so it will force you to edit the Data layer to get the data needed for the View layer. This is how is should be.

Code smell There is just something wrong about hitting the database from your View. You know that an IQueryable hasn't actually hit the database yet right so forget that object. Make sure your database is hit before it leaves your data layer.

So the answer

Your code should be (in my opinion) like this

DataLayer:

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;
}

Controller:

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);
}

Once you have done this and understand this then perhaps you can begin experimenting with having an IoC container handle context but definitely not before. Head my warning - I've seen two large scale failures :)

But honestly do what you like, programming is fun and should be a matter of preference. I'm just telling you mine. But whatever you do, don't start using IoC context per controller or per request just because "all the cool kids are doing it." Do it because you really truly care about it's benefits and understand how it's done correctly.

这篇关于关于实体框架上下文生命周期的问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆