2012-06-03 65 views
24

使用代码优先迁移将新的不可为空列添加到表中时,它会自动为您创建默认值。这很有意义,因为现有行需要为新列创建一个值(因为它不能为空)。这很好,但在此之后,我们不再需要它了。它是不可空的,因为我想确保总是显式插入一个值。如果一切默认为''或0,那么我会有魔术字符串。无论如何,我可以用一个解决方案来解决问题,我并不感到兴奋,但它很有效。先在代码中添加新列后删除默认约束

添加列后,我放弃默认约束。

public override void Up() 
{ 
    AddColumn("dbo.SomeTable", "NewColumn", c => c.Int(nullable: false)); 
    Sql(Helpers.DropDefaultConstraint("dbo.SomeTable", "NewColumn")); 
} 

...

public static string DropDefaultConstraint(string table, string column) 
{ 
    return string.Format(@" 
     DECLARE @name sysname 

     SELECT @name = dc.name 
     FROM sys.columns c 
     JOIN sys.default_constraints dc ON dc.object_id = c.default_object_id 
     WHERE c.object_id = OBJECT_ID('{0}') 
     AND c.name = '{1}' 

     IF @name IS NOT NULL 
      EXECUTE ('ALTER TABLE {0} DROP CONSTRAINT ' + @name) 
     ", 
     table, column); 
} 

优点:一旦辅助方法来实现,我只需要添加一个简单的线条,以删除约束。 CONS:似乎没有必要创建一个索引来删除它。

另一种方法是更改​​生成的迁移,因此我们添加它为空,更新所有值,然后使其不可空。

public override void Up() 
{ 
    AddColumn("dbo.SomeTable", "NewColumn", c => c.Int()); 
    Sql("UPDATE dbo.SomeTableSET NewColumn= 1"); 
    AlterColumn("dbo.SomeTable", "NewColumn", c => c.Int(nullable: false)); 
} 

优点:简单,似乎/清洁

缺点:必须暂时改变我的约束(我假设这运行在一个事务,因此,我们不应该让坏的数据)。大桌子上的更新可能会很慢。

哪种方法更可取?还是有更好的方法,我错过了?

注意:我已经演示了您一次添加和清理列定义的情况。如果您只是清除先前迁移的默认设置,则第二种方法无效。

+2

解决方案1帮助我删除了默认约束,谢谢。 – angularsen

+0

这真棒 –

回答

10

就我个人而言,我可以看到第一种方法没有错。是的,您必须创建默认约束才能将非空列添加到非空数据集。是的,如果您需要确保新列总是按照您的要求明确添加,那么您必须在以后删除它。

即使您仍然有这种方法的问题,问题是,除了你的第二种方法之外,很可能没有别的选择。用默认值更新可能较大的表的成本似乎大于创建并立即删除默认约束的成本。

我可能会考虑稍微修改,虽然我也许可以在SQL约束,以避免仰视发动机指定的默认名称,像这样大惊小怪:

Sql("ALTER TABLE tablename 
    ADD columnnametype NOT NULL 
    CONSTRAINT DF_tablename_columnname DEFAULT defaultvalue"); 

(可重写使用一个辅助功能)

删除约束则是作为执行单个ALTER TABLE语句微不足道:

Sql("ALTER TABLE tablename 
    DROP CONSTRAINT DF_tablename_columnname"); 

(同样,帮手功能很容易在这里使用。)

但是,这些都可能是一个T-SQL开发人员,我说的比C#更大声。所以你可能很喜欢你所发布的例子。

+0

感谢您验证我的想法。我确实考虑过自己创建约束,但是我更喜欢使用AddColumn,因为它很容易读取并且一致,还允许其他一些约束条件,如独特。我决定坚持选项1.谢谢。 –