FluentMigrator откатывается к столбцу Not Nullable?

Учитывая следующую миграцию:

[Migration(1)]
public class Mig001 : Migration
{
    public override void Up()
    {
        Alter.Table("foo").AlterColumn("bar").AsInt32().Nullable();
    }

    public override void Down()
    {
        Alter.Table("foo").AlterColumn("bar").AsInt32().NotNullable();
    }
}

Мигратор изменяет столбец и делает его обнуляемым, а при откате делает обратное и снова делает его не обнуляемым.

Допустим, данные были добавлены в foo с момента миграции; теперь есть строки с нулевым значением в столбце bar.

Если его откатить, операция завершится ошибкой. Есть ли способ в fluentmigrator справиться с этим сценарием? Или что является лучшей практикой.


person user1838662    schedule 10.06.2013    source источник


Ответы (3)


Короткий ответ — установить значение по умолчанию для всех столбцов, которые имеют значение, допускающее значение NULL. Вы можете сделать это только с помощью sql, используя выражение Execute.Sql. Это должно быть перед выражением Alter.Table.

public override void Down()
{
    Execute.Sql("update foo set bar = 0 where bar is null");
    Alter.Table("foo").AlterColumn("bar").AsInt32().NotNullable();
}

Длинный ответ заключается в том, что требуется много работы, чтобы всегда гарантировать, что вы можете откатить миграцию, и вы уверены, что вам нужно это делать?

Например, если действие вверх — создать таблицу, а действие вниз — удалить ее, следует ли сохранять данные во временной таблице, чтобы они не исчезли? В большинстве случаев действие down используется при развертывании в тестовых средах или при откате неудачного развертывания, и довольно редко вы откатываете миграцию после ее развертывания.

person Daniel Lee    schedule 11.06.2013
comment
Я предполагаю, что это не сработало бы, если бы bar был столбцом внешнего ключа? Можно ли оставить метод Down пустым? - person user1838662; 11.06.2013
comment
Если это столбец внешнего ключа, то запрос sql должен быть немного умнее и найти правильное значение для установки. Или у вас есть значение внешнего ключа, которое будет работать по умолчанию? - person Daniel Lee; 11.06.2013
comment
К сожалению, нет значения внешнего ключа по умолчанию. '0' Указывает на несуществующую запись в родительской таблице. - person user1838662; 12.06.2013
comment
Можно ли написать SQL-запрос, который найдет правильную родительскую запись? Если это так, вы можете запустить его с помощью Execute.Sql. Если это не так, вам придется сделать это вручную, я думаю. - person Daniel Lee; 12.06.2013

Вот альтернативный способ выполнения миграции, который не требует прямого выполнения SQL.

public override void Down()
{
    Update.Table("foo").Set(new { bar = 0 }).Where(new { bar = (int?) null });
    Alter.Table("foo").AlterColumn("bar").AsInt32().NotNullable();
}
person Lucas    schedule 09.08.2013

Старая тема, но вы можете сделать это, чтобы присвоить существующим строкам (новое) значение:

            migration.Alter.Table("foo")
                .AlterColumn("bar")
                .AsDateTime()
                .NotNullable()
                .SetExistingRowsTo(DateTime.UtcNow)
            ;
person PitAttack76    schedule 13.01.2016
comment
но добавляет ли SetExistingRowsTo условие where bar is null? Или он использует все строки... - person Serg046; 04.12.2016
comment
SetExistingRowsTo установит все существующие строки, так как его целью было упростить добавление столбцов, отличных от NULL, без значения по умолчанию. Нам понадобится дополнительный помощник, такой как SetNullRowsTo или что-то в этом роде, но, честно говоря, в случае обновления существующего столбца с нулевого на ненулевой, я думаю, что использование метода, предложенного Лукасом, является лучшим подходом и не приведет к засорение апи ложными вспомогательными методами. - person Mike; 10.05.2017