Entity framework core 在.NET Core 3.x中使用Autofac.AspNetCore.Multitenant时,如何在启动时执行数据库迁移?

Entity framework core 在.NET Core 3.x中使用Autofac.AspNetCore.Multitenant时,如何在启动时执行数据库迁移?,entity-framework-core,autofac,database-migration,multi-tenant,asp.net-core-3.0,Entity Framework Core,Autofac,Database Migration,Multi Tenant,Asp.net Core 3.0,在单租户.NET Core应用程序中,EF Core数据库迁移(和数据库种子设定)可以在IHost构建后立即执行(通常在Program.cs中): 等待构建主机(args) .MigrateDbContext() .RunAsync(); } 因为到目前为止,唯一的数据库上下文已经注册 在多租户应用程序中,HTTPContext可用后,multitenantContainer.ConfigureTenant(…)回调中的 问题是,在执行此回调之后,似乎没有位置可以检索特定于租户的上下文以调用迁

在单租户.NET Core应用程序中,EF Core数据库迁移(和数据库种子设定)可以在IHost构建后立即执行(通常在Program.cs中):

等待构建主机(args)
.MigrateDbContext()
.RunAsync();
}
因为到目前为止,唯一的数据库上下文已经注册

在多租户应用程序中,HTTPContext可用后,multitenantContainer.ConfigureTenant(…)回调中的

问题是,在执行此回调之后,似乎没有位置可以检索特定于租户的上下文以调用迁移

我确信在
multitenantContainer.ConfigureTenant(…)
回调结束时执行此操作是错误的,因为它的功能似乎纯粹是组件注册


迁移应该从何处执行?

您可以在每个租户内注册一个
IStartable
组件来启动迁移过程

public class AutomigrateDatabase : IStartable
{
   public void AutomigrateDatabase(XContext xContext)
   {
       this._xContext = xContext; 
   }

   private readonly XContext _xContext; 

   public void Start()
   {
      this._xContext.Database.Migrate(); 
   }
}
并按如下方式注册:

mtc.ConfigureTenant('1', b => {
    b.RegisterType<AutomigrateDatabase>().As<IStartable>().SingleInstance();
});
mtc.ConfigureTenant('1',b=>{

b、 RegisterType

我使用Aufofac的
OnActivated()
实现了这一点

Startup.cs
中:

public static MultitenantContainer ConfigureMultitenantContainer(IContainer container)
{
    // retrieve tenant settings
    CONFIG.Tenancy tenancyConfig = null;
    var tenancyOptions = container.Resolve<IOptions<CONFIG.Tenancy>>();
    if (tenancyOptions != null)
        tenancyConfig = tenancyOptions.Value;

    // create multitenant container
    var accessor = container.Resolve<IHttpContextAccessor>();
    var tenantIdentificationStrategy = new HELP.RequestHeaderTenantIdentificationStrategy(accessor, tenancyOptions, container);
    var multitenantContainer = new MultitenantContainer(tenantIdentificationStrategy, container);

    // configure tenant-specific dependencies here
    foreach (CONFIG.Tenant tenancy in tenancyConfig.Tenant)
    {
        multitenantContainer.ConfigureTenant(tenancy.Token, containerBuilder =>
        {
            containerBuilder
                .Register(componentContext =>
                {
                    var serviceProvider = componentContext.Resolve<IServiceProvider>();
                    var dbContextOptions = new DbContextOptions<I.ProjectsContext>(new Dictionary<Type, IDbContextOptionsExtension>());

                    var optionsBuilder = new DbContextOptionsBuilder<I.ProjectsContext>(dbContextOptions)
                        .EnableSensitiveDataLogging()
                        .EnableDetailedErrors()
                        .UseApplicationServiceProvider(serviceProvider)
                        .UseMySql(
                            tenancy.DBConnection.Projects,
                            serverOptions => serverOptions.EnableRetryOnFailure(
                                maxRetryCount: 5,
                                maxRetryDelay: TimeSpan.FromSeconds(30),
                                errorNumbersToAdd: null));

                    return optionsBuilder.Options;
                })
                .As<DbContextOptions<I.ProjectsContext>>()
                .InstancePerDependency();

            containerBuilder.Register(componentContext => componentContext.Resolve<DbContextOptions<I.ProjectsContext>>())
                .As<DbContextOptions>()
                .InstancePerDependency();

            containerBuilder.RegisterType<I.ProjectsContext>()
                .AsSelf()
                .InstancePerDependency()
                .OnActivated(sr =>
                    // migrate database after the component is activated
                    sr.Instance.Database.MigrateAsync());
        });
    }

    return multitenantContainer;
}
公共静态多租户容器配置多租户容器(IContainer容器)
{
//检索租户设置
CONFIG.Tenancy-CONFIG=null;
var tenacyoptions=container.Resolve();
if(租户选项!=null)
tenacyconfig=tenacycoptions.Value;
//创建多租户容器
var accessor=container.Resolve();
var tenantIdentificationStrategy=new HELP.RequestHeaderTenantIdentificationStrategy(访问者、租户选项、容器);
var multitenantContainer=新的multitenantContainer(租户身份识别策略,容器);
//在此处配置特定于租户的依赖项
foreach(tenacyconfig.Tenant中的CONFIG.Tenant租约)
{
multitenantContainer.ConfigureTenant(tenancy.Token,containerBuilder=>
{
集装箱船
.Register(组件上下文=>
{
var serviceProvider=componentContext.Resolve();
var dbContextOptions=newdbcontextoptions(newdictionary());
var optionsBuilder=new DbContextOptionsBuilder(dbContextOptions)
.EnableSensitiveDataLogging()
.EnableDetailedErrors()
.UseApplicationServiceProvider(服务提供者)
.UseMySql(
tenancy.DBConnection.Projects,
serverOptions=>serverOptions.EnableRetryOnFailure(
最大计数:5,
maxRetryDelay:TimeSpan.FromSeconds(30),
errorNumbersToAdd:null));
返回选项生成器。选项;
})
.As()
.InstancePerDependence();
containerBuilder.Register(componentContext=>componentContext.Resolve())
.As()
.InstancePerDependence();
containerBuilder.RegisterType()
.AsSelf()
.InstancePerDependency()实例
.on已激活(sr=>
//在激活组件后迁移数据库
sr.Instance.Database.MigrateAsync());
});
}
返回多租户容器;
}

这是实体框架吗?DbUp?可以添加一些标签来帮助合适的人看到这一点。它是EF Core。很好-编辑并交换了一个标签(已经使用了最多五个!)Hi Cyril,不幸的是,自从
开始()
IStartable
的方法在容器构建后会被调用,但是
ConfigureTenant()
直到稍后才会被调用。为了澄清这一点,在
ConfigureTenant()
内部设置的每个租户回调直到稍后才会被调用。
public static MultitenantContainer ConfigureMultitenantContainer(IContainer container)
{
    // retrieve tenant settings
    CONFIG.Tenancy tenancyConfig = null;
    var tenancyOptions = container.Resolve<IOptions<CONFIG.Tenancy>>();
    if (tenancyOptions != null)
        tenancyConfig = tenancyOptions.Value;

    // create multitenant container
    var accessor = container.Resolve<IHttpContextAccessor>();
    var tenantIdentificationStrategy = new HELP.RequestHeaderTenantIdentificationStrategy(accessor, tenancyOptions, container);
    var multitenantContainer = new MultitenantContainer(tenantIdentificationStrategy, container);

    // configure tenant-specific dependencies here
    foreach (CONFIG.Tenant tenancy in tenancyConfig.Tenant)
    {
        multitenantContainer.ConfigureTenant(tenancy.Token, containerBuilder =>
        {
            containerBuilder
                .Register(componentContext =>
                {
                    var serviceProvider = componentContext.Resolve<IServiceProvider>();
                    var dbContextOptions = new DbContextOptions<I.ProjectsContext>(new Dictionary<Type, IDbContextOptionsExtension>());

                    var optionsBuilder = new DbContextOptionsBuilder<I.ProjectsContext>(dbContextOptions)
                        .EnableSensitiveDataLogging()
                        .EnableDetailedErrors()
                        .UseApplicationServiceProvider(serviceProvider)
                        .UseMySql(
                            tenancy.DBConnection.Projects,
                            serverOptions => serverOptions.EnableRetryOnFailure(
                                maxRetryCount: 5,
                                maxRetryDelay: TimeSpan.FromSeconds(30),
                                errorNumbersToAdd: null));

                    return optionsBuilder.Options;
                })
                .As<DbContextOptions<I.ProjectsContext>>()
                .InstancePerDependency();

            containerBuilder.Register(componentContext => componentContext.Resolve<DbContextOptions<I.ProjectsContext>>())
                .As<DbContextOptions>()
                .InstancePerDependency();

            containerBuilder.RegisterType<I.ProjectsContext>()
                .AsSelf()
                .InstancePerDependency()
                .OnActivated(sr =>
                    // migrate database after the component is activated
                    sr.Instance.Database.MigrateAsync());
        });
    }

    return multitenantContainer;
}