2 回答
TA贡献1802条经验 获得超6个赞
当直接从数据库提供 IEnumerable 时,控制器如何工作?
(我假设你的意思是直接从你的IEnumerable返回一个未执行的)IQueryableDbContext
他们不会,你也不应该- 这是因为未执行的IQueryable数据并不代表已加载的数据 - 当它执行时,它只能从打开的数据库连接加载数据 - 这需要一个活动且有效的DbContext.
...所以如果 被DbContext处置,则IQueryable无法执行。
如果您DbContext在控制器内部创建操作并IQueryable在视图中渲染或在ObjectResponse(对于 Web API)中返回它,那么它总是会失败:
public IActionResult GetPeople()
{
// WARNING: NEVER DO THIS!
using( MyDbContext db = new MyDbContext( GetConnectionString() ) )
{
return this.Ok( db.People.Where( p => p.Name == "John Smith" ) );
// or:
return this.View( model: db.People.Where( p => p.Name == "John Smith" ) );
}
}
请记住,.Ok()andthis.View()不会触发视图的评估或向客户端发送对象响应 - 相反,它会导致控制器操作首先结束,然后将数据传递到 ASP.NET 管道中的下一步(即视图) 。请记住:视图在控制器操作完成后执行。
如果您使用依赖注入在控制器中拥有一个现成的实例DbContext,那么结果就不太可预测:IQueryable在操作方法返回后仍然可以对 进行评估,因为DbContext直到控制器被处置之后才会被处置,通常是在视图已呈现,但是您仍然不应该这样做,因为您IQueryable仍然可能会传递到某个比您的 Controller 类的生命周期更长的进程,这会导致失败。您还应该避免它,因为视图被设计为快速同步渲染 - 外部数据库或 IO 调用会破坏该设计。
(无论如何,您都不应该使用实体框架实体对象作为根 ViewModel,但这是另一个讨论)。
如果您总是使用操作async(DbContext例如ToListAsync(),ToDictionaryAsync等 - 因为它们分别返回 aTask<List<T>>或TaskDictionary<TKey,TValue>>- 这需要一个await编译器默认情况下会阻止您在视图或对象结果中执行的操作,则可以避免这种习惯(您可以await在视图中使用,但这是不可取的,需要在某处设置一些设置)。
简而言之,始终这样做:
public async Task<IActionResult> GetPeople()
{
using( MyDbContext db = new MyDbContext( GetConnectionString() ) )
{
List<Person> list = await db.People
.Where( p => p.Name == "John Smith" )
.ToListAsync();
// WebAPI:
return this.Ok( list ); // returning an evaluated list, loaded into memory. (Make sure Lazy Navigation Properties are disabled too)
// MVC:
PeopleListViewModel vm = new PeopleListViewModel(); // in MVC always use a custom class for root view-models so you're not accepting nor returning Entity Framework entity types directly
vm.List = list;
return this.View( vm );
}
}
TA贡献1995条经验 获得超2个赞
您正在返回一个由 mvc 框架执行的任务;
当你等待一个任务时,你就开始(异步)运行它,然后获取结果并将其交给 mvc 框架;
您将返回一个由 mvc 框架执行的枚举器。
我会选择选项#2,因为您确切知道数据库查询何时执行。由于您要返回任务并正确使用 async 和 wait 关键字,因此框架将尽可能多地保持线程繁忙,从而利用应用程序的吞吐量。
- 2 回答
- 0 关注
- 147 浏览
添加回答
举报