为什么将 IQueryable 转换为 .toList() 包含对象 DbContext 的数据
本文关键字:对象 包含 DbContext 数据 IQueryable 转换 toList 为什么 | 更新日期: 2023-09-27 18:36:22
我有一个使用实体框架的代码示例
这个正在工作:
public ActionResult Index()
{
BlogContext dbContext = new BlogContext();
dbContext.Posts.Include(a => a.Tags).ToList();
return View(dbContext.Posts.ToList());
}
而这个不是:
public ActionResult Index()
{
BlogContext dbContext = new BlogContext();
dbContext.Posts.Include(a => a.Tags);
return View(dbContext.Posts.ToList());
}
所以我不明白,为什么只投射到List
就足以包含模型中的标签(List<Tags>
),我会理解它是否会像这样,这也很好(我正在使用那个!问题与代码格式无关!
public ActionResult Index()
{
BlogContext dbContext = new BlogContext();
var model=dbContext.Posts.Include(a => a.Tags).ToList();
return View(model);
}
但不一定。所以我的问题是:为什么将 IQueryable 转换为 toList 是将数据包含在对象dbContext
?我知道在实体框架中我们正在使用扩展,但据我所知,扩展返回值而不是为对象分配一个。
这是我崩溃的部分视图:
@using BlogWeb.Models
@model Post
<h1>@Model.Title</h1>
<p class="lead">
by <a href="#">1234</a>
</p>
<hr>
<p>@Model.Created</p>
<p class="lead">
@Model.Body
</p>
@Html.Partial("_Tags", Model.Tags) -<< this is what is throwing error
<hr>
这是一个部分标签视图
@using BlogWeb.Models
@model List<Tag>
@foreach (Tag tag in Model)
{
@Html.Label('#' + tag.TagName)
@Html.Raw(" ")
}
错误信息:
传递到字典中的模型项的类型为"BlogWeb.Models.Post",但此字典需要的模型项键入"System.Collections.Generic.List'1[BlogWeb.Models.Tag]"。
当你调用dbContext.Posts.Include(a => a.Tags);
时,你只是在创建一个查询。不会从数据库引入任何元素。
调用dbContext.Posts.Include(a => a.Tags).ToList();
时,您正在创建并执行查询。元素加载到内存中(包括Tags
属性)。
在第二个示例中,当您执行return View(dbContext.Posts.ToList());
时,内存中没有元素,并且您不会告诉包含元素何时来自数据库Tags
。
在第一个示例中,不包括Tags
,但 EF 会跟踪以前加载的元素以避免数据库查询,并且加载的这些元素包括Tags
。这就是为什么结果包括Tags
属性。
将这些 Linq 方法链接在一起时,您将在后台构建查询。添加Include(...)
告诉它在执行之前联接其他数据。调用 ToList()
时,将使用 Include(...)
执行 Linq 查询。
在第二个示例中,您没有执行查询,因此当您调用dbContext.Posts.ToList()
时,它没有缓存任何内容,并且是一个不同的查询,在没有Include(...)
的情况下执行。
,在使用集合ToList
、ToArray
、AsEnumerable
(我认为这就是全部)时,都会强制 EF 针对数据库执行并将对象具体化回内存。换句话说,如果您不迭代集合或调用其中一个集合,则不会发生任何事情。
这个正在工作:
public ActionResult Index()
{
BlogContext dbContext = new BlogContext();
dbContext.Posts.Include(a => a.Tags).ToList();
return View(dbContext.Posts.ToList());
}
EF 在内部跟踪实体的状态。因此,使用代码行dbContext.Posts.Include(a => a.Tags).ToList();
将检索所有帖子以及每个帖子的标签。当您调用return View(dbContext.Posts.ToList());
标签时,标签已经从数据库中检索到,除非您在那几分之一秒内添加了新帖子,否则不会有任何问题。
而这个不是:
public ActionResult Index()
{
BlogContext dbContext = new BlogContext();
dbContext.Posts.Include(a => a.Tags);
return View(dbContext.Posts.ToList());
}
第 dbContext.Posts.Include(a => a.Tags);
行告诉 EF 包含标记,但不会对它执行任何其他操作,您实际上只是扔掉了您正在处理的命令。然后,您调用dbContext.Posts.ToList()
,它只检索帖子。所以现在你有帖子,但没有包含的标签。
public ActionResult Index()
{
BlogContext dbContext = new BlogContext();
var model = dbContext.Posts.Include(a => a.Tags).ToList();
return View(model);
}
这是使用 EF 的方法,因为现在您不会丢弃DbSet<t>
上的结果。所有 EF 扩展命令都具体化了某些内容,并且您打算使用该结果。DbSets<T>
本身不是为了跟踪在其上执行的内容(使用 EF 实体跟踪,但这不是我要说的)。DbSet 不是命令对象,因此您不必这样使用它。