29

コード ファースト マイグレーションを使用して新しい null 非許容列をテーブルに追加すると、既定値が自動的に作成されます。既存の行は新しい列の値を持つ必要があるため (null にすることはできないため)、これは理にかなっています。それは問題ありませんが、その値がどこにでも割り当てられた後は、もう必要ありません。値が常に明示的に挿入されるようにしたいので、null 不可です。すべてのデフォルトが '' または 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);
}

長所: ヘルパー メソッドを実装したら、単純な 1 行を追加して制約を削除するだけです。短所: 削除するためだけにインデックスを作成する必要はないようです。

もう 1 つの方法は、生成された移行を変更することです。そのため、null 許容を追加し、すべての値を更新してから、null 非許容にします。

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 番目の方法は役に立ちません。

4

2 に答える 2

12

個人的には、最初のアプローチに問題はないと思います。はい、null 非許容列を空でないデータセットに追加するには、デフォルトの制約を作成する必要があります。はい、必要に応じて、新しい列が将来常に明示的に追加されるようにする必要がある場合は、後で削除する必要があります。

このアプローチにまだ問題がある場合でも、問題は、2 番目のアプローチ以外に代替手段がない可能性が高いことです。また、おそらく大きなテーブルをデフォルト値で更新するコストは、デフォルトの制約を作成してすぐに削除するコストよりも大きいように思えます。

エンジンによって割り当てられたデフォルト名を検索する手間を省くために、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 に答える