Я верю, что вы можете получить то, что хотите, кэшируя MetadataWorkspace самостоятельно.По сути, это то, что DbContext делает внутренне при использовании Code First.Это не так просто сделать, но я разработал быстрый прототип, который, по моему мнению, должен работать.
Основная идея здесь - позволить EF создать MetadataWorkspace один раз, а затем кэшировать его и использовать его явно каждый раз, когда вам нужносоздать экземпляр контекста.Это, очевидно, допустимо только в том случае, если каждый экземпляр контекста использует одну и ту же модель - т.е. один и тот же EDMX.Чтобы сделать эту работу, я создал производный ObjectContext, который обрабатывает кэширование:
public class SingleModelCachingObjectContext : ObjectContext
{
private static readonly object WorkspaceLock = new object();
private static MetadataWorkspace _workspace;
public SingleModelCachingObjectContext(string connectionStringName)
: base(CreateEntityConnection(connectionStringName))
{
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
((EntityConnection)Connection).StoreConnection.Dispose();
}
}
private static EntityConnection CreateEntityConnection(string connectionStringName)
{
lock (WorkspaceLock)
{
if (_workspace == null)
{
_workspace = new EntityConnection("name=" + connectionStringName).GetMetadataWorkspace();
}
}
var builder =
new DbConnectionStringBuilder
{
ConnectionString = ConfigurationManager.ConnectionStrings[connectionStringName].ConnectionString
};
var storeConnection = DbProviderFactories.GetFactory((string)builder["provider"]).CreateConnection();
storeConnection.ConnectionString = (string)builder["provider connection string"];
return new EntityConnection(_workspace, storeConnection);
}
}
Затем вы могли бы использовать это, создав конструктор в вашем классе DbContext следующим образом:
public MyDbContext(string connectionStringName)
: base(new SingleModelCachingObjectContext(connectionStringName),
dbContextOwnsObjectContext: true)
{
}
Этокак это устроено.Когда вы создаете экземпляр вашего DbContext, он, в свою очередь, создает экземпляр SingleModelCachingObjectContext, передавая имя строки подключения EF, которую вы хотите использовать.Он также говорит DbContext, что нужно избавиться от этого ObjectContext при удалении DbContext.
В SingleModelCachingObjectContext строка подключения EF используется для создания пространства MetadataWorkspace и кэширует его в статическом поле после его создания.Это очень простое кэширование и простая защита потоков с блокировкой - не стесняйтесь, чтобы сделать ее более подходящей для ваших приложений.
Получив MetadataWorkspace, строка соединения EF теперь анализируется для получения строки соединения хранилищаи провайдер.Затем это используется для создания обычного соединения с хранилищем.
Соединение хранилища и кэшированное MetadataWorkspace используются для создания EntityConnection, а затем ObjectContext, который будет использовать кэшированное MetadataWorkspace вместо использования обычных механизмов кэширования.
Этот ObjectContext используется для поддержки DbContext.Метод Dispose переопределяется, поэтому соединение с хранилищем не протекает.Когда DbContext удаляется, он удаляет ObjectContext, который, в свою очередь, вызывает Dispose, и соединение с хранилищем будет удалено.
Я действительно не проверял это, кроме как чтобы убедиться, что он работает.Было бы очень интересно узнать, действительно ли это помогает при использовании памяти.