From 83f9d34120fe14c15ae77c3820ea0841324656b4 Mon Sep 17 00:00:00 2001 From: Yunus Emre Kalkan Date: Mon, 21 Dec 2020 15:57:57 +0300 Subject: [PATCH] =?UTF-8?q?=C4=B0mplement=20DatabaseManagementSystemChange?= =?UTF-8?q?Step=20&=20migration=20recreater?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Volo/Abp/Cli/Commands/NewCommand.cs | 58 ++++++++++++---- .../Building/DatabaseManagementSystem.cs | 1 + .../DatabaseManagementSystemChangeStep.cs | 68 ++++++++++++++----- .../TemplateProjectBuildPipelineBuilder.cs | 1 - .../EfCoreMigrationRecreater.cs | 46 +++++++++++++ 5 files changed, 144 insertions(+), 30 deletions(-) create mode 100644 framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/EfCoreMigrationRecreater.cs diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/NewCommand.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/NewCommand.cs index f998a6c09e..c3b9302d3b 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/NewCommand.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/NewCommand.cs @@ -1,6 +1,7 @@ using System; using System.Diagnostics; using System.IO; +using System.Linq; using System.Runtime.InteropServices; using System.Text; using System.Text.Json; @@ -16,6 +17,7 @@ using Volo.Abp.Cli.ProjectBuilding; using Volo.Abp.Cli.ProjectBuilding.Building; using Volo.Abp.Cli.ProjectBuilding.Templates.App; using Volo.Abp.Cli.ProjectBuilding.Templates.Console; +using Volo.Abp.Cli.ProjectModification; using Volo.Abp.Cli.Utils; using Volo.Abp.DependencyInjection; using Volo.Abp.Threading; @@ -24,14 +26,17 @@ namespace Volo.Abp.Cli.Commands { public class NewCommand : IConsoleCommand, ITransientDependency { + private readonly EfCoreMigrationRecreater _efCoreMigrationRecreater; public ILogger Logger { get; set; } protected TemplateProjectBuilder TemplateProjectBuilder { get; } public ITemplateInfoProvider TemplateInfoProvider { get; } public NewCommand(TemplateProjectBuilder templateProjectBuilder - , ITemplateInfoProvider templateInfoProvider) + , ITemplateInfoProvider templateInfoProvider, + EfCoreMigrationRecreater efCoreMigrationRecreater) { + _efCoreMigrationRecreater = efCoreMigrationRecreater; TemplateProjectBuilder = templateProjectBuilder; TemplateInfoProvider = templateInfoProvider; @@ -84,22 +89,29 @@ namespace Volo.Abp.Cli.Commands Logger.LogInformation("Database provider: " + databaseProvider); } + var connectionString = GetConnectionString(commandLineArgs); + if (connectionString != null) + { + Logger.LogInformation("Connection string: " + connectionString); + } + var databaseManagementSystem = GetDatabaseManagementSystem(commandLineArgs); if (databaseManagementSystem != DatabaseManagementSystem.NotSpecified) { - Logger.LogInformation("DBSM: " + databaseManagementSystem); + Logger.LogInformation("DBMS: " + databaseManagementSystem); } - var uiFramework = GetUiFramework(commandLineArgs); - if (uiFramework != UiFramework.NotSpecified) + if (databaseManagementSystem != DatabaseManagementSystem.NotSpecified + && databaseManagementSystem != DatabaseManagementSystem.SQLServer + && connectionString == null) { - Logger.LogInformation("UI Framework: " + uiFramework); + throw new CliUsageException($"Connection string must be set if a Database Management System other than SQLServer is set. Use \"--{Options.ConnectionString.Long}\" parameter to set connection string"); } - var connectionString = GetConnectionString(commandLineArgs); - if (connectionString != null) + var uiFramework = GetUiFramework(commandLineArgs); + if (uiFramework != UiFramework.NotSpecified) { - Logger.LogInformation("Connection string: " + connectionString); + Logger.LogInformation("UI Framework: " + uiFramework); } var mobileApp = GetMobilePreference(commandLineArgs); @@ -203,6 +215,8 @@ namespace Volo.Abp.Cli.Commands } } + ReCreateMigrationsIfNeeded(databaseProvider, databaseManagementSystem, outputFolder); + Logger.LogInformation($"'{projectName}' has been successfully created to '{outputFolder}'"); if (AppTemplateBase.IsAppTemplate(template ?? (await TemplateInfoProvider.GetDefaultAsync()).Name)) @@ -212,6 +226,23 @@ namespace Volo.Abp.Cli.Commands } } + private void ReCreateMigrationsIfNeeded(DatabaseProvider databaseProvider, DatabaseManagementSystem databaseManagementSystem, string outputFolder) + { + if (databaseManagementSystem == DatabaseManagementSystem.NotSpecified || databaseManagementSystem == DatabaseManagementSystem.SQLServer) + { + return; + } + + if (databaseProvider != DatabaseProvider.NotSpecified && databaseProvider != DatabaseProvider.EntityFrameworkCore) + { + return; + } + + Logger.LogInformation($"Re-creating migrations... ({databaseManagementSystem})"); + + _efCoreMigrationRecreater.Recreate(outputFolder); + } + private void OpenThanksPage(UiFramework uiFramework, DatabaseProvider databaseProvider, bool tiered, bool commercial) { uiFramework = uiFramework == UiFramework.NotSpecified || uiFramework == UiFramework.None ? UiFramework.Mvc : uiFramework; @@ -274,7 +305,7 @@ namespace Volo.Abp.Cli.Commands sb.AppendLine("-ts|--template-source (your local or network abp template source)"); sb.AppendLine("-csf|--create-solution-folder (default: true)"); sb.AppendLine("-cs|--connection-string (your database connection string)"); - sb.AppendLine("--dbms (your database management system)"); + sb.AppendLine("--dbms (your database management system. Requires --connection-string to be set)"); sb.AppendLine("--tiered (if supported by the template)"); sb.AppendLine("--no-ui (if supported by the template)"); sb.AppendLine("--no-random-port (Use template's default ports)"); @@ -297,7 +328,7 @@ namespace Volo.Abp.Cli.Commands sb.AppendLine(" abp new Acme.BookStore -ts \"D:\\localTemplate\\abp\""); sb.AppendLine(" abp new Acme.BookStore -csf false"); sb.AppendLine(" abp new Acme.BookStore --local-framework-ref --abp-path \"D:\\github\\abp\""); - sb.AppendLine(" abp new Acme.BookStore --dbms mysql"); + sb.AppendLine(" abp new Acme.BookStore --dbms mysql --connection-string \"Server=myServerName\\myInstanceName;Database=myDatabase;User Id=myUsername;Password=myPassword\""); sb.AppendLine(" abp new Acme.BookStore --connection-string \"Server=myServerName\\myInstanceName;Database=myDatabase;User Id=myUsername;Password=myPassword\""); sb.AppendLine(""); sb.AppendLine("See the documentation for more info: https://docs.abp.io/en/abp/latest/CLI"); @@ -326,7 +357,7 @@ namespace Volo.Abp.Cli.Commands protected virtual DatabaseManagementSystem GetDatabaseManagementSystem(CommandLineArgs commandLineArgs) { - var optionValue = commandLineArgs.Options.GetOrNull(Options.DatabaseManagementSystem.Long); + var optionValue = commandLineArgs.Options.GetOrNull(Options.DatabaseManagementSystem.Short, Options.DatabaseManagementSystem.Long); if (optionValue == null) { @@ -343,6 +374,8 @@ namespace Volo.Abp.Cli.Commands return DatabaseManagementSystem.PostgreSQL; case "oracle": return DatabaseManagementSystem.Oracle; + case "oracle-devart": + return DatabaseManagementSystem.OracleDevart; case "sqlite": return DatabaseManagementSystem.SQLite; default: @@ -399,7 +432,8 @@ namespace Volo.Abp.Cli.Commands public static class DatabaseManagementSystem { - public const string Long = "dbsm"; + public const string Short = "dbms"; + public const string Long = "database-management-system"; } public static class OutputFolder diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/DatabaseManagementSystem.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/DatabaseManagementSystem.cs index edf30abce1..fcb3130854 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/DatabaseManagementSystem.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/DatabaseManagementSystem.cs @@ -7,6 +7,7 @@ MySQL, PostgreSQL, Oracle, + OracleDevart, SQLite } } 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 cbbaa8d64a..f0f7c12872 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 @@ -1,13 +1,6 @@ using System; -using System.Collections.Generic; -using System.IO; using System.Linq; -using System.Text; -using System.Text.RegularExpressions; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; using Volo.Abp.Cli.ProjectBuilding.Files; -using Volo.Abp.Text; namespace Volo.Abp.Cli.ProjectBuilding.Building.Steps { @@ -17,24 +10,65 @@ namespace Volo.Abp.Cli.ProjectBuilding.Building.Steps { switch (context.BuildArgs.DatabaseManagementSystem) { - case DatabaseManagementSystem.NotSpecified: - return; - - case DatabaseManagementSystem.SQLServer: - return; - case DatabaseManagementSystem.MySQL: - return; + ChangeEntityFrameworkCoreDependency(context,"Volo.Abp.EntityFrameworkCore.MySQL", + "Volo.Abp.EntityFrameworkCore.MySQL", + "AbpEntityFrameworkCoreMySQLModule"); + ChangeUseSqlServer(context,"UseMySql"); + break; case DatabaseManagementSystem.PostgreSQL: - return; + ChangeEntityFrameworkCoreDependency(context,"Volo.Abp.EntityFrameworkCore.PostgreSql", + "Volo.Abp.EntityFrameworkCore.PostgreSql", + "AbpEntityFrameworkCorePostgreSqlModule"); + ChangeUseSqlServer(context,"UseNpgsql"); + break; case DatabaseManagementSystem.Oracle: - return; + ChangeEntityFrameworkCoreDependency(context,"Volo.Abp.EntityFrameworkCore.Oracle", + "Volo.Abp.EntityFrameworkCore.Oracle", + "AbpEntityFrameworkCoreOracleModule"); + ChangeUseSqlServer(context,"UseOracle"); + break; + + case DatabaseManagementSystem.OracleDevart: + ChangeEntityFrameworkCoreDependency(context,"Volo.Abp.EntityFrameworkCore.Oracle.Devart", + "Volo.Abp.EntityFrameworkCore.Oracle.Devart", + "AbpEntityFrameworkCoreOracleDevartModule"); + ChangeUseSqlServer(context,"UseOracle"); + break; case DatabaseManagementSystem.SQLite: - return; + ChangeEntityFrameworkCoreDependency(context,"Volo.Abp.EntityFrameworkCore.Sqlite", + "Volo.Abp.EntityFrameworkCore.Sqlite", + "AbpEntityFrameworkCoreSqliteModule"); + ChangeUseSqlServer(context,"UseSqlite"); + break; + + default: + return; } } + + private void ChangeEntityFrameworkCoreDependency(ProjectBuildContext context, string newPackageName, string newModuleNamespace, string newModuleClass) + { + var efCoreProjectFile = context.Files.First(f => f.Name.EndsWith("EntityFrameworkCore.csproj", StringComparison.OrdinalIgnoreCase)); + efCoreProjectFile.ReplaceText("Volo.Abp.EntityFrameworkCore.SqlServer", newPackageName); + + var efCoreModuleClass = context.Files.First(f => f.Name.EndsWith("EntityFrameworkCoreModule.cs", StringComparison.OrdinalIgnoreCase)); + efCoreModuleClass.ReplaceText("Volo.Abp.EntityFrameworkCore.SqlServer", newModuleNamespace); + efCoreModuleClass.ReplaceText("AbpEntityFrameworkCoreSqlServerModule", newModuleClass); + } + + private void ChangeUseSqlServer(ProjectBuildContext context, string newUseMethod) + { + var oldUseMethod = "UseSqlServer"; + + var efCoreModuleClass = context.Files.First(f => f.Name.EndsWith("EntityFrameworkCoreModule.cs", StringComparison.OrdinalIgnoreCase)); + efCoreModuleClass.ReplaceText(oldUseMethod, newUseMethod); + + var dbContextFactoryFile = context.Files.First(f => f.Name.EndsWith("MigrationsDbContextFactory.cs", StringComparison.OrdinalIgnoreCase)); + dbContextFactoryFile.ReplaceText(oldUseMethod, newUseMethod); + } } } diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/TemplateProjectBuildPipelineBuilder.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/TemplateProjectBuildPipelineBuilder.cs index c7cf29de20..40ba54a3c0 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/TemplateProjectBuildPipelineBuilder.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/TemplateProjectBuildPipelineBuilder.cs @@ -32,7 +32,6 @@ namespace Volo.Abp.Cli.ProjectBuilding.Building pipeline.Steps.Add(new RemoveRootFolderStep()); } - if (context.BuildArgs.ConnectionString != null) { pipeline.Steps.Add(new ConnectionStringChangeStep()); diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/EfCoreMigrationRecreater.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/EfCoreMigrationRecreater.cs new file mode 100644 index 0000000000..1f9dc7d93d --- /dev/null +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/EfCoreMigrationRecreater.cs @@ -0,0 +1,46 @@ +using System; +using System.IO; +using System.Linq; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; +using Volo.Abp.Cli.Utils; +using Volo.Abp.DependencyInjection; + +namespace Volo.Abp.Cli.ProjectModification +{ + public class EfCoreMigrationRecreater : ITransientDependency + { + public ILogger Logger { get; set; } + + public EfCoreMigrationRecreater() + { + Logger = NullLogger.Instance; + } + + public void Recreate(string solutionFolder) + { + if (Directory.Exists(Path.Combine(solutionFolder, "aspnet-core"))) + { + solutionFolder = Path.Combine(solutionFolder, "aspnet-core"); + } + + var srcFolder = Path.Combine(solutionFolder, "src"); + + try + { + var migrationsFolder = Directory.GetDirectories(srcFolder).First(d => d.EndsWith(".EntityFrameworkCore.DbMigrations")); + Directory.Delete(Path.Combine(migrationsFolder, "Migrations"), true); + + var migratorFolder = Directory.GetDirectories(srcFolder).First(d => d.EndsWith(".DbMigrator")); + var migratorProjectFile = Directory.GetFiles(migratorFolder).First(d => d.EndsWith(".DbMigrator.csproj")); + var addMigrationCommand = $"dotnet ef migrations add Initial --startup-project {migratorProjectFile}"; + CmdHelper.RunCmd($"cd {migrationsFolder} && {addMigrationCommand}"); + } + catch (Exception e) + { + Logger.LogWarning($"\"Re-creating migrations process failed."); + throw e; + } + } + } +}