前言

踩了一个坑, 下面是 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. oeasy教您玩转vim - 37 - # 删除字符

    ​ 通过十进制的 ascii 值输入字符 在输入模式下 输入 ctrl + v 然后再输入 065 通过十六进制的 unicode 在输入模式下 输入 ctrl + v 然后再输入 u2642 就可以 ...

  2. oeasy教您玩转vim - 71 - # 视图view

    ​ 视图view 回忆上次折叠的细节 折叠方式很多 我们一般就用默认的就行 indent 很好用 前提是缩进语法严格到位 这样语法和排版都能同时确保 打开关闭 zc.zo 是打开关闭当前行 zm.zr ...

  3. C#枚举高级应用

    文章开头先看一道题: 在设计某小型项目的数据库(假设用的是 MySQL)时,如果给用户表(User)添加一个字段(Roles)用来存储用户的角色,你会给这个字段设置什么类型?提示:要考虑到角色在后端开 ...

  4. Java工具库——Hutool的常用方法

    Hutool-All(或简称Hutool)是一个功能强大的Java编程工具库,旨在简化Java应用程序的开发. 它提供了大量的工具类和方法,涵盖了各种常见任务,包括字符串处理.日期时间操作.文件操作. ...

  5. 【SpringCloud】Nacos集群部署(Centos平台)

    一.前提环境准备 Nacos 下载 https://github.com/alibaba/nacos/releases 或者使用其它博主备份的 https://blog.csdn.net/weixin ...

  6. 【MongoDB】Re05 分片集群(Win平台搭建)

    分片副本集1 (3实例)  主1 从1 裁1 分片副本集2 (3实例)  主1 从1 裁1 配置副本集(3实例) 主1 从2 路由(2配置) 用Windows平台搭建 配置目录设置: ├─config ...

  7. 【SpringBoot】02 概述

    [目标] - 什么是SpringBoot? 并不是新技术,只是一个Spring的加强 解脱XML配置,增加了新的注解,但是并不是新的内容 - 新型配置文件技术 YAML - 自动装配原理[了解即可,不 ...

  8. 【Quartz】

    一.Quartz概述 Quartz是用来做定时任务调度的JavaEE框架 需求场景: 1.在每个月末,自动网易云会员续费,或者百度云盘会员续费 2.在迅雷下载完一个超过10G的资源的30秒之后自动关机 ...

  9. 神奇的发现——所有的aarch64架构的CPU平台下的深度学习框架均不原生支持CUDA

    一个记录: 神奇的发型--所有的aarch64架构的CPU平台下的深度学习框架均不原生支持CUDA 不论是mindspore.pytorch.TensorFlow框架只要是aarch64架构的CPU下 ...

  10. WPF Boolean类型转化器收集 反转转化器

    参考链接 https://stackoverflow.com/questions/534575/how-do-i-invert-booleantovisibilityconverter Boolean ...