Решение было дано в комментарии Бу Ивана Стоева и работает.
Невозможно отключить это без использования отражения, если для свойства InternalContext.InitializerDisabled установить значение true, пропустить словарь .
Итак:
- Использовать конструктор DbContext, который предоставляет DbCachedModel
- Использовать Database.SetInitializer (null);
- Установить InternalContext.InitializerDisabled = true с использованием отражения
Код из примера, который я использовал для проверки этого, в качестве тестовой установки у меня была 1 основная таблица с разделами 30k, сами разделы запрашиваются, потому что postgres (особенно 9.x ) плохо масштабируется при большом количестве разделов:
public class PartContext : DbContext {
private static readonly string _ConnectionString = new NpgsqlConnectionStringBuilder {
Host = "localhost",
Port = 5432,
Database = "postgres",
Username = "postgres",
Password = "password"
}.ConnectionString;
public readonly string Table;
public readonly string Partition;
public PartContext(string pMainTable, string pPartition) : base(
new NpgsqlConnection() { ConnectionString = _ConnectionString },
PartDbModelBuilder.Get(_ConnectionString, pPartition),
true
) {
Table = pMainTable;
Partition = pPartition;
Database.SetInitializer<PartContext>(null);
/**
* Disable database initialization so that the DbCachedModels are not kept internally in Entity
* This causes high memory usage when having a lot of tables
* In EF 6.4.2 there was no way to 'manage' that Dictionary externally
*/
try {
var InternalContext = typeof(PartContext).BaseType.GetProperty("InternalContext", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(this, null);
InternalContext.GetType().GetProperty("InitializerDisabled").SetValue(InternalContext, true);
} catch(Exception) { }
}
public DbSet<MyPart> Parts { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder) {
modelBuilder.HasDefaultSchema("public");
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
}
}
Это обеспечивает DbCachedModels:
Я рекомендую добавить некоторый пользовательский код кэширования и т. д. c, это только из примера
class PartDbModelBuilder {
public static DbCompiledModel Get(string pConnectionString, string pTable) {
DbModelBuilder builder = new DbModelBuilder();
builder.Entity<MyPart>().ToTable(pTable, "public");
using (var connection = new NpgsqlConnection() { ConnectionString = pConnectionString }) {
var obj = builder.Build(connection).Compile();
return obj;
}
}
}
Это объект, который я использовал в качестве теста:
public class MyPart {
public int id { get; set; }
public string name { get; set; }
public string value { get; set; }
}
Класс I, использованный для запуска теста:
class EFTest {
public void Run(int tableCount) {
int done = 0;
Parallel.For(0, tableCount, new ParallelOptions { MaxDegreeOfParallelism = 5 }, (i) => {
string id = i.ToString().PadLeft(5, '0');
using (var context = new PartContext("mypart", "mypart_" + id)) {
var objResult = context.Parts.First();
Console.WriteLine(objResult.name);
}
done++;
Console.WriteLine(done + " DONE");
});
}
}
Определение таблицы:
CREATE TABLE IF NOT EXISTS mypart (
id SERIAL,
name text,
value text
) partition by list (name);
CREATE TABLE IF NOT EXISTS part partition of mypart_00000 for values in ('mypart00000');
CREATE TABLE IF NOT EXISTS part partition of mypart_00001 for values in ('mypart00001');
CREATE TABLE IF NOT EXISTS part partition of mypart_00002 for values in ('mypart00002');
...
* 1 031 *Postgres 9:
CREATE TABLE IF NOT EXISTS mypart (
id SERIAL,
name text,
value text
);
CREATE TABLE IF NOT EXISTS ".$name."( CHECK ( name = 'mypart00000')) INHERITS (mypart);
CREATE TABLE IF NOT EXISTS ".$name."( CHECK ( name = 'mypart00001')) INHERITS (mypart);
CREATE TABLE IF NOT EXISTS ".$name."( CHECK ( name = 'mypart00002')) INHERITS (mypart);
...