Применение миграции EF Core для схемы клиента - PullRequest
8 голосов
/ 29 мая 2020

Я работаю с. 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 уже созданы миграции.

...