Daibitx.EFCore.AutoMigrate:模块化架构下更安全、可控的 EF Core 自动迁移方案
在实际项目中,数据库迁移是一个绕不开的环节。
尤其是在 模块化架构、微服务、多团队协作 的场景下,EF Core 自带的迁移机制在灵活性上并不能完全覆盖工程化的需求:
- 不同模块可能分别管理自己的 DbContext
- 多人并行开发会带来迁移冲突
- 生产环境不允许随意修改或删除结构
- 某些实体仅用于 DTO 映射,不应生成数据库表
- 不同数据库的大小写敏感问题可能导致迁移失败
基于这些痛点,我开发了 Daibitx.EFCore.AutoMigrate ------ 一个增强 EF Core 的自动迁移库,目标是在不破坏原生体验的前提下,提供更安全、更可控、更工程化的迁移能力。
本文从工程实践出发,系统介绍其设计理念、主要功能以及适用于模块化开发的使用方式。
🚀 项目 GitHub(欢迎 Star 支持开发)
https://github.com/daibitx/Daibitx.EFCore.AutoMigrate
📦 NuGet 包下载
https://www.nuget.org/packages/Daibitx.EFCore.AutoMigrate
一、为什么需要一个增强版的 EF Core 迁移工具?
EF Core 的迁移机制是强大且方便的,但它默认面向的是:
单应用、单团队、单上下文的开发场景。
而在模块化架构中,我们往往遇到:
1. 多模块、多 DbContext
不同模块拥有自己的实体和迁移,合并到一个数据库结构中时,管理难度显著提升。
2. 多团队协作带来的迁移冲突
团队 A 添加字段,团队 B 删除字段,如果没有控制,很容易对线上数据库造成破坏。
3. 生产环境限制
如:
- 禁止 Drop Table / Drop Column
- 禁止 Rename Column 等高风险操作
- 需要事务保护与错误回滚
4. 某些实体只是 DTO 或 ReadModel,不应该落地
这一点是很多项目容易忽略的问题:
随着 CQRS、查询模型复杂化,存在大量"实体类不是数据表"的情况。
如果这些类被误参与迁移,将造成数据库结构污染。
5. 多数据库大小写敏感问题
如 PostgreSQL / MySQL 的字段大小写敏感导致:
- 表名重复
- 索引重复
- 列名解析失败
这些问题往往在生产环境才暴露。
二、Daibitx.EFCore.AutoMigrate 的设计目标
基于上述挑战,这个库的核心目标是:
让 EF Core 的迁移更适合模块化、微服务、多人协作,并确保生产环境的结构安全。
核心理念包括:
- 默认安全(安全模式)
- 明确控制哪些操作允许、哪些禁止
- 并发安全
- 提供迁移步骤分析
- 生产环境可控、不破坏现有结构
- 多数据库一致性
- 支持 DTO/只读模型过滤,不污染数据库结构
三、核心能力概述
1. 安全模式(SafeMode)
默认禁止所有破坏性操作,尤其适合生产环境:
- 禁止 Drop Table
- 禁止 Drop/Alter Column
- 禁止 Rename Table/Column
- 仅允许 Add Table / Add Column
这是模块化协作中非常关键的一点,避免团队之间互相影响。
2. 事务式迁移
迁移过程有完整事务保护,一旦某个步骤失败,全部回滚。
3. DTO 自动过滤:以 Dto 结尾的实体不会参与迁移
这是 Daibitx.EFCore.AutoMigrate 专门针对工程实践加入的机制。
在实际项目中,存在大量以下结构:
UserDtoProductDetailDtoOrderQueryDTOReportDto
它们用于:
- 读模型(ReadModel)
- 多表联合查询结果映射
- 内部 DTO
- ViewModel 投影
这些类型 不应该生成数据库表,也不应该影响迁移脚本。
因此,AutoMigrate 默认:
任何以 Dto / DTO(大小写不敏感)结尾的实体类型,将自动排除在数据库迁移之外。
源码过滤逻辑:
var tableInfo = _dbContext.Model.GetEntityTypes()
.Where(e => !e.ClrType.Name.EndsWith("Dto", StringComparison.OrdinalIgnoreCase))
.Select(e => (Schema: e.GetSchema(), Table: e.GetTableName()))
.Where(t => !string.IsNullOrWhiteSpace(t.Table))
.Distinct()
.ToList();
这一点会显著减少数据库噪音,提高团队分工的清晰度。
4. 多数据库支持
已支持并适配多种数据库:
- SQL Server
- MySQL
- PostgreSQL
- Sqlite
- 理论支持任何实现EF Core驱动的数据库
5. 并发安全
微服务启动时不会因为多个实例同时迁移而产生冲突。
6. 灵活的设计时服务加载
多个数据库 Provider 可在模块中独立配置,符合模块化架构特性。
四、使用示例
方式 1:在 ASP.NET Core 中自动迁移(推荐)
app.Services.AutoMigrate<MyDbContext>(services =>
{
// 配置设计时服务
}, options =>
{
options.AsSafeMode();
});
方式 2:手动迁移
context.AutoMigrate(...);
方式 3:使用 Builder 模式
var runner = new MigrateBuilder<MyDbContext>(dbContext)
.WithOptions(new AutoMigrationOptions().AsSafeMode())
.Build();
await runner.ExecuteAsync();
五、生产环境最佳实践
1. 强烈建议使用安全模式
options.AsSafeMode();
2. 不要直接修改列结构
请采用:
- 新增列
- 数据迁移
- 删除旧列(开发或测试环境执行)
3. 注意数据库大小写敏感设置
(这里原文已有说明,不重复)
六、关于 DTO 过滤的设计思考
这个机制是根据大量实际项目经验总结出来的。
在模块化或 DDD 项目中,一个复杂模块通常包含:
- 聚合根实体
- ValueObject
- 多个 DTO(读模型、投影模型)
- 后台报表模型
但其中真正对应数据库表的只有一部分。
如果所有类都被 EF Core 扫描并参与迁移------
- 迁移文件会变得巨大且无意义
- 数据库会出现大量无用表
- 模块之间可能因为 DTO 冲突导致迁移失败
因此,AutoMigrate 内置过滤规则,可以说是模块化数据库建模中一个非常实用、工程化的功能点。
七、总结
Daibitx.EFCore.AutoMigrate 的核心价值在于:
- 让 EF Core 的迁移机制更适合模块化、多团队协作的体系
- 提供清晰、可控、安全的迁移策略
- 解决 DTO/查询模型误导致数据库结构污染的问题
- 对生产环境更友好
- 提供工程级的事务、安全保护与数据库兼容性支持
如果你的架构包含:
- 多模块
- 多 DbContext
- 多团队协作
- 多环境(开发、测试、生产)
- 多数据库适配
那么 AutoMigrate 可能正是你需要的那一层"工程化补丁"。