web-dev-qa-db-ja.com

個別のアセンブリのコンテキストを使用した移行を有効にしますか?

update-databaseを実行したいプロジェクトが1つありますが、モデルとコンテキストは別のプロジェクトにあります。

enable-migrationsを実行すると、次のエラーが表示されます。アセンブリ 'MyProject'でコンテキストタイプが見つかりませんでした。

これはおそらく、私のコンテキストがMyProject.MVCにあるためです。

MyProject.MVCに対してenable-migrationsを実行する場合、アプリの構成ファイルを追加する必要があります。多くのプロジェクトでコードを使用したいので、私はそれをしたくありません。

MyProjectに対してenable-migrationsを実行し、何らかの方法でMyProject.MVCでコンテキストを調べるように指示できますか?

64
Jon

これはEF 6でのみ機能しますが、-ContextProjectNameパラメーターを-enable-migrationsコマンドに追加する release がありました。このコマンドを使用すると、次のことができます。

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

これにより、MyProject.MVCのコンテキストを使用して、MyProjectプロジェクトに移行が追加されます。 Migrationsを含むプロジェクトが、コンテキストを含むプロジェクトへの参照を持っていることを確認する必要があります。つまり、MyProject references MyProject.MVC

100
SOfanatic

Database Contextクラスを含むプロジェクトでのみ「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に「Migrations」フォルダーを作成します

「Update-Database」が続きます->移行は、スタートアッププロジェクトからのWeb.configの接続文字列を使用して移行を実行します

12
cronixis

回避策は次のとおりです。

クラスをMyProject(移行用のプロジェクト)に追加します。このクラスにdbcontext(MyProject.MVCの1つ)を継承させます。

次に、MyProjectでEF移行コマンドを実行します。

3
Jan Bizub

同じ問題があり、EntityFramework 4.3.1を使用しています。 EF6はこの問題を解決しているようです(@SOfanaticの回答による)が、いくつかの重大な変更(たとえば、DataAnnotationsなど)のためにEF6にアップグレードしたくありませんでした。

だから、私はこれを解決するために何をしたか(そしてその過程で学んだこと):

  1. 新しいソリューション(空のプロジェクト)を作成し、移行を有効にするモデルがあるプロジェクト(この場合はMyProject.MVC)を追加します。既存のプロジェクトを追加する前に、必要なNuGetパッケージをインストールする必要がある場合があります。

  2. 接続文字列を使用して構成ファイルを追加します(心配しないでください。これは移行エンジンをだますためだけです)。既存のデータベースをモデルプロジェクトの出力フォルダーにコピーします(この場合、MVC\bin\Debugである必要があります)。構成ファイルの接続文字列がそのデータベースを指していることを確認してください。

    <connectionStrings>
        <add name="MyDB" providerName="System.Data.SqlServerCe.4.0" connectionString="DataSource=|DataDirectory|\MyDB.sdf"/>
      </connectionStrings>
    
  3. 新しいソリューションにいるので、モデルプロジェクトをスタートアッププロジェクトとして設定します(既定のプロジェクトを削除できます)。

  4. パッケージマネージャーコンソールでenable-migrationsコマンドを実行します。 Configuration.csとタイムスタンプ付きのInitialCreate.csファイルの2つのファイルでMigrationsフォルダーを作成する必要があります。 InitialCreateがあると便利です。そのため、既存のデータベースをモデルプロジェクトの出力フォルダーに配置します(ただし、これはオプションです)。

  5. これらの変更が更新されるように、元のソリューションをリロードします。

私が学んだこと(私が理解する限り):

  1. 移行エンジンを使用するには、有効な接続のように見えるものが必要です。接続文字列をコードで(別のプロジェクトで)作成していましたが、うまくいきませんでした。 Migrationsエンジンに機能させるための「有効な」接続文字列を指定しました。
  2. データベースを移行エンジンが検索できる場所(モデルプロジェクトの出力フォルダー)に配置して、移行の開始点を作成します。この出発点は基本的に、移行APIで記述されたデータベーススキーマです。
  3. 移行が適切に設定されると、すべてを以前の状態に復元でき、正常に機能します。
  4. 移行を手動で追加するたびに、初めてと同様に、移行エンジンを再度「トリック」する必要があります。このアプローチもうまくいくと思うので、自動移行を試したことはありません。

ところで、私はSQL Server CE 4.0データベースを使用しているので、接続文字列に関するいくつかのことは、標準のSQL Server DBまたはLocalDBと比べて少しひねりがあります。それに加えて、すべて同じです。

これが参考になり、洞察が得られることを願っています。この移行の仕組みについて詳しく知っている場合はコメントしてください。

0
Hannish