2013-09-12 5 views
33

Я изучаю миграцию, чтобы очистить наши процессы развертывания. Чем меньше ручное вмешательство требуется при нажатии на изменение производства, тем лучше.Entity Framework - миграция - первый код - седиментация на миграцию

Я столкнулся с тремя основными корягами с системой миграции. Это шоу-стопы, если я не могу понять, как их можно обойти.

1. Как добавить данные семян в миграции:

я выполнить команду «надстройку миграции», который каркасах новый файл миграции с функциями вверх и вниз. Теперь я хочу автоматически вносить изменения в данные с изменениями Up и Down. Я не хочу добавлять данные Seed в метод Configuration.Seed, поскольку он выполняется для всех миграций, который заканчивается всеми видами проблем с дублированием.

2. Если вышеизложенное невозможно, как избежать дублирования?

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

foreach(var enumValue in Enum.GetValues(typeof(Access.Level))) 
{ 
    context.Access.AddOrUpdate(
     new Access { AccessId = ((int)enumValue), Name = enumValue.ToString() } 
    ); 
} 
context.SaveChanges(); 

Несмотря на то, что я использую AddOrUpdate, я по-прежнему получаю дубликаты в базе данных. Вышеприведенный код приводит меня к моей третьей и последней проблеме:

3. Как я могу семенировать первичные ключи?

Мой перечислимы с выше код:

public class Access 
{ 
    public enum Level 
    { 
     None = 10, 
     Read = 20, 
     ReadWrite = 30 
    } 
    public int AccessId { get; set; } 
    public string Name { get; set; } 
} 

Я с указанием значения, которые я хочу в качестве основного ключа, но Entity Framework, кажется, игнорировать его. Они все еще в конечном итоге составляют 1,2,3. Как мне получить 10,20,30?

Являются ли эти ограничения EF на данный момент или являются ли они преднамеренными ограничениями для предотвращения какой-либо другой катастрофы, которую я не вижу?

ответ

25
  1. Когда я исправил данные, которые я хочу, чтобы вставить с миграцией, я положил вставку непосредственно в миграции вверх() с помощью вызовов Sql("Insert ..."). См. Примечание наполовину вниз по этой странице: how to insert fixed data
  2. Вы предотвращаете дубликаты в методе Seed, вызывая перегрузку AddOrUpdate, которая принимает выражение идентификатора, указывающее естественный ключ - см. this answer и this blog entry.
  3. Основные ключи, которые являются целыми числами, по умолчанию создаются как поля для идентификации. Чтобы указать, в противном случае используйте атрибут [DatabaseGenerated(DatabaseGeneratedOption.None)]

Я думаю, что это хорошее объяснение Initializer and Seed methods

Вот пример того, как использовать метод AddOrUpdate:

foreach(var enumValue in Enum.GetValues(typeof(Access.Level))) 
{ 
    context.Access.AddOrUpdate(
     x => x.Name, //the natural key is "Name" 
     new Access { AccessId = ((int)enumValue), Name = enumValue.ToString() } 
    ); 
} 
3

Привет Я нашел очень полезную информацию для вашей проблемы в этой ссылке: Safari Books Online

«1. Как добавить данные семян в миграции:» Как вы видите на примере вам нужно создать новую конфессию для посева. Это семя Конфигурация должна быть вызвана после миграции.

public sealed class Configuration : DbMigrationsConfiguration 
{ 
    public Configuration() 
    { 
     AutomaticMigrationsEnabled = false; 
    } 

    protected override void Seed(SafariCodeFirst.SeminarContext context) 
    { 
     // This method will be called after migrating to the latest version. 

     // You can use the DbSet<T>.AddOrUpdate() helper extension method 
     // to avoid creating duplicate seed data. E.g. 
     // 
     // context.People.AddOrUpdate(
     //  p => p.FullName, 
     //  new Person { FullName = "Andrew Peters" }, 
     //  new Person { FullName = "Brice Lambson" }, 
     //  new Person { FullName = "Rowan Miller" } 
     // ); 
     // 
    } 
} 

«2. Если выше не представляется возможным, как избежать дублирования?»

AddOrUpdate Должно помочь вам точно avoding дубликаты, если вы получите ошибку здесь вы, возможно, ошибка конфигурации вывесить стек вызовов, пожалуйста. См. Пример!

«3. Как перенести первичные ключи?»

Здесь также по вашему определению. Если ваш ключ DatabaseGenerated(DatabaseGeneratedOption.Identity), то вам не нужно его предоставлять. В некоторых других сенариях вам нужно создать новый, в зависимости от типа ключа.

«Являются ли эти ограничения EF на данный момент или являются преднамеренными ограничениями для предотвращения какой-либо другой катастрофы, которую я не вижу?»
Не знаю, что я знаю!

+2

У меня есть данные в этом методе семени. Но он продолжает добавлять дубликаты, хотя я использую AddOrUpdate. Проблема в том, что когда я использую «add-migration», она не создает собственную конфигурацию. Поэтому, независимо от того, какую миграцию вы выполняете, он по-прежнему выполняет общий метод семени, который я не хочу. Я хочу иметь отдельный метод Seed для файла миграции. – Talon

+0

look У меня есть аналогичная проблема. Что я сделал в конструкторе DbMigrationsConfiguration; Вы должны установить MigrationsNamespace, например, this.MigrationsNamespace = «DataAccessLayer.Repository.Migrations»; и в желаемом файле миграции вам необходимо изменить пространство имен в соответствии с DbMigrationsConfiguration. Этот трюк, который я основал сам после долгого боя, и теперь Entity Framework пойдет только в желаемом файле миграции. Я надеюсь, что это решит вашу проблему. 2. –

+0

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

3

ОК, так что, немного сбившись, мне удалось вбить EF в подчинение. Вот что я сделал:

1. Невозможно найти данные для определенной миграции. Все это должно войти в общий метод Configuration.Seed.

2. Чтобы избежать дубликатов, мне пришлось сделать 2 вещи. Для моих перечислений, я написал следующий код семян:

foreach (var enumValue in Enum.GetValues(typeof(Access.Level))) 
{ 
    var id = (int)enumValue; 
    var val = enumValue.ToString(); 

    if(!context.Access.Any(e => e.AccessId == id)) 
     context.Access.Add(
      new Access { AccessId = id, Name = val } 
     ); 
} 
context.SaveChanges(); 

Так в основном, просто проверить, если он существует, и добавление, если не

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

public class Access 
{ 
    public enum Level 
    { 
     None = 10, 
     Read = 20, 
     ReadWrite = 30 
    } 

    [DatabaseGenerated(DatabaseGeneratedOption.None)] 
    public int AccessId { get; set; } 
    public string Name { get; set; } 
} 
10

В качестве возможного решения пункт 1, я внедрил реализацию стратегии IDatabaseInitializer, которая будет запускать метод Seed для каждой ожидающей миграции только для вас, вам нужно будет реализовать пользовательский интерфейс IMigrationSeed в каждом из ваших классов DbMigration,Методбудет реализован сразу после Up и Down методов каждого класса миграции.

Это помогает решить две проблемы для меня:

  1. Database Group Модель миграции с базы данных миграции данных (или высева)
  2. Проверьте, что часть семян миграции кода должно быть действительно работает, а не проверки данных в базе данных, но используя уже известные данные, которые были только что созданы.

Интерфейс выглядит следующим образом

public interface IMigrationSeed<TContext> 
{ 
    void Seed(TContext context); 
} 

Ниже приводится новая реализация, которая будет вызывать эту Seed методы

public class CheckAndMigrateDatabaseToLatestVersion<TContext, TMigrationsConfiguration> 
    : IDatabaseInitializer<TContext> 
    where TContext : DbContext 
    where TMigrationsConfiguration : DbMigrationsConfiguration<TContext>, new() 
{ 
    public virtual void InitializeDatabase(TContext context) 
    { 
     var migratorBase = ((MigratorBase)new DbMigrator(Activator.CreateInstance<TMigrationsConfiguration>())); 

     var pendingMigrations = migratorBase.GetPendingMigrations().ToArray(); 
     if (pendingMigrations.Any()) // Is there anything to migrate? 
     { 
      // Applying all migrations 
      migratorBase.Update(); 
      // Here all migrations are applied 

      foreach (var pendingMigration in pendingMigrations) 
      { 
       var migrationName = pendingMigration.Substring(pendingMigration.IndexOf('_') + 1); 
       var t = typeof(TMigrationsConfiguration).Assembly.GetType(
        typeof(TMigrationsConfiguration).Namespace + "." + migrationName); 

       if (t != null 
        && t.GetInterfaces().Any(x => x.IsGenericType 
         && x.GetGenericTypeDefinition() == typeof(IMigrationSeed<>))) 
       { 
        // Apply migration seed 
        var seedMigration = (IMigrationSeed<TContext>)Activator.CreateInstance(t); 
        seedMigration.Seed(context); 
        context.SaveChanges(); 
       } 
      } 
     } 
    } 
} 

Хорошая вещь здесь у вас есть реальный контекст EF манипулировать Seed Данные, как и стандартная реализация EF Seed. Однако это может стать странным, если, например, вы решили удалить таблицу, которая была высеяна при предыдущей миграции, вам придется соответствующим образом реорганизовать существующий код семян.

EDIT: В качестве альтернативы реализации метода семян после Up и Down вы можете создать частичный класс того же класса миграции, я нашел это полезным, поскольку он позволяет мне безопасно удалять класс миграции, когда я хочу для повторного посева той же миграции.

+1

Это гений !!! Для этого вам нужно больше очков. Единственные изменения, которые я сделал, это попробовать/наконец-то вокруг Update, чтобы семена продолжались, если одна миграция завершилась неудачно. Также после обновления называется GetDatabaseTransaction() и сравнивается с ожидающим, так что только успешные миграции будут Seed. Также завернутый вызов Seed в его собственную транзакцию (опять же, на случай, если один не удался.) – Joshua

+0

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

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