0

我有一个空的 DbContext。映射是动态创建的,通常使用 Set() 使用 DbContext;

以下是我的通用 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 字段的同一对象。

我的问题是,当我 new() 第二次启动 MethodObjectContext 并进行查询时,未调用 ModelCreating 方法,导致出现以下错误。

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

Product2 将是正在调用的 ModelCreating 事件的上下文的一部分,但事实并非如此。有任何想法吗?

注意:我预计会出现错误,因为我们使用的是相同的连接字符串 (sdf),并且正在创建的数据库没有创建我的第二次调用 (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 回答