29

使用代码优先迁移向表中添加新的不可为空的列时,它将自动为您创建一个默认值。这是有道理的,因为现有的行需要有一个新列的值(因为它不能为空)。没关系,但是在到处分配该值之后,我不再想要它了。它是不可为空的,因为我想确保始终显式插入一个值。如果所有内容都默认为 '' 或 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);
}

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

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

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));
}

优点:看起来更简单/更干净

缺点:必须暂时更改我的约束(我假设这在事务中运行,因此我们不应该允许错误数据进入)。大桌子上的更新可能很慢。

哪种方法更可取?还是有更好的方法让我想念?

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

4

2 回答 2

12

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

即使您仍然对这种方法有疑问,但问题是,除了您的第二种方法之外,很可能没有其他选择。在我看来,使用默认值更新可能很大的表的成本似乎大于创建和立即删除默认约束的成本。

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

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

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

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

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

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

但这一切都可能是我的 T-SQL 开发人员说话比 C# 更响亮。因此,您很可能会像您发布的示例那样使用代码。

于 2012-06-03T19:44:09.967 回答
0

首先使用 EF 代码从列中删除默认值约束的解决方案 - 如果列不再具有 NULL 值 [Not Null],您可以使用下面的 Code First 方法从表中删除下面的 SQL 脚本。在迁移文件中设置“defaultValueSql:null”。

删除默认列值约束 ----> ALTER TABLE [dbo].[Attachments] ADD DEFAULT ('00000000-0000-0000-0000-000000000000') FOR [DocumentUniqueId]

应用此代码优先 C#---->

protected override void Up(MigrationBuilder migrationBuilder)
        {
            migrationBuilder.AlterColumn<Guid>(
                name: "ColumnName",
                schema: "dbo",
                table: "TableName",
                type: "uniqueidentifier",
                nullable: false,
                **defaultValueSql: null,**
                oldClrType: typeof(Guid),
                oldType: "uniqueidentifier");
        }

我没有得到任何地方,所以我发布它以帮助其他人,有助于数据库清理。

于 2020-05-26T20:45:31.630 回答