EF 4.3 Автоматическая миграция с несколькими DbContexts в одной базе данных - PullRequest
21 голосов
/ 02 февраля 2012

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

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

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

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

Спасибо!

Ответы [ 9 ]

32 голосов
/ 04 апреля 2012

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

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

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

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

Add-Migration -configuration Configuration1 Context1Init

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

Add-Migration -configuration Configuration2 Context2Init

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

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

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

6 голосов
/ 11 февраля 2012

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

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

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

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

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

3 голосов
/ 24 февраля 2012

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

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

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

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

1 голос
/ 08 января 2013

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

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

1 голос
/ 10 ноября 2012

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

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

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

1 голос
/ 27 мая 2012

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

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

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

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

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

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

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

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

В моем случае я решил, что ЭФФЕКТИВНОСТЬ важнее миграций. Итак, что я в итоге сделал, так это то, что после того, как я запустился в контексте Super и имел все таблицы на месте, я вошел в базу данных и вручную удалил таблицу _MigrationHistory.

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

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

Хотя у меня это сработало.

0 голосов
/ 29 ноября 2013

Я хочу, чтобы люди знали, что ответ с этим ниже - то, что сработало для меня, но с одним предупреждением: не используйте строку 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";
   }
}

Однако у меня уже были установлены 2 базы данных с определенными их собственными контекстами, поэтому я обнаружил, что получаю сообщение об ошибке «Пространство имен 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;
   }
}

Затем я снова выполнил команду Context -Init Add-Migration -configuration Configuration1 и снова строку Configuration1 -configuration Configuration1 (для моего 2-го контекста), и, наконец, теперь все работает отлично.

0 голосов
/ 17 октября 2012

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

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

0 голосов
/ 03 мая 2012

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

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

...