实体框架,DBContext和using()+ async?

Obj*_*der 25 .net c# asynchronous entity-framework using

关于实体框架,有很长时间以来一直困扰着我.

去年我为使用EF的客户编写了一个大型应用程序.在开发过程中,一切都很顺利.

我们八月发货了.但几周后我开始在生产服务器上看到奇怪的内存泄漏.运行几天后,我的ASP.NET MVC 4进程占用了机器的所有资源(8 GB).这不好.我在网上搜索,看到你应该在一个using()块中包围所有的EF查询和操作,以便可以处理上下文.

在一天中,我重构了我要使用的所有代码using(),这解决了我的问题,因为这个过程依赖于稳定的内存使用.

我首先没有围绕我的查询的原因是我从Visualofite中包含的Microsofts自己的脚手架开始了我的第一个控制器和存储库,这些没有使用包围它的查询,而是它具有DbContext作为实例变量的控制器本身.

首先:如果处理上下文非常重要(某些事情不会很奇怪,dbconnection需要关闭等等),微软可能应该在他们的所有示例中都有这个!

现在,我已开始与我在我的后脑勺所有学习收获一个新的大项目工作,我一直在试用的.NET 4.5和EF 6的新功能asyncawait.EF 6.0具有所有这些异步方法(例如SaveChangesAsync,ToListAsync等等).

public Task<tblLanguage> Post(tblLanguage language)
{
    using (var langRepo = new TblLanguageRepository(new Entities()))
    {
        return langRepo.Add(RequestOrganizationTypeEnum, language);
    }
}
Run Code Online (Sandbox Code Playgroud)

在课堂上TblLanguageRepo:

public async Task<tblLanguage> Add(OrganizationTypeEnum requestOrganizationTypeEnum, tblLanguage language)
{
    ...
    await Context.SaveChangesAsync();
    return langaugeDb;
}
Run Code Online (Sandbox Code Playgroud)

但是,当我现在在一个using()块中包含我的语句时,我得到异常DbContext was disposed,在查询能够返回之前.这是预期的行为.查询运行async,using块在查询之前完成.但是在使用ef 6的async和await函数时,我应该如何以适当的方式处理我的上下文?

请指出我正确的方向.

using()需要EF 6?为什么微软自己的例子从未有过这样的特色?如何正确使用异步功能并处理上下文?

Ste*_*ary 24

你的代码:

public Task<tblLanguage> Post(tblLanguage language)
{
    using (var langRepo = new TblLanguageRepository(new Entities()))
    {
        return langRepo.Add(RequestOrganizationTypeEnum, language);
    }
}
Run Code Online (Sandbox Code Playgroud)

在返回之前处理存储库Task.如果您制作代码async:

public async Task<tblLanguage> Post(tblLanguage language)
{
    using (var langRepo = new TblLanguageRepository(new Entities()))
    {
        return await langRepo.Add(RequestOrganizationTypeEnum, language);
    }
}
Run Code Online (Sandbox Code Playgroud)

然后它将在Task完成之前处置存储库.实际发生的是当你点击时await,该方法返回一个不完整的Task(注意该using块在此时仍然是"活动的").然后,当langRepo.Add任务完成时,该Post方法继续执行并处理langRepo.当Post方法完成后,返回的Task完成.

有关更多信息,请参阅我的async介绍.

  • @danludwig:在这个案例中的`Add`在op的问题中给出.它是等待的(应该真的称为`AddAsync`). (7认同)

Dir*_*oer 5

我会采用“每个请求一个DbContext”的方式,并在请求内重用DbContext。由于所有任务都应在请求结束时完成,因此您可以安全地再次处置它。

请参见ie:ASP.NET MVC中的每个请求一个DbContext(没有IOC容器)

其他优点:

  • 在先前的查询中,某些实体可能已经在DbContext中实现,从而节省了一些额外的查询。
  • 您没有所有这些多余的using语句会使您的代码混乱。


dan*_*wig 1

同意@Dirk Boer 的观点,即管理 DbContext 生命周期的最佳方法是使用 IoC 容器,该容器在 http 请求完成时处理上下文。但是,如果这不是一个选择,您也可以执行以下操作:

var dbContext = new MyDbContext();
var results = await dbContext.Set<MyEntity>.ToArrayAsync();
dbContext.Dispose();
Run Code Online (Sandbox Code Playgroud)

using语句只是用于在代码块末尾处理对象的语法糖。using您只需调用自己即可达到相同的效果,无需阻塞.Dispose

想想看,如果您await在 using 块中使用关键字,则不应出现对象处置异常:

public async Task<tblLanguage> Post(tblLanguage language)
{
    using (var langRepo = new TblLanguageRepository(new Entities()))
    {
        var returnValue = langRepo.Add(RequestOrganizationTypeEnum, language);
        await langRepo.SaveChangesAsync();
        return returnValue;
    }
}
Run Code Online (Sandbox Code Playgroud)