diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/AddModuleCommand.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/AddModuleCommand.cs index 8129435266..a2c47af69b 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/AddModuleCommand.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/AddModuleCommand.cs @@ -59,7 +59,6 @@ namespace Volo.Abp.Cli.Commands await SolutionModuleAdder.AddAsync( solutionFile, commandLineArgs.Target, - commandLineArgs.Options.GetOrNull(Options.StartupProject.Short, Options.StartupProject.Long), version, skipDbMigrations, withSourceCode, @@ -167,12 +166,6 @@ namespace Volo.Abp.Cli.Commands public const string Skip = "skip-db-migrations"; } - public static class StartupProject - { - public const string Short = "sp"; - public const string Long = "startup-project"; - } - public static class SourceCode { public const string Long = "with-source-code"; diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/CreateMigrationAndRunMigratorCommand.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/CreateMigrationAndRunMigratorCommand.cs index 68fae779ce..2a3c4652af 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/CreateMigrationAndRunMigratorCommand.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/CreateMigrationAndRunMigratorCommand.cs @@ -26,7 +26,9 @@ namespace Volo.Abp.Cli.Commands throw new CliUsageException("DbMigrations folder path is missing!"); } - var dbMigratorProjectPath = GetDbMigratorProjectPath(commandLineArgs.Target); + var dbMigrationsFolder = commandLineArgs.Target; + + var dbMigratorProjectPath = GetDbMigratorProjectPath(dbMigrationsFolder); if (dbMigratorProjectPath == null) { throw new Exception("DbMigrator is not found!"); @@ -37,13 +39,17 @@ namespace Volo.Abp.Cli.Commands InstallDotnetEfTool(); } - var addMigrationCmd = $"cd \"{commandLineArgs.Target}\" && " + - $"dotnet ef migrations add Initial -s \"{dbMigratorProjectPath}\""; + var tenantDbContextName = FindTenantDbContextName(dbMigrationsFolder); + var dbContextName = tenantDbContextName != null ? + FindDbContextName(dbMigrationsFolder) + : null; + + var migrationOutput = AddMigrationAndGetOutput(dbMigrationsFolder, dbContextName, "Migrations"); + var tenantMigrationOutput = tenantDbContextName != null ? + AddMigrationAndGetOutput(dbMigrationsFolder, tenantDbContextName, "TenantMigrations") + : null; - var output = CmdHelper.RunCmdAndGetOutput(addMigrationCmd); - if (output.Contains("Done.") && - output.Contains("To undo this action") && - output.Contains("ef migrations remove")) + if (CheckMigrationOutput(migrationOutput) && CheckMigrationOutput(tenantMigrationOutput)) { // Migration added successfully CmdHelper.RunCmd("cd \"" + Path.GetDirectoryName(dbMigratorProjectPath) + "\" && dotnet run"); @@ -51,22 +57,70 @@ namespace Volo.Abp.Cli.Commands } else { - var exceptionMsg = "Migrations failed! The following command didn't run successfully:" + + var exceptionMsg = "Migrations failed! A migration command didn't run successfully:" + Environment.NewLine + - addMigrationCmd + - Environment.NewLine + output; + Environment.NewLine + migrationOutput + + Environment.NewLine + + Environment.NewLine + tenantMigrationOutput; Logger.LogError(exceptionMsg); throw new Exception(exceptionMsg); } } + private string FindTenantDbContextName(string dbMigrationsFolder) + { + var tenantDbContext = Directory + .GetFiles(dbMigrationsFolder, "*TenantMigrationsDbContext.cs", SearchOption.AllDirectories) + .FirstOrDefault(); + + if (tenantDbContext == null) + { + return null; + } + + return Path.GetFileName(tenantDbContext).RemovePostFix(".cs"); + } + + private string FindDbContextName(string dbMigrationsFolder) + { + var dbContext = Directory + .GetFiles(dbMigrationsFolder, "*MigrationsDbContext.cs", SearchOption.AllDirectories) + .FirstOrDefault(fp => !fp.EndsWith("TenantMigrationsDbContext.cs")); + + if (dbContext == null) + { + return null; + } + + return Path.GetFileName(dbContext).RemovePostFix(".cs"); + } + + private static string AddMigrationAndGetOutput(string dbMigrationsFolder, string dbContext, string outputDirectory) + { + var dbContextOption = string.IsNullOrWhiteSpace(dbContext) + ? string.Empty + : $"--context {dbContext}"; + + var addMigrationCmd = $"cd \"{dbMigrationsFolder}\" && " + + $"dotnet ef migrations add Initial --output-dir {outputDirectory} {dbContextOption}"; + + return CmdHelper.RunCmdAndGetOutput(addMigrationCmd); + } + private static bool IsDotNetEfToolInstalled() { var output = CmdHelper.RunCmdAndGetOutput("dotnet tool list -g"); return output.Contains("dotnet-ef"); } + private static bool CheckMigrationOutput(string output) + { + return output == null || (output.Contains("Done.") && + output.Contains("To undo this action") && + output.Contains("ef migrations remove")); + } + private void InstallDotnetEfTool() { Logger.LogInformation("Installing dotnet-ef tool..."); @@ -95,4 +149,4 @@ namespace Volo.Abp.Cli.Commands return string.Empty; } } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/DatabaseManagementSystemChangeStep.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/DatabaseManagementSystemChangeStep.cs index 4286710899..605cc842f5 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/DatabaseManagementSystemChangeStep.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/DatabaseManagementSystemChangeStep.cs @@ -54,7 +54,8 @@ namespace Volo.Abp.Cli.ProjectBuilding.Building.Steps private void AdjustOracleDbContextOptionsBuilder(ProjectBuildContext context) { - var dbContextFactoryFile = context.Files.First(f => f.Name.EndsWith("MigrationsDbContextFactory.cs", StringComparison.OrdinalIgnoreCase)); + var dbContextFactoryFile = context.Files.FirstOrDefault(f => f.Name.EndsWith("MigrationsDbContextFactoryBase.cs", StringComparison.OrdinalIgnoreCase)) + ?? context.Files.First(f => f.Name.EndsWith("MigrationsDbContextFactory.cs", StringComparison.OrdinalIgnoreCase)); dbContextFactoryFile.ReplaceText("new DbContextOptionsBuilder", $"(DbContextOptionsBuilder<{context.BuildArgs.SolutionName.ProjectName}MigrationsDbContext>) new DbContextOptionsBuilder"); @@ -62,7 +63,8 @@ namespace Volo.Abp.Cli.ProjectBuilding.Building.Steps private void AddMySqlServerVersion(ProjectBuildContext context) { - var dbContextFactoryFile = context.Files.First(f => f.Name.EndsWith("MigrationsDbContextFactory.cs", StringComparison.OrdinalIgnoreCase)); + var dbContextFactoryFile = context.Files.FirstOrDefault(f => f.Name.EndsWith("MigrationsDbContextFactoryBase.cs", StringComparison.OrdinalIgnoreCase)) + ?? context.Files.First(f => f.Name.EndsWith("MigrationsDbContextFactory.cs", StringComparison.OrdinalIgnoreCase)); dbContextFactoryFile.ReplaceText("configuration.GetConnectionString(\"Default\")", "configuration.GetConnectionString(\"Default\"), MySqlServerVersion.LatestSupportedServerVersion"); @@ -90,7 +92,8 @@ namespace Volo.Abp.Cli.ProjectBuilding.Building.Steps var efCoreModuleClass = context.Files.First(f => f.Name.EndsWith("EntityFrameworkCoreModule.cs", StringComparison.OrdinalIgnoreCase)); efCoreModuleClass.ReplaceText(oldUseMethod, newUseMethodForEfModule); - var dbContextFactoryFile = context.Files.First(f => f.Name.EndsWith("MigrationsDbContextFactory.cs", StringComparison.OrdinalIgnoreCase)); + var dbContextFactoryFile = context.Files.FirstOrDefault(f => f.Name.EndsWith("MigrationsDbContextFactoryBase.cs", StringComparison.OrdinalIgnoreCase)) + ?? context.Files.First(f => f.Name.EndsWith("MigrationsDbContextFactory.cs", StringComparison.OrdinalIgnoreCase)); dbContextFactoryFile.ReplaceText(oldUseMethod, newUseMethodForDbContext); } } diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/RemoveCmsKitStep.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/RemoveCmsKitStep.cs index 4f63d377ea..789f9e47cb 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/RemoveCmsKitStep.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/RemoveCmsKitStep.cs @@ -11,6 +11,7 @@ namespace Volo.Abp.Cli.ProjectBuilding.Building.Steps f.Name.EndsWith(".csproj") || f.Name.EndsWith("Module.cs") || f.Name.EndsWith("MyProjectNameMigrationsDbContext.cs") || + f.Name.EndsWith("MyProjectNameMigrationsDbContextBase.cs") || f.Name.EndsWith("MyProjectNameGlobalFeatureConfigurator.cs") || (f.Name.EndsWith(".cshtml") && f.Name.Contains("MyCompanyName.MyProjectName.Web.Public")) ); diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Templates/App/AppTemplateBase.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Templates/App/AppTemplateBase.cs index 2a596b73a7..7541894181 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Templates/App/AppTemplateBase.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Templates/App/AppTemplateBase.cs @@ -24,6 +24,7 @@ namespace Volo.Abp.Cli.ProjectBuilding.Templates.App { var steps = new List(); + ConfigureTenantSchema(context, steps); SwitchDatabaseProvider(context, steps); DeleteUnrelatedProjects(context, steps); RemoveMigrations(context, steps); @@ -38,6 +39,19 @@ namespace Volo.Abp.Cli.ProjectBuilding.Templates.App return steps; } + private static void ConfigureTenantSchema(ProjectBuildContext context, List steps) + { + if (context.BuildArgs.ExtraProperties.ContainsKey("separate-tenant-schema")) + { + steps.Add(new RemoveProjectFromSolutionStep("MyCompanyName.MyProjectName.EntityFrameworkCore.DbMigrations")); + steps.Add(new AppTemplateProjectRenameStep("MyCompanyName.MyProjectName.EntityFrameworkCore.SeparateDbMigrations", "MyCompanyName.MyProjectName.EntityFrameworkCore.DbMigrations")); + } + else + { + steps.Add(new RemoveProjectFromSolutionStep("MyCompanyName.MyProjectName.EntityFrameworkCore.SeparateDbMigrations")); + } + } + private static void SwitchDatabaseProvider(ProjectBuildContext context, List steps) { if (context.BuildArgs.DatabaseProvider == DatabaseProvider.MongoDb) @@ -284,6 +298,7 @@ namespace Volo.Abp.Cli.ProjectBuilding.Templates.App SemanticVersion.Parse(context.BuildArgs.Version) > new SemanticVersion(4,1,99)) { steps.Add(new RemoveFolderStep("/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore.DbMigrations/Migrations")); + steps.Add(new RemoveFolderStep("/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore.DbMigrations/TenantMigrations")); } } diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/EfCoreMigrationManager.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/EfCoreMigrationManager.cs index b15ffaa274..8143acf7b8 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/EfCoreMigrationManager.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/EfCoreMigrationManager.cs @@ -17,14 +17,38 @@ namespace Volo.Abp.Cli.ProjectModification Logger = NullLogger.Instance; } - public void AddMigration(string dbMigrationsCsprojFile, string module, string startupProject) + public void AddMigration(string dbMigrationsCsprojFile, string module) { + var dbMigrationsProjectFolder = Path.GetDirectoryName(dbMigrationsCsprojFile); var moduleName = ParseModuleName(module); var migrationName = "Added_" + moduleName + "_Module" + GetUniquePostFix(); - CmdHelper.RunCmd("cd \"" + Path.GetDirectoryName(dbMigrationsCsprojFile) + - "\" && dotnet ef migrations add " + migrationName + - GetStartupProjectOption(startupProject)); + var tenantDbContextName = FindTenantDbContextName(dbMigrationsProjectFolder); + var dbContextName = tenantDbContextName != null ? + FindDbContextName(dbMigrationsProjectFolder) + : null; + + if (!string.IsNullOrEmpty(tenantDbContextName)) + { + RunAddMigrationCommand(dbMigrationsProjectFolder, migrationName, tenantDbContextName, "TenantMigrations"); + } + + RunAddMigrationCommand(dbMigrationsProjectFolder, migrationName, dbContextName, "Migrations"); + } + + protected virtual void RunAddMigrationCommand( + string dbMigrationsProjectFolder, + string migrationName, + string dbContext, + string outputDirectory) + { + var dbContextOption = string.IsNullOrWhiteSpace(dbContext) + ? string.Empty + : $"--context {dbContext}"; + + CmdHelper.RunCmd($"cd \"{dbMigrationsProjectFolder}\" && dotnet ef migrations add {migrationName}" + + $" --output-dir {outputDirectory}" + + $" {dbContextOption}"); } protected virtual string ParseModuleName(string fullModuleName) @@ -43,9 +67,32 @@ namespace Volo.Abp.Cli.ProjectModification return "_" + new Random().Next(1, 99999); } - protected virtual string GetStartupProjectOption(string startupProject) + protected virtual string FindDbContextName(string dbMigrationsFolder) { - return startupProject.IsNullOrWhiteSpace() ? "" : $" -s {startupProject}"; + var dbContext = Directory + .GetFiles(dbMigrationsFolder, "*MigrationsDbContext.cs", SearchOption.AllDirectories) + .FirstOrDefault(fp => !fp.EndsWith("TenantMigrationsDbContext.cs")); + + if (dbContext == null) + { + return null; + } + + return Path.GetFileName(dbContext).RemovePostFix(".cs"); + } + + protected virtual string FindTenantDbContextName(string dbMigrationsFolder) + { + var tenantDbContext = Directory + .GetFiles(dbMigrationsFolder, "*TenantMigrationsDbContext.cs", SearchOption.AllDirectories) + .FirstOrDefault(); + + if (tenantDbContext == null) + { + return null; + } + + return Path.GetFileName(tenantDbContext).RemovePostFix(".cs"); } } } diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/SolutionModuleAdder.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/SolutionModuleAdder.cs index c84713ffcb..d550912691 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/SolutionModuleAdder.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/SolutionModuleAdder.cs @@ -78,7 +78,6 @@ namespace Volo.Abp.Cli.ProjectModification public virtual async Task AddAsync( [NotNull] string solutionFile, [NotNull] string moduleName, - string startupProject, string version, bool skipDbMigrations = false, bool withSourceCode = false, @@ -128,7 +127,7 @@ namespace Volo.Abp.Cli.ProjectModification await RunBundleForBlazorAsync(projectFiles, module); - ModifyDbContext(projectFiles, module, startupProject, skipDbMigrations); + ModifyDbContext(projectFiles, module, skipDbMigrations); } private async Task RunBundleForBlazorAsync(string[] projectFiles, ModuleWithMastersInfo module) @@ -450,8 +449,7 @@ namespace Volo.Abp.Cli.ProjectModification } } - protected void ModifyDbContext(string[] projectFiles, ModuleInfo module, string startupProject, - bool skipDbMigrations = false) + protected void ModifyDbContext(string[] projectFiles, ModuleInfo module, bool skipDbMigrations = false) { if (string.IsNullOrWhiteSpace(module.EfCoreConfigureMethodName)) { @@ -463,11 +461,6 @@ namespace Volo.Abp.Cli.ProjectModification return; } - if (string.IsNullOrWhiteSpace(startupProject)) - { - startupProject = projectFiles.FirstOrDefault(p => p.EndsWith(".DbMigrator.csproj")); - } - var dbMigrationsProject = projectFiles.FirstOrDefault(p => p.EndsWith(".DbMigrations.csproj")); if (dbMigrationsProject == null) @@ -498,7 +491,7 @@ namespace Volo.Abp.Cli.ProjectModification { if (addedNewBuilder) { - EfCoreMigrationManager.AddMigration(dbMigrationsProject, module.Name, startupProject); + EfCoreMigrationManager.AddMigration(dbMigrationsProject, module.Name); } RunMigrator(projectFiles);