在EF5 Code First中更改列默认值

我正在尝试使用CF为现有数据库构建模型。 我有一个专栏,我忘了设置一个合理的默认值。 而不是通过改变它来破坏初始迁移的纯度,我只是想我创建另一个迁移(这是迁移的目的,对吧?:)

public override void Up() { AlterColumn("Config", "DefaultTaxPerDollar", c => c.Decimal(nullable: false, precision: 19, scale: 5, defaultValue: 0.087m)); } public override void Down() { AlterColumn("Config", "DefaultTaxPerDollar", c => c.Decimal(nullable: false, precision: 19, scale: 5, defaultValue: 0.0m)); } 

但是这会产生Column already has a DEFAULT bound to it. 来自SQL Server的错误。

如何使用CF迁移更改默认值? 或者,如何简单地删除默认值(然后使用不同的值重新创建它)?

编辑:

这是SQL生成的:

 ALTER TABLE [Config] ADD CONSTRAINT DF_DefaultTaxPerDollar DEFAULT 0.087 FOR [DefaultTaxPerDollar] ALTER TABLE [Config] ALTER COLUMN [DefaultTaxPerDollar] [decimal](19, 5) NOT NULL 

我想我可能已经找到了一个解决方案,使用Sql()方法和一些受这篇文章启发的复杂SQL。 问题源于这样一个事实:SQL Server使用约束来实现默认值(OH!我多么想念MySQL!),并为约束生成了名称。 因此Code First团队不能简单地更改或删除/重新创建默认值。

删除受Entity Framework for SQL Server生成的反向迁移启发的默认约束

  public static void DropDefaultConstraint(string tableName, string columnName, Action executeSQL) { string constraintVariableName = string.Format("@constraint_{0}", Guid.NewGuid().ToString("N")); string sql = string.Format(@" DECLARE {0} nvarchar(128) SELECT {0} = name FROM sys.default_constraints WHERE parent_object_id = object_id(N'{1}') AND col_name(parent_object_id, parent_column_id) = '{2}'; IF {0} IS NOT NULL EXECUTE('ALTER TABLE {1} DROP CONSTRAINT ' + {0})", constraintVariableName, tableName, columnName); executeSQL(sql); } 

它略短,但使用方法相同。

 DropDefaultConstraint(TableName, "DefaultTaxPerDollar", q => Sql(q)); 

Guid用于创建唯一的变量名称,以防您在一次迁移中删除多个约束。

这是一个灵感来自这篇文章的解决方案。 这不是一个优雅的方法,但它适用于我。

 public static void DropDefaultConstraint(string tableName, string columnName, Action executeSQL) { // Execute query that drops the UDF that finds the default constraint name var query = @" -- recreate UDF if object_id('[dbo].[GetDefaultConstraintName]') is not null begin drop function [dbo].[GetDefaultConstraintName] end "; executeSQL(query); // Execute query that (re)creates UDF that finds the default constraint name query = @" create function [dbo].[GetDefaultConstraintName] ( @TableName varchar(max), @ColumnName varchar(max)) returns varchar(max) as begin -- Returns the name of the default constraint for a column declare @Command varchar(max) select @Command = d.name from (( sys.tables t join sys.default_constraints d on d.parent_object_id = t.object_id) join sys.columns c on c.object_id = t.object_id and c.column_id = d.parent_column_id) where t.name = @TableName and c.name = @ColumnName return @Command end "; executeSQL(query); // Execute query that actually drops the constraint query = string.Format(@" -- Use UDF to find constraint name DECLARE @Constraint_Name VARCHAR(100) SET @Constraint_Name = [dbo].GetDefaultConstraintName('{0}','{1}') if LEN(@Constraint_Name) > 0 BEGIN DECLARE @query VARCHAR(300) SET @query = 'ALTER TABLE {0} DROP CONSTRAINT ' + @Constraint_Name execute(@query) END", tableName, columnName); executeSQL(query); } 

在您的迁移中,您可以这样调用它:

 DropDefaultConstraint(TableName, "DefaultTaxPerDollar", q => Sql(q)); 

使用lamba的原因是因为你必须对Sql()进行三次不同的调用。 我无法将其作为一个长查询工作 – 在许多不同的地方尝试了许多关键字GO组合。 我还尝试在第一个查询上反转逻辑,以便只有UDF不存在才会重新创建它,并且它不起作用。 我想每次重建它都会更加强大。