前言

踩了一个坑, 下面是 2 个 scope 的调用, 第 1 和 3 是一个 Audit log filter action, 第 2 个是 controller.

// open tran
// edit entity 1
// save change 1 // save point A
// edit entity 2
// save change 2 (fail, let's said due to sql unique constrain)
// catch { rollback to save point A } // edit entity 3
// save change 3 // commit (expected 1,3 will be saved)

需求是即使 controller 报错了, 但是 audit log 还是要记入. 直觉认为 controller 报错或 rollback to save point 就 ok 了,

但最终结果是 save change 3 也报错了. 因为 rollback to save point 并不会 rollback dbcontext state. 与至于 save change 3 耶跑了 edit entity 2, 这就报错了.

然后我就找到了这个 issue: DbContextTransaction should also rollback dbcontext, 提问者视乎也遇到了相同的情况.

参考:

Use both AddDbContextFactory() and AddDbContext() extension methods in the same project

Scoped service in DBContext with DBContextFactory can't resolve from root provider

DbContextTransaction should also rollback dbcontext

DbContext Lifetime, Configuration, and Initialization

DbContext = Unit of Work

在 EF Core Team 的回复中, 他们的角度是. 如果想要有一个 unit of work, 就开 1 个 dbcontext.

在这个 dbcontext 里面, 它负责维护修修改改的 entity state, 当 save changes 调用时, 它把所有 state 转换成 SQL query.

如果 save changes 顺利执行, 那么所有的 state 会 clear 掉 (变成 unchanged), 然后你可以开始下一轮的 unit of work.

如果 save changes 失败, 那么所有的 state 会保留着, 你可以修修改改在重试.

绝大部分情况下, 1 个 http request 用一个 unit of work 就足够了, 也就是一个 dbcontext 来 handle 就很恰当了, 所以默认 dbcontext 在 DI 是 scoped level.

但某些情况下可能会想要多个 unit of work for 1 http request, 这也是合理的.

可以使用 DbContextFactory 来创建.

要注意 lifetime, 它默认是 Singleton, 如果 ApplicationDbContext 有注入 scoped service 的话, 这里要改成 scoped.

总结, dbcontext 就像一个环境, 管理 entity state, 在一个 http request 中, 可以创建多个相同的 dbcontext, 来执行多个 unit of work, 这取决于想怎样去管理.

Unit of Work != Transaction

dbcontext 可以开启 transaction, 但也可以复用 transaction. 意味着, 多个 unit of work 是可以共享 transaction 的.

dbcontext save changes 以后, unit of work 就算完成了. 后续它有没有真的写入数据库, 这个得开 transaction 是否 commit/rollback.

所以可以理解 dbcontext 和 transaction 的职责是分的很开的. 这也是为什么 transaction rollback, dbcontext 却没有 rollback, 因为它们本来就没有什么牵连.

dbcontext save changes 成功的话, state 立马就 clear 了. 但这时 transaction 要 commit/rollback 根本还没有决定. 它才开始进入这个 step 而已.

总结

dbcontext = unit of work

1 个 http request 可以有多个 dbcontext 管理 entity state (比如 1 个 for audit log, 1 个 for controller, 它们互相不影响)

在 save changes 失败或, entity state 依旧会保留着, 可以 retry 也可以通过 dbContext.ChangeTracker.Clear() 清空它, 它可以把 Added 变成 Detached.

1 transaction 可以 shared with multiple dbcontext.

transaction 接手 dbcontext save changes 后的工作. 它决定那么 save changes 是否要永久写入数据库. 或者回滚, 或者回滚某些 save changes (基于 save point)

EF Core – Unit of Work, DbContext, Transaction 概念解释的更多相关文章

  1. EF Core 2.0中Transaction事务会对DbContext底层创建和关闭数据库连接的行为有所影响

    数据库 我们先在SQL Server数据库中建立一个Book表: CREATE TABLE [dbo].[Book]( ,) NOT NULL, ) NULL, ) NULL, ) NULL, [Cr ...

  2. EF Core如何输出日志到Visual Studio的输出窗口

    我们在使用EF Core的时候,很多时候需要在Visual Studio的输出窗口中知道EF Core在后台生成的SQL语句是什么,这个需求可以通过自定义EF Core的ILoggerFactory和 ...

  3. Asp.Net Core中创建多DbContext并迁移到数据库

    在我们的项目中我们有时候需要在我们的项目中创建DbContext,而且这些DbContext之间有明显的界限,比如系统中两个DbContext一个是和整个数据库的权限相关的内容而另外一个DbConte ...

  4. Asp.net core 学习笔记 ( ef core transaction scope & change level )

    ef core 有 unit of work 的概念,当我们 save change 时会自动使用 transaction 确保更新的一致性. 隔离级别是默认的 read committed 不允许脏 ...

  5. EF Core利用Transaction对数据进行回滚保护

    What? 首先,说一下什么是EF Core中的Transaction Transaction允许以原子方式处理多个数据库操作,如果事务已提交,则所有操作都应用于数据库,如果事务回滚,则没有任何操作应 ...

  6. asp.net core 系列 22 EF(连接字符串,连接复原,DbContext)

    一.连接字符串 在上二篇中,ASP.NET Core 应用程序连接字符串是写死在ConfigureServices代码中,下面介绍通过配置来实现.连接字符串可以存储在 appsettings.json ...

  7. 第三节:EF Core上下文DbContext相关配置和生命周期

    一. 配置相关 1. 数据库连接字符串的写法 (1).账号密码:Server=localhost;Database=EFDB01;User ID=sa;Password=123456; (2).win ...

  8. EF Core 快速上手——创建应用的DbContext

    系列文章 EF Core 快速上手--EF Core 入门 EF Core 快速上手--EF Core的三种主要关系类型 本节导航 定义应用的DbContext 创建DbContext的一个实例 创建 ...

  9. EF Core中DbContext可以被Dispose多次

    我们知道,在EF Core中DbContext用完后要记得调用Dispose方法释放资源.但是其实DbContext可以多次调用Dispose方法,虽然只有第一次Dispose会起作用,但是DbCon ...

  10. EF Core 中DbContext不会跟踪聚合方法和Join方法返回的结果,及FromSql方法使用讲解

    EF Core中: 如果调用Queryable.Count等聚合方法,不会导致DbContext跟踪(track)任何实体. 此外调用Queryable.Join方法返回的匿名类型也不会被DbCont ...

随机推荐

  1. Session的默认保存路径

    在php.ini里的配置session.save_path是注释掉的,那么Seesion保存的路径在不同类型操作系统保存在什么位置? Linux:/tmp 或 /var/lib/php/session ...

  2. linux系统是未来_大小写敏感_case_sensitive_编程原生态

    修改 py 文件 回忆上次内容 上次尝试了 两个vim 同时打开 同一py文件 vim出现了Error 有各种选择     错误拼写 pront 导致 运行时 出现了NameError         ...

  3. oeasy 教您玩转 linux 之 010301 电子宠物 pet

    我们来回顾一下 上一部分我们都讲了什么? 中️文诗词fortune=zh的使用 建立自己的彩色诗词库 通过pip把输出结果交给cowsay或boxes 我们这次讲一讲桌面的一些应用 oneko 我们可 ...

  4. WPF/C#:实现导航功能

    前言 在WPF中使用导航功能可以使用Frame控件,这是比较基础的一种方法.前几天分享了wpfui中NavigationView的基本用法,但是如果真正在项目中使用起来,基础的用法是无法满足的.今天通 ...

  5. Sonar 扫描之分析参数介绍

    Sonar扫描之分析参数介绍 强制参数 服务器 Key 描述 默认 sonar.host.url 服务器网址 http://localhost:9000 项目配置 Key 描述 默认 sonar.pr ...

  6. 推荐几款.NET开源且功能强大的实用工具,助你提高工作开发效率!

    前言 俗话说得好"工欲善其事,必先利其器",今天大姚给大家推荐8款.NET开源且功能强大的实用工具,助你提高工作开发效率! DevToys 一款基于C#开源(MIT License ...

  7. 2023/4/14 SCRUM个人博客

    1.我昨天的任务 初步了解项目的整体框架,并对接下来的人脸识别库以及组件有基本了解和安装 2.遇到了什么困难 ------------ 3.我今天的任务 获得了人脸识别作弊检测和绘制界面的分工,准备先 ...

  8. Jmeter函数助手15-FiletoString

    FiletoString函数用于一次读取整个文件值. 输入文件的全路径:填入文件路径 File encoding if not the platform default (opt):读取文件的编码格式 ...

  9. SQL提高查询性能的几种方式

    创建索引,提高性能 索引可以极大地提高查询性能,其背后的原理: 索引是的数据库引擎能够快速的找到表中的数据,它们类似于书籍的目录,使得你不需要逐页查找所需要的信息 索引能够帮助数据库引擎直接定位到所需 ...

  10. 【Java】图片压缩处理

    需求如下: 一些图片太大了,手机拍摄上传的图片有5M大小,然后阅读的内容其实不需要特别高的分辨率 1M以下的图片并不需要被压缩,压缩只是针对部分过大的图片处理 图片处理库: 我看了几篇,还是选代码量最 ...