SaveChanges 是 EF Core 将内存中增删改操作持久化到数据库的核心方法,它基于变更追踪自动识别状态、生成 SQL、启用事务并确保原子性。

EF Core 的 SaveChanges 是把内存中对实体的增删改操作真正写入数据库的“最后一道指令”。它不是简单地执行 SQL,而是基于变更追踪(Change Tracking)自动识别哪些实体变了、怎么变的,再生成并执行对应命令。用对了,省心又安全;用错了,可能数据不一致、事务失效,甚至漏保存。
SaveChanges 做了什么
调用它时,EF Core 会按顺序完成三件事:
- 扫描 DbContext 中所有被跟踪的实体,检查它们的状态(Added / Modified / Deleted)
- 根据状态生成一条或多条 SQL 命令(INSERT / UPDATE / DELETE),必要时自动处理主键回填(比如自增 ID)、外键关联(如先插 Blog 再插 Post)
- 在数据库连接上启动一个事务(默认开启),执行全部命令;任一失败则整体回滚,确保原子性
基本用法就这几种
不需要手动拼 SQL,也不用管事务开关(除非你明确要关):
-
新增:用
Add()或AddRange()加入实体,再调SaveChanges() -
修改:从查询加载实体后直接改属性值(如
blog.Title = "新标题"),EF 自动标记为 Modified -
删除:用
Remove()或RemoveRange(),或设Entry(e).State = EntityState.Deleted -
混合操作:一次 Add + 一次 Modify + 一次 Remove,全在同一个
SaveChanges()中提交,天然事务保障
事务控制的关键细节
默认情况下,每个 SaveChanges() 都自带事务——但仅限本次调用内所有操作。跨多次调用必须手动管事务:
- 单次 SaveChanges:自动事务,无需干预。例如批量插入 10 条客户记录,失败则全不入库
- 多次 SaveChanges:比如先加 Product,再用它的 ID 加 Order,这时得用
BeginTransaction()包住两次 SaveChanges,否则第二次失败会导致 Product 白存了 - 想关掉默认事务?可以设
context.Database.AutoTransactionsEnabled = false,但极少需要,关了就失去原子保障
异步和性能注意点
高并发或耗时操作建议用异步版本:
-
SaveChangesAsync()是推荐做法,避免线程阻塞,尤其 Web 应用 - EF Core 会自动批处理同类型命令(比如连续 5 个 INSERT),减少数据库往返,提升性能
- 别在循环里反复调 SaveChanges —— 每次都开事务、建连接、发命令,效率低。应先 AddRange,最后统一 SaveChanges
基本上就这些。核心就一条:让 EF 跟踪你的实体,它自然知道该做什么;你只管业务逻辑,事务和 SQL 交给它兜底。










