【问题标题】:Using the same dbcontext for different models对不同模型使用相同的 dbcontext
【发布时间】:2012-04-07 02:10:54
【问题描述】:

我有一个空的 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) 所需的附加字段。

【问题讨论】:

    标签: entity-framework code-first


    【解决方案1】:

    我的 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);
    }
    

    【讨论】:

    • 请注意缓存的存在是有原因的。构建模型可能会很昂贵,如果每次使用上下文时都完成,那么您的应用程序可能会出现性能问题。更好的方法是直接使用 DbModelBuilder 来创建 DbCompiledModels,然后您可以根据需要对其进行缓存。 DbContext 具有接受 DbCompiledModel 的构造函数。
    猜你喜欢
    • 2015-07-30
    • 1970-01-01
    • 2017-10-15
    • 2020-09-09
    • 2020-01-08
    • 2014-09-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多