2011-12-21 6 views
31

Я добавил EntityFramework.Migrations (Beta 1) в существующее приложение Code-First, которое проходит через некоторые изменения (как для возможностей миграции, так и для более точной настройки таблиц, которые я генерирую из моего первого кода кода) и столкнулся с сценарий GETDATE().Возможно ли по умолчанию использовать поле DateTime для GETDATE() с миграциями Entity Framework?

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

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

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

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

+0

Я не смотрю на попадание в теорию вращающейся вокруг»... используя ORM, вы не должны вводить логику в базу данных ... ». Я это понимаю. Просто хочу удостовериться, что никто не отбрасывает пример POCO с помощью DateTime.Now в конструкторе :) – adammokan

+0

просто похоже на подобное, и нашел хорошее решение. Надеюсь, это поможет: http://stackoverflow.com/questions/9830216/ef-4-3-1-migration-exception-altercolumn-defaultvaluesql-creates-same-default/ –

ответ

14

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

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

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

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

Edit:

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

+0

Спасибо. У меня уже была функциональность SQL Script до перехода на EF.Migrations, так что это никоим образом не помогло мне. – adammokan

+0

Я отметил это как ответ. Не тот ответ, на который я надеялся, но я решил, что это так. – adammokan

1

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

79

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

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

Update 2012-10-10:

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

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

Подробнее об объекте Framework Framework First Migrations here.

+1

где этот код идет? что такое переменная «c» ?? Можете ли вы предоставить немного больше контекста вокруг этой строки кода? –

+1

@ThiagoSilva Добавил немного дополнительного контекста для ответа, как вы и предполагали. –

19

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

Создав класс, который реализует 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(); 
    } 
} 

Я надеюсь, что это помогает

+0

Для EF6 это сработало отлично. хороший. – tony

+1

Хотелось бы, чтобы я мог наградить вас специальным вознаграждением за это. Я беру существующий проект, который начал свою жизнь в качестве проекта nHibernate, который затем заменил на EF6. Они не прошли лишнюю милю, чтобы получить все от миграции из-за временных ограничений, которые я намереваюсь сделать сейчас. Это позволило удалить несколько одноразовых скриптов, которые они запускали в их ручном генераторе БД. Спасибо! –

0

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

First ДобавитьDatabaseGeneratedOption.ComputedDataAnnotion вашей собственности

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

+1

Этот ответ должен, вероятно, включать специальный пользовательский SqlServerMigrationSqlGenerator. Ответ JonnySchnittger - это широкая кисть и не включает поддержку аннотации атрибутов per-property или плавных определений конфигурации. (Если я в конечном итоге реализую это вместо изменения миграции, я отредактирую его) – JoeBrockhaus

0

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

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

Создать переход:

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

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

 Смежные вопросы

  • Нет связанных вопросов^_^