为什么脚手架生成的控制器在将其传递到视图之前将其 DbContext 的 DbSet 属性 转换为列表?

Why does the scaffolding-generated controller convert its DbContext's DbSet property to a List before passing it into a view?

我正在关注 Microsoft's ASP.NET MVC tutorial,作为其中的一部分,我通过脚手架为模型 Movie 生成了 CRUD 操作。

索引视图顶部有以下行:

@model IEnumerable<MvcMovie.Models.Movie>

然后控制器通过首先将其 DbContextDbSet<MvcMovie.Models.Movie> 转换为列表来传递该对象:

public async Task<IActionResult> Index()
{
    return View(await _context.Movie.ToListAsync());
}

教程确认这是预期的行为:

Examine the Index.cshtml view and the Index method in the Movies controller. Notice how the code creates a List object when it calls the View method. The code passes this Movies list from the Index action method to the view:

但是,查看 DbSet class,它实现了 IEnumerable<TEntity>,在这种情况下,TEntity 是 Movie 对象。那么,为什么要把它转换成列表呢?

我按原样通过 _context.Movie 测试了这个,它似乎工作得很好。

那么这样做有什么原因吗?

I tested this by passing _context.Movie as-is, and it seems to work perfectly fine.

似乎 工作得很好,在最简单的情况下,它甚至可以工作。然而:

View方法需要遍历你传入的数据。在DbSet<T>的情况下,这意味着整个数据库table将是SELECTed 同步。关于包括数据库调用在内的同步和异步操作之间的区别,有很多posts/etc,所以我不会深入细节,只是说:在大多数情况下,Entity Framework Core 的同步用法必须是避免了。
这意味着,为了确保查询的异步执行,必须使用其中一个异步查询执行器,ToListAsync 是一个常见的选择,尽管 ToArrayAsync 可以很好地用于此目的。

这是第一部分。第二部分是,由于您要返回对 DbSet<T> 的引用,数据还不在内存中,因此在执行查询的某个时间点之前,需要打开与数据库的连接。另一个问题是查询可能最终被执行多次,这取决于将结果发送回客户端的任何实现。