web-dev-qa-db-ja.com

Entity FrameworkのEF Migrations Add-Migrationステップでデータベース接続文字列が必要なのはなぜですか?

私はEF移行を使用して理解しようとしています(EF 4.3.1、コードファーストを使用)。新しい変更を足場するためには、次のようなコマンドを使用する必要があります。

Add-Migration MyMigration
   -ConnectionString "Data Source=.;Initial Catalog=mydb;" 
   -ConnectionProviderName "System.Data.SqlClient"
   -StartUpProjectName MyWebsite 
   -ProjectName MyEF.Migrations

Add-Migrationに接続文字列データが必要なのはなぜですか? Update-Database必要です。それは理にかなっています。しかし、Add-Migrationには、DbContextと構成から必要なものがすべて揃っていませんか?

それは単にアイドル状態の不思議ではなく、データベースを提供することは非常に混乱します。なぜなら、目的のデータベースが柔軟であり、静的コンパイル時に言うまでもなく、要求ごとに変化する可能性がある「マルチテナンシー」があるからです。したがって、Add-Migrationは実際にはそのデータベースを何にでも使用しています。問題があります。

更新:私たちはEFの移行をあきらめ、代わりに Fluent Migrator を使用しており、満足しています。これははるかに高速で、2回(EFオブジェクトに対して1回、Migrationに対して1回)いくつかのことを書かなければならないという事実を考慮しても、この質問で説明されている問題はありません。

24
Scott Stafford

Add-Migrationは、データベースの存在を確認し、__MigrationHistoryテーブルと対話します。 @Anders Abelが言及したように、保留中の移行を調査し、変更を実際に見つけるために以前のモデルを選択するためにも使用されます-自動移行が有効になっているソリューションに明示的な移行を追加する場合、これは特に重要です。

12
Ladislav Mrnka

私はあなたの質問を読んで不思議に思ったので、Sql Server Profilerを起動して、add-migrationが実行されているときに何が起こっているのかを調べました。実際にデータベースに接続し、DBにアクセスして__MigrationHistoryテーブルを確認します。

これは、最初のコードを実行せずに2番目のコードベースの移行を作成しようとしたときに生成されるエラーメッセージでも示されます。

次の明示的な移行が保留中のため、明示的な移行を生成できません:[201205291928386_foo]。新しい明示的な移行を生成する前に、保留中の明示的な移行を適用します。

移行エンジンは、データベースからのシリアル化されたモデルを使用して、新しい移行に含める必要のある移行手順を計算すると思います。

私の理解する限り、データベースはコード生成のヘルパーとしてのみ使用されます。使用するさまざまなデータベースがすべてコード内のモデルと互換性がある限り、これは問題になりません。

編集する

@Ladislav Mrnkaが指摘しているように、コードベースの移行と自動移行を混在させる場合は、データベースを確認する必要があります。新しいマイグレーションを足場にする場合、前回のマイグレーション以降にモデルで変更されたものをすべて含める必要があります。自動移行を使用している場合、それらはコードで追跡されません。移行に含める変更を計算するとき、最後に実行された移行がベースとして使用されます。自動マイグレーションがオンになっている可能性があるため、それを確認する唯一の方法はデータベースです。

コードベースの移行のみを実行している場合(これは制御を維持するための唯一のオプションだと思います)、そのデータベースは単なるコード生成のヘルプと見なすことができます。接続するすべてのデータベースでモデルの互換性が確保されている限り、すべてが機能するはずです。

9
Anders Abel

Rowan Millerが2014年3月からこのビデオを視聴しました: Migrations-Under the Hood

ビデオでローワンはAdd-Migrationコマンドは、EdmModelDifferというコンポーネントを含むいくつかのステップを実行します。 EdmModelDifferは、現在のモデルを前回の移行(以前の移行のresxファイルに埋め込まれている)の以前のモデルと比較し、データベースに必要な変更を計算します。

そのため、EdmModelDifferコンポーネントにはデータベース接続が必要です。

ビデオで説明されている手順は次のとおりです。

  1. コードから現在のモデルを構築する
  2. 最後の移行から以前のモデルを取得(resxファイルにスナップショットとして保存)
  3. 必要なデータベース変更を計算します(EdmModelDifferによって実行されます)
  4. 新しい移行ファイルを生成しました

理論的には、新しい移行を生成するには、その現在のモデルを最後の移行のモデルと比較するだけで十分だと推定できます。しかしその間、他の人々もデータベースに変更を加えた可能性があります。データベースに対するチェックも行われているのは、おそらくそのためです。これを行わない場合、結果の移行ファイルは正しい必要はありません。


Migrations-Team Environments と呼ばれる2番目のビデオもご覧ください。

0
Martin

OPは書きました:

しかし、Add-Migrationには、DbContextと構成から必要なものがすべて揃っていませんか?

いいえ-他の人がここで言及したように、手動移行のコードのデザイナー部分(add-migrationによって作成されたもの)には、データベーススキーマのスナップショットが含まれています。

つまり、接続文字列などを使用しているという事実は非常に奇妙です。 EFは通常、DbContextクラスとWeb.Configからそれを意味します。 1つのデータベースと1つのDbContextがあるプロジェクトで、Configurationクラスを作成し、次のコマンドで手動の移行を追加します。

add-migration

他のコマンドライン引数を渡す必要はありません。それはEF 4.3.1にあります-おそらくあなたはCTPまたはいくつかの古いバージョンを使用していたか、単にドキュメントを誤解しましたか?

複数のDBまたはDbContextsがある場合、複数の構成クラスがあり、たとえば次のように使用します。

add-migration -conf Log

Web.configのConfigurationクラスと関連する接続文字列を使用して、そのデータベース/ DbContextの手動移行を追加します。

ログを格納するためのシンプルなDbContextの長いコード例を次に示します(メインデータベースとは別)。

namespace MyProj.Models.Log
{
    public class LogDb : DbContext
    {
        public DbSet<LogLine> LogLines { get; set; }
        public DbSet<LogTag> LogTags { get; set; }


        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
        }
    }

    public LogDb()
#if DEPLOYDB
         : base("LogDeploy")
#else
         : base()
#endif
     {
     }
}

namespace MyProj.Migrations
{
    internal sealed class Log : DbMigrationsConfiguration<LogDb>
    {
        public Log()
        {
            AutomaticMigrationsEnabled = true;
        }
    }
}

Web.Config:

<add name="LogDb" connectionString="Initial Catalog=Log;Data Source=.\SqlExpress;Integrated Security=SSPI;MultipleActiveResultSets=true" providerName="System.Data.SqlClient" />
<add name="LogDeploy" connectionString="Initial Catalog=Log;Data Source=00.00.000.00,12345;User ID=sql;Password=xxx;Network Library=DBMSSOCN" providerName="System.Data.SqlClient" />

したがって、この例では、複数のデータベースと複数のDbContextがあります。 LogDbは、コンパイル時に「DBDEPLOY」が定義されているかどうかに基づいて、Web.Configで異なる接続文字列を使用します。ある場合は、「LogDeploy」を使用します。そうでない場合、それはデフォルトを使用します-クラス「LogDb」と同じ名前の接続文字列。これにより、プロジェクト構成を切り替え、SQL dbマシンのポートを開いて実行することにより、ローカルマシンからDBの変更をサーバーに簡単にデプロイできます。

> update-database -conf Log

パッケージマネージャーコンソールで。

0
Chris Moschini