首先在代码中添加新列后删除默认约束

Dan*_*man 26 t-sql ef-migrations

使用代码优先迁移向表中添加新的非可空列时,它将自动为您创建默认值.这是有道理的,因为现有行需要具有新列的值(因为它不能为null).那很好,但是在那个值分配到处之后,我不再需要了.它是不可空的,因为我想确保始终显式插入值.如果一切都默认为''或0,那么我将拥有魔术字符串.所以无论如何,我可以提出一个解决方案,我并不感到兴奋,但它确实有效.

添加列后,我删除默认约束.

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

...

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);
}
Run Code Online (Sandbox Code Playgroud)

PROS:一旦实现了辅助方法,我只需要添加一条简单的行来删除约束.缺点:似乎没有必要创建索引只是为了删除它.

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

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));
}
Run Code Online (Sandbox Code Playgroud)

PROS:似乎更简单/更清洁

缺点:必须暂时改变我的约束(我假设它在一个事务中运行,因此我们不应该允许坏数据).大表上的更新可能会很慢.

哪种方法更可取?还是有更好的方式让我失踪?

注意:我已经演示了一次添加和清除列定义的情况.如果您只是清理以前迁移的默认值,则第二种方法没有帮助.

And*_*y M 11

我个人认为第一种方法没有错.是的,您必须创建默认约束以将非可空列添加到非空数据集.是的,如果您需要确保将来始终根据您的要求明确添加新列,则必须在之后删除它.

即使你仍然遇到这种方法的问题,问题是,除了你的第二种方法之外,很可能没有其他选择.使用默认值更新可能较大的表的成本似乎比创建和立即删除默认约束的成本更高.

不过我可能会考虑稍作修改:我可能会在SQL中创建约束,以避免查找引擎分配的默认名称这样的大惊小怪,如下所示:

Sql("ALTER TABLE tablename
  ADD columnname type NOT NULL
  CONSTRAINT DF_tablename_columnname DEFAULT defaultvalue");
Run Code Online (Sandbox Code Playgroud)

(可以重写以使用辅助函数.)

删除约束将与执行单个ALTER TABLE语句一样简单:

Sql("ALTER TABLE tablename
  DROP CONSTRAINT DF_tablename_columnname");
Run Code Online (Sandbox Code Playgroud)

(同样,这里可以很容易地使用辅助函数.)

但是在我看来,所有人都可能是一个T-SQL开发人员,而不是C#.所以你很可能会像你发布的例子那样使用代码.