Подтвердить что ты не робот

Удаление ограничения по умолчанию после добавления нового столбца в код сначала

При добавлении нового столбца с непустым значением в таблицу с использованием первых миграций кода он автоматически создаст для вас значение по умолчанию. Это имеет смысл, поскольку существующие строки должны иметь значение для нового столбца (поскольку оно не может быть нулевым). Это прекрасно, но после этого значения присваивается везде, я больше этого не хочу. Он не является нулевым, потому что я хочу убедиться, что значение всегда явно вставлено. Если все значения по умолчанию равны '' или 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);
}

PROS: После того, как метод helper реализован, мне просто нужно добавить одну простую строку, чтобы удалить ограничение. 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));
}

PROS: Кажется, проще/чище

CONS: нужно временно изменить мои ограничения (я предполагаю, что это выполняется в транзакции, и поэтому мы не должны допускать попадание плохих данных). Обновление может быть медленным на больших таблицах.

Какой способ является предпочтительным? Или есть лучший способ, который мне не хватает?

Примечание. Я продемонстрировал случай, когда вы добавляете и очищаете определения столбцов за один раз. Если вы просто очищаете значения по умолчанию от предыдущих миграций, второй подход не помогает.

4b9b3361

Ответ 1

Лично я не вижу ничего плохого в первом подходе. Да, вы должны создать ограничение по умолчанию, чтобы добавить столбец, не содержащий NULL, в непустой набор данных. И да, вы должны удалить его впоследствии, если вам нужно убедиться, что новый столбец всегда добавляется явно в будущем, согласно вашему требованию.

И даже если у вас все еще есть проблемы с этим подходом, проблема в том, что, скорее всего, нет другой альтернативы, кроме вашего второго подхода. И стоимость обновления потенциально большой таблицы со значением по умолчанию показалась бы мне больше, чем затраты на создание и немедленное удаление ограничения по умолчанию.

Я мог бы подумать о небольшой модификации: я мог бы создать ограничение в 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, который я говорю громче, чем С#. Таким образом, вы можете очень хорошо пойти с кодом, как пример, который вы опубликовали.