2012-04-06 5 views
0

У меня есть DbContext, который пуст. Сопоставления создаются динамически и 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 является объектом ПОК, и мой класс Product2 тот же объект с дополнительным дб полем.

Моя проблема заключается в том, что когда я new() вверх по MethodObjectContext второй раз и выполняю запрос, метод ModelCreating не вызывается, из-за чего я получаю следующую ошибку.

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

Продукт2 был бы частью контекста события ModelCreating, но это не так. Есть идеи?

ПРИМЕЧАНИЕ: Я ожидаю ошибок, так как мы используем одну и ту же строку соединения (sdf), и созданная db не создала дополнительное поле, которое требует мой второй вызов (Product2).

ответ

0

My 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); 
} 
+3

Помните, что кэширование существует по какой-либо причине. Построение модели может быть дорогостоящим, и если это делается каждый раз, когда используется контекст, тогда могут возникнуть проблемы с вашим приложением. Лучшим подходом было бы использовать DbModelBuilder непосредственно для создания DbCompiledModels, который вы затем можете кэшировать по мере необходимости. У DbContext есть конструкторы, которые принимают DbCompiledModel. –