Mic*_*cki 7 c# sql-server entity-framework-core .net-core entity-framework-migrations
我正在使用 .NET Core 3.1 和 EntityFramework Core 3.1.3。我正在尝试使用 DB 模式实现租户数据分离。我读了这个。我知道它有点过时了,所以我已经调整了。
我已经创建了一个 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();
}
}
Run Code Online (Sandbox Code Playgroud)
ITenantProvider 是 .NET Core DI 中的注册范围服务。这个 AppDataContext 是这样注册的:
services.AddDbContext<AppDataContext>((ctx, opt) =>
{
opt.UseSqlServer(Configuration["SqlConnectionString"]);
});
Run Code Online (Sandbox Code Playgroud)
现在,我的想法是,无论何时我想配置另一个租户,我都会像这样进行调用(数据库实例已经存在并且可能已经有一些表/模式):
var connString = GetConnString(); // Where does connection string and tenant name come from is not important
var tenantName = GetTenantName();
AppDataContext.ApplyMigrations(connString, tenantName);
Run Code Online (Sandbox Code Playgroud)
在此之后,我将拥有一个新的唯一数据库模式,其中所有表都为租户设置。
不幸的是,它不起作用。仍在为默认的“dbo”架构创建表(我使用的是 SqlServer)。
我开始在互联网上四处寻找,首先我找到了这个。对我来说看起来有点奇怪,但还是尝试了:
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();
}
Run Code Online (Sandbox Code Playgroud)
没用。我可以看到模式已创建(使用 SSMS),但表仍位于“dbo”中。
然后我想,可能是定位迁移历史表有问题,所以我尝试了这样的 MigrationsHistoryTable:
optionsBuilder.UseSqlServer(connectionString, x => x.MigrationsHistoryTable("__EFMigrationsHistory", tenant));
Run Code Online (Sandbox Code Playgroud)
但是不,迁移历史表确实是在新模式中创建的,但所有其他表仍然在“dbo”中。
我错过了什么?或者可能无法同时使用 EF 迁移和架构分离?
提前致谢。
编辑:为了清楚起见:我正在使用代码优先方法。已经为 AppDataContext 生成了迁移。
您需要通过在配置的 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);
}
}
Run Code Online (Sandbox Code Playgroud)
然后,告诉 EF 在构建表时使用该配置:
public class AppDataContext : DbContext
{
private readonly string _schema = "special_schema";
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.ApplyConfiguration(new SpecialSchemaEntityConfiguration(this._schema));
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
795 次 |
| 最近记录: |