首页 > 其他分享 >EFCore 中的工作单元

EFCore 中的工作单元

时间:2024-03-30 17:23:54浏览次数:23  
标签:实体 更改 数据库 EF 工作 跟踪 EFCore SaveChanges 单元

保存数据

本文内容
方法 1:更改跟踪和 SaveChanges
方法 2:ExecuteUpdate 和 ExecuteDelete(“批量更新”)
总结
虽然查询允许从数据库中读取数据,但保存数据意味着向数据库添加新实体、删除实体或以某种方式修改现有实体的属性。 Entity Framework Core (EF Core) 支持将数据保存到数据库的两种基本方法。

方法 1:更改跟踪和 SaveChanges
在许多情况下,程序需要查询数据库中的某些数据,对其执行一些修改,并保存这些修改;这有时称为“工作单元”。 例如,假设你有一组博客,并且你想要更改其中一个博客的 Url 属性。 在 EF 中,这通常按如下方式完成:

c#

复制
using (var context = new BloggingContext())
{
var blog = context.Blogs.Single(b => b.Url == "http://example.com");
blog.Url = "http://example.com/blog";
context.SaveChanges();
}
上述代码执行以下步骤:

它使用常规 LINQ 查询从数据库加载实体(请参阅查询数据)。 默认情况下跟踪 EF 的查询,这意味着 EF 在其内部更改跟踪器中跟踪加载的实体。
通过分配 .NET 属性来照常操作加载的实体实例。 此步骤不涉及 EF。
最后调用 DbContext.SaveChanges()。 此时,EF 会自动检测任何更改,方法是将实体与加载实体时的快照进行比较。 检测到的任何更改都将保存到数据库;使用关系数据库时,这通常涉及发送 SQL UPDATE 来更新相关行。
请注意,上面描述了现有数据的典型更新操作,但添加和删除实体时遵循类似的原则。 通过调用 DbSet<TEntity>.Add 和 Remove 与 EF 的更改跟踪器交互,从而跟踪更改。 然后,当调用 SaveChanges() 时,EF 会将所有跟踪的更改应用于数据库(例如,在使用关系数据库时通过 SQL INSERT 和 DELETE)。

SaveChanges() 提供以下优势:

无需编写代码来跟踪已更改的实体和属性 - EF 会自动为你执行此操作,并且仅更新数据库中的这些属性,从而提高性能。 想象一下,如果加载的实体绑定到 UI 组件,允许用户更改他们想要的任何属性;EF 减轻了找出哪些实体和属性实际已更改的负担。
保存对数据库的更改有时可能很复杂! 例如,如果要添加一个博客并为该博客添加一些帖子,则可能需要为插入的博客提取数据库生成的密钥,然后才能插入帖子(因为它们需要引用博客)。 EF 为你完成所有这些操作,从而消除了复杂性。
EF 可以检测并发问题,例如,当其他人在你的查询和 SaveChanges() 之间修改了数据库行时。 并发冲突中提供了更多详细信息。
在支持它的数据库中,SaveChanges() 自动包装事务中的多个更改,确保在发生故障时数据保持一致。 事务中提供了更多详细信息。
在许多情况下,SaveChanges() 还会对多个更改进行批处理,从而显著减少数据库往返次数并大幅提高性能。 高效更新中提供了更多详细信息。
有关基本 SaveChanges() 用法的详细信息和代码示例,请参阅基本 SaveChanges。 有关 EF 更改跟踪的详细信息,请参阅更改跟踪概述。

方法 2:ExecuteUpdate 和 ExecuteDelete(“批量更新”)
备注

EF Core 7.0 中已引入此功能。

虽然更改跟踪和 SaveChanges() 是保存更改的强大方法,但它们确实存在某些缺点。

首先,SaveChanges() 要求查询和跟踪要修改或删除的所有实体。 如果需要删除评分低于特定阈值的所有博客,则必须查询、具体化和跟踪可能大量的行,并让 SaveChanges() 为每个行生成 DELETE 语句。 关系数据库提供了一个更高效的替代方法:可以发送单个 DELETE 命令,通过 WHERE 子句指定要删除的行,但 SaveChanges() 模型不允许生成该行。

若要支持此“批量更新”方案,可以使用 ExecuteDelete,如下所示:

c#

复制
context.Blogs.Where(b => b.Rating < 3).ExecuteDelete();
这允许通过常规 LINQ 运算符(类似于常规 LINQ 查询)来表达 SQL DELETE 语句,从而针对数据库执行以下 SQL:

SQL

复制
DELETE FROM [b]
FROM [Blogs] AS [b]
WHERE [b].[Rating] < 3
这会在数据库中非常高效地执行,无需从数据库加载任何数据或涉及 EF 的更改跟踪器。 同样,ExecuteUpdate 允许表达 SQL UPDATE 语句。

即使未批量更改实体,也可能确切地知道要更改哪个实体的哪些属性。 使用更改跟踪 API 执行更改可能过于复杂,需要创建实体实例,通过 Attach 跟踪它,进行更改,最后调用 SaveChanges()。 对于此类方案,ExecuteUpdate 和 ExecuteDelete 可能是表示相同操作的更简单方法。

最后,更改跟踪和 SaveChanges() 本身都会产生特定的运行时开销。 如果要编写高性能应用程序,则使用 ExecuteUpdate 和 ExecuteDelete 可以避免这两个组件并有效地生成所需的语句。

但是,请注意,ExecuteUpdate 和 ExecuteDelete 也有一些限制:

这些方法会立即执行,目前无法与其他操作一起批处理。 另一方面,SaveChanges() 可以同时批处理多个操作。
由于不涉及更改跟踪,因此你有责任确切地知道需要更改哪些实体和属性。 这可能意味着更多的手动、低级别代码跟踪需要更改的内容和不需要更改的内容。
此外,由于不涉及更改跟踪,因此在保留更改时,这些方法不会自动应用并发控制。 但是,你仍然可以显式添加 Where 子句来自行实现并发控制。
目前仅支持更新和删除;必须通过 DbSet<TEntity>.Add 和 SaveChanges() 完成插入。
有关详细信息和代码示例,请参阅 ExecuteUpdate 和 ExecuteDelete。

总结
下面是有关何时使用哪种方法的一些准则。 请注意,这些不是绝对规则,但提供了有用规则的缩略图:

如果事先不知道将发生哪些更改,请使用 SaveChanges;它将自动检测需要应用的更改。 示例方案:
“我想要从数据库加载博客并显示允许用户更改它的表单”
如果需要操作一个对象图(即多个相互连接的对象),请使用 SaveChanges;它将确定更改的正确顺序以及如何将所有内容链接在一起。
“我想要更新博客,更改其中某些帖子并删除其他帖子”
如果要根据某些条件更改可能大量的实体,请使用 ExecuteUpdate 和 ExecuteDelete。 示例方案:
“我想要给所有员工加薪”
“我想要删除名称以 X 开头的所有博客”
如果已经确切地知道要修改哪些实体以及如何更改它们,请使用 ExecuteUpdate 和 ExecuteDelete。 示例方案:
“我想要删除名称为‘Foo’的博客”
“我想要将 ID 为 5 的博客名称更改为 'Bar'”

标签:实体,更改,数据库,EF,工作,跟踪,EFCore,SaveChanges,单元
From: https://www.cnblogs.com/zy8899/p/18105759

相关文章

  • EFCore中ExecuteUpdate 和 ExecuteDelete
    ExecuteUpdate和ExecuteDelete项目2023/05/114个参与者反馈本文内容ExecuteDeleteExecuteUpdateChangetracking事务显示另外3个备注EFCore7.0中已引入此功能。ExecuteUpdate和ExecuteDelete是一种将数据保存到数据库的方法,无需使用EF的传统更改跟踪和SaveChang......
  • 基于SpringBoot+Vue的高校工作室管理系统的详细设计和实现(源码+lw+部署文档+讲解等)
    文章目录前言详细视频演示具体实现截图技术栈后端框架SpringBoot前端框架Vue持久层框架MyBaitsPlus系统测试系统测试目的系统功能测试系统测试结论为什么选择我自己的网站自己的小程序(小蔡coding)代码参考数据库参考源码获取前言......
  • 经典Prompt欣赏 - 给代码生成单元测试
    在Twitter上看到一段给代码生成单元测试的Prompt:https://twitter.com/mattshumer_/status/1773385952699789808虽然它是针对Claude3的,但理论上来说可以适用于绝大部分模型。Prompt如下:<prompt_explanation>Youareanexpertsoftwaretestertaskedwiththoroughlytest......
  • 经典Prompt欣赏 - 给代码生成单元测试
    在Twitter上看到一段给代码生成单元测试的Prompt:https://twitter.com/mattshumer_/status/1773385952699789808虽然它是针对Claude3的,但理论上来说可以适用于绝大部分模型。Prompt如下:<prompt_explanation>Youareanexpertsoftwaretestertaskedwiththoroughlytest......
  • 2024-03-30:用go语言,集团里有 n 名员工,他们可以完成各种各样的工作创造利润, 第 i 种工
    2024-03-30:用go语言,集团里有n名员工,他们可以完成各种各样的工作创造利润,第i种工作会产生profit[i]的利润,它要求group[i]名成员共同参与,如果成员参与了其中一项工作,就不能参与另一项工作,工作的任何至少产生minProfit利润的子集称为盈利计划,并且工作的成员总数最多为......
  • SpringBoot + Activiti 工作流搭建与实现(附文档+源码)
      前言activiti工作流引擎项目,企业erp、oa、hr、crm等企事业办公系统轻松落地,一套完整并且实际运用在多套项目中的案例,满足日常业务流程审批需求。一、项目形式springboot+vue+activiti集成了activiti在线编辑器,流行的前后端分离部署开发模式,快速开发平台,可插拔工作流服务......
  • 在Linux中,什么是虚拟内存?它是如何工作的?
    虚拟内存是一种内存管理技术,它允许操作系统使用硬盘空间来模拟额外的内存资源。虚拟内存的工作原理涉及以下几个关键概念:地址空间:每个进程拥有自己的虚拟地址空间,这个空间对于进程来说是一致的和私有的。虚拟地址空间的大小通常远大于物理内存的大小。分页机制:操作系统将物理......
  • Junit深入讲解(JAVA单元测试框架)
    1、此处用的是Junit5,此处pom文件需要引的依赖是<dependency><groupId>org.junit.jupiter</groupId><artifactId>junit-jupiter-api</artifactId><version>5.9.1</version><scope&......
  • mysql之MyBatis核心工作原理
    MyBatis核心工作原理一、源码环境1.手动编译源码工欲善其事必先利其器。为了方便我们在看源码的过程中能够方便的添加注释,我们可以自己来从官网下载源码编译生成对应的Jar包,然后上传到本地maven仓库,再引用这个Jar。大家可以自行去官网下载*gitclonehttps://github.co......
  • 客快物流大数据项目(六十八):工作流调度 azkaban介绍及用法 一般有用 图片偏多 看1
    工作流调度一、工作流产生背景工作流(Workflow),指“业务过程的部分或整体在计算机应用环境下的自动化”。是对工作流程及其各操作步骤之间业务规则的抽象、概括描述。工作流解决的主要问题是:为了实现某个业务目标,利用计算机软件在多个参与者之间按某种预定规则自动传递文档、信息......