entity-framework-core - 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() 开关的影响吗?
解决方案
您真正要问的是 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()
.
推荐阅读
- java - 在 64 位 Windows 上找不到 PKCS#11 库
- python - 气流任务取决于另一个任务结果?
- gulp - gulp init 要求进行本地安装,但我有 CLI 版本
- tensorflow - 为什么我在 TensorFlow Keras 中的损失函数和指标之间得到不同的值?
- sql-server - 如何从 LSN 中减去
- node.js - mac 中缺少对 /usr/local/lib/node_modules 的写访问权限
- environment-variables - 在生态系统配置中启用 CI 秘密变量?
- java - 在 RxJava 中的另一个线程上发出第一个元素
- visual-c++ - 作为左操作数的函数 - 我该怎么办?
- xamarin.forms - 工具栏项的 Xamarin 表单自动化 ID