11

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 が制約を使用してデフォルトを実装するという事実に起因します (ああ、MySQL が恋しい!) 制約の名前が生成されます。したがって、Code First チームは、デフォルト値を簡単に変更または削除/再作成することはできませんでした。

4

2 に答える 2

15

Entity Framework forSQLServerによって生成された逆移行に触発されたデフォルトの制約の削除

    public static void DropDefaultConstraint(string tableName, string columnName, Action<string> 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は、1回の移行で複数の制約を削除する場合に備えて、一意の変数名を作成するために使用されます。

于 2012-11-07T17:59:13.957 に答える
6

これがこの投稿に触発された解決策です。これは必ずしもエレガントな方法ではありませんが、私にとってはうまくいきます。


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

ランバを使用する理由は、に3つの異なる呼び出しを行う必要があるためですSql()。私はこれを1つの長いクエリとして機能させることができませんでした-GO多くの異なる場所でキーワードの多くの組み合わせを試しました。また、最初のクエリでロジックを逆にして、UDFが存在しない場合にのみ再作成され、機能しないようにしました。とにかく毎回それを再現する方が頑強だと思います。

于 2012-08-15T23:57:06.023 に答える