Я работаю с продуктом SaaS, который имеет довольно большую базу пользователей.До сих пор наш подход к изоляции данных о клиентах заключался в том, чтобы иметь конкретные клиентские базы данных.Это отлично работает с Entity Framework 6, так как все, что нам нужно сделать, это передать специфическую для клиента строку соединения в DbContext
, и все работает отлично.
По причинам, не имеющим отношения к этому вопросу, мы должны отойти от этогоодна база данных для модели клиента.С точки зрения изоляции данных было бы неплохо иметь одну схему базы данных для каждого клиента вместо одной базы данных для каждого клиента.После выполнения некоторых тестов кажется, что это довольно непригодно, когда мы говорим о большом количестве различных схем.
Вот упрощенный пример того, как мы в настоящее время используем DbContext
:
public class CustomDbContext : DbContext
public CustomDbContext(IConnectionStringProvider provider)
: base(provider.ConnectionString)
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new SomeEntityMap());
modelBuilder.Configurations.Add(new SomeOtherEntityMap());
}
}
И вот пример того, как мы думали, что это может работать:
public class CustomDbContext : DbContext, IDbModelCacheKeyProvider
public CustomDbContext(IConnectionStringProvider provider)
: base(provider.ConnectionString)
{
CacheKey = provider.Schema;
}
public string CacheKey { get; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.HasDefaultSchema(CacheKey);
modelBuilder.Configurations.Add(new SomeEntityMap());
modelBuilder.Configurations.Add(new SomeOtherEntityMap());
}
}
Microsoft была достаточно любезна, чтобы разрешить обход кэширования по умолчанию для модели базы данных.Использование имени схемы в качестве ключа кэша вынуждает Entity Framework создавать новую модель для каждой схемы.В теории это работает.На практике не очень.Я создал тестовое приложение, которое отправляет запросы в службу, которая вызывает создание экземпляра DbContext
.Он рандомизирует CacheKey
из группы из 5000 ключей, поэтому в основном при первом запуске приложения почти каждый запрос вызывает OnModelCreating()
.После нескольких сотен запросов процесс IIS Worker сожрал всю доступную память (использовал около 9 ГБ), загрузка ЦП была близка к 100%, а служба практически остановилась.
Я посмотрел на источник Entity Frameworkкодирует и надеется, что использование пустой строки со строителем модели HasDefaultSchema()
заставит EF использовать схему по умолчанию для пользователя базы данных.Затем мы могли бы кэшировать только одну модель и иметь схему, «определенную в строке подключения», установив схему по умолчанию для учетных данных каждого клиента в базе данных.Однако EF выдает исключение, если схема представляет собой пустую строку.
Таким образом, вопрос в том, сталкивался ли кто-нибудь с такой же проблемой, и если да, то как вы ее решили?Если решение состоит в том, чтобы просто разветвить Entity Framework, я был бы признателен за понимание того, насколько обширными являются требуемые изменения.