Включить миграцию с контекстом в отдельной сборке?

У меня есть один проект, из которого я хочу запустить my update-database, но у меня есть мои модели и контекст в отдельном проекте.

Если я запустил enable-migrations, я получаю эту ошибку: В сборке "MyProject" не было найдено никакого контекстного типа.

Это, по-видимому, потому, что мой контекст находится в MyProject.MVC.

Если я запустил enable-migrations в MyProject.MVC, я должен добавить файл конфигурации приложения. Я не хочу этого делать, поскольку хочу использовать код для многих проектов.

Итак, могу ли я запустить enable-migrations против MyProject и как-то сказать ему посмотреть в MyProject.MVC для контекста?

Ответ 1

Это будет работать только в EF 6, но был релиз, который добавил параметр -ContextProjectName в команду -enable-migrations. Используя эту команду, вы можете сделать следующее:

enable-migrations -ContextProjectName MyProject.MVC -StartUpProjectName MyProject.MVC 
-ContextTypeName MyProject.MVC.MyContextFolder.MyContextName -ProjectName MyProject

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

Ответ 2

Вы можете запускать только "Enable-Migrations" в проекте, содержащем класс контекста базы данных.

Ваше решение будет содержать 2 проекта:

1) MyProject.Models
    |- Migrations
        |- 201401061557314_InitialCreate.cs
        |- Configuration.cs
    |- MyContext.cs
    |- App.config (no connection string)


App.config

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <configSections>
    <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
  </configSections>
  <entityFramework>
    <defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework" />
    <providers>
      <provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
    </providers>
  </entityFramework>
</configuration>


2) MyProject.MVC
        |- Filters
            |- InitializeSimpleMembershipAttribute.cs


InitializeSimpleMembershipAttribute.cs

namespace MyProject.MVC.Filters
{
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
    public sealed class InitializeSimpleMembershipAttribute : ActionFilterAttribute
    {
        private static SimpleMembershipInitializer _initializer;
        private static object _initializerLock = new object();
        private static bool _isInitialized;

        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            // Ensure ASP.NET Simple Membership is initialized only once per app start
            LazyInitializer.EnsureInitialized(ref _initializer, ref _isInitialized, ref _initializerLock);
        }

        private class SimpleMembershipInitializer
        {
            public SimpleMembershipInitializer()
            {
                try
                {
                    Database.SetInitializer<MyContext>(new MigrateDatabaseToLatestVersion<MyContext, MyProject.Model.Migrations.Configuration>());

                    using (var context = new MyContext())
                    {
                        context.Database.Initialize(force: true);
                        if (!context.Database.Exists())
                        {
                            // Create the SimpleMembership database without Entity Framework migration schema
                            ((IObjectContextAdapter)context).ObjectContext.CreateDatabase();
                        }
                    }

                    WebSecurity.InitializeDatabaseConnection("DefaultConnection", "UserProfile", "UserId", "UserName", autoCreateTables: true);
                }
                catch (Exception ex)
                {
                    throw new InvalidOperationException("The ASP.NET Simple Membership database could not be initialized. For more information, please see http://go.microsoft.com/fwlink/?LinkId=256588", ex);
                }
            }
        }
    }
}

Задайте MyProject.MVC как проект запуска

В диспетчере пакетов выберите проект: MyProject.Models

Затем запустите "Enable-Migrations" для создания папки "Миграции" в MyProject.Models

В соответствии с параметрами "Обновить-База данных" → миграции будет использоваться строка подключения в Web.config из проекта запуска для выполнения миграции

Ответ 3

Вот обходной путь:

Добавить класс в MyProject (проект для миграции). Сделайте этот класс наследующим dbcontext (тот, что в MyProject.MVC).

Затем запустите команды миграции EF в MyProject.

Ответ 4

У меня была та же проблема, и я использую EntityFramework 4.3.1. Кажется, что EF6 решает эту проблему (в соответствии с ответом @SOfanatic), но я не хотел обновляться до EF6 из-за некоторых нарушений (например, в DataAnnotations).

Итак, что я сделал, чтобы решить эту проблему (и то, что я узнал в процессе):

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

  • Добавьте файл конфигурации со строкой подключения (не беспокойтесь, это только для того, чтобы обмануть механизм миграции). Скопируйте существующую базу данных в выходную папку проекта модели (должен быть MVC\bin\Debug в вашем случае). Убедитесь, что строка подключения в файле конфигурации указывает на эту базу данных:

    <connectionStrings>
        <add name="MyDB" providerName="System.Data.SqlServerCe.4.0" connectionString="DataSource=|DataDirectory|\MyDB.sdf"/>
      </connectionStrings>
    
  • Поскольку вы находитесь в новом решении, задайте проект модели как проект запуска (вы можете удалить проект по умолчанию).

  • Запустите команду enable-migrations в консоли диспетчера пакетов. Он должен создать папку Migrations с двумя файлами: Configuration.cs и timestamped файл InitialCreate.cs. Приятно иметь InitialCreate, поэтому вы помещаете свою существующую базу данных в выходную папку проекта модели (но это необязательно).

  • Перезагрузите оригинальное решение, чтобы эти изменения были обновлены.

Что я узнал (насколько я понимаю):

  • Для механизма миграции требуется что-то похожее на действительное соединение для работы. Я создал строку подключения в коде (в другом проекте), и это не сработало. Я просто дал движку Migrations "правильную" строку подключения, чтобы заставить ее работать.
  • Поместите свою базу данных, где механизм миграции может ее найти (например, модельную папку вывода проекта), поэтому она создает отправную точку для переноса. Эта отправная точка - это в основном ваша схема базы данных, написанная в API миграции.
  • Вы можете восстановить все до своего предыдущего состояния после того, как миграция будет установлена ​​на место, и она будет работать нормально.
  • Каждый раз, когда вы хотите вручную добавить перенос, вы должны снова "обмануть" механизм миграции, как и в первый раз. Я не пробовал автоматические миграции, я думаю, что этот подход также работает.

В-четвертых, я использую базу данных SQL Server CE 4.0, поэтому некоторые вещи о строке подключения немного отличаются от стандартной базы данных SQL Server или LocalDB. Кроме того, все то же самое.

Надеюсь, это полезно и даст вам некоторое представление. Прокомментируйте, если вы знаете больше о том, как работают эти миграции.