Entity Framework 6に移行した後、ビルドサーバーで単体テストを実行するとエラーが発生します。
DropCreateDatabaseIfModelChanges
初期化子を使用しています。 MigrateDatabaseToLatestVersion
に変更すると、すべてが機能しますが、以前の初期化子を使用したいと思います。
私が得ているエラーは次のとおりです。
System.InvalidOperationException:System.InvalidOperationException:データベースが作成されてから、「AppContext」コンテキストをサポートするモデルが変更されました。 Code First Migrationsを使用してデータベースを更新することを検討してください( http://go.Microsoft.com/fwlink/?LinkId=238269 )。
どちらが正しいか、変更されましたが、DropCreateDatabaseIfModelChanges
初期化子を使用して、再作成する必要があります。何か案は?
EFはApp.configで構成されます。関連する部分は次のとおりです。
<connectionStrings>
<add name="AppContext" connectionString="Data Source=(localdb)\v11.0;Initial Catalog=my.app.unittest;Integrated Security=True" providerName="System.Data.SqlClient" />
</connectionStrings>
<entityFramework>
<defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework">
<parameters>
<parameter value="v11.0" />
</parameters>
</defaultConnectionFactory>
<contexts>
<context type="my.app.core.Data.AppContext, my.app.core">
<databaseInitializer type="System.Data.Entity.DropCreateDatabaseIfModelChanges`1[[my.app.core.Data.AppContext, my.app.core]], EntityFramework" />
</context>
</contexts>
<providers>
<provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
</providers>
</entityFramework>
EF6.0では新しいルールが導入されているようです。
「DbContextがイニシャライザーを使用していて、移行が構成されている場合、モデルのビルド時に例外をスローします」。
EF 6 RCまでは、これは強制されませんでした。厄介な部分は、「移行が構成されている」がDbMigrationsConfigurationの実装によって定義されていることです。テストで移行をプログラムで無効にする方法はないようです-実装した場合
Sebastian Piuと非常によく似た方法で回避しました。テストからConfigurationクラスを削除する必要がありましたが、メインプロジェクトに移行を使用しているため、削除することはできませんでした。ああ!
これは以前の私のコードでした:
public class MyDbContext : DbDContext, IMyDbContext
{
public IDbSet<Users> Users {get; set;}
public IDbSet<Widgets> Widgets {get; set;}
}
// Migrations are considered configured for MyDbContext because this class implementation exists.
internal sealed class Configuration : DbMigrationsConfiguration<MyDbContext>
{
public Configuration()
{
AutomaticMigrationsEnabled = false;
}
}
// Declaring (and elsewhere registering) this DB initializer of type MyDbContext - but a DbMigrationsConfiguration already exists for that type.
public class TestDatabaseInitializer : DropCreateDatabaseAlways<MyDbContext>
{
protected override void Seed(MyDbContext context) { }
}
テストコードでDbContextを初期化するときに、System.InvalidOperationExceptionが発生しました。アプリケーションはイニシャライザーを使用しないため、以前のようにアプリの実行に問題はありませんでした。これは私のテストを破っただけです。
解決策(EFに欠けているものの回避策のように感じます)は、InitializerとDbMigrationsConfigurationをセグメント化して、ランタイム環境で1つだけが表示されるようにすることです。テストでInitializerを使用し、アプリケーションでDbMigrationsConfigurationを使用する必要があります。これは、DbContextにインターフェイスがあれば、よりクリーンに実行できますが、残念ながら、IObjectContextAdapterのみを実装します。
まず、DbContextを抽象化しました。
public abstract class MyDbContextBase : DbContext, IMyDbContext
{
public IDbSet<Users> Users {get; set;}
public IDbSet<Widgets> Widgets {get; set;}
}
次に、2つのクラスを導出しました。
public class MyDbContext : MyDbContextBase
{
public MyDbContext(string connectionStringOrName, IDatabaseInitializer<MyDbContext> dbInitializer)
: base(connectionStringOrName)
{
}
}
public class MyTestDbContext : MyDbContextBase
{
public MyTestDbContext(string connectionStringOrName, IDatabaseInitializer<MyDbContext> dbInitializer)
: base(connectionStringOrName)
{
Database.SetInitializer(dbInitializer);
}
}
MyDbContextとMyTestDbContextはどちらもIMyDbContextであるため、既存の依存性注入の設定は変更を必要とせずに機能するはずです。 Spring.NETのみをテストしました。
私のDbMigrationsConfigurationは、テストで使用されない派生型を実装しています。
internal sealed class Configuration : DbMigrationsConfiguration<MyDbContext>
{
public Configuration()
{
AutomaticMigrationsEnabled = false;
}
}
最後に、初期化子の型が派生テストクラス型に移動されました。
public class TestDatabaseInitializer : DropCreateDatabaseAlways<MyTestDbContext>
{
protected override void Seed(MyTestDbContext context) { }
}
テストに合格し、アプリケーション(および移行)が以前と同じように機能していることを確認できます。
EF6にアップグレードした直後に同じ問題が見つかりました。 Stefanのコメントを読み、彼が説明したのと同じ症状が出た後(テストでは、メインプロジェクトからConfigurationクラスをロードしていました)
私の場合の解決策/回避策は
class TestContext: MyDataContext
を作成しますDropCreateDatabaseAlways<MyDataContext>
からDropCreateDatabaseAlways<TestContext>
に変更します私のテストのほとんどはPersistenceTestクラスから拡張されているため、これを行うことができます。したがって、大きなカタログがある場合、これを変更するのは面倒かもしれません。だから他の解決策を楽しみにしています
移行が有効になっていて、DropCreateDatabaseIfModelChanges初期化子を使用しているため、これはスローされます。 Entityframeworkは、移行でのこの初期化子の使用をサポートしていません。 2つのオプションがあります。
または
この動作は意図されたもののようです。開発者の1人からの引用は次のとおりです。
EF5は定義された移行を使用せずにデータベースを作成するため、この動作の変更は仕様によるものでした。つまり、初期化子によって作成されたデータベースは、移行によって作成されたデータベースとは異なる可能性があります。これにより、1つのデータベーススキーマに対してテストを行うことができますが、別のデータベーススキーマに対して本番環境で実行することができます。ただし、この動作に変更を加えることを暫定的に決定しました。これはここで追跡されています: https://entityframework.codeplex.com/workitem/1709
私にとってうまく機能するのは、define
を使用した移行を除外することです。方法は次のとおりです。
Test
を定義するTEST
という新しい構成を作成しますTEST
が定義されていない場合にエラーをスローします。TEST
が定義されている場合は、移行を除外します。#if !TEST
internal sealed class Configuration : DbMigrationsConfiguration<Context>
{
//...
}
#endif
すべての移行を除外する必要があるかもしれませんが、これも完全には満足のいくものではありません(ただし、まだ移行がないため、試していません)。