Я работаю с. NET Core 3.1 и EntityFramework Core 3.1.3. Я пытаюсь реализовать разделение данных клиента с помощью схем БД. Я прочитал это . Я знаю, что он немного устарел, поэтому я скорректировал.
Я создал реализацию DbContext:
public class AppDataContext : DbContext
{
private readonly ITenantProvider _tenantProvider;
public AppDataContext(DbContextOptions<AppDataContext> options, ITenantProvider tenantProvider) : base(options)
{
_tenantProvider = tenantProvider;
}
public DbSet<Book> Books { get; set; }
public DbSet<Comics> Comics { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
// Tenant schema mapping
var tenant = _tenantProvider.GetTenantString();
modelBuilder.HasDefaultSchema(tenant);
}
public static void ApplyMigrations(string connectionString, string tenant)
{
var optionsBuilder = new DbContextOptionsBuilder<AppDataContext>();
optionsBuilder.UseSqlServer(connectionString, x => x.MigrationsHistoryTable("__EFMigrationsHistory", tenant));
var ctx = new AppDataContext(optionsBuilder.Options, StaticTenantProvider.WithTenant(tenant));
ctx.Database.Migrate();
}
}
ITenantProvider - это зарегистрированная служба с ограниченной областью действия в. NET Core DI. Этот AppDataContext зарегистрирован следующим образом:
services.AddDbContext<AppDataContext>((ctx, opt) =>
{
opt.UseSqlServer(Configuration["SqlConnectionString"]);
});
Теперь моя идея заключалась бы в том, что в любое время, когда я хочу предоставить другого клиента, я бы сделал такой вызов (экземпляр базы данных уже существует и может иметь несколько таблиц / схем уже):
var connString = GetConnString(); // Where does connection string and tenant name come from is not important
var tenantName = GetTenantName();
AppDataContext.ApplyMigrations(connString, tenantName);
И после этого у меня будет новая уникальная схема БД со всеми таблицами, настроенными для клиента.
К сожалению, это не работает. Таблицы все еще создаются для схемы «dbo» по умолчанию (я использую SqlServer).
Я начал искать inte rnet, сначала я нашел это . Для меня это выглядело немного странно, но все равно попробовал:
public static void ApplyMigrations(string connectionString, string tenant)
{
var optionsBuilder = new DbContextOptionsBuilder<AppDataContext>();
optionsBuilder.UseSqlServer(connectionString);
var ctx = new AppDataContext(optionsBuilder.Options, StaticTenantProvider.WithTenant(tenant));
var command = $"IF (NOT EXISTS (SELECT * FROM sys.schemas WHERE name = N'{tenant}')) " +
"BEGIN" +
$" EXEC ('CREATE SCHEMA {tenant}');" +
"END";
ctx.Database.ExecuteSqlRaw(command);
ctx.Database.Migrate();
}
Не сработало. Я мог видеть, что схема была создана (с использованием SSMS), но таблицы по-прежнему находятся в «dbo».
Затем я подумал, что, возможно, у него проблемы с поиском таблицы истории миграции, поэтому я попробовал MigrationsHistoryTable следующим образом:
optionsBuilder.UseSqlServer(connectionString, x => x.MigrationsHistoryTable("__EFMigrationsHistory", tenant));
Но нет, таблица истории миграции была создана в новой схеме , но все остальные таблицы все еще были в "dbo".
Что мне не хватает? Или, может быть, невозможно использовать EF Migrations и разделение схемы одновременно?
Заранее спасибо.
EDIT : Чтобы прояснить ситуацию: I Я использую подход Code First. Для AppDataContext уже созданы миграции.