0

空の DbContext があります。マッピングは動的に作成され、DbContext は Set(); を使用して一般的に使用されます。

以下は私の一般的な DbContext です。

/// <summary>
/// Object context
/// </summary>
public class MethodObjectContext : DbContext, IDbContext
{
    private readonly IEventPublisher _eventPublisher;

    public MethodObjectContext(string nameOrConnectionString, IEventPublisher eventPublisher)
        : base(nameOrConnectionString)
    {
        _eventPublisher = eventPublisher;
    }

    public MethodObjectContext(DbConnection existingConnection, bool contextOwnsConnection, IEventPublisher eventPublisher)
        : base(existingConnection, contextOwnsConnection)
    {
        _eventPublisher = eventPublisher;
    }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        _eventPublisher.Publish(new ModelCreating(modelBuilder));
        base.OnModelCreating(modelBuilder);
    }

    public new IDbSet<TEntity> Set<TEntity>() where TEntity : class
    {
        return base.Set<TEntity>();
    }
}

(ModelCreating イベントから) マッピングを変更すると、データベースが同期していないことをアサートする単体テストを作成しようとしています。

以下は私のテストコードです。

[TestClass]
public class MigrationTests
{
    private string _connectionString = string.Empty;
    private string _testDb = string.Empty;

    public MigrationTests()
    {
        _testDb = Path.Combine("C:\\", System.Reflection.Assembly.GetExecutingAssembly().GetName().Name.Replace(".", "") + ".sdf");

        if (File.Exists(_testDb))
            File.Delete(_testDb);

        _connectionString = string.Format("Data Source={0};Persist Security Info=False;", _testDb);

        Database.DefaultConnectionFactory = new SqlCeConnectionFactory("System.Data.SqlServerCe.4.0");
    }

    [TestMethod]
    public void ThrowsErrorForOutOfDateDatabase()
    {
        // The initializer will handle migrating the database. 
        // If ctor param is false, auto migration is off and an error will be throw saying the database is out of date.
        Database.SetInitializer(new MigrationDatabaseInitializer<MethodObjectContext>(false));

        // Create the initial database and do a query.
        // This will create the database with the conventions of the Product1 type.
        TryQueryType<Product1>("Product");

        // The next query will create a new model that has conventions for the product2 type.
        // It has an additional property which makes the database (created from previous query) out of date.
        // An error should be thrown indicating that the database is out of sync.
        ExceptionAssert.Throws<InvalidOperationException>(() => TryQueryType<Product2>("Product"));
    }

    private void TryQueryType<T>(string tableName) where T : class
    {
        using (var context = new MethodObjectContext(_connectionString, new FakeEventPublisher(x => x.ModelBuilder.Entity<T>().ToTable(tableName))))
        {
            var respository = new EfRepository<T>(context);
            var items = respository.Table.ToList();
        }
    }
}

私の Product1 クラスは POCO オブジェクトであり、私の Product2 クラスは追加の db フィールドを持つ同じオブジェクトです。

私の問題は、2 回目に MethodObjectContext を new() してクエリを実行すると、ModelCreating メソッドが呼び出されず、次のエラーが発生することです。

The entity type Product2 is not part of the model for the current context.

Product2 は、呼び出された ModelCreating イベントのコンテキストの一部になりますが、そうではありません。何か案は?

注: 同じ接続文字列 (sdf) を使用していて、作成中のデータベースが 2 番目の呼び出し (Product2) に必要な追加フィールドを作成していないため、エラーが発生することが予想されます。

4

1 に答える 1

0

私の DbCompiledModel はキャッシュされていました。以下はキャッシュをフラッシュしました。

private void ClearDbCompiledModelCache()
{
    var type = Type.GetType("System.Data.Entity.Internal.LazyInternalContext, EntityFramework");
    var cmField = type.GetField("CachedModels",System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic);
    var cachedModels = cmField.GetValue(null);
    cachedModels.GetType().InvokeMember("Clear", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.InvokeMethod, null, cachedModels, null);
}
于 2012-04-06T18:10:54.723 に答える