如何阻止FluentMigrator在SQL Server建表时给计算列加NULL/NOT NULL
问题重现
创建带计算列的表时使用以下代码:
Create.Table("ComputedColumnTest") .WithColumn("Id").AsGuid().PrimaryKey().WithDefaultValue("(newid())").Indexed().NotNullable() .WithColumn("Num").AsInt32() .WithColumn("NumSquared").AsComputedColumn("(([Num]) * ([Num]))");
自定义扩展方法:
public static class ICreateTableColumnAsTypeSyntaxExtensions { public static ICreateTableColumnOptionOrWithColumnSyntax AsComputedColumn(this ICreateTableColumnAsTypeSyntax createTableColumnAsTypeSyntax, string computation) { return createTableColumnAsTypeSyntax.AsCustom(" as " + computation); } }
执行迁移时触发SQL Server错误:
执行以下SQL时出错:
CREATE TABLE [dbo].[ComputedColumnTest] ([Id] UNIQUEIDENTIFIER NOT NULL CONSTRAINT [DF_ComputedColumnTest_Id] DEFAULT N'(newid())', [Num] INT NOT NULL, [NumSquared] as (([Num]) * ([Num])) NOT NULL, CONSTRAINT [PK_ComputedColumnTest] PRIMARY KEY ([Id]))只有UNIQUE或PRIMARY KEY约束可用于计算列,而CHECK、FOREIGN KEY和NOT NULL约束要求计算列必须持久化。
手动移除计算列后的NOT NULL约束可正常执行,但添加.Nullable()会生成NULL约束,依然报错。
问题原因
FluentMigrator中,列类型(如AsInt32())默认会添加NOT NULL约束,而SQL Server要求非持久化计算列不能带有NOT NULL或NULL约束——只有持久化的计算列才能添加这类约束。
解决方法
修改自定义扩展方法,确保生成的计算列不包含任何可空性约束:
方案1:修改扩展方法自动移除约束
public static class ICreateTableColumnAsTypeSyntaxExtensions { public static ICreateTableColumnOptionOrWithColumnSyntax AsComputedColumn(this ICreateTableColumnAsTypeSyntax createTableColumnAsTypeSyntax, string computation) { return createTableColumnAsTypeSyntax .AsCustom($" as {computation}") .WithOption(column => column.RemoveConstraint("NotNull")); } }
方案2:在列定义中手动移除约束
如果不想修改扩展方法,也可以在创建计算列时显式移除默认的可空性约束:
Create.Table("ComputedColumnTest") .WithColumn("Id").AsGuid().PrimaryKey().WithDefaultValue("(newid())").Indexed().NotNullable() .WithColumn("Num").AsInt32() .WithColumn("NumSquared") .AsComputedColumn("(([Num]) * ([Num]))") .WithOption(col => col.RemoveConstraint("NotNull"));
两种方案都会让FluentMigrator生成不带可空性约束的计算列定义,符合SQL Server的要求,解决报错问题。
内容的提问来源于stack exchange,提问作者Phil

