新生自动报名所有必修课:EntityFrameworkCore.Triggered级联触发器实战演示
【免费下载链接】EntityFrameworkCore.TriggeredTriggers for EFCore. Respond to changes in your DbContext before and after they are committed to the database.项目地址: https://gitcode.com/gh_mirrors/en/EntityFrameworkCore.Triggered
EntityFrameworkCore.Triggered 是一个专为 EF Core 打造的触发器(Trigger)扩展库,它让你可以在实体写入数据库之前或之后自动执行业务逻辑。今天我们就用它的官方"小学示例"实战演示:当一个新生被添加到数据库时,如何借助级联触发器自动完成所有必修课的报名,而你的业务代码一行都不用写。🎓
一、为什么需要 EF Core 触发器?
想象这样一个场景:每新增一名学生,系统都要确保他报名了所有必修课。没有触发器时,这段逻辑通常散落在各种 Service、Controller 里,很容易漏掉某个入口(比如批量导入、API 调用)。
EntityFrameworkCore.Triggered 的思路是:把业务规则绑定到实体上,而不是绑到调用入口上。只要你对DbContext调用了SaveChanges,与实体相关的触发器就会被自动执行,无论这次保存来自哪个功能模块。
核心能力一览:
- ⚡Before 触发器:在数据落库前执行,可以直接修改实体或往 DbContext 里追加新实体
- 🚀After 触发器:在数据落库后执行,适合发通知、记日志
- 🔄级联触发器:Before 触发器里新增的实体,还能继续触发它们自己的触发器
- 🛡错误触发器:
SaveChanges抛出异常时执行IAfterSaveFailedTrigger做善后
二、官方示例:PrimarySchool 里的自动报名
项目自带了一个非常直观的示例,位于samples/2 - PrimarySchool/目录,我们直接拆解它。
数据模型:学生、课程、选课记录
samples/2 - PrimarySchool/ApplicationDbContext.cs中定义了三个实体:
| 实体 | 作用 |
|---|---|
Student | 学生,含学号、姓名、注册日期 |
Course | 课程,含IsMandatory标记是否为必修课 |
StudentCourse | 学生与课程的关联表,以(学生Id、课程Id)为复合主键 |
注册触发器:一行 UseTriggers 搞定
在samples/2 - PrimarySchool/Program.cs中,整个集成只需要在配置 DbContext 时加一个UseTriggers:
options.UseInMemoryDatabase("PrimarySchool") .UseTriggers(triggerOptions => { triggerOptions.AddTrigger<Triggers.StudentSignupToMandatoryCourses>(); });注册完成后,程序往数据库里添加了两门课程(必修的数学、选修的美术),然后添加了一名叫 Joe 的学生并调用SaveChanges。最终控制台输出:
Joe is registered for course Mathematics
Joe 被自动报上了必修课——这就是我们接下来要看的核心机制。✨
三、触发器代码解读:自动报名是怎么发生的?
自动报名的全部逻辑都在samples/2 - PrimarySchool/Triggers/StudentSignupToMandatoryCourses.cs里,它实现了IBeforeSaveAsyncTrigger<Student>接口,意思是"Student 实体保存前,先执行我"。
它做了三件事:
- 查询出所有
IsMandatory == true的必修课 - 逐个检查当前学生是否已经报名(
StudentCourses.Find) - 没有报名的课程,就往 DbContext 里追加一条
StudentCourse记录
关键在于第 3 步:触发器是在SaveChanges真正写库之前执行的,此时往 DbContext 追加的新实体会被一起提交。换句话说,你保存 1 个学生,数据库里却写入了 1 个学生 + N 条选课记录,浑然一体。💪
四、级联是如何工作的:EntityAndType 级联策略
这里就引出了标题中的主角——级联(Cascading)。
在 Before 触发器里往 DbContext 追加了新实体后,库会重新扫描变更集。如果新实体也有注册的触发器,这些触发器同样会被触发,就像多米诺骨牌一样层层传递。
但级联必须防止死循环(A 触发 B,B 又触发 A)。库默认采用EntityAndType级联策略:同一个实体 + 同一种变更类型(新增/修改/删除)只触发一次,从而天然杜绝了无限循环。
相关源码可以参考:
- 级联行为定义:
src/EntityFrameworkCore.Triggered/Infrastructure/CascadeBehavior.cs - 级联策略实现:
src/EntityFrameworkCore.Triggered/Internal/CascadeStrategies/ - 核心调度器:
src/EntityFrameworkCore.Triggered/TriggerSession.cs
一个更震撼的级联场景:多层级软删除
集成测试test/EntityFrameworkCore.Triggered.IntegrationTests/CascadingSoftDeletes/演示了一个多层级联:树形结构 3 级分支,每级都注册了"软删除"触发器。此时只调用Remove(根节点),结果:
- 删除最深层节点 → 该节点被软删除 ✅
- 删除第 2 层节点 → 第 2 层 + 第 3 层都被软删除 ✅
- 删除根节点 → 3 级全部被软删除 ✅
一次删除,级联触发器顺着父→子的引用把整条链都"软删除"了。这种"保存即生效"的级联能力,正是 EntityFrameworkCore.Triggered 最实用的特性之一。🌳
五、如何为你的项目快速接入?
三步完成集成:
第 1 步:安装 NuGet 包
在项目中安装EntityFrameworkCore.Triggered包即可(纯接口包EntityFrameworkCore.Triggered.Abstractions可单独引用)。
第 2 步:编写触发器
实现IBeforeSaveTrigger<TEntity>(同步)或IBeforeSaveAsyncTrigger<TEntity>(异步)接口,在方法里通过context.Entity拿到实体、通过context.ChangeType判断是新增还是修改。参考samples/1 - HelloWorld/Triggers/StudentAssignRegistrationDate.cs,它仅用几行代码就实现了"新增学生时自动填写注册日期"。
第 3 步:注册触发器
在UseTriggers中逐个AddTrigger即可;如果项目里触发器较多,还可以用EntityFrameworkCore.Triggered.Extensions包提供的方法对整个程序集批量扫描注册。
💡 小贴士:使用异步触发器时,请配合
SaveChangesAsync调用,避免同步调用异步导致的线程阻塞问题(官方 README 中有专门说明)。
想亲手跑一遍本文示例?克隆仓库后进入示例目录执行dotnet run:
git clone https://gitcode.com/gh_mirrors/en/EntityFrameworkCore.Triggered cd EntityFrameworkCore.Triggered/samples/2\ -\ PrimarySchool dotnet run六、进阶能力速览
学完基础后,这些特性值得了解(详见项目根目录的README.md):
- 🎯执行优先级:实现
ITriggerPriority接口可自定义同一实体的多个触发器执行顺序,CommonTriggerPriorities提供了一组常用预设值 - 🧬继承支持:触发器按"从抽象类型到具体类型"的顺序执行,基类触发器先跑,子类后跑
- 💼事务触发器:
EntityFrameworkCore.Triggered.Transactions扩展包支持在提交前/提交后、回滚前/回滚后各挂触发器,覆盖完整的数据库事务生命周期 - 📡生命周期触发器:
Lifecycles命名空间下提供AfterSaveCompleted等钩子,在"本次保存的所有触发器都执行完"后统一执行一次,适合做批量汇总统计
总结
EntityFrameworkCore.Triggered 把"数据变更后的业务规则"从散乱的业务代码中抽离出来,统一挂载到DbContext的保存流程上。通过本文的 PrimarySchool 示例我们看到了它的核心价值:
- 用Before 触发器在写库前自动补全数据(新生自动报名必修课)
- 靠EntityAndType 级联策略让触发器安全地层层传递,不陷入死循环
- 配合异步接口与事务扩展,能覆盖从简单记账到复杂事务的绝大多数场景
如果你正在用 EF Core 管理 .NET 项目,不妨从samples/目录的四个示例入手,你会发现"触发器"真的能让数据维护这件事变得自动化。🚀
【免费下载链接】EntityFrameworkCore.TriggeredTriggers for EFCore. Respond to changes in your DbContext before and after they are committed to the database.项目地址: https://gitcode.com/gh_mirrors/en/EntityFrameworkCore.Triggered
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考