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

EF 4.3 Автоматическая миграция с несколькими DbContexts в одной базе данных

Я пытаюсь использовать EF 4.3 миграции с несколькими кодовыми DbContexts. Мое приложение разделено на несколько плагинов, которые, возможно, имеют свой собственный DbContext в отношении своего домена. Приложение должно использовать одну единственную базу данных sql.

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

Итак, мой вопрос:

  • Как я могу передать конфигурацию миграции только для того, чтобы следить за таблицами, определенными в их соответствующем контексте, и оставить всех остальных в покое?
  • Каков правильный рабочий процесс для работы с несколькими DbContexts с автоматической миграцией в одной базе данных?

Спасибо!

4b9b3361

Ответ 1

First First Migrations предполагает, что для каждой базы данных (и одного контекста для каждой конфигурации) существует только одна конфигурация миграции.

Я могу представить два возможных решения:

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

  • Используйте отдельные базы данных для каждого контекста. Если у вас есть общие объекты между контекстами, добавьте настраиваемую миграцию и замените вызов CreateTable(...) вызовом Sql("CREATE VIEW ..."), чтобы получить данные из базы данных "originating".

Я бы попробовал # 1, так как он хранит все в одной базе данных. Вы можете создать отдельный проект в своем решении, чтобы содержать ваши миграции и этот "супер" контекст. Просто добавьте проект, сориентируйте все проекты ваших плагинов, создайте контекст, который включает все объекты, а затем вызовите Enable-Migrations в этом новом проекте. После этого все должно работать, как ожидается.

Ответ 2

Вот что вы можете сделать. очень просто.

Вы можете создать класс конфигурации для каждого из ваших контекстов. например,

internal sealed class Configuration1 : DbMigrationsConfiguration<Context1>{
   public Configuration1 (){
        AutomaticMigrationsEnabled = false;
        MigrationsNamespace = "YourProject.Models.ContextNamespace1";
   }
}

internal sealed class Configuration2 : DbMigrationsConfiguration<Context2>{
   public Configuration2 (){
        AutomaticMigrationsEnabled = false;
        MigrationsNamespace = "YourProject.Models.ContextNamespace2";
   }
}

Теперь вы добавляете миграцию. Вам не нужно активировать миграцию, поскольку вы уже сделали это с классом 2, указанным выше.

Add-Migration -configuration Configuration1 Context1Init

Это создаст миграцию script для context1. вы можете повторить это снова для других Контекстов.

Add-Migration -configuration Configuration2 Context2Init

Обновить базу данных

Update-Database -configuration Configuration1
Update-Database -configuration Configuration2

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

Ответ 3

У меня есть рабочий сайт с несколькими контекстами с использованием миграции. Однако вам необходимо использовать отдельную базу данных для каждого контекста, и все это было отключено от * класса конфигурации в пространстве имен Migrations вашего проекта, поэтому, например, CompanyDbContext указывает на Company.sdf, используя CompanyConfiguration. update-database -configurationtypename CompanyConfiguration. Другой LogDbContext указывает на Log.sdf с использованием LogConfiguration и т.д.

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

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Ignore<OtherContextsClass>();
    // more of these
}

Так как миграции работают с ModelBuilder, это может сделать работу.

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

Ответ 4

Хорошо, я боролся с этим уже целый день, и вот решение для тех, кто ищет ответ...

Я предполагаю, что большинство людей, читающих этот пост, здесь, потому что у них большой класс DbContext с большим количеством свойств DbSet < > , и загрузка занимает много времени. Вы, наверное, подумали о себе, да, это имеет смысл, я должен разделить контекст, так как я не буду использовать все dbsets сразу, и я загружу только "частичный" контекст, основанный на ситуации, в которой мне нужно Это. Таким образом, вы разделили их, только чтобы узнать, что миграция Code First не поддерживает ваш путь революционного мышления.

Итак, ваш первый шаг должен был разделить контексты, а затем вы добавили класс MigrationConfiguration для каждого из новых контекстов, вы добавили строки соединений, названные так же, как и ваши новые классы контекста.

Затем вы попытались запустить вновь разделенные контексты один за другим, выполнив Add-Migration Context1, затем сделав Update-Database -Verbose...

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

Это связано с тем, что текущая модель Migrations ожидает Single DbContext для базы данных и должна быть зеркальным совпадением.

То, что я также пробовал, и кто-то предложил здесь сделать это, - создать один SuperContext, в котором есть все Db-множества. Создайте один класс конфигурации миграции и запустите его. Оставьте свои частичные классы контекста на месте и попробуйте создать и использовать их. EF жалуется, что модель Backing изменилась. Опять же, это связано с тем, что EF сравнивает ваш частичный dbcontext с сигнатурой контекста All-Sets, оставшейся от миграции Super Context.

Это главный недостаток, на мой взгляд.

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

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

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

Это сработало для меня.

Ответ 5

Как упоминалось выше Брайсом, наиболее практичным решением является наличие 1 супер DbContext для каждого приложения/базы данных.

Использование только одного DbContext для целого приложения, по-видимому, является критическим техническим и методологическим недостатком, поскольку оно влияет на модульность между прочим. Кроме того, если вы используете службы данных WCF, вы можете использовать только 1 DataService для каждого приложения, поскольку DataService может отображать только 1 DbContext. Таким образом, это значительно изменяет архитектуру.

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

Ответ 6

Я только наткнулся на эту проблему и понял, почему я разделил их на разные контексты, было чисто, чтобы группировать связанные модели в управляемые куски, а не по какой-либо другой технической причине. Вместо этого я объявил свой контекст как частичный класс, и теперь разные файлы кода с разными моделями в них могут добавлять DbSets в DbContext.

Таким образом, все еще работает магия миграции.

Ответ 7

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

Похоже, что это довольно немного, но я уверен, что было бы непросто поддерживать его, если бы не было дублирования между DbContexts.

Ответ 8

Разумеется, решение должно быть изменено командой EntityFramework для изменения API для поддержки прямой модификации таблицы _MigrationHistory в имя таблицы по вашему выбору, например _MigrationHistory_Context1, чтобы оно могло обрабатывать модификацию независимых объектов DbContext. Таким образом, все они рассматриваются отдельно, а его разработчик должен гарантировать, что имена объектов не сталкиваются.

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

Ответ 9

Я хочу, чтобы люди знали, что ответ с этим ниже - это то, что сработало для меня, но с одной оговоркой: не используйте строку MigrationsNamespace.

internal sealed class Configuration1 : DbMigrationsConfiguration<Context1>{
       public Configuration1 (){
        AutomaticMigrationsEnabled = false;
        MigrationsNamespace = "YourProject.Models.ContextNamespace1";
   }
 }

internal sealed class Configuration2 : DbMigrationsConfiguration<Context2>{
   public Configuration2 (){
        AutomaticMigrationsEnabled = false;
        MigrationsNamespace = "YourProject.Models.ContextNamespace2";
   }
}

Тем не менее, у меня уже были установлены две базы данных с их собственными контекстами, поэтому я обнаружил, что получаю сообщение об ошибке: "Пространство имен YourProject.Models уже определено ContextNamespace1". Это произошло потому, что "MigrationsNamespace =" YourProject.Models.ContextNamespace2 ";" вызывал dbcontext для определения в пространстве имен YourProjects.Models дважды после того, как я попробовал Init (один раз в файле Context1Init миграции и один раз, когда я определил его ранее).

Итак, я обнаружил, что то, что я должен был сделать в этот момент, - это запустить мою базу данных и миграции с нуля (к счастью, у меня не было данных, которые мне нужно было сохранить), следуя указаниям здесь: http://pawel.sawicz.eu/entity-framework-reseting-migrations/

Затем я изменил код, чтобы НЕ включать строку MigrationsNamespace.

internal sealed class Configuration1 : DbMigrationsConfiguration<Context1>{
       public Configuration1 (){
        AutomaticMigrationsEnabled = false;
   }
 }

internal sealed class Configuration2 : DbMigrationsConfiguration<Context2>{
   public Configuration2 (){
        AutomaticMigrationsEnabled = false;
   }
}

Затем я снова запустил команду Add-Migration -configuration Configuration1 Context1Init и строку Configuration-Configuration-Configurationfigure Configuration1 (для моего второго контекста), и, наконец, теперь все работает отлично.