为什么将 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]"。

为什么将 IQueryable 转换为 .toList() 包含对象 DbContext 的数据

当你调用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(...)的情况下执行。

请记住

,在使用集合ToListToArrayAsEnumerable(我认为这就是全部)时,都会强制 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 不是命令对象,因此您不必这样使用它。

相关文章: