EF Core 10 给 SQL Server 的默认约束(default constraint)带来了一个看似不起眼的新能力:给每个默认值起一个稳定的名字。这个能力解决的是数据库运维里一个很实际的痛点——以前 SQL Server 自动生成的名字长这样:DF__Jobs__Status__...,后面那串随机字符在脚本和故障处理手册里根本没法预测。
但新功能有个容易踩的坑:如果你在已有的模型上启用这个命名约定,下一次迁移会把模型里每一个默认约束全部改一遍。这不是改一两个字段的小事,而是牵动整个表结构的批量变更。
![]()
这种小配置改动,恰恰是最该在部署前加一道迁移闸门(migration gate)的场景。问题来了:到底会有多少列受影响?实际会执行什么 SQL?能不能不连真实数据库就把预览脚本拉出来看?
两种命名方式,一个全局开关
EF Core 10 为 SQL Server 的默认值提供了两种命名选择。第一种是直接在HasDefaultValue或HasDefaultValueSql方法里传名字;第二种是启用全局约定,在OnModelCreating里加一行modelBuilder.UseNamedDefaultConstraints(),然后所有默认值都会自动获得可预测的名字。
比如下面这段配置:
protected override void OnModelCreating(ModelBuilder modelBuilder)modelBuilder.UseNamedDefaultConstraints();modelBuilder.Entity(entity =>entity.Property(job => job.Status).HasDefaultValue("queued");entity.Property(job => job.CreatedUtc).HasDefaultValueSql("SYSUTCDATETIME()");entity.Property(job => job.RetryCount).HasDefaultValue(0);
生成的名字是DF_Jobs_Status、DF_Jobs_CreatedUtc、DF_Jobs_RetryCount。这种可预测性在部署脚本、DBA 排查、回滚流程里非常有用——你不需要去数据库里查名字,直接按规则写就行。
坑在哪儿:全局约定不是"只加不改"
关键问题在于,这个全局调用对已有 schema 来说不是纯元数据操作。微软在 EF Core 10 的发布说明里明确警告:启用约定后,下一次迁移会重命名模型里所有默认约束。
如果构建流程只检查迁移能否编译通过,根本看不出这次改动的真实范围。编译通过 ≠ 影响面小,这是很多团队容易忽略的点。
为了验证实际效果,我搭了一个可运行的示例项目,包含两个已提交的迁移。第一个InitialSchema代表旧模型,有三个未命名的默认约束;第二个NameDefaultConstraints是在添加全局约定后生成的。
第二个迁移里发生了什么
第二个迁移包含三个AlterColumn操作。每个操作保持相同的 CLR 类型和默认值,但新增了一个关系型注解(relational annotation),用来指定约束名:
migrationBuilder.AlterColumn(name: "Status",table: "Jobs",type: "nvarchar(32)",maxLength: 32,nullable: false,defaultValue: "queued",oldClrType: typeof(string),oldType: "nvarchar(32)",oldMaxLength: 32,oldDefaultValue: "queued").Annotation("Relational:DefaultConstraintName","DF_Jobs_Status");
也就是说,表面上只是加了个名字,但迁移系统会把它当成一次列结构变更来处理。三个字段就是三个AlterColumn,字段越多,迁移脚本越长,部署窗口的风险也越大。
不连数据库也能看预览 SQL
好消息是,生成迁移脚本不需要实时数据库连接。SQL Server provider 可以在本地直接翻译已提交的迁移操作。用这几条命令就能拿到预览:
dotnet tool restoredotnet restoredotnet build -c Release --no-restoredotnet tool run dotnet-ef migrations script `InitialSchema NameDefaultConstraints `--no-build --configuration Release
这个流程的核心价值在于:在部署之前,你就能看到完整的 SQL 变更内容,不需要把工具指向任何真实数据库。对于"启用命名约定会不会搞出大动静"这种问题,跑一遍脚本预览就能得到确切答案。
我的判断:小改动,大影响,预览是底线
正方观点:命名默认约束是长期收益,可预测的名字让运维脚本和故障排查省心不少,值得做。
反方观点:一次迁移改动所有默认约束,风险面太大,尤其是生产环境表多、约束多的情况下,一个 AlterColumn 就可能触发锁表或长时间阻塞。
我的判断是:功能本身没问题,但启用方式决定了风险等级。如果你在已有模型上直接开全局约定,务必先跑一遍迁移脚本预览,确认改动范围,再决定是分批处理还是接受一次性全量变更。对于新项目,从一开始就启用命名约定,完全不会有这个烦恼。
EF Core 10 的这个特性,本质上是把"数据库对象名字可预测"这件事从手动约定变成了框架行为。但框架替你做的决定,你得先看清楚它到底改了什么。
特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.