为每个租户架构应用EF Core迁移

时间:2020-05-29 16:02:09

标签: c# sql-server .net-core entity-framework-core entity-framework-migrations

我正在使用.NET Core 3.1和EntityFramework Core 3.1.3。 我正在尝试使用数据库模式来实现租户数据分离。我已经读过this。我知道它有些过时了,所以我已经调整了。

我创建了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)。

我已经开始环顾互联网,首先发现了this。对我来说有点奇怪,但还是尝试了:

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迁移和架构分离?

谢谢。

编辑:要弄清楚:我正在使用“代码优先”方法。已经为AppDataContext生成了迁移。

0 个答案:

没有答案
相关问题