Возможно ли по умолчанию поле DateTime для GETDATE () с миграциями Entity Framework? - PullRequest
33 голосов
/ 21 декабря 2011

Я добавил EntityFramework.Migrations (бета-версия 1) в существующее приложение Code-First, которое претерпевает некоторые изменения (как для возможностей миграции, так и для более тонкой настройки таблиц, которые я генерирую из своего API-интерфейса с кодом), и выполнилв сценарий GETDATE ().

Я уже использовал свой класс инициализатора в моем DbContext для запуска сценариев SQL для установки некоторых полей и создания индексов в моей базе данных.Несколько моих сценариев AlterTable являются первичными только для настройки полей со значениями по умолчанию (например, для некоторых полей DateTime установлено значение GETDATE ()).Я действительно надеялся, что у EntityFramework.Migrations будет ответ на этот вопрос, так как вы можете легко указать defaultValue, но пока я его не вижу.

Есть идеи?Я действительно надеялся, что выполнение следующего волшебным образом сработает.(В конце концов, это «волшебный единорог»)

DateCreated = c.DateTime(nullable: false, defaultValue: DateTime.Now)

К сожалению, и логично, он установил мое значение по умолчанию на время, когда была выполнена команда Update-Database.

Ответы [ 7 ]

91 голосов
/ 30 января 2012

Вы можете использовать

DateCreated = c.DateTime(nullable: false, defaultValueSql: "GETDATE()")

Использование:

public partial class MyMigration : DbMigration
{
    public override void Up()
    {
        CreateTable("dbo.Users",
            c => new
                {
                    Created = c.DateTime(nullable: false, defaultValueSql: "GETDATE()"),
                })
            .PrimaryKey(t => t.ID);
 ...

Обновление 2012-10-10:

По просьбе Тиаго в его комментарии я добавляю немного дополнительного контекста.

Приведенный выше код представляет собой файл миграции, сгенерированный EF Migrations путем запуска Add-Migration MyMigration в качестве команды в консоли диспетчера пакетов. Сгенерированный код основан на моделях в DbContext, связанных с миграциями. В ответе предлагается изменить сгенерированный сценарий, чтобы при создании базы данных добавлялось значение по умолчанию.

Подробнее о первых миграциях кода Entity Framework можно прочитать здесь .

23 голосов
/ 09 января 2014

Я недавно столкнулся с этой проблемой в EF6 (так как они до сих пор не исправили ее).Я нашел самый простой способ сделать это без необходимости вручную изменять класс Migration - это переопределить CodeGenerator в вашем классе Configuration.

Создав класс, который реализует MigrationCodeGenerator, а затем переопределив метод Generate, вы можете выполнить итерацию по всемопераций и примените те изменения, которые вы хотите.

После внесения изменений вы можете инициализировать CSharpMigrationCodeGenerator и вернуть его значение по умолчанию.

public class ExtendedMigrationCodeGenerator : MigrationCodeGenerator
{
    public override ScaffoldedMigration Generate(string migrationId, IEnumerable<MigrationOperation> operations, string sourceModel, string targetModel, string @namespace, string className)
    {
        foreach (MigrationOperation operation in operations)
        {
            if (operation is CreateTableOperation)
            {
                foreach (var column in ((CreateTableOperation)operation).Columns)
                    if (column.ClrType == typeof(DateTime) && column.IsNullable.HasValue && !column.IsNullable.Value && string.IsNullOrEmpty(column.DefaultValueSql))
                        column.DefaultValueSql = "GETDATE()";
            }
            else if (operation is AddColumnOperation)
            {
                ColumnModel column = ((AddColumnOperation)operation).Column;

                if (column.ClrType == typeof(DateTime) && column.IsNullable.HasValue && !column.IsNullable.Value && string.IsNullOrEmpty(column.DefaultValueSql))
                    column.DefaultValueSql = "GETDATE()";
            }
        }

        CSharpMigrationCodeGenerator generator = new CSharpMigrationCodeGenerator();

        return generator.Generate(migrationId, operations, sourceModel, targetModel, @namespace, className);
    }
}

internal sealed class Configuration : DbMigrationsConfiguration<Project.Models.Context.DatabaseContext>
{
    public Configuration()
    {
        AutomaticMigrationsEnabled = false;
        MigrationsDirectory = @"Migrations";
        this.CodeGenerator = new ExtendedMigrationCodeGenerator();
    }
}

Надеюсь, это поможет

14 голосов
/ 22 декабря 2011

Вы должны использовать собственный сценарий SQL в методе Up для установки значения по умолчанию:

Sql("ALTER TABLE TableName ADD CONSTRAINT ConstraintName DEFAULT GETDATE() FOR ColumnName");

Установка значения по умолчанию в коде допускает только статические значения - без функций уровня базы данных.

В любом случае, установка его в конструкторе POCO - правильный путь, если вы собираетесь сначала использовать код.Также, если вы хотите установить значение в приложении для некоторых особых случаев, вы не можете использовать значение по умолчанию в базе данных, потому что значение по умолчанию в базе данных требует либо DatabaseGeneratedOption.Identity, либо DatabaseGeneratedOption.Computed.Обе эти опции позволяют установить свойство только в базе данных.

Редактировать:

Поскольку продукт все еще находится в разработке, мой ответ больше не действителен.Проверьте в ответе @gius фактический способ выполнения этого требования с помощью defaultValueSql (он не был доступен в EF Migrations Beta 1, но был добавлен в EF 4.3 Beta 1, которая уже включает в себя миграции).

5 голосов
/ 22 июля 2016

Создать миграцию:

public partial class Table_Alter : DbMigration
{
    public override void Up()
    {
        AddColumn("dbo.tableName", "columnName", 
           c => c.DateTime(nullable: false, defaultValueSql: "GETDATE()"));
    }

    public override void Down()
    {
        DropColumn("dbo.tableName", "columnName");
    }
}

Для существующих записей будет установлена ​​дата и время запуска команды Update-Database, для новых записей будет установлена ​​дата и время создания

1 голос
/ 25 декабря 2011

В качестве альтернативы, если ваши объекты наследуют от общего интерфейса, вы можете переопределить метод SaveChanges в DbContext и установить или обновить свойства в этой точке (отлично подходит для Дата создания и Дата последнего изменения)

0 голосов
/ 17 февраля 2016

Улучшение: проверьте, существует ли ограничение:

Sql(@"
if not exists (
    select *
      from sys.all_columns c
      join sys.tables t on t.object_id = c.object_id
      join sys.schemas s on s.schema_id = t.schema_id
      join sys.default_constraints d on c.default_object_id = d.object_id
    where 
      d.name = 'DF_ThubOutputEmail_Created'
)
begin
    ALTER TABLE dbo.ThubOutputEmails ADD CONSTRAINT DF_ThubOutputEmail_Created default getdate() for Created;
end");
0 голосов
/ 17 апреля 2015

Это самый простой способ.

Сначала добавьте DatabaseGeneratedOption.Computed DataAnnotion в вашу собственность

, и теперь вы можете изменить де SqlServerMigrationSqlGenarator, переопределитьМетод Genarate и установить DefaultValueSql = "GETDATE()" or "GETUTCDATE()";

...