Ответ 1
Может быть, старый EF4 Docu еще в EF6. см. modelBuilder.CacheForContextType недоступен
См. также конструктор DbContext для передачи в модели DbContext Constructor
Я не пробовал, но теоретически вы можете проходить в модели каждый раз.
Следуя документации MSDN, мы можем прочитать:
Модель для этого контекста затем кэшируется и предназначена для всех остальных экземпляров контекста в домене приложения. Это кэширование можно отключить, установив свойство ModelCaching на данный ModelBuidler, но обратите внимание, что это может серьезно ухудшить производительность.
Проблема заключается в том, что модельный конструктор не содержит никакого свойства с именем ModelCaching.
Как можно отключить кэширование модели (например, для изменения конфигурации модели во время выполнения)?
Может быть, старый EF4 Docu еще в EF6. см. modelBuilder.CacheForContextType недоступен
См. также конструктор DbContext для передачи в модели DbContext Constructor
Я не пробовал, но теоретически вы можете проходить в модели каждый раз.
Предупреждение о переходе: само собой разумеется, что приведенный ниже механизм будет охватывать ваши потребности, если вам не нужно выполнять объединения между таблицами, которые поступают из разных контекстов. Если вам нужны такие операции, вам придется дополнительно уточнить механизм, показанный ниже, с помощью небольшого API, чтобы вы могли динамически связывать указанные таблицы с некоторой строкой или номером (чтобы вы могли динамически получать и комбинировать свои соответствующие DBS файлы во время выполнения), Выполнение такого рода -больше общего - немного сложное и выходит за рамки этого ответа.
Здесь полномасштабная реализация механизма, выдвинутого байрогом, - все это относится к нему. Обратите внимание, что мы получаем подключение к базе данных через новый DbContext по причинам, объясняемым в комментариях:
using System;
using System.Collections.Concurrent;
using System.ComponentModel.DataAnnotations;
using System.Data.Common;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Data.Entity.ModelConfiguration;
namespace Utilities
{
// usage:
//
// var context1 = new FooContext("Schema1", "PingTable1", "PongTable1");
// context1.Ping.Select(x => x.Id > 10).ToList();
// context1.Pong.Select(x => x.Id > 20).ToList();
public class FooContext : DbContext
{
public DbSet<Ping> Ping { get; set; }
public DbSet<Pong> Pong { get; set; }
static public FooContext Spawn(string nameOrConnectionString, string pingTablename, string pongTablename, string schemaName = null) //minifactory
{
//if (string.IsNullOrWhiteSpace(schemaName?.Trim())) throw new ArgumentException(nameof(schemaName)); //canbe
if (string.IsNullOrWhiteSpace(pingTablename?.Trim())) throw new ArgumentException(nameof(pingTablename));
if (string.IsNullOrWhiteSpace(pongTablename?.Trim())) throw new ArgumentException(nameof(pongTablename));
var dummyDbContext = new DbContext(nameOrConnectionString); //0 stupidhack for retrieving the connection
return new FooContext(dummyDbContext, GetModelBuilderAndCacheIt(dummyDbContext.Database.Connection, pingTablename, pongTablename, schemaName));
}
//0 stupidhack over EntityConnection("name=NameOfConnectionStringFromWebConfig") which wasnt working because it demands metadata on the
// codefirst connection to an oracle db (at least oracledb ver11 - go figure ...)
//
// update: I finally had success using the *managed* driver oracle.manageddataaccess with oracle-odac ver12+ one may now use:
//
// var connectionString = ConfigurationManager.ConnectionStrings[nameOrConnectionString];
// if (connectionString == null) return null;
//
// var factory = DbProviderFactories.GetFactory(connectionString.ProviderName);
// var connection = factory.CreateConnection();
// connection.ConnectionString = connectionString.ConnectionString; //vital
//
// new FooContext(dummyDbContext, GetModelBuilderAndCacheIt(connection, pingTablename, pongTablename, schemaName));
private static readonly object DbCompiledModelRegistrarLocker = new object(); // ReSharper disable InconsistentlySynchronizedField
private static readonly ConcurrentDictionary<Tuple<string, string, string>, DbCompiledModel> DbModelBuilderCache = new ConcurrentDictionary<Tuple<string, string, string>, DbCompiledModel>();
static private DbCompiledModel GetModelBuilderAndCacheIt(DbConnection databaseConnection, string pingTablename, string pongTablename, string schemaName) //0
{
var key = Tuple.Create(pingTablename, pongTablename, schemaName);
if (DbModelBuilderCache.ContainsKey(key))
return DbModelBuilderCache[key];
lock (DbCompiledModelRegistrarLocker)
{
if (DbModelBuilderCache.ContainsKey(key))
return DbModelBuilderCache[key];
var modelBuilder = new DbModelBuilder();
modelBuilder.Configurations.Add(new PingFluentConfiguration(schemaName, pingTablename));
modelBuilder.Configurations.Add(new PongFluentConfiguration(schemaName, pongTablename));
//setting a maxsize for the cache so that least used dbmodels get flushed away is left as an exercise to the reader
return DbModelBuilderCache[key] = modelBuilder.Build(databaseConnection).Compile();
}
}
//0 building the same model over and over is very expensive operation and this is why we resorted to caching the modelbuilders
// ReSharper restore InconsistentlySynchronizedField
private DbContext _dummyDbContext;
private FooContext(DbContext dummyDbContext, DbCompiledModel compiledModel)
: base(dummyDbContext.Database.Connection, compiledModel, contextOwnsConnection: true)
{
_dummyDbContext = dummyDbContext;
Database.SetInitializer<FooContext>(strategy: null); //0
}
//0 http://stackoverflow.com/a/39710954/863651 ef by default attempts to create the database if it doesnt exist
// however in this case we want ef to just do nothing if the underlying database doesnt exist
//protected override void OnModelCreating(DbModelBuilder modelBuilder) //0 here be dragons beware that this approach wont work as intended down the road
//{
// modelBuilder.Configurations.Add(new PingFluentConfiguration(_schemaName, _tablename)); //0 here be dragons beware that this approach wont work as intended down the road
// base.OnModelCreating(modelBuilder);
//}
protected override void Dispose(bool disposing)
{
if (disposing)
{
_dummyDbContext?.Dispose();
_dummyDbContext = null;
}
base.Dispose(disposing);
}
}
public sealed class PingFluentConfiguration : EntityTypeConfiguration<Ping>
{
public PingFluentConfiguration(string schemaName, string tableName)
{
HasKey(t => t.Id);
ToTable(schemaName: schemaName, tableName: tableName);
}
}
public sealed class PongFluentConfiguration : EntityTypeConfiguration<Pong>
{
public PongFluentConfiguration(string schemaName, string tableName)
{
HasKey(t => t.Id);
ToTable(schemaName: schemaName, tableName: tableName);
}
}
public class Ping
{
[Key]
[Required]
public string Id { get; set; }
[Required]
public string Name { get; set; }
}
public class Pong
{
[Key]
[Required]
public string Id { get; set; }
[Required]
public string Name { get; set; }
}
}
Здесь похож вопрос
Единственный доступный подход исходит от диспетчера программ команды Entity Framework (Rowan Miller (MSFT)):
Мы удалили CacheForContextType в CTP5, мы изначально предполагали, что он будет использоваться, когда люди захотят использовать один и тот же контекст в том же AppDomain с разными моделями. Проблема в том, что он создавал бы модель при каждой инициализации и не позволял бы каким-либо образом кэшировать ряд моделей и выбирать, какой из них использовать при каждой инициализации. Создание модели дорого, поэтому мы хотели продвинуть лучшую модель.
Мы рекомендуем использовать внешний конструктор ModelBuilder → DbDatabaseMapping → DbModel для каждой модели, которую вы хотите использовать. DbModel следует кэшировать и использовать для создания экземпляров контекста. ModelBuilder → Рабочий процесс DbModel немного запутан и имена классов невелики, они будут убраны для RTM.
Я пробовал следующий подход:
В результате я смог изменить параметры DbCompiledModel каждый раз, когда я вызываю конструктор DbContext. Это все, что мне нужно.
У меня такая же проблема: один контекст db, 2 или более разные модели db (только по именам таблиц)
Мое решение для EF6: все еще можно использовать внутреннее кэширование структуры Entity Framework модели db, но сделать дифференциацию между DbModel (s) в одном и том же DbContext, реализовав IDbModelCacheKeyProvider Interface в производном DbContext.
MSDN doc находится здесь: https://msdn.microsoft.com/en-us/library/system.data.entity.infrastructure.idbmodelcachekeyprovider(v=vs.113).aspx И он говорит:
Внедрите этот интерфейс в свой контекст, чтобы использовать пользовательскую логику для вычисления ключа, используемого для поиска уже созданной модели в кеше. Этот интерфейс позволяет вам иметь один тип контекста, который может использоваться с разными моделями в одном и том же приложении AppDomain или с несколькими типами контекстов, которые используют одну и ту же модель.
Надеюсь, что это поможет кому-то.