【问题标题】:Applying EF Core migrations per tenant schema按租户架构应用 EF Core 迁移
【发布时间】:2020-09-17 06:23:46
【问题描述】:

我正在使用 .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 生成了迁移。

【问题讨论】:

  • “小”问题是 EF Core 不支持自动迁移,这对于链接到的 EF 代码至关重要。在 EF Core 中,迁移是使用 Add-Migration 命令创建的,并嵌入(编译)在应用程序代码中。架构名称也嵌入在迁移中。 OnModelCreating` 仅影响运行时映射或下一个Add-Migration 命令,但不影响现有迁移。
  • 我确实知道如何创建迁移。我认为这在问题中得到了明确的理解。自动迁移是什么意思?架构名称如何嵌入到迁移中?那么 HasDefaultSchema() 或流利的表映射的目的是什么?
  • 我知道您必须阅读几篇文章才能实现这一目标。我发现了以下内容:stackoverflow.com/questions/19458943/… 你在帖子中添加的 romiller 文章让我很好奇,我会睁大眼睛。
  • 你能提供一些迁移代码的例子吗?

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


【解决方案1】:

您需要通过在配置的 IEntityTypeConfiguration.ToTable(...) 重载中提供架构来告诉 EF 将每个表放在哪里。

首先为实体定义一个配置:

public class SpecialSchemaEntityConfiguration : IEntityTypeConfiguration<SpecialSchemaEntity>
{
    private readonly string _schema;

    public SpecialSchemaEntityConfiguration(string schema) => this._schema = schema;

    public void Configure(EntityTypeBuilder<SpecialSchemaEntity> builder)
    {
        builder.ToTable("SpecialSchemaEntity", this._schema);
    }
}

然后,告诉 EF 在构建表时使用该配置:

public class AppDataContext : DbContext
{
    private readonly string _schema = "special_schema";

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
         modelBuilder.ApplyConfiguration(new SpecialSchemaEntityConfiguration(this._schema));
    }
}

【讨论】:

    猜你喜欢
    • 2021-11-23
    • 1970-01-01
    • 2022-11-11
    • 2019-02-25
    • 2013-12-23
    • 2017-11-30
    • 2018-10-02
    • 2021-03-21
    • 1970-01-01
    相关资源
    最近更新 更多