在 MVC 控制器中,想要异步返回 EntityFramework CodeFirst 数据
In MVC Controller, wanting async for returning EntityFramework CodeFirst data
我想在我的 ASP.NET MVC 控制器中使用 async/await 模式。我收到错误
The ObjectContext instance has been disposed and can no longer be used
最终,我想缓存我的结果,但现在我认为第一步只是弄清楚如何使用 EF 和 return 以及 async/await
public class SpeakerController : Controller
{
public async Task<ActionResult> Index()
{
using (var context = new MultiTenantContext())
{
var speakersAll = await context.Speakers.ToListAsync();
return View("Index", speakersAll);
}
}
找到的解决方案:
private MultiTenantContext context = new MultiTenantContext();
public async Task<ActionResult> Index()
{
var speakersAll = await context.Speakers.ToListAsync();
return View("Index", speakersAll);
}
正如我在下面的评论中所说,从 using 中提取上下文会导致它在 ToListAsync() 实际执行时不会被释放。
如果您是 lazy-loading Speaker.Sessions,您的上下文在使用时早已消失,因此出现了问题。
试试这个:
await context.Speakers.Include(x => x.Sessions).ToListAsync();
确保在上下文超出范围之前加载会话。
您可以使用不同的模式;例如允许 Context 寿命更长,但我个人认为 very-short-lived 上下文在 using()
块内,就像你所做的那样,如果你不需要某种工作单元模式,那是最好的。
虽然这不是这里的问题 - 您也不应该在 EF 中混合使用 lazy-loading 和 async-await:
您应该避免在 Web 应用程序中使用延迟加载,因为目标是最大限度地减少 HTTP 请求的响应时间,而这最好通过较少的数据库请求来实现。特别是在 MVC and/or Web API 中,你有非常精细的操作方法,在大多数情况下应该可以准确地确定你的数据需求是什么,并将这些包含在一个或很少的 requests/queries.这会减轻数据库服务器的负载,并提高 Web 请求的性能。
至于使用语句和 dbcontexts,如果可以的话,您不应该在控制器中实例化 dbcontexts。最好注入它们,让你的容器决定如何管理它们的生命周期。通常,您会希望每个请求只有一个 dbcontext 实例,这将可用于您需要 EF 在请求生命周期内进行的所有查询(无论这些查询可能很少)。如果您使用的是 StructureMap(我的偏好),您可以通过以下方式实现:
For<DbContext>.HybridHttpOrThreadLocalScoped().Use<MyContext>();
(请注意,此语法随 StructureMap 4 一起更新)
如果您不确定是否相信我的建议,请考虑 EF7 正在进一步采纳此建议,并且在不使用依赖项注入的情况下很难使用 EF7 和 MVC 6 ,努力推动开发人员做正确的事(陷入 "the pit of success" )。有关示例,请参阅官方 asp.net 文档中的 EF7/MVC6 教程 (http://docs.asp.net/projects/mvc/en/latest/tutorials/mvc-with-entity-framework.html)。
摘录:
Notice that we don’t set any value for Logger and BookContext. The
dependency injection (DI) subsystem automatically sets these
properties at runtime. DI also handles the object lifetimes, so you
don’t need to call Dispose. For more information, see Dependency
Injection.
我想在我的 ASP.NET MVC 控制器中使用 async/await 模式。我收到错误
The ObjectContext instance has been disposed and can no longer be used
最终,我想缓存我的结果,但现在我认为第一步只是弄清楚如何使用 EF 和 return 以及 async/await
public class SpeakerController : Controller
{
public async Task<ActionResult> Index()
{
using (var context = new MultiTenantContext())
{
var speakersAll = await context.Speakers.ToListAsync();
return View("Index", speakersAll);
}
}
找到的解决方案:
private MultiTenantContext context = new MultiTenantContext();
public async Task<ActionResult> Index()
{
var speakersAll = await context.Speakers.ToListAsync();
return View("Index", speakersAll);
}
正如我在下面的评论中所说,从 using 中提取上下文会导致它在 ToListAsync() 实际执行时不会被释放。
如果您是 lazy-loading Speaker.Sessions,您的上下文在使用时早已消失,因此出现了问题。
试试这个:
await context.Speakers.Include(x => x.Sessions).ToListAsync();
确保在上下文超出范围之前加载会话。
您可以使用不同的模式;例如允许 Context 寿命更长,但我个人认为 very-short-lived 上下文在 using()
块内,就像你所做的那样,如果你不需要某种工作单元模式,那是最好的。
虽然这不是这里的问题 - 您也不应该在 EF 中混合使用 lazy-loading 和 async-await:
您应该避免在 Web 应用程序中使用延迟加载,因为目标是最大限度地减少 HTTP 请求的响应时间,而这最好通过较少的数据库请求来实现。特别是在 MVC and/or Web API 中,你有非常精细的操作方法,在大多数情况下应该可以准确地确定你的数据需求是什么,并将这些包含在一个或很少的 requests/queries.这会减轻数据库服务器的负载,并提高 Web 请求的性能。
至于使用语句和 dbcontexts,如果可以的话,您不应该在控制器中实例化 dbcontexts。最好注入它们,让你的容器决定如何管理它们的生命周期。通常,您会希望每个请求只有一个 dbcontext 实例,这将可用于您需要 EF 在请求生命周期内进行的所有查询(无论这些查询可能很少)。如果您使用的是 StructureMap(我的偏好),您可以通过以下方式实现:
For<DbContext>.HybridHttpOrThreadLocalScoped().Use<MyContext>();
(请注意,此语法随 StructureMap 4 一起更新)
如果您不确定是否相信我的建议,请考虑 EF7 正在进一步采纳此建议,并且在不使用依赖项注入的情况下很难使用 EF7 和 MVC 6 ,努力推动开发人员做正确的事(陷入 "the pit of success" )。有关示例,请参阅官方 asp.net 文档中的 EF7/MVC6 教程 (http://docs.asp.net/projects/mvc/en/latest/tutorials/mvc-with-entity-framework.html)。
摘录:
Notice that we don’t set any value for Logger and BookContext. The dependency injection (DI) subsystem automatically sets these properties at runtime. DI also handles the object lifetimes, so you don’t need to call Dispose. For more information, see Dependency Injection.