首页 > 解决方案 > EntityFramework Core 如何在内部管理数据?

问题描述

我试图了解 EntityFramework Core 如何在内部管理数据,因为它会影响我调用 DbSet 的方式。特别是,它是指内存中的数据还是每次都重新查询数据库?

示例 1)

如果我调用_context.ToDo.Where(x => x.id == 123).First()然后在不同的过程中再次调用相同的命令,EF 会给我内存中的值还是重新查询数据库?

例 2)

如果我打电话_context.ToDo.Where(x => x.id == 123).First(),然后几行之后打电话_context.ToDo.Find(123).Where(x => x.id == 123).Incude(x => x.Children).First(),它会使用内存,然后只在数据库中查询“儿童”还是召回整个数据集?

我想我想知道是否重复通话是否重要?

这受 AsNoTracking() 开关的影响吗?

标签: entity-framework-core

解决方案


您真正要问的是 EF Core 中的缓存是如何工作的,而不是 DbContext 如何管理数据。

EF 始终提供第一级缓存 - 只要上下文保持活动状态,它就会将其加载的实体保存在内存中。这就是它可以跟踪更改并在SaveChanges调用时保存所有更改的方式。

缓存查询本身,因此它不知道这Where(....).First()意味着返回那些特定的实体。你必须Find()改用。如果禁用跟踪,则不会保留任何实体。

这在查询和查找实体中进行了解释,尤其是使用主键查找实体

DbSet 上的 Find 方法使用主键值来尝试查找上下文跟踪的实体。如果在上下文中未找到实体,则将向数据库发送查询以在其中查找实体。如果在上下文或数据库中找不到实体,则返回 Null。

查找与使用查询在两个重要方面不同:

  • 只有在上下文中找不到具有给定键的实体时,才会对数据库进行往返。
  • Find 将返回处于已添加状态的实体。也就是说,Find 将返回已添加到上下文但尚未保存到数据库的实体。

在示例 #2 中,查询是不同的。Include强制预先加载,因此返回的结果和实体是不同的。但是,如果第一个实体和上下文仍然存在,则无需再次调用它。您可以只迭代该属性,EF 将使用延迟加载Children一个一个地加载相关实体。

EF 将为它加载的每个子项执行 1 个查询。如果您需要加载所有这些,这很。慢到有自己的名字,N+1 选择问题。为避免这种情况,您可以使用显式加载显式加载相关集合,例如。:

_context.Entry(todo).Collection(t=>t.Children).Load();

但是,当您知道要使用所有子对象时,最好使用Include().


推荐阅读