From 2d3ab102b5d96f864c28c53d49527e8a152cb619 Mon Sep 17 00:00:00 2001 From: colin Date: Wed, 2 Apr 2025 08:16:48 +0800 Subject: [PATCH 1/4] feat(elsa): Added automatic elsa database migration --- ....Abp.Elsa.EntityFrameworkCore.MySql.csproj | 8 + .../AbpElsaEntityFrameworkCoreMySqlModule.cs | 9 + .../MySql/Migrations/Initial.sql | 315 ++++++++++++++++++ .../Migrations/MySqlElsaDataBaseInstaller.cs | 130 ++++++++ .../AbpElsaEntityFrameworkCoreModule.cs | 13 +- .../Migrations/IElsaDataBaseInstaller.cs | 8 + 6 files changed, 482 insertions(+), 1 deletion(-) create mode 100644 aspnet-core/modules/elsa/LINGYUN.Abp.Elsa.EntityFrameworkCore.MySql/LINGYUN/Abp/Elsa/EntityFrameworkCore/MySql/Migrations/Initial.sql create mode 100644 aspnet-core/modules/elsa/LINGYUN.Abp.Elsa.EntityFrameworkCore.MySql/LINGYUN/Abp/Elsa/EntityFrameworkCore/MySql/Migrations/MySqlElsaDataBaseInstaller.cs create mode 100644 aspnet-core/modules/elsa/LINGYUN.Abp.Elsa.EntityFrameworkCore/LINGYUN/Abp/Elsa/EntityFrameworkCore/Migrations/IElsaDataBaseInstaller.cs diff --git a/aspnet-core/modules/elsa/LINGYUN.Abp.Elsa.EntityFrameworkCore.MySql/LINGYUN.Abp.Elsa.EntityFrameworkCore.MySql.csproj b/aspnet-core/modules/elsa/LINGYUN.Abp.Elsa.EntityFrameworkCore.MySql/LINGYUN.Abp.Elsa.EntityFrameworkCore.MySql.csproj index ab9fcb726..e77867d78 100644 --- a/aspnet-core/modules/elsa/LINGYUN.Abp.Elsa.EntityFrameworkCore.MySql/LINGYUN.Abp.Elsa.EntityFrameworkCore.MySql.csproj +++ b/aspnet-core/modules/elsa/LINGYUN.Abp.Elsa.EntityFrameworkCore.MySql/LINGYUN.Abp.Elsa.EntityFrameworkCore.MySql.csproj @@ -13,6 +13,14 @@ + + + + + + + + diff --git a/aspnet-core/modules/elsa/LINGYUN.Abp.Elsa.EntityFrameworkCore.MySql/LINGYUN/Abp/Elsa/EntityFrameworkCore/MySql/AbpElsaEntityFrameworkCoreMySqlModule.cs b/aspnet-core/modules/elsa/LINGYUN.Abp.Elsa.EntityFrameworkCore.MySql/LINGYUN/Abp/Elsa/EntityFrameworkCore/MySql/AbpElsaEntityFrameworkCoreMySqlModule.cs index 45069e0a8..5b8ce2f5a 100644 --- a/aspnet-core/modules/elsa/LINGYUN.Abp.Elsa.EntityFrameworkCore.MySql/LINGYUN/Abp/Elsa/EntityFrameworkCore/MySql/AbpElsaEntityFrameworkCoreMySqlModule.cs +++ b/aspnet-core/modules/elsa/LINGYUN.Abp.Elsa.EntityFrameworkCore.MySql/LINGYUN/Abp/Elsa/EntityFrameworkCore/MySql/AbpElsaEntityFrameworkCoreMySqlModule.cs @@ -3,6 +3,7 @@ using Elsa.Options; using Microsoft.Extensions.DependencyInjection; using Volo.Abp.EntityFrameworkCore.MySQL; using Volo.Abp.Modularity; +using Volo.Abp.VirtualFileSystem; namespace LINGYUN.Abp.Elsa.EntityFrameworkCore.MySql; @@ -26,4 +27,12 @@ public class AbpElsaEntityFrameworkCoreMySqlModule : AbpModule elsa.AddFeatures(startups, configuration); }); } + + public override void ConfigureServices(ServiceConfigurationContext context) + { + Configure(options => + { + options.FileSets.AddEmbedded(); + }); + } } diff --git a/aspnet-core/modules/elsa/LINGYUN.Abp.Elsa.EntityFrameworkCore.MySql/LINGYUN/Abp/Elsa/EntityFrameworkCore/MySql/Migrations/Initial.sql b/aspnet-core/modules/elsa/LINGYUN.Abp.Elsa.EntityFrameworkCore.MySql/LINGYUN/Abp/Elsa/EntityFrameworkCore/MySql/Migrations/Initial.sql new file mode 100644 index 000000000..0ca9b20ae --- /dev/null +++ b/aspnet-core/modules/elsa/LINGYUN.Abp.Elsa.EntityFrameworkCore.MySql/LINGYUN/Abp/Elsa/EntityFrameworkCore/MySql/Migrations/Initial.sql @@ -0,0 +1,315 @@ +-- basic script + +USE `${DataBase}`; + +CREATE TABLE IF NOT EXISTS `__EFMigrationsHistory` ( + `MigrationId` varchar(150) CHARACTER SET utf8mb4 NOT NULL, + `ProductVersion` varchar(32) CHARACTER SET utf8mb4 NOT NULL, + CONSTRAINT `PK___EFMigrationsHistory` PRIMARY KEY (`MigrationId`) +) CHARACTER SET utf8mb4; + +START TRANSACTION; + +ALTER DATABASE CHARACTER SET utf8mb4; + +CREATE TABLE `Bookmarks` ( + `Id` varchar(255) CHARACTER SET utf8mb4 NOT NULL, + `TenantId` varchar(255) CHARACTER SET utf8mb4 NULL, + `Hash` varchar(255) CHARACTER SET utf8mb4 NOT NULL, + `Model` longtext CHARACTER SET utf8mb4 NOT NULL, + `ModelType` longtext CHARACTER SET utf8mb4 NOT NULL, + `ActivityType` varchar(255) CHARACTER SET utf8mb4 NOT NULL, + `ActivityId` varchar(255) CHARACTER SET utf8mb4 NOT NULL, + `WorkflowInstanceId` varchar(255) CHARACTER SET utf8mb4 NOT NULL, + `CorrelationId` varchar(255) CHARACTER SET utf8mb4 NULL, + CONSTRAINT `PK_Bookmarks` PRIMARY KEY (`Id`) +) CHARACTER SET utf8mb4; + +CREATE TABLE `WorkflowDefinitions` ( + `Id` varchar(255) CHARACTER SET utf8mb4 NOT NULL, + `DefinitionId` varchar(255) CHARACTER SET utf8mb4 NOT NULL, + `TenantId` varchar(255) CHARACTER SET utf8mb4 NULL, + `Name` varchar(255) CHARACTER SET utf8mb4 NULL, + `DisplayName` longtext CHARACTER SET utf8mb4 NULL, + `Description` longtext CHARACTER SET utf8mb4 NULL, + `Version` int NOT NULL, + `IsSingleton` tinyint(1) NOT NULL, + `PersistenceBehavior` int NOT NULL, + `DeleteCompletedInstances` tinyint(1) NOT NULL, + `IsPublished` tinyint(1) NOT NULL, + `IsLatest` tinyint(1) NOT NULL, + `Tag` varchar(255) CHARACTER SET utf8mb4 NULL, + `Data` longtext CHARACTER SET utf8mb4 NULL, + CONSTRAINT `PK_WorkflowDefinitions` PRIMARY KEY (`Id`) +) CHARACTER SET utf8mb4; + +CREATE TABLE `WorkflowExecutionLogRecords` ( + `Id` varchar(255) CHARACTER SET utf8mb4 NOT NULL, + `TenantId` varchar(255) CHARACTER SET utf8mb4 NULL, + `WorkflowInstanceId` varchar(255) CHARACTER SET utf8mb4 NOT NULL, + `ActivityId` varchar(255) CHARACTER SET utf8mb4 NOT NULL, + `ActivityType` varchar(255) CHARACTER SET utf8mb4 NOT NULL, + `Timestamp` datetime(6) NOT NULL, + `EventName` longtext CHARACTER SET utf8mb4 NULL, + `Message` longtext CHARACTER SET utf8mb4 NULL, + `Source` longtext CHARACTER SET utf8mb4 NULL, + `Data` longtext CHARACTER SET utf8mb4 NULL, + CONSTRAINT `PK_WorkflowExecutionLogRecords` PRIMARY KEY (`Id`) +) CHARACTER SET utf8mb4; + +CREATE TABLE `WorkflowInstances` ( + `Id` varchar(255) CHARACTER SET utf8mb4 NOT NULL, + `DefinitionId` varchar(255) CHARACTER SET utf8mb4 NOT NULL, + `TenantId` varchar(255) CHARACTER SET utf8mb4 NULL, + `Version` int NOT NULL, + `WorkflowStatus` int NOT NULL, + `CorrelationId` varchar(255) CHARACTER SET utf8mb4 NULL, + `ContextType` varchar(255) CHARACTER SET utf8mb4 NULL, + `ContextId` varchar(255) CHARACTER SET utf8mb4 NULL, + `Name` varchar(255) CHARACTER SET utf8mb4 NULL, + `CreatedAt` datetime(6) NOT NULL, + `LastExecutedAt` datetime(6) NULL, + `FinishedAt` datetime(6) NULL, + `CancelledAt` datetime(6) NULL, + `FaultedAt` datetime(6) NULL, + `Data` longtext CHARACTER SET utf8mb4 NULL, + CONSTRAINT `PK_WorkflowInstances` PRIMARY KEY (`Id`) +) CHARACTER SET utf8mb4; + +CREATE INDEX `IX_Bookmark_ActivityId` ON `Bookmarks` (`ActivityId`); + +CREATE INDEX `IX_Bookmark_ActivityType` ON `Bookmarks` (`ActivityType`); + +CREATE INDEX `IX_Bookmark_ActivityType_TenantId_Hash` ON `Bookmarks` (`ActivityType`, `TenantId`, `Hash`); + +CREATE INDEX `IX_Bookmark_CorrelationId` ON `Bookmarks` (`CorrelationId`); + +CREATE INDEX `IX_Bookmark_Hash` ON `Bookmarks` (`Hash`); + +CREATE INDEX `IX_Bookmark_Hash_CorrelationId_TenantId` ON `Bookmarks` (`Hash`, `CorrelationId`, `TenantId`); + +CREATE INDEX `IX_Bookmark_TenantId` ON `Bookmarks` (`TenantId`); + +CREATE INDEX `IX_Bookmark_WorkflowInstanceId` ON `Bookmarks` (`WorkflowInstanceId`); + +CREATE UNIQUE INDEX `IX_WorkflowDefinition_DefinitionId_VersionId` ON `WorkflowDefinitions` (`DefinitionId`, `Version`); + +CREATE INDEX `IX_WorkflowDefinition_IsLatest` ON `WorkflowDefinitions` (`IsLatest`); + +CREATE INDEX `IX_WorkflowDefinition_IsPublished` ON `WorkflowDefinitions` (`IsPublished`); + +CREATE INDEX `IX_WorkflowDefinition_Name` ON `WorkflowDefinitions` (`Name`); + +CREATE INDEX `IX_WorkflowDefinition_Tag` ON `WorkflowDefinitions` (`Tag`); + +CREATE INDEX `IX_WorkflowDefinition_TenantId` ON `WorkflowDefinitions` (`TenantId`); + +CREATE INDEX `IX_WorkflowDefinition_Version` ON `WorkflowDefinitions` (`Version`); + +CREATE INDEX `IX_WorkflowExecutionLogRecord_ActivityId` ON `WorkflowExecutionLogRecords` (`ActivityId`); + +CREATE INDEX `IX_WorkflowExecutionLogRecord_ActivityType` ON `WorkflowExecutionLogRecords` (`ActivityType`); + +CREATE INDEX `IX_WorkflowExecutionLogRecord_TenantId` ON `WorkflowExecutionLogRecords` (`TenantId`); + +CREATE INDEX `IX_WorkflowExecutionLogRecord_Timestamp` ON `WorkflowExecutionLogRecords` (`Timestamp`); + +CREATE INDEX `IX_WorkflowExecutionLogRecord_WorkflowInstanceId` ON `WorkflowExecutionLogRecords` (`WorkflowInstanceId`); + +CREATE INDEX `IX_WorkflowInstance_ContextId` ON `WorkflowInstances` (`ContextId`); + +CREATE INDEX `IX_WorkflowInstance_ContextType` ON `WorkflowInstances` (`ContextType`); + +CREATE INDEX `IX_WorkflowInstance_CorrelationId` ON `WorkflowInstances` (`CorrelationId`); + +CREATE INDEX `IX_WorkflowInstance_CreatedAt` ON `WorkflowInstances` (`CreatedAt`); + +CREATE INDEX `IX_WorkflowInstance_DefinitionId` ON `WorkflowInstances` (`DefinitionId`); + +CREATE INDEX `IX_WorkflowInstance_FaultedAt` ON `WorkflowInstances` (`FaultedAt`); + +CREATE INDEX `IX_WorkflowInstance_FinishedAt` ON `WorkflowInstances` (`FinishedAt`); + +CREATE INDEX `IX_WorkflowInstance_LastExecutedAt` ON `WorkflowInstances` (`LastExecutedAt`); + +CREATE INDEX `IX_WorkflowInstance_Name` ON `WorkflowInstances` (`Name`); + +CREATE INDEX `IX_WorkflowInstance_TenantId` ON `WorkflowInstances` (`TenantId`); + +CREATE INDEX `IX_WorkflowInstance_WorkflowStatus` ON `WorkflowInstances` (`WorkflowStatus`); + +CREATE INDEX `IX_WorkflowInstance_WorkflowStatus_DefinitionId` ON `WorkflowInstances` (`WorkflowStatus`, `DefinitionId`); + +CREATE INDEX `IX_WorkflowInstance_WorkflowStatus_DefinitionId_Version` ON `WorkflowInstances` (`WorkflowStatus`, `DefinitionId`, `Version`); + +INSERT INTO `__EFMigrationsHistory` (`MigrationId`, `ProductVersion`) +VALUES ('20210523093427_Initial', '5.0.10'); + +COMMIT; + +START TRANSACTION; + +ALTER TABLE `WorkflowInstances` MODIFY COLUMN `CorrelationId` varchar(255) CHARACTER SET utf8mb4 NOT NULL DEFAULT ''; + +ALTER TABLE `WorkflowInstances` ADD `LastExecutedActivityId` longtext CHARACTER SET utf8mb4 NULL; + +ALTER TABLE `WorkflowDefinitions` ADD `OutputStorageProviderName` longtext CHARACTER SET utf8mb4 NULL; + +INSERT INTO `__EFMigrationsHistory` (`MigrationId`, `ProductVersion`) +VALUES ('20210611200027_Update21', '5.0.10'); + +COMMIT; + +START TRANSACTION; + +ALTER TABLE `WorkflowDefinitions` DROP COLUMN `OutputStorageProviderName`; + +ALTER TABLE `WorkflowInstances` RENAME `WorkflowInstances`; + +ALTER TABLE `WorkflowExecutionLogRecords` RENAME `WorkflowExecutionLogRecords`; + +ALTER TABLE `WorkflowDefinitions` RENAME `WorkflowDefinitions`; + +ALTER TABLE `Bookmarks` RENAME `Bookmarks`; + +INSERT INTO `__EFMigrationsHistory` (`MigrationId`, `ProductVersion`) +VALUES ('20210923112211_Update23', '5.0.10'); + +COMMIT; + +START TRANSACTION; + +ALTER TABLE `WorkflowInstances` ADD `DefinitionVersionId` longtext CHARACTER SET utf8mb4 NOT NULL; + +ALTER TABLE `Bookmarks` MODIFY COLUMN `CorrelationId` varchar(255) CHARACTER SET utf8mb4 NOT NULL DEFAULT ''; + +INSERT INTO `__EFMigrationsHistory` (`MigrationId`, `ProductVersion`) +VALUES ('20211215100204_Update24', '5.0.10'); + +COMMIT; + +START TRANSACTION; + +ALTER TABLE `WorkflowInstances` MODIFY COLUMN `DefinitionVersionId` varchar(255) CHARACTER SET utf8mb4 NOT NULL; + +CREATE INDEX `IX_WorkflowInstance_DefinitionVersionId` ON `WorkflowInstances` (`DefinitionVersionId`); + +INSERT INTO `__EFMigrationsHistory` (`MigrationId`, `ProductVersion`) +VALUES ('20220120170050_Update241', '5.0.10'); + +COMMIT; + +START TRANSACTION; + +CREATE TABLE `Triggers` ( + `Id` varchar(255) CHARACTER SET utf8mb4 NOT NULL, + `TenantId` varchar(255) CHARACTER SET utf8mb4 NULL, + `Hash` varchar(255) CHARACTER SET utf8mb4 NOT NULL, + `Model` longtext CHARACTER SET utf8mb4 NOT NULL, + `ModelType` longtext CHARACTER SET utf8mb4 NOT NULL, + `ActivityType` varchar(255) CHARACTER SET utf8mb4 NOT NULL, + `ActivityId` varchar(255) CHARACTER SET utf8mb4 NOT NULL, + `WorkflowDefinitionId` varchar(255) CHARACTER SET utf8mb4 NOT NULL, + CONSTRAINT `PK_Triggers` PRIMARY KEY (`Id`) +) CHARACTER SET utf8mb4; + +CREATE INDEX `IX_Trigger_ActivityId` ON `Triggers` (`ActivityId`); + +CREATE INDEX `IX_Trigger_ActivityType` ON `Triggers` (`ActivityType`); + +CREATE INDEX `IX_Trigger_ActivityType_TenantId_Hash` ON `Triggers` (`ActivityType`, `TenantId`, `Hash`); + +CREATE INDEX `IX_Trigger_Hash` ON `Triggers` (`Hash`); + +CREATE INDEX `IX_Trigger_Hash_TenantId` ON `Triggers` (`Hash`, `TenantId`); + +CREATE INDEX `IX_Trigger_TenantId` ON `Triggers` (`TenantId`); + +CREATE INDEX `IX_Trigger_WorkflowDefinitionId` ON `Triggers` (`WorkflowDefinitionId`); + +INSERT INTO `__EFMigrationsHistory` (`MigrationId`, `ProductVersion`) +VALUES ('20220120204150_Update25', '5.0.10'); + +COMMIT; + +START TRANSACTION; + +ALTER TABLE `WorkflowDefinitions` ADD `CreatedAt` datetime(6) NOT NULL DEFAULT '0001-01-01 00:00:00'; + +INSERT INTO `__EFMigrationsHistory` (`MigrationId`, `ProductVersion`) +VALUES ('20220512203646_Update28', '5.0.10'); + +COMMIT; + + +-- webhooks + +CREATE TABLE IF NOT EXISTS `__EFMigrationsHistory` ( + `MigrationId` varchar(150) CHARACTER SET utf8mb4 NOT NULL, + `ProductVersion` varchar(32) CHARACTER SET utf8mb4 NOT NULL, + CONSTRAINT `PK___EFMigrationsHistory` PRIMARY KEY (`MigrationId`) +) CHARACTER SET utf8mb4; + +START TRANSACTION; + +ALTER DATABASE CHARACTER SET utf8mb4; + +CREATE TABLE `WebhookDefinitions` ( + `Id` varchar(255) CHARACTER SET utf8mb4 NOT NULL, + `TenantId` varchar(255) CHARACTER SET utf8mb4 NULL, + `Name` varchar(255) CHARACTER SET utf8mb4 NOT NULL, + `Path` varchar(255) CHARACTER SET utf8mb4 NOT NULL, + `Description` varchar(255) CHARACTER SET utf8mb4 NULL, + `PayloadTypeName` varchar(255) CHARACTER SET utf8mb4 NULL, + `IsEnabled` tinyint(1) NOT NULL, + CONSTRAINT `PK_WebhookDefinitions` PRIMARY KEY (`Id`) +) CHARACTER SET utf8mb4; + +CREATE INDEX `IX_WebhookDefinition_Description` ON `WebhookDefinitions` (`Description`); + +CREATE INDEX `IX_WebhookDefinition_IsEnabled` ON `WebhookDefinitions` (`IsEnabled`); + +CREATE INDEX `IX_WebhookDefinition_Name` ON `WebhookDefinitions` (`Name`); + +CREATE INDEX `IX_WebhookDefinition_Path` ON `WebhookDefinitions` (`Path`); + +CREATE INDEX `IX_WebhookDefinition_PayloadTypeName` ON `WebhookDefinitions` (`PayloadTypeName`); + +CREATE INDEX `IX_WebhookDefinition_TenantId` ON `WebhookDefinitions` (`TenantId`); + +INSERT INTO `__EFMigrationsHistory` (`MigrationId`, `ProductVersion`) +VALUES ('20210604065041_Initial', '5.0.10'); + +COMMIT; + + +-- workflow-settings + +CREATE TABLE IF NOT EXISTS `__EFMigrationsHistory` ( + `MigrationId` varchar(150) CHARACTER SET utf8mb4 NOT NULL, + `ProductVersion` varchar(32) CHARACTER SET utf8mb4 NOT NULL, + CONSTRAINT `PK___EFMigrationsHistory` PRIMARY KEY (`MigrationId`) +) CHARACTER SET utf8mb4; + +START TRANSACTION; + +ALTER DATABASE CHARACTER SET utf8mb4; + +CREATE TABLE `WorkflowSettings` ( + `Id` varchar(255) CHARACTER SET utf8mb4 NOT NULL, + `WorkflowBlueprintId` varchar(255) CHARACTER SET utf8mb4 NULL, + `Key` varchar(255) CHARACTER SET utf8mb4 NULL, + `Value` varchar(255) CHARACTER SET utf8mb4 NULL, + CONSTRAINT `PK_WorkflowSettings` PRIMARY KEY (`Id`) +) CHARACTER SET utf8mb4; + +CREATE INDEX `IX_WorkflowSetting_Key` ON `WorkflowSettings` (`Key`); + +CREATE INDEX `IX_WorkflowSetting_Value` ON `WorkflowSettings` (`Value`); + +CREATE INDEX `IX_WorkflowSetting_WorkflowBlueprintId` ON `WorkflowSettings` (`WorkflowBlueprintId`); + +INSERT INTO `__EFMigrationsHistory` (`MigrationId`, `ProductVersion`) +VALUES ('20210730112043_Initial', '5.0.10'); + +COMMIT; diff --git a/aspnet-core/modules/elsa/LINGYUN.Abp.Elsa.EntityFrameworkCore.MySql/LINGYUN/Abp/Elsa/EntityFrameworkCore/MySql/Migrations/MySqlElsaDataBaseInstaller.cs b/aspnet-core/modules/elsa/LINGYUN.Abp.Elsa.EntityFrameworkCore.MySql/LINGYUN/Abp/Elsa/EntityFrameworkCore/MySql/Migrations/MySqlElsaDataBaseInstaller.cs new file mode 100644 index 000000000..2c3fbdddb --- /dev/null +++ b/aspnet-core/modules/elsa/LINGYUN.Abp.Elsa.EntityFrameworkCore.MySql/LINGYUN/Abp/Elsa/EntityFrameworkCore/MySql/Migrations/MySqlElsaDataBaseInstaller.cs @@ -0,0 +1,130 @@ +using LINGYUN.Abp.Elsa.EntityFrameworkCore.Migrations; +using Microsoft.Extensions.FileProviders; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; +using MySqlConnector; +using System; +using System.Data; +using System.Threading.Tasks; +using Volo.Abp.Data; +using Volo.Abp.DependencyInjection; +using Volo.Abp.VirtualFileSystem; + +namespace LINGYUN.Abp.Elsa.EntityFrameworkCore.MySql.Migrations; + +[Dependency(ReplaceServices = true)] +public class MySqlElsaDataBaseInstaller : IElsaDataBaseInstaller, ITransientDependency +{ + public ILogger Logger { protected get; set; } + + private readonly IVirtualFileProvider _virtualFileProvider; + private readonly IConnectionStringResolver _connectionStringResolver; + + public MySqlElsaDataBaseInstaller( + IVirtualFileProvider virtualFileProvider, + IConnectionStringResolver connectionStringResolver) + { + _virtualFileProvider = virtualFileProvider; + _connectionStringResolver = connectionStringResolver; + + Logger = NullLogger.Instance; + } + + public async virtual Task InstallAsync() + { + var connectionString = await _connectionStringResolver.ResolveAsync("Workflow"); + if (connectionString.IsNullOrWhiteSpace()) + { + Logger.LogWarning("Please configure the `Workflow` database connection string Workflow!"); + throw new ArgumentNullException(nameof(connectionString)); + } + + var builder = new MySqlConnectionStringBuilder(connectionString); + + var dataBaseName = await CreateDataBaseIfNotExists(builder.Database, builder); + + builder.Database = dataBaseName; + + using var mySqlConnection = new MySqlConnection(builder.ConnectionString); + + if (mySqlConnection.State == ConnectionState.Closed) + { + await mySqlConnection.OpenAsync(); + } + + using (var mySqlCommand = new MySqlCommand("SELECT COUNT(1) FROM `information_schema`.`TABLES` WHERE `TABLE_SCHEMA` = @DataBaseName;", mySqlConnection)) + { + mySqlCommand.Parameters.Add("@DataBaseName", MySqlDbType.String).Value = dataBaseName; + + var rowsAffects = await mySqlCommand.ExecuteScalarAsync() as long?; + if (rowsAffects > 0) + { + Logger.LogInformation($"The `{dataBaseName}` database has already exists."); + return; + } + } + + var sqlScript = await GetInitSqlScript(); + + // USE `${DataBase}` -> USE `Workflow`;; + sqlScript = sqlScript.ReplaceFirst("${DataBase}", dataBaseName); + + using (var mySqlCommand = new MySqlCommand(sqlScript, mySqlConnection)) + { + Logger.LogInformation("The database initialization script `Initial.sql` starts..."); + + await mySqlCommand.ExecuteNonQueryAsync(); + } + + Logger.LogInformation("Database initialization script `Initial.sql` complete!"); + } + + public async virtual Task CreateDataBaseIfNotExists(string dataBase, MySqlConnectionStringBuilder connectionStringBuilder) + { + // 切换主数据库查询数据库是否存在 + connectionStringBuilder.Database = "mysql"; + using var mySqlConnection = new MySqlConnection(connectionStringBuilder.ConnectionString); + if (mySqlConnection.State == ConnectionState.Closed) + { + await mySqlConnection.OpenAsync(); + } + + var checkDataBaseName = ""; + using (var mySqlCommand = new MySqlCommand("SELECT `SCHEMA_NAME` FROM `information_schema`.`SCHEMATA` WHERE `SCHEMA_NAME` = @DataBaseName;", mySqlConnection)) + { + var dataBaseParamter = mySqlCommand.Parameters.Add("DataBaseName", DbType.String); + dataBaseParamter.Value = dataBase; + + checkDataBaseName = await mySqlCommand.ExecuteScalarAsync() as string; + } + + if (checkDataBaseName.IsNullOrWhiteSpace()) + { + using (var mySqlCommand = new MySqlCommand($"CREATE DATABASE `{dataBase}` CHARACTER SET 'utf8mb4' COLLATE 'utf8mb4_general_ci';", mySqlConnection)) + { + await mySqlCommand.ExecuteNonQueryAsync(); + } + } + + return dataBase; + } + + public async virtual Task GetInitSqlScript() + { + var sqlScriptFileInfo = _virtualFileProvider.GetFileInfo("/LINGYUN/Abp/Elsa/EntityFrameworkCore/MySql/Migrations/Initial.sql"); + if (!sqlScriptFileInfo.Exists || sqlScriptFileInfo.IsDirectory) + { + Logger.LogWarning("Please Check that the `Initial.sql` file exists!"); + throw new InvalidOperationException("The `Initial.sql` database initialization script file does not exist or is not valid!"); + } + + var sqlScript = await sqlScriptFileInfo.ReadAsStringAsync(); + if (sqlScript.IsNullOrWhiteSpace()) + { + Logger.LogWarning("The contents of the `Initial.sql` file are empty or invalid!"); + throw new InvalidOperationException("The contents of the `Initial.sql` file are empty or invalid!"); + } + + return sqlScript; + } +} diff --git a/aspnet-core/modules/elsa/LINGYUN.Abp.Elsa.EntityFrameworkCore/LINGYUN/Abp/Elsa/EntityFrameworkCore/AbpElsaEntityFrameworkCoreModule.cs b/aspnet-core/modules/elsa/LINGYUN.Abp.Elsa.EntityFrameworkCore/LINGYUN/Abp/Elsa/EntityFrameworkCore/AbpElsaEntityFrameworkCoreModule.cs index 8d5ba8a20..025f6fb61 100644 --- a/aspnet-core/modules/elsa/LINGYUN.Abp.Elsa.EntityFrameworkCore/LINGYUN/Abp/Elsa/EntityFrameworkCore/AbpElsaEntityFrameworkCoreModule.cs +++ b/aspnet-core/modules/elsa/LINGYUN.Abp.Elsa.EntityFrameworkCore/LINGYUN/Abp/Elsa/EntityFrameworkCore/AbpElsaEntityFrameworkCoreModule.cs @@ -1,4 +1,8 @@ -using Volo.Abp.EntityFrameworkCore; +using LINGYUN.Abp.Elsa.EntityFrameworkCore.Migrations; +using Microsoft.Extensions.DependencyInjection; +using System.Threading.Tasks; +using Volo.Abp; +using Volo.Abp.EntityFrameworkCore; using Volo.Abp.Modularity; namespace LINGYUN.Abp.Elsa.EntityFrameworkCore; @@ -8,4 +12,11 @@ namespace LINGYUN.Abp.Elsa.EntityFrameworkCore; typeof(AbpEntityFrameworkCoreModule))] public class AbpElsaEntityFrameworkCoreModule : AbpModule { + public async override Task OnPreApplicationInitializationAsync(ApplicationInitializationContext context) + { + // 实现 IElsaStoreMigrator 接口自动初始化数据库 + await context.ServiceProvider + .GetService() + ?.InstallAsync(); + } } diff --git a/aspnet-core/modules/elsa/LINGYUN.Abp.Elsa.EntityFrameworkCore/LINGYUN/Abp/Elsa/EntityFrameworkCore/Migrations/IElsaDataBaseInstaller.cs b/aspnet-core/modules/elsa/LINGYUN.Abp.Elsa.EntityFrameworkCore/LINGYUN/Abp/Elsa/EntityFrameworkCore/Migrations/IElsaDataBaseInstaller.cs new file mode 100644 index 000000000..14a98839a --- /dev/null +++ b/aspnet-core/modules/elsa/LINGYUN.Abp.Elsa.EntityFrameworkCore/LINGYUN/Abp/Elsa/EntityFrameworkCore/Migrations/IElsaDataBaseInstaller.cs @@ -0,0 +1,8 @@ +using System.Threading.Tasks; + +namespace LINGYUN.Abp.Elsa.EntityFrameworkCore.Migrations; + +public interface IElsaDataBaseInstaller +{ + Task InstallAsync(); +} From a1beec4be943697cd99affa38c0266845188053f Mon Sep 17 00:00:00 2001 From: colin Date: Wed, 2 Apr 2025 08:18:40 +0800 Subject: [PATCH 2/4] feat(quartz): Added automatic migration of Quartz database --- .../FodyWeavers.xml | 3 + .../LINGYUN.Abp.Quartz.MySqlInstaller.csproj | 30 ++ .../AbpQuartzMySqlInstallerModule.cs | 30 ++ .../MySqlInstaller/QuartzMySqlInstaller.cs | 136 +++++++ .../Quartz/MySqlInstaller/Scripts/Initial.sql | 181 +++++++++ .../FodyWeavers.xml | 3 + ...NGYUN.Abp.Quartz.SqlServerInstaller.csproj | 30 ++ .../AbpQuartzSqlServerInstallerModule.cs | 30 ++ .../QuartzSqlServerInstaller.cs | 136 +++++++ .../SqlServerInstaller/Scripts/Initial.sql | 370 ++++++++++++++++++ 10 files changed, 949 insertions(+) create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.Quartz.MySqlInstaller/FodyWeavers.xml create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.Quartz.MySqlInstaller/LINGYUN.Abp.Quartz.MySqlInstaller.csproj create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.Quartz.MySqlInstaller/LINGYUN/Abp/Quartz/MySqlInstaller/AbpQuartzMySqlInstallerModule.cs create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.Quartz.MySqlInstaller/LINGYUN/Abp/Quartz/MySqlInstaller/QuartzMySqlInstaller.cs create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.Quartz.MySqlInstaller/LINGYUN/Abp/Quartz/MySqlInstaller/Scripts/Initial.sql create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.Quartz.SqlServerInstaller/FodyWeavers.xml create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.Quartz.SqlServerInstaller/LINGYUN.Abp.Quartz.SqlServerInstaller.csproj create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.Quartz.SqlServerInstaller/LINGYUN/Abp/Quartz/SqlServerInstaller/AbpQuartzSqlServerInstallerModule.cs create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.Quartz.SqlServerInstaller/LINGYUN/Abp/Quartz/SqlServerInstaller/QuartzSqlServerInstaller.cs create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.Quartz.SqlServerInstaller/LINGYUN/Abp/Quartz/SqlServerInstaller/Scripts/Initial.sql diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.Quartz.MySqlInstaller/FodyWeavers.xml b/aspnet-core/modules/task-management/LINGYUN.Abp.Quartz.MySqlInstaller/FodyWeavers.xml new file mode 100644 index 000000000..1715698cc --- /dev/null +++ b/aspnet-core/modules/task-management/LINGYUN.Abp.Quartz.MySqlInstaller/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.Quartz.MySqlInstaller/LINGYUN.Abp.Quartz.MySqlInstaller.csproj b/aspnet-core/modules/task-management/LINGYUN.Abp.Quartz.MySqlInstaller/LINGYUN.Abp.Quartz.MySqlInstaller.csproj new file mode 100644 index 000000000..7f15d10c2 --- /dev/null +++ b/aspnet-core/modules/task-management/LINGYUN.Abp.Quartz.MySqlInstaller/LINGYUN.Abp.Quartz.MySqlInstaller.csproj @@ -0,0 +1,30 @@ + + + + + + + netstandard2.0;netstandard2.1;net8.0;net9.0 + LINGYUN.Abp.Quartz.MySqlInstaller + LINGYUN.Abp.Quartz.MySqlInstaller + false + false + false + + + + + + + + + + + + + + + + + + diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.Quartz.MySqlInstaller/LINGYUN/Abp/Quartz/MySqlInstaller/AbpQuartzMySqlInstallerModule.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.Quartz.MySqlInstaller/LINGYUN/Abp/Quartz/MySqlInstaller/AbpQuartzMySqlInstallerModule.cs new file mode 100644 index 000000000..b7878f537 --- /dev/null +++ b/aspnet-core/modules/task-management/LINGYUN.Abp.Quartz.MySqlInstaller/LINGYUN/Abp/Quartz/MySqlInstaller/AbpQuartzMySqlInstallerModule.cs @@ -0,0 +1,30 @@ +using Microsoft.Extensions.DependencyInjection; +using System.Threading.Tasks; +using Volo.Abp; +using Volo.Abp.Modularity; +using Volo.Abp.Quartz; +using Volo.Abp.VirtualFileSystem; + +namespace LINGYUN.Abp.Quartz.MySqlInstaller; + +[DependsOn( + typeof(AbpQuartzModule), + typeof(AbpVirtualFileSystemModule))] +public class AbpQuartzMySqlInstallerModule : AbpModule +{ + public override void ConfigureServices(ServiceConfigurationContext context) + { + Configure(options => + { + options.FileSets.AddEmbedded(); + }); + } + + public async override Task OnPreApplicationInitializationAsync(ApplicationInitializationContext context) + { + // 初始化 Quartz Mysql 数据库 + await context.ServiceProvider + .GetRequiredService() + .InstallAsync(); + } +} \ No newline at end of file diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.Quartz.MySqlInstaller/LINGYUN/Abp/Quartz/MySqlInstaller/QuartzMySqlInstaller.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.Quartz.MySqlInstaller/LINGYUN/Abp/Quartz/MySqlInstaller/QuartzMySqlInstaller.cs new file mode 100644 index 000000000..40e6dfb22 --- /dev/null +++ b/aspnet-core/modules/task-management/LINGYUN.Abp.Quartz.MySqlInstaller/LINGYUN/Abp/Quartz/MySqlInstaller/QuartzMySqlInstaller.cs @@ -0,0 +1,136 @@ +using Microsoft.Extensions.FileProviders; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; +using Microsoft.Extensions.Options; +using MySqlConnector; +using System; +using System.Data; +using System.Threading.Tasks; +using Volo.Abp.Quartz; +using Volo.Abp.VirtualFileSystem; +using static Quartz.SchedulerBuilder; + +namespace LINGYUN.Abp.Quartz.MySqlInstaller; + +public class QuartzMySqlInstaller +{ + public ILogger Logger { protected get; set; } + + private readonly IVirtualFileProvider _virtualFileProvider; + private readonly AbpQuartzOptions _quartzOptions; + + public QuartzMySqlInstaller( + IVirtualFileProvider virtualFileProvider, + IOptions quartzOptions) + { + _quartzOptions = quartzOptions.Value; + _virtualFileProvider = virtualFileProvider; + + Logger = NullLogger.Instance; + } + + public async virtual Task InstallAsync() + { + var dataSource = _quartzOptions.Properties["quartz.jobStore.dataSource"] ?? AdoProviderOptions.DefaultDataSourceName; + var connectionString = _quartzOptions.Properties[$"quartz.dataSource.{dataSource}.connectionString"]; + var tablePrefix = _quartzOptions.Properties["quartz.jobStore.tablePrefix"] ?? "QRTZ_"; + + if (connectionString.IsNullOrWhiteSpace()) + { + Logger.LogWarning($"Please configure the `{dataSource}` database connection string in `quartz.jobStore.dataSource`!"); + throw new ArgumentNullException(nameof(connectionString)); + } + + Logger.LogInformation("Install Quartz MySql..."); + + var builder = new MySqlConnectionStringBuilder(connectionString); + + var dataBaseName = await CreateDataBaseIfNotExists(builder.Database, builder); + + builder.Database = dataBaseName; + + using var mySqlConnection = new MySqlConnection(builder.ConnectionString); + + if (mySqlConnection.State == ConnectionState.Closed) + { + await mySqlConnection.OpenAsync(); + } + + using (var mySqlCommand = new MySqlCommand("SELECT COUNT(1) FROM `information_schema`.`TABLES` WHERE `TABLE_SCHEMA` = @DataBaseName;", mySqlConnection)) + { + mySqlCommand.Parameters.Add("@DataBaseName", MySqlDbType.String).Value = dataBaseName; + + var rowsAffects = await mySqlCommand.ExecuteScalarAsync() as long?; + if (rowsAffects > 0) + { + Logger.LogInformation($"The `{dataBaseName}` tables has already exists."); + return; + } + } + + var sqlScript = await GetInitSqlScript(); + + // USE `${DataBase}` -> USE `Workflow`; + sqlScript = sqlScript.ReplaceFirst("${DataBase}", dataBaseName); + // CREATE TABLE $(TablePrefix)JOB_DETAILS` -> CREATE TABLE QRTZ_JOB_DETAILS; + sqlScript = sqlScript.Replace("${TablePrefix}", tablePrefix); + + using (var mySqlCommand = new MySqlCommand(sqlScript, mySqlConnection)) + { + Logger.LogInformation("The database initialization script `Initial.sql` starts..."); + + await mySqlCommand.ExecuteNonQueryAsync(); + } + + Logger.LogInformation("Database initialization script `Initial.sql` complete!"); + } + + public async virtual Task CreateDataBaseIfNotExists(string dataBase, MySqlConnectionStringBuilder connectionStringBuilder) + { + // 切换主数据库查询数据库是否存在 + connectionStringBuilder.Database = "mysql"; + using var mySqlConnection = new MySqlConnection(connectionStringBuilder.ConnectionString); + if (mySqlConnection.State == ConnectionState.Closed) + { + await mySqlConnection.OpenAsync(); + } + + var checkDataBaseName = ""; + using (var mySqlCommand = new MySqlCommand("SELECT `SCHEMA_NAME` FROM `information_schema`.`SCHEMATA` WHERE `SCHEMA_NAME` = @DataBaseName;", mySqlConnection)) + { + var dataBaseParamter = mySqlCommand.Parameters.Add("DataBaseName", DbType.String); + dataBaseParamter.Value = dataBase; + + checkDataBaseName = await mySqlCommand.ExecuteScalarAsync() as string; + } + + if (checkDataBaseName.IsNullOrWhiteSpace()) + { + using (var mySqlCommand = new MySqlCommand($"CREATE DATABASE `{dataBase}` CHARACTER SET 'utf8mb4' COLLATE 'utf8mb4_general_ci';", mySqlConnection)) + { + await mySqlCommand.ExecuteNonQueryAsync(); + } + } + + return dataBase; + } + + public async virtual Task GetInitSqlScript() + { + var sqlScriptFileInfo = _virtualFileProvider.GetFileInfo("/LINGYUN/Abp/Quartz/MySqlInstaller/Scripts/Initial.sql"); + if (!sqlScriptFileInfo.Exists || sqlScriptFileInfo.IsDirectory) + { + Logger.LogWarning("Please Check that the `Initial.sql` file exists!"); + throw new InvalidOperationException("The `Initial.sql` database initialization script file does not exist or is not valid!"); + } + + var sqlScript = await sqlScriptFileInfo.ReadAsStringAsync(); + if (sqlScript.IsNullOrWhiteSpace()) + { + Logger.LogWarning("The contents of the `Initial.sql` file are empty or invalid!"); + throw new InvalidOperationException("The contents of the `Initial.sql` file are empty or invalid!"); + } + + return sqlScript; + } +} diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.Quartz.MySqlInstaller/LINGYUN/Abp/Quartz/MySqlInstaller/Scripts/Initial.sql b/aspnet-core/modules/task-management/LINGYUN.Abp.Quartz.MySqlInstaller/LINGYUN/Abp/Quartz/MySqlInstaller/Scripts/Initial.sql new file mode 100644 index 000000000..85a70bfff --- /dev/null +++ b/aspnet-core/modules/task-management/LINGYUN.Abp.Quartz.MySqlInstaller/LINGYUN/Abp/Quartz/MySqlInstaller/Scripts/Initial.sql @@ -0,0 +1,181 @@ +# By: Ron Cordell - roncordell +# I didn't see this anywhere, so I thought I'd post it here. This is the script from Quartz to create the tables in a MySQL database, modified to use INNODB instead of MYISAM. + + +# make sure you have UTF-8 collaction for best .NET interoperability +# CREATE DATABASE quartznet CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + +USE `${DataBase}`; + +DROP TABLE IF EXISTS ${TablePrefix}FIRED_TRIGGERS; +DROP TABLE IF EXISTS ${TablePrefix}PAUSED_TRIGGER_GRPS; +DROP TABLE IF EXISTS ${TablePrefix}SCHEDULER_STATE; +DROP TABLE IF EXISTS ${TablePrefix}LOCKS; +DROP TABLE IF EXISTS ${TablePrefix}SIMPLE_TRIGGERS; +DROP TABLE IF EXISTS ${TablePrefix}SIMPROP_TRIGGERS; +DROP TABLE IF EXISTS ${TablePrefix}CRON_TRIGGERS; +DROP TABLE IF EXISTS ${TablePrefix}BLOB_TRIGGERS; +DROP TABLE IF EXISTS ${TablePrefix}TRIGGERS; +DROP TABLE IF EXISTS ${TablePrefix}JOB_DETAILS; +DROP TABLE IF EXISTS ${TablePrefix}CALENDARS; + +CREATE TABLE ${TablePrefix}JOB_DETAILS( +SCHED_NAME VARCHAR(120) NOT NULL, +JOB_NAME VARCHAR(200) NOT NULL, +JOB_GROUP VARCHAR(200) NOT NULL, +DESCRIPTION VARCHAR(250) NULL, +JOB_CLASS_NAME VARCHAR(250) NOT NULL, +IS_DURABLE BOOLEAN NOT NULL, +IS_NONCONCURRENT BOOLEAN NOT NULL, +IS_UPDATE_DATA BOOLEAN NOT NULL, +REQUESTS_RECOVERY BOOLEAN NOT NULL, +JOB_DATA BLOB NULL, +PRIMARY KEY (SCHED_NAME,JOB_NAME,JOB_GROUP)) +ENGINE=InnoDB; + +CREATE TABLE ${TablePrefix}TRIGGERS ( +SCHED_NAME VARCHAR(120) NOT NULL, +TRIGGER_NAME VARCHAR(200) NOT NULL, +TRIGGER_GROUP VARCHAR(200) NOT NULL, +JOB_NAME VARCHAR(200) NOT NULL, +JOB_GROUP VARCHAR(200) NOT NULL, +DESCRIPTION VARCHAR(250) NULL, +NEXT_FIRE_TIME BIGINT(19) NULL, +PREV_FIRE_TIME BIGINT(19) NULL, +PRIORITY INTEGER NULL, +TRIGGER_STATE VARCHAR(16) NOT NULL, +TRIGGER_TYPE VARCHAR(8) NOT NULL, +START_TIME BIGINT(19) NOT NULL, +END_TIME BIGINT(19) NULL, +CALENDAR_NAME VARCHAR(200) NULL, +MISFIRE_INSTR SMALLINT(2) NULL, +JOB_DATA BLOB NULL, +PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP), +FOREIGN KEY (SCHED_NAME,JOB_NAME,JOB_GROUP) +REFERENCES ${TablePrefix}JOB_DETAILS(SCHED_NAME,JOB_NAME,JOB_GROUP)) +ENGINE=InnoDB; + +CREATE TABLE ${TablePrefix}SIMPLE_TRIGGERS ( +SCHED_NAME VARCHAR(120) NOT NULL, +TRIGGER_NAME VARCHAR(200) NOT NULL, +TRIGGER_GROUP VARCHAR(200) NOT NULL, +REPEAT_COUNT BIGINT(7) NOT NULL, +REPEAT_INTERVAL BIGINT(12) NOT NULL, +TIMES_TRIGGERED BIGINT(10) NOT NULL, +PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP), +FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) +REFERENCES ${TablePrefix}TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)) +ENGINE=InnoDB; + +CREATE TABLE ${TablePrefix}CRON_TRIGGERS ( +SCHED_NAME VARCHAR(120) NOT NULL, +TRIGGER_NAME VARCHAR(200) NOT NULL, +TRIGGER_GROUP VARCHAR(200) NOT NULL, +CRON_EXPRESSION VARCHAR(120) NOT NULL, +TIME_ZONE_ID VARCHAR(80), +PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP), +FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) +REFERENCES ${TablePrefix}TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)) +ENGINE=InnoDB; + +CREATE TABLE ${TablePrefix}SIMPROP_TRIGGERS + ( + SCHED_NAME VARCHAR(120) NOT NULL, + TRIGGER_NAME VARCHAR(200) NOT NULL, + TRIGGER_GROUP VARCHAR(200) NOT NULL, + STR_PROP_1 VARCHAR(512) NULL, + STR_PROP_2 VARCHAR(512) NULL, + STR_PROP_3 VARCHAR(512) NULL, + INT_PROP_1 INT NULL, + INT_PROP_2 INT NULL, + LONG_PROP_1 BIGINT NULL, + LONG_PROP_2 BIGINT NULL, + DEC_PROP_1 NUMERIC(13,4) NULL, + DEC_PROP_2 NUMERIC(13,4) NULL, + BOOL_PROP_1 BOOLEAN NULL, + BOOL_PROP_2 BOOLEAN NULL, + TIME_ZONE_ID VARCHAR(80) NULL, + PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP), + FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) + REFERENCES ${TablePrefix}TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)) +ENGINE=InnoDB; + +CREATE TABLE ${TablePrefix}BLOB_TRIGGERS ( +SCHED_NAME VARCHAR(120) NOT NULL, +TRIGGER_NAME VARCHAR(200) NOT NULL, +TRIGGER_GROUP VARCHAR(200) NOT NULL, +BLOB_DATA BLOB NULL, +PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP), +INDEX (SCHED_NAME,TRIGGER_NAME, TRIGGER_GROUP), +FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) +REFERENCES ${TablePrefix}TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)) +ENGINE=InnoDB; + +CREATE TABLE ${TablePrefix}CALENDARS ( +SCHED_NAME VARCHAR(120) NOT NULL, +CALENDAR_NAME VARCHAR(200) NOT NULL, +CALENDAR BLOB NOT NULL, +PRIMARY KEY (SCHED_NAME,CALENDAR_NAME)) +ENGINE=InnoDB; + +CREATE TABLE ${TablePrefix}PAUSED_TRIGGER_GRPS ( +SCHED_NAME VARCHAR(120) NOT NULL, +TRIGGER_GROUP VARCHAR(200) NOT NULL, +PRIMARY KEY (SCHED_NAME,TRIGGER_GROUP)) +ENGINE=InnoDB; + +CREATE TABLE ${TablePrefix}FIRED_TRIGGERS ( +SCHED_NAME VARCHAR(120) NOT NULL, +ENTRY_ID VARCHAR(140) NOT NULL, +TRIGGER_NAME VARCHAR(200) NOT NULL, +TRIGGER_GROUP VARCHAR(200) NOT NULL, +INSTANCE_NAME VARCHAR(200) NOT NULL, +FIRED_TIME BIGINT(19) NOT NULL, +SCHED_TIME BIGINT(19) NOT NULL, +PRIORITY INTEGER NOT NULL, +STATE VARCHAR(16) NOT NULL, +JOB_NAME VARCHAR(200) NULL, +JOB_GROUP VARCHAR(200) NULL, +IS_NONCONCURRENT BOOLEAN NULL, +REQUESTS_RECOVERY BOOLEAN NULL, +PRIMARY KEY (SCHED_NAME,ENTRY_ID)) +ENGINE=InnoDB; + +CREATE TABLE ${TablePrefix}SCHEDULER_STATE ( +SCHED_NAME VARCHAR(120) NOT NULL, +INSTANCE_NAME VARCHAR(200) NOT NULL, +LAST_CHECKIN_TIME BIGINT(19) NOT NULL, +CHECKIN_INTERVAL BIGINT(19) NOT NULL, +PRIMARY KEY (SCHED_NAME,INSTANCE_NAME)) +ENGINE=InnoDB; + +CREATE TABLE ${TablePrefix}LOCKS ( +SCHED_NAME VARCHAR(120) NOT NULL, +LOCK_NAME VARCHAR(40) NOT NULL, +PRIMARY KEY (SCHED_NAME,LOCK_NAME)) +ENGINE=InnoDB; + +CREATE INDEX IDX_${TablePrefix}J_REQ_RECOVERY ON ${TablePrefix}JOB_DETAILS(SCHED_NAME,REQUESTS_RECOVERY); +CREATE INDEX IDX_${TablePrefix}J_GRP ON ${TablePrefix}JOB_DETAILS(SCHED_NAME,JOB_GROUP); + +CREATE INDEX IDX_${TablePrefix}T_J ON ${TablePrefix}TRIGGERS(SCHED_NAME,JOB_NAME,JOB_GROUP); +CREATE INDEX IDX_${TablePrefix}T_JG ON ${TablePrefix}TRIGGERS(SCHED_NAME,JOB_GROUP); +CREATE INDEX IDX_${TablePrefix}T_C ON ${TablePrefix}TRIGGERS(SCHED_NAME,CALENDAR_NAME); +CREATE INDEX IDX_${TablePrefix}T_G ON ${TablePrefix}TRIGGERS(SCHED_NAME,TRIGGER_GROUP); +CREATE INDEX IDX_${TablePrefix}T_STATE ON ${TablePrefix}TRIGGERS(SCHED_NAME,TRIGGER_STATE); +CREATE INDEX IDX_${TablePrefix}T_N_STATE ON ${TablePrefix}TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP,TRIGGER_STATE); +CREATE INDEX IDX_${TablePrefix}T_N_G_STATE ON ${TablePrefix}TRIGGERS(SCHED_NAME,TRIGGER_GROUP,TRIGGER_STATE); +CREATE INDEX IDX_${TablePrefix}T_NEXT_FIRE_TIME ON ${TablePrefix}TRIGGERS(SCHED_NAME,NEXT_FIRE_TIME); +CREATE INDEX IDX_${TablePrefix}T_NFT_ST ON ${TablePrefix}TRIGGERS(SCHED_NAME,TRIGGER_STATE,NEXT_FIRE_TIME); +CREATE INDEX IDX_${TablePrefix}T_NFT_MISFIRE ON ${TablePrefix}TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME); +CREATE INDEX IDX_${TablePrefix}T_NFT_ST_MISFIRE ON ${TablePrefix}TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_STATE); +CREATE INDEX IDX_${TablePrefix}T_NFT_ST_MISFIRE_GRP ON ${TablePrefix}TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_GROUP,TRIGGER_STATE); + +CREATE INDEX IDX_${TablePrefix}FT_TRIG_INST_NAME ON ${TablePrefix}FIRED_TRIGGERS(SCHED_NAME,INSTANCE_NAME); +CREATE INDEX IDX_${TablePrefix}FT_INST_JOB_REQ_RCVRY ON ${TablePrefix}FIRED_TRIGGERS(SCHED_NAME,INSTANCE_NAME,REQUESTS_RECOVERY); +CREATE INDEX IDX_${TablePrefix}FT_J_G ON ${TablePrefix}FIRED_TRIGGERS(SCHED_NAME,JOB_NAME,JOB_GROUP); +CREATE INDEX IDX_${TablePrefix}FT_JG ON ${TablePrefix}FIRED_TRIGGERS(SCHED_NAME,JOB_GROUP); +CREATE INDEX IDX_${TablePrefix}FT_T_G ON ${TablePrefix}FIRED_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP); +CREATE INDEX IDX_${TablePrefix}FT_TG ON ${TablePrefix}FIRED_TRIGGERS(SCHED_NAME,TRIGGER_GROUP); + +commit; \ No newline at end of file diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.Quartz.SqlServerInstaller/FodyWeavers.xml b/aspnet-core/modules/task-management/LINGYUN.Abp.Quartz.SqlServerInstaller/FodyWeavers.xml new file mode 100644 index 000000000..1715698cc --- /dev/null +++ b/aspnet-core/modules/task-management/LINGYUN.Abp.Quartz.SqlServerInstaller/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.Quartz.SqlServerInstaller/LINGYUN.Abp.Quartz.SqlServerInstaller.csproj b/aspnet-core/modules/task-management/LINGYUN.Abp.Quartz.SqlServerInstaller/LINGYUN.Abp.Quartz.SqlServerInstaller.csproj new file mode 100644 index 000000000..e8ae8b21b --- /dev/null +++ b/aspnet-core/modules/task-management/LINGYUN.Abp.Quartz.SqlServerInstaller/LINGYUN.Abp.Quartz.SqlServerInstaller.csproj @@ -0,0 +1,30 @@ + + + + + + + netstandard2.0;netstandard2.1;net8.0;net9.0 + LINGYUN.Abp.Quartz.SqlServerInstaller + LINGYUN.Abp.Quartz.SqlServerInstaller + false + false + false + + + + + + + + + + + + + + + + + + diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.Quartz.SqlServerInstaller/LINGYUN/Abp/Quartz/SqlServerInstaller/AbpQuartzSqlServerInstallerModule.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.Quartz.SqlServerInstaller/LINGYUN/Abp/Quartz/SqlServerInstaller/AbpQuartzSqlServerInstallerModule.cs new file mode 100644 index 000000000..c3c69701e --- /dev/null +++ b/aspnet-core/modules/task-management/LINGYUN.Abp.Quartz.SqlServerInstaller/LINGYUN/Abp/Quartz/SqlServerInstaller/AbpQuartzSqlServerInstallerModule.cs @@ -0,0 +1,30 @@ +using Microsoft.Extensions.DependencyInjection; +using System.Threading.Tasks; +using Volo.Abp; +using Volo.Abp.Modularity; +using Volo.Abp.Quartz; +using Volo.Abp.VirtualFileSystem; + +namespace LINGYUN.Abp.Quartz.SqlServerInstaller; + +[DependsOn( + typeof(AbpQuartzModule), + typeof(AbpVirtualFileSystemModule))] +public class AbpQuartzSqlServerInstallerModule : AbpModule +{ + public override void ConfigureServices(ServiceConfigurationContext context) + { + Configure(options => + { + options.FileSets.AddEmbedded(); + }); + } + + public async override Task OnPreApplicationInitializationAsync(ApplicationInitializationContext context) + { + // 初始化 Quartz SqlServer 数据库 + await context.ServiceProvider + .GetRequiredService() + .InstallAsync(); + } +} \ No newline at end of file diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.Quartz.SqlServerInstaller/LINGYUN/Abp/Quartz/SqlServerInstaller/QuartzSqlServerInstaller.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.Quartz.SqlServerInstaller/LINGYUN/Abp/Quartz/SqlServerInstaller/QuartzSqlServerInstaller.cs new file mode 100644 index 000000000..5d4ac3166 --- /dev/null +++ b/aspnet-core/modules/task-management/LINGYUN.Abp.Quartz.SqlServerInstaller/LINGYUN/Abp/Quartz/SqlServerInstaller/QuartzSqlServerInstaller.cs @@ -0,0 +1,136 @@ +using Microsoft.Data.SqlClient; +using Microsoft.Extensions.FileProviders; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; +using Microsoft.Extensions.Options; +using System; +using System.Data; +using System.Threading.Tasks; +using Volo.Abp.Quartz; +using Volo.Abp.VirtualFileSystem; +using static Quartz.SchedulerBuilder; + +namespace LINGYUN.Abp.Quartz.SqlServerInstaller; + +public class QuartzSqlServerInstaller +{ + public ILogger Logger { protected get; set; } + + private readonly IVirtualFileProvider _virtualFileProvider; + private readonly AbpQuartzOptions _quartzOptions; + + public QuartzSqlServerInstaller( + IVirtualFileProvider virtualFileProvider, + IOptions quartzOptions) + { + _quartzOptions = quartzOptions.Value; + _virtualFileProvider = virtualFileProvider; + + Logger = NullLogger.Instance; + } + + public async virtual Task InstallAsync() + { + var dataSource = _quartzOptions.Properties["quartz.jobStore.dataSource"] ?? AdoProviderOptions.DefaultDataSourceName; + var connectionString = _quartzOptions.Properties[$"quartz.dataSource.{dataSource}.connectionString"]; + var tablePrefix = _quartzOptions.Properties["quartz.jobStore.tablePrefix"] ?? "QRTZ_"; + + if (connectionString.IsNullOrWhiteSpace()) + { + Logger.LogWarning($"Please configure the `{dataSource}` database connection string in `quartz.jobStore.dataSource`!"); + throw new ArgumentNullException(nameof(connectionString)); + } + + Logger.LogInformation("Install Quartz SqlServer..."); + + var builder = new SqlConnectionStringBuilder(connectionString); + + var dataBaseName = await CreateDataBaseIfNotExists(builder.InitialCatalog, builder); + + builder.InitialCatalog = dataBaseName; + + using var sqlConnection = new SqlConnection(builder.ConnectionString); + + if (sqlConnection.State == ConnectionState.Closed) + { + await sqlConnection.OpenAsync(); + } + + using (var sqlCommand = new SqlCommand("SELECT COUNT(1) FROM [sys].[objects] WHERE type=N'U'", sqlConnection)) + { + sqlCommand.Parameters.Add("@DataBaseName", SqlDbType.NVarChar).Value = dataBaseName; + + var rowsAffects = await sqlCommand.ExecuteScalarAsync() as long?; + if (rowsAffects > 0) + { + Logger.LogInformation($"The `{dataBaseName}` tables has already exists."); + return; + } + } + + var sqlScript = await GetInitSqlScript(); + + // USE `${DataBase}` -> USE `Workflow`; + sqlScript = sqlScript.ReplaceFirst("${DataBase}", dataBaseName); + // CREATE TABLE $(TablePrefix)JOB_DETAILS` -> CREATE TABLE QRTZ_JOB_DETAILS; + sqlScript = sqlScript.Replace("${TablePrefix}", tablePrefix); + + using (var sqlCommand = new SqlCommand(sqlScript, sqlConnection)) + { + Logger.LogInformation("The database initialization script `Initial.sql` starts..."); + + await sqlCommand.ExecuteNonQueryAsync(); + } + + Logger.LogInformation("Database initialization script `Initial.sql` complete!"); + } + + public async virtual Task CreateDataBaseIfNotExists(string dataBase, SqlConnectionStringBuilder connectionStringBuilder) + { + // 切换主数据库查询数据库是否存在 + connectionStringBuilder.InitialCatalog = "master"; + using var sqlConnection = new SqlConnection(connectionStringBuilder.ConnectionString); + if (sqlConnection.State == ConnectionState.Closed) + { + await sqlConnection.OpenAsync(); + } + + var checkDataBaseName = ""; + using (var sqlCommand = new SqlCommand("SELECT [name] FROM [master].[dbo].[sysdatabases] WHERE [name] = @DataBaseName;", sqlConnection)) + { + var dataBaseParamter = sqlCommand.Parameters.Add("DataBaseName", SqlDbType.NVarChar); + dataBaseParamter.Value = dataBase; + + checkDataBaseName = await sqlCommand.ExecuteScalarAsync() as string; + } + + if (checkDataBaseName.IsNullOrWhiteSpace()) + { + using (var sqlCommand = new SqlCommand($"CREATE DATABASE {dataBase};", sqlConnection)) + { + await sqlCommand.ExecuteNonQueryAsync(); + } + } + + return dataBase; + } + + public async virtual Task GetInitSqlScript() + { + var sqlScriptFileInfo = _virtualFileProvider.GetFileInfo("/LINGYUN/Abp/Quartz/SqlServerInstaller/Scripts/Initial.sql"); + if (!sqlScriptFileInfo.Exists || sqlScriptFileInfo.IsDirectory) + { + Logger.LogWarning("Please Check that the `Initial.sql` file exists!"); + throw new InvalidOperationException("The `Initial.sql` database initialization script file does not exist or is not valid!"); + } + + var sqlScript = await sqlScriptFileInfo.ReadAsStringAsync(); + if (sqlScript.IsNullOrWhiteSpace()) + { + Logger.LogWarning("The contents of the `Initial.sql` file are empty or invalid!"); + throw new InvalidOperationException("The contents of the `Initial.sql` file are empty or invalid!"); + } + + return sqlScript; + } +} diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.Quartz.SqlServerInstaller/LINGYUN/Abp/Quartz/SqlServerInstaller/Scripts/Initial.sql b/aspnet-core/modules/task-management/LINGYUN.Abp.Quartz.SqlServerInstaller/LINGYUN/Abp/Quartz/SqlServerInstaller/Scripts/Initial.sql new file mode 100644 index 000000000..5c4478d7d --- /dev/null +++ b/aspnet-core/modules/task-management/LINGYUN.Abp.Quartz.SqlServerInstaller/LINGYUN/Abp/Quartz/SqlServerInstaller/Scripts/Initial.sql @@ -0,0 +1,370 @@ +-- this script is for SQL Server and Azure SQL + +-- This initializes the database to pristine for Quartz, by first removing any existing Quartz tables +-- and then recreating them from scratch. +-- Should you only require it to create the tables, set @DropDb to 0. + +USE [${DataBase}]; +GO + +DECLARE @DropDb BIT = 1; -- Set this to 0 to skip DROP statements, 1 to include them + +IF @DropDb = 1 +BEGIN + -- drop indexes if they exist and rebuild if current ones + DROP INDEX IF EXISTS [IDX_${TablePrefix}T_J] ON [dbo].[${TablePrefix}TRIGGERS]; + DROP INDEX IF EXISTS [IDX_${TablePrefix}T_JG] ON [dbo].[${TablePrefix}TRIGGERS]; + DROP INDEX IF EXISTS [IDX_${TablePrefix}T_C] ON [dbo].[${TablePrefix}TRIGGERS]; + DROP INDEX IF EXISTS [IDX_${TablePrefix}T_G] ON [dbo].[${TablePrefix}TRIGGERS]; + DROP INDEX IF EXISTS [IDX_${TablePrefix}T_G_J] ON [dbo].[${TablePrefix}TRIGGERS]; + DROP INDEX IF EXISTS [IDX_${TablePrefix}T_STATE] ON [dbo].[${TablePrefix}TRIGGERS]; + DROP INDEX IF EXISTS [IDX_${TablePrefix}T_N_STATE] ON [dbo].[${TablePrefix}TRIGGERS]; + DROP INDEX IF EXISTS [IDX_${TablePrefix}T_N_G_STATE] ON [dbo].[${TablePrefix}TRIGGERS]; + DROP INDEX IF EXISTS [IDX_${TablePrefix}T_NEXT_FIRE_TIME] ON [dbo].[${TablePrefix}TRIGGERS]; + DROP INDEX IF EXISTS [IDX_${TablePrefix}T_NFT_ST] ON [dbo].[${TablePrefix}TRIGGERS]; + DROP INDEX IF EXISTS [IDX_${TablePrefix}T_NFT_MISFIRE] ON [dbo].[${TablePrefix}TRIGGERS]; + DROP INDEX IF EXISTS [IDX_${TablePrefix}T_NFT_ST_MISFIRE] ON [dbo].[${TablePrefix}TRIGGERS]; + DROP INDEX IF EXISTS [IDX_${TablePrefix}T_NFT_ST_MISFIRE_GRP] ON [dbo].[${TablePrefix}TRIGGERS]; + DROP INDEX IF EXISTS [IDX_${TablePrefix}FT_TRIG_INST_NAME] ON [dbo].[${TablePrefix}FIRED_TRIGGERS]; + DROP INDEX IF EXISTS [IDX_${TablePrefix}FT_INST_JOB_REQ_RCVRY] ON [dbo].[${TablePrefix}FIRED_TRIGGERS]; + DROP INDEX IF EXISTS [IDX_${TablePrefix}FT_J_G] ON [dbo].[${TablePrefix}FIRED_TRIGGERS]; + DROP INDEX IF EXISTS [IDX_${TablePrefix}FT_JG] ON [dbo].[${TablePrefix}FIRED_TRIGGERS]; + DROP INDEX IF EXISTS [IDX_${TablePrefix}FT_T_G] ON [dbo].[${TablePrefix}FIRED_TRIGGERS]; + DROP INDEX IF EXISTS [IDX_${TablePrefix}FT_TG] ON [dbo].[${TablePrefix}FIRED_TRIGGERS]; + DROP INDEX IF EXISTS [IDX_${TablePrefix}FT_G_J] ON [dbo].[${TablePrefix}FIRED_TRIGGERS]; + DROP INDEX IF EXISTS [IDX_${TablePrefix}FT_G_T] ON [dbo].[${TablePrefix}FIRED_TRIGGERS]; + + IF OBJECT_ID(N'[dbo].[FK_${TablePrefix}TRIGGERS_${TablePrefix}JOB_DETAILS]', N'F') IS NOT NULL + ALTER TABLE [dbo].[${TablePrefix}TRIGGERS] DROP CONSTRAINT [FK_${TablePrefix}TRIGGERS_${TablePrefix}JOB_DETAILS]; + + IF OBJECT_ID(N'[dbo].[FK_${TablePrefix}CRON_TRIGGERS_${TablePrefix}TRIGGERS]', N'F') IS NOT NULL + ALTER TABLE [dbo].[${TablePrefix}CRON_TRIGGERS] DROP CONSTRAINT [FK_${TablePrefix}CRON_TRIGGERS_${TablePrefix}TRIGGERS]; + + IF OBJECT_ID(N'[dbo].[FK_${TablePrefix}SIMPLE_TRIGGERS_${TablePrefix}TRIGGERS]', N'F') IS NOT NULL + ALTER TABLE [dbo].[${TablePrefix}SIMPLE_TRIGGERS] DROP CONSTRAINT [FK_${TablePrefix}SIMPLE_TRIGGERS_${TablePrefix}TRIGGERS]; + + IF OBJECT_ID(N'[dbo].[FK_${TablePrefix}SIMPROP_TRIGGERS_${TablePrefix}TRIGGERS]', N'F') IS NOT NULL + ALTER TABLE [dbo].[${TablePrefix}SIMPROP_TRIGGERS] DROP CONSTRAINT [FK_${TablePrefix}SIMPROP_TRIGGERS_${TablePrefix}TRIGGERS]; + + IF EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_${TablePrefix}JOB_LISTENERS_${TablePrefix}JOB_DETAILS]') AND parent_object_id = OBJECT_ID(N'[dbo].[${TablePrefix}JOB_LISTENERS]')) + ALTER TABLE [dbo].[${TablePrefix}JOB_LISTENERS] DROP CONSTRAINT [FK_${TablePrefix}JOB_LISTENERS_${TablePrefix}JOB_DETAILS]; + + IF EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_${TablePrefix}TRIGGER_LISTENERS_${TablePrefix}TRIGGERS]') AND parent_object_id = OBJECT_ID(N'[dbo].[${TablePrefix}TRIGGER_LISTENERS]')) + ALTER TABLE [dbo].[${TablePrefix}TRIGGER_LISTENERS] DROP CONSTRAINT [FK_${TablePrefix}TRIGGER_LISTENERS_${TablePrefix}TRIGGERS]; + + IF OBJECT_ID(N'[dbo].[${TablePrefix}CALENDARS]', N'U') IS NOT NULL + DROP TABLE [dbo].[${TablePrefix}CALENDARS]; + + IF OBJECT_ID(N'[dbo].[${TablePrefix}CRON_TRIGGERS]', N'U') IS NOT NULL + DROP TABLE [dbo].[${TablePrefix}CRON_TRIGGERS]; + + IF OBJECT_ID(N'[dbo].[${TablePrefix}BLOB_TRIGGERS]', N'U') IS NOT NULL + DROP TABLE [dbo].[${TablePrefix}BLOB_TRIGGERS]; + + IF OBJECT_ID(N'[dbo].[${TablePrefix}FIRED_TRIGGERS]', N'U') IS NOT NULL + DROP TABLE [dbo].[${TablePrefix}FIRED_TRIGGERS]; + + IF OBJECT_ID(N'[dbo].[${TablePrefix}PAUSED_TRIGGER_GRPS]', N'U') IS NOT NULL + DROP TABLE [dbo].[${TablePrefix}PAUSED_TRIGGER_GRPS]; + + IF OBJECT_ID(N'[dbo].[${TablePrefix}JOB_LISTENERS]', N'U') IS NOT NULL + DROP TABLE [dbo].[${TablePrefix}JOB_LISTENERS]; + + IF OBJECT_ID(N'[dbo].[${TablePrefix}SCHEDULER_STATE]', N'U') IS NOT NULL + DROP TABLE [dbo].[${TablePrefix}SCHEDULER_STATE]; + + IF OBJECT_ID(N'[dbo].[${TablePrefix}LOCKS]', N'U') IS NOT NULL + DROP TABLE [dbo].[${TablePrefix}LOCKS]; + + IF OBJECT_ID(N'[dbo].[${TablePrefix}TRIGGER_LISTENERS]', N'U') IS NOT NULL + DROP TABLE [dbo].[${TablePrefix}TRIGGER_LISTENERS]; + + IF OBJECT_ID(N'[dbo].[${TablePrefix}JOB_DETAILS]', N'U') IS NOT NULL + DROP TABLE [dbo].[${TablePrefix}JOB_DETAILS]; + + IF OBJECT_ID(N'[dbo].[${TablePrefix}SIMPLE_TRIGGERS]', N'U') IS NOT NULL + DROP TABLE [dbo].[${TablePrefix}SIMPLE_TRIGGERS]; + + IF OBJECT_ID(N'[dbo].[${TablePrefix}SIMPROP_TRIGGERS]', N'U') IS NOT NULL + DROP TABLE [dbo].[${TablePrefix}SIMPROP_TRIGGERS]; + + IF OBJECT_ID(N'[dbo].[${TablePrefix}TRIGGERS]', N'U') IS NOT NULL + DROP TABLE [dbo].[${TablePrefix}TRIGGERS]; +END + +CREATE TABLE [dbo].[${TablePrefix}CALENDARS] ( + [SCHED_NAME] nvarchar(120) NOT NULL, + [CALENDAR_NAME] nvarchar(200) NOT NULL, + [CALENDAR] varbinary(max) NOT NULL +); + +CREATE TABLE [dbo].[${TablePrefix}CRON_TRIGGERS] ( + [SCHED_NAME] nvarchar(120) NOT NULL, + [TRIGGER_NAME] nvarchar(150) NOT NULL, + [TRIGGER_GROUP] nvarchar(150) NOT NULL, + [CRON_EXPRESSION] nvarchar(120) NOT NULL, + [TIME_ZONE_ID] nvarchar(80) +); + +CREATE TABLE [dbo].[${TablePrefix}FIRED_TRIGGERS] ( + [SCHED_NAME] nvarchar(120) NOT NULL, + [ENTRY_ID] nvarchar(140) NOT NULL, + [TRIGGER_NAME] nvarchar(150) NOT NULL, + [TRIGGER_GROUP] nvarchar(150) NOT NULL, + [INSTANCE_NAME] nvarchar(200) NOT NULL, + [FIRED_TIME] bigint NOT NULL, + [SCHED_TIME] bigint NOT NULL, + [PRIORITY] int NOT NULL, + [STATE] nvarchar(16) NOT NULL, + [JOB_NAME] nvarchar(150) NULL, + [JOB_GROUP] nvarchar(150) NULL, + [IS_NONCONCURRENT] bit NULL, + [REQUESTS_RECOVERY] bit NULL +); + +CREATE TABLE [dbo].[${TablePrefix}PAUSED_TRIGGER_GRPS] ( + [SCHED_NAME] nvarchar(120) NOT NULL, + [TRIGGER_GROUP] nvarchar(150) NOT NULL +); + +CREATE TABLE [dbo].[${TablePrefix}SCHEDULER_STATE] ( + [SCHED_NAME] nvarchar(120) NOT NULL, + [INSTANCE_NAME] nvarchar(200) NOT NULL, + [LAST_CHECKIN_TIME] bigint NOT NULL, + [CHECKIN_INTERVAL] bigint NOT NULL +); + +CREATE TABLE [dbo].[${TablePrefix}LOCKS] ( + [SCHED_NAME] nvarchar(120) NOT NULL, + [LOCK_NAME] nvarchar(40) NOT NULL +); + +CREATE TABLE [dbo].[${TablePrefix}JOB_DETAILS] ( + [SCHED_NAME] nvarchar(120) NOT NULL, + [JOB_NAME] nvarchar(150) NOT NULL, + [JOB_GROUP] nvarchar(150) NOT NULL, + [DESCRIPTION] nvarchar(250) NULL, + [JOB_CLASS_NAME] nvarchar(250) NOT NULL, + [IS_DURABLE] bit NOT NULL, + [IS_NONCONCURRENT] bit NOT NULL, + [IS_UPDATE_DATA] bit NOT NULL, + [REQUESTS_RECOVERY] bit NOT NULL, + [JOB_DATA] varbinary(max) NULL +); + +CREATE TABLE [dbo].[${TablePrefix}SIMPLE_TRIGGERS] ( + [SCHED_NAME] nvarchar(120) NOT NULL, + [TRIGGER_NAME] nvarchar(150) NOT NULL, + [TRIGGER_GROUP] nvarchar(150) NOT NULL, + [REPEAT_COUNT] int NOT NULL, + [REPEAT_INTERVAL] bigint NOT NULL, + [TIMES_TRIGGERED] int NOT NULL +); + +CREATE TABLE [dbo].[${TablePrefix}SIMPROP_TRIGGERS] ( + [SCHED_NAME] nvarchar(120) NOT NULL, + [TRIGGER_NAME] nvarchar(150) NOT NULL, + [TRIGGER_GROUP] nvarchar(150) NOT NULL, + [STR_PROP_1] nvarchar(512) NULL, + [STR_PROP_2] nvarchar(512) NULL, + [STR_PROP_3] nvarchar(512) NULL, + [INT_PROP_1] int NULL, + [INT_PROP_2] int NULL, + [LONG_PROP_1] bigint NULL, + [LONG_PROP_2] bigint NULL, + [DEC_PROP_1] numeric(13,4) NULL, + [DEC_PROP_2] numeric(13,4) NULL, + [BOOL_PROP_1] bit NULL, + [BOOL_PROP_2] bit NULL, + [TIME_ZONE_ID] nvarchar(80) NULL +); + +CREATE TABLE [dbo].[${TablePrefix}BLOB_TRIGGERS] ( + [SCHED_NAME] nvarchar(120) NOT NULL, + [TRIGGER_NAME] nvarchar(150) NOT NULL, + [TRIGGER_GROUP] nvarchar(150) NOT NULL, + [BLOB_DATA] varbinary(max) NULL +); + +CREATE TABLE [dbo].[${TablePrefix}TRIGGERS] ( + [SCHED_NAME] nvarchar(120) NOT NULL, + [TRIGGER_NAME] nvarchar(150) NOT NULL, + [TRIGGER_GROUP] nvarchar(150) NOT NULL, + [JOB_NAME] nvarchar(150) NOT NULL, + [JOB_GROUP] nvarchar(150) NOT NULL, + [DESCRIPTION] nvarchar(250) NULL, + [NEXT_FIRE_TIME] bigint NULL, + [PREV_FIRE_TIME] bigint NULL, + [PRIORITY] int NULL, + [TRIGGER_STATE] nvarchar(16) NOT NULL, + [TRIGGER_TYPE] nvarchar(8) NOT NULL, + [START_TIME] bigint NOT NULL, + [END_TIME] bigint NULL, + [CALENDAR_NAME] nvarchar(200) NULL, + [MISFIRE_INSTR] int NULL, + [JOB_DATA] varbinary(max) NULL +); +GO + +ALTER TABLE [dbo].[${TablePrefix}CALENDARS] WITH NOCHECK ADD + CONSTRAINT [PK_${TablePrefix}CALENDARS] PRIMARY KEY CLUSTERED + ( + [SCHED_NAME], + [CALENDAR_NAME] + ); +GO + +ALTER TABLE [dbo].[${TablePrefix}CRON_TRIGGERS] WITH NOCHECK ADD + CONSTRAINT [PK_${TablePrefix}CRON_TRIGGERS] PRIMARY KEY CLUSTERED + ( + [SCHED_NAME], + [TRIGGER_NAME], + [TRIGGER_GROUP] + ); +GO + +ALTER TABLE [dbo].[${TablePrefix}FIRED_TRIGGERS] WITH NOCHECK ADD + CONSTRAINT [PK_${TablePrefix}FIRED_TRIGGERS] PRIMARY KEY CLUSTERED + ( + [SCHED_NAME], + [ENTRY_ID] + ); +GO + +ALTER TABLE [dbo].[${TablePrefix}PAUSED_TRIGGER_GRPS] WITH NOCHECK ADD + CONSTRAINT [PK_${TablePrefix}PAUSED_TRIGGER_GRPS] PRIMARY KEY CLUSTERED + ( + [SCHED_NAME], + [TRIGGER_GROUP] + ); +GO + +ALTER TABLE [dbo].[${TablePrefix}SCHEDULER_STATE] WITH NOCHECK ADD + CONSTRAINT [PK_${TablePrefix}SCHEDULER_STATE] PRIMARY KEY CLUSTERED + ( + [SCHED_NAME], + [INSTANCE_NAME] + ); +GO + +ALTER TABLE [dbo].[${TablePrefix}LOCKS] WITH NOCHECK ADD + CONSTRAINT [PK_${TablePrefix}LOCKS] PRIMARY KEY CLUSTERED + ( + [SCHED_NAME], + [LOCK_NAME] + ); +GO + +ALTER TABLE [dbo].[${TablePrefix}JOB_DETAILS] WITH NOCHECK ADD + CONSTRAINT [PK_${TablePrefix}JOB_DETAILS] PRIMARY KEY CLUSTERED + ( + [SCHED_NAME], + [JOB_NAME], + [JOB_GROUP] + ); +GO + +ALTER TABLE [dbo].[${TablePrefix}SIMPLE_TRIGGERS] WITH NOCHECK ADD + CONSTRAINT [PK_${TablePrefix}SIMPLE_TRIGGERS] PRIMARY KEY CLUSTERED + ( + [SCHED_NAME], + [TRIGGER_NAME], + [TRIGGER_GROUP] + ); +GO + +ALTER TABLE [dbo].[${TablePrefix}SIMPROP_TRIGGERS] WITH NOCHECK ADD + CONSTRAINT [PK_${TablePrefix}SIMPROP_TRIGGERS] PRIMARY KEY CLUSTERED + ( + [SCHED_NAME], + [TRIGGER_NAME], + [TRIGGER_GROUP] + ); +GO + +ALTER TABLE [dbo].[${TablePrefix}TRIGGERS] WITH NOCHECK ADD + CONSTRAINT [PK_${TablePrefix}TRIGGERS] PRIMARY KEY CLUSTERED + ( + [SCHED_NAME], + [TRIGGER_NAME], + [TRIGGER_GROUP] + ); +GO + +ALTER TABLE [dbo].[${TablePrefix}BLOB_TRIGGERS] WITH NOCHECK ADD + CONSTRAINT [PK_${TablePrefix}BLOB_TRIGGERS] PRIMARY KEY CLUSTERED + ( + [SCHED_NAME], + [TRIGGER_NAME], + [TRIGGER_GROUP] + ); +GO + +ALTER TABLE [dbo].[${TablePrefix}CRON_TRIGGERS] ADD + CONSTRAINT [FK_${TablePrefix}CRON_TRIGGERS_${TablePrefix}TRIGGERS] FOREIGN KEY + ( + [SCHED_NAME], + [TRIGGER_NAME], + [TRIGGER_GROUP] + ) REFERENCES [dbo].[${TablePrefix}TRIGGERS] ( + [SCHED_NAME], + [TRIGGER_NAME], + [TRIGGER_GROUP] + ) ON DELETE CASCADE; +GO + +ALTER TABLE [dbo].[${TablePrefix}SIMPLE_TRIGGERS] ADD + CONSTRAINT [FK_${TablePrefix}SIMPLE_TRIGGERS_${TablePrefix}TRIGGERS] FOREIGN KEY + ( + [SCHED_NAME], + [TRIGGER_NAME], + [TRIGGER_GROUP] + ) REFERENCES [dbo].[${TablePrefix}TRIGGERS] ( + [SCHED_NAME], + [TRIGGER_NAME], + [TRIGGER_GROUP] + ) ON DELETE CASCADE; +GO + +ALTER TABLE [dbo].[${TablePrefix}SIMPROP_TRIGGERS] ADD + CONSTRAINT [FK_${TablePrefix}SIMPROP_TRIGGERS_${TablePrefix}TRIGGERS] FOREIGN KEY + ( + [SCHED_NAME], + [TRIGGER_NAME], + [TRIGGER_GROUP] + ) REFERENCES [dbo].[${TablePrefix}TRIGGERS] ( + [SCHED_NAME], + [TRIGGER_NAME], + [TRIGGER_GROUP] + ) ON DELETE CASCADE; +GO + +ALTER TABLE [dbo].[${TablePrefix}TRIGGERS] ADD + CONSTRAINT [FK_${TablePrefix}TRIGGERS_${TablePrefix}JOB_DETAILS] FOREIGN KEY + ( + [SCHED_NAME], + [JOB_NAME], + [JOB_GROUP] + ) REFERENCES [dbo].[${TablePrefix}JOB_DETAILS] ( + [SCHED_NAME], + [JOB_NAME], + [JOB_GROUP] + ); +GO + +-- Create indexes +CREATE INDEX [IDX_${TablePrefix}T_G_J] ON [dbo].[${TablePrefix}TRIGGERS](SCHED_NAME, JOB_GROUP, JOB_NAME); +CREATE INDEX [IDX_${TablePrefix}T_C] ON [dbo].[${TablePrefix}TRIGGERS](SCHED_NAME, CALENDAR_NAME); + +CREATE INDEX [IDX_${TablePrefix}T_N_G_STATE] ON [dbo].[${TablePrefix}TRIGGERS](SCHED_NAME, TRIGGER_GROUP, TRIGGER_STATE); +CREATE INDEX [IDX_${TablePrefix}T_STATE] ON [dbo].[${TablePrefix}TRIGGERS](SCHED_NAME, TRIGGER_STATE); +CREATE INDEX [IDX_${TablePrefix}T_N_STATE] ON [dbo].[${TablePrefix}TRIGGERS](SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP, TRIGGER_STATE); +CREATE INDEX [IDX_${TablePrefix}T_NEXT_FIRE_TIME] ON [dbo].[${TablePrefix}TRIGGERS](SCHED_NAME, NEXT_FIRE_TIME); +CREATE INDEX [IDX_${TablePrefix}T_NFT_ST] ON [dbo].[${TablePrefix}TRIGGERS](SCHED_NAME, TRIGGER_STATE, NEXT_FIRE_TIME); +CREATE INDEX [IDX_${TablePrefix}T_NFT_ST_MISFIRE] ON [dbo].[${TablePrefix}TRIGGERS](SCHED_NAME, MISFIRE_INSTR, NEXT_FIRE_TIME, TRIGGER_STATE); +CREATE INDEX [IDX_${TablePrefix}T_NFT_ST_MISFIRE_GRP] ON [dbo].[${TablePrefix}TRIGGERS](SCHED_NAME, MISFIRE_INSTR, NEXT_FIRE_TIME, TRIGGER_GROUP, TRIGGER_STATE); + +CREATE INDEX [IDX_${TablePrefix}FT_INST_JOB_REQ_RCVRY] ON [dbo].[${TablePrefix}FIRED_TRIGGERS](SCHED_NAME, INSTANCE_NAME, REQUESTS_RECOVERY); +CREATE INDEX [IDX_${TablePrefix}FT_G_J] ON [dbo].[${TablePrefix}FIRED_TRIGGERS](SCHED_NAME, JOB_GROUP, JOB_NAME); +CREATE INDEX [IDX_${TablePrefix}FT_G_T] ON [dbo].[${TablePrefix}FIRED_TRIGGERS](SCHED_NAME, TRIGGER_GROUP, TRIGGER_NAME); +GO \ No newline at end of file From 2959f4ad50bafc63e392f8063e7d604e12257080 Mon Sep 17 00:00:00 2001 From: colin Date: Wed, 2 Apr 2025 08:20:47 +0800 Subject: [PATCH 3/4] feat(saas): Added database connection string check --- .../Dto/TenantConnectionStringCheckInput.cs | 18 +++++++ .../TenantConnectionStringCheckResultDto.cs | 15 ++++++ .../Abp/Saas/Tenants/ITenantAppService.cs | 2 + .../Abp/Saas/Tenants/TenantAppService.cs | 54 +++++++++---------- .../FodyWeavers.xml | 3 ++ .../FodyWeavers.xsd | 30 +++++++++++ .../LINGYUN.Abp.Saas.DbChecker.csproj | 28 ++++++++++ .../Abp/Saas/AbpSaasDbCheckerModule.cs | 24 +++++++++ .../MySql/MySqlConnectionStringChecker.cs | 39 ++++++++++++++ .../Oracle/OracleConnectionStringChecker.cs | 35 ++++++++++++ .../NpgsqlConnectionStringChecker.cs | 40 ++++++++++++++ .../SqlServerConnectionStringChecker.cs | 40 ++++++++++++++ .../Sqlite/SqliteConnectionStringChecker.cs | 33 ++++++++++++ .../LINGYUN/Abp/Saas/AbpSaasErrorCodes.cs | 6 ++- .../Abp/Saas/Localization/Resources/en.json | 2 + .../Saas/Localization/Resources/zh-Hans.json | 2 + .../AbpSaasConnectionStringCheckOptions.cs | 15 ++++++ .../DataBaseConnectionStringCheckResult.cs | 9 ++++ .../IDataBaseConnectionStringChecker.cs | 8 +++ .../Abp/Saas/Tenants/TenantController.cs | 7 +++ 20 files changed, 381 insertions(+), 29 deletions(-) create mode 100644 aspnet-core/modules/saas/LINGYUN.Abp.Saas.Application.Contracts/LINGYUN/Abp/Saas/Tenants/Dto/TenantConnectionStringCheckInput.cs create mode 100644 aspnet-core/modules/saas/LINGYUN.Abp.Saas.Application.Contracts/LINGYUN/Abp/Saas/Tenants/Dto/TenantConnectionStringCheckResultDto.cs create mode 100644 aspnet-core/modules/saas/LINGYUN.Abp.Saas.DbChecker/FodyWeavers.xml create mode 100644 aspnet-core/modules/saas/LINGYUN.Abp.Saas.DbChecker/FodyWeavers.xsd create mode 100644 aspnet-core/modules/saas/LINGYUN.Abp.Saas.DbChecker/LINGYUN.Abp.Saas.DbChecker.csproj create mode 100644 aspnet-core/modules/saas/LINGYUN.Abp.Saas.DbChecker/LINGYUN/Abp/Saas/AbpSaasDbCheckerModule.cs create mode 100644 aspnet-core/modules/saas/LINGYUN.Abp.Saas.DbChecker/LINGYUN/Abp/Saas/MySql/MySqlConnectionStringChecker.cs create mode 100644 aspnet-core/modules/saas/LINGYUN.Abp.Saas.DbChecker/LINGYUN/Abp/Saas/Oracle/OracleConnectionStringChecker.cs create mode 100644 aspnet-core/modules/saas/LINGYUN.Abp.Saas.DbChecker/LINGYUN/Abp/Saas/PostgreSql/NpgsqlConnectionStringChecker.cs create mode 100644 aspnet-core/modules/saas/LINGYUN.Abp.Saas.DbChecker/LINGYUN/Abp/Saas/SqlServer/SqlServerConnectionStringChecker.cs create mode 100644 aspnet-core/modules/saas/LINGYUN.Abp.Saas.DbChecker/LINGYUN/Abp/Saas/Sqlite/SqliteConnectionStringChecker.cs create mode 100644 aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain/LINGYUN/Abp/Saas/AbpSaasConnectionStringCheckOptions.cs create mode 100644 aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain/LINGYUN/Abp/Saas/Tenants/DataBaseConnectionStringCheckResult.cs create mode 100644 aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain/LINGYUN/Abp/Saas/Tenants/IDataBaseConnectionStringChecker.cs diff --git a/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Application.Contracts/LINGYUN/Abp/Saas/Tenants/Dto/TenantConnectionStringCheckInput.cs b/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Application.Contracts/LINGYUN/Abp/Saas/Tenants/Dto/TenantConnectionStringCheckInput.cs new file mode 100644 index 000000000..0adf83f11 --- /dev/null +++ b/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Application.Contracts/LINGYUN/Abp/Saas/Tenants/Dto/TenantConnectionStringCheckInput.cs @@ -0,0 +1,18 @@ +using System.ComponentModel.DataAnnotations; +using Volo.Abp.Auditing; +using Volo.Abp.Validation; + +namespace LINGYUN.Abp.Saas.Tenants; + +public class TenantConnectionStringCheckInput +{ + [Required] + public string Provider { get; set; } + + public string Name { get; set; } + + [Required] + [DisableAuditing] + [DynamicStringLength(typeof(TenantConnectionStringConsts), nameof(TenantConnectionStringConsts.MaxValueLength))] + public string ConnectionString { get; set; } +} diff --git a/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Application.Contracts/LINGYUN/Abp/Saas/Tenants/Dto/TenantConnectionStringCheckResultDto.cs b/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Application.Contracts/LINGYUN/Abp/Saas/Tenants/Dto/TenantConnectionStringCheckResultDto.cs new file mode 100644 index 000000000..ba9766ebe --- /dev/null +++ b/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Application.Contracts/LINGYUN/Abp/Saas/Tenants/Dto/TenantConnectionStringCheckResultDto.cs @@ -0,0 +1,15 @@ +namespace LINGYUN.Abp.Saas.Tenants; + +public class TenantConnectionStringCheckResultDto +{ + public bool Connected { get; set; } + public TenantConnectionStringCheckResultDto() + { + + } + + public TenantConnectionStringCheckResultDto(bool connected) + { + Connected = connected; + } +} diff --git a/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Application.Contracts/LINGYUN/Abp/Saas/Tenants/ITenantAppService.cs b/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Application.Contracts/LINGYUN/Abp/Saas/Tenants/ITenantAppService.cs index db5a30ad1..25575cbec 100644 --- a/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Application.Contracts/LINGYUN/Abp/Saas/Tenants/ITenantAppService.cs +++ b/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Application.Contracts/LINGYUN/Abp/Saas/Tenants/ITenantAppService.cs @@ -31,4 +31,6 @@ public interface ITenantAppService : Task DeleteConnectionStringAsync( Guid id, [Required] string connectionName); + + Task CheckConnectionStringAsync(TenantConnectionStringCheckInput input); } diff --git a/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Application/LINGYUN/Abp/Saas/Tenants/TenantAppService.cs b/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Application/LINGYUN/Abp/Saas/Tenants/TenantAppService.cs index 682914293..c3f938279 100644 --- a/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Application/LINGYUN/Abp/Saas/Tenants/TenantAppService.cs +++ b/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Application/LINGYUN/Abp/Saas/Tenants/TenantAppService.cs @@ -1,6 +1,7 @@ using LINGYUN.Abp.Saas.Features; using Microsoft.AspNetCore.Authorization; using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; using System; using System.Collections.Generic; using System.Linq; @@ -20,18 +21,18 @@ public class TenantAppService : AbpSaasAppServiceBase, ITenantAppService protected IDistributedEventBus EventBus { get; } protected ITenantRepository TenantRepository { get; } protected ITenantManager TenantManager { get; } - protected IConnectionStringChecker ConnectionStringChecker { get; } + protected AbpSaasConnectionStringCheckOptions ConnectionStringCheckOptions { get; } public TenantAppService( ITenantRepository tenantRepository, ITenantManager tenantManager, IDistributedEventBus eventBus, - IConnectionStringChecker connectionStringChecker) + IOptions connectionStringCheckOptions) { EventBus = eventBus; TenantRepository = tenantRepository; TenantManager = tenantManager; - ConnectionStringChecker = connectionStringChecker; + ConnectionStringCheckOptions = connectionStringCheckOptions.Value; } public async virtual Task GetAsync(Guid id) @@ -85,14 +86,12 @@ public class TenantAppService : AbpSaasAppServiceBase, ITenantAppService if (!input.UseSharedDatabase) { - await CheckConnectionString(input.DefaultConnectionString); tenant.SetDefaultConnectionString(input.DefaultConnectionString); if (input.ConnectionStrings.Any()) { foreach (var connectionString in input.ConnectionStrings) { - await CheckConnectionString(connectionString.Value, connectionString.Name); tenant.SetConnectionString(connectionString.Name, connectionString.Value); } } @@ -215,8 +214,6 @@ public class TenantAppService : AbpSaasAppServiceBase, ITenantAppService [Authorize(AbpSaasPermissions.Tenants.ManageConnectionStrings)] public async virtual Task SetConnectionStringAsync(Guid id, TenantConnectionStringSetInput input) { - await CheckConnectionString(input.Value, input.Name); - var tenant = await TenantRepository.GetAsync(id); var oldConnectionString = tenant.FindConnectionString(input.Name); @@ -275,33 +272,34 @@ public class TenantAppService : AbpSaasAppServiceBase, ITenantAppService await CurrentUnitOfWork.SaveChangesAsync(); } - protected async virtual Task CheckConnectionString(string connectionString, string name = null) + public async virtual Task CheckConnectionStringAsync(TenantConnectionStringCheckInput input) { - try + if (!ConnectionStringCheckOptions.ConnectionStringCheckers.TryGetValue(input.Provider, out var connectionStringChecker)) { - var checkResult = await ConnectionStringChecker.CheckAsync(connectionString); - // 检查连接是否可用 - if (!checkResult.Connected) - { - throw name.IsNullOrWhiteSpace() - ? new BusinessException(AbpSaasErrorCodes.InvalidDefaultConnectionString) - : new BusinessException(AbpSaasErrorCodes.InvalidConnectionString) - .WithData("Name", name); - } - // 默认连接字符串改变不能影响到现有数据库 - if (checkResult.DatabaseExists && name.IsNullOrWhiteSpace()) - { - throw new BusinessException(AbpSaasErrorCodes.DefaultConnectionStringDatabaseExists); - } + throw new BusinessException(AbpSaasErrorCodes.ConnectionStringProviderNotSupport) + .WithData("Name", input.Provider); } - catch (Exception e) + + var checkResult = await connectionStringChecker.CheckAsync(input.ConnectionString); + + if (checkResult.Error != null) + { + Logger.LogWarning(checkResult.Error, "An error occurred while checking the database connection."); + } + + // 检查连接是否可用 + if (!checkResult.Connected) { - Logger.LogWarning("An error occurred while checking the validity of the connection string"); - Logger.LogWarning(e.Message); - throw name.IsNullOrWhiteSpace() + throw input.Name.IsNullOrWhiteSpace() ? new BusinessException(AbpSaasErrorCodes.InvalidDefaultConnectionString) : new BusinessException(AbpSaasErrorCodes.InvalidConnectionString) - .WithData("Name", name); + .WithData("Name", input.Name); } + // 默认连接字符串改变不能影响到现有数据库 + // 移除此检查, 需要配合数据库迁移才有效 + //if (checkResult.DatabaseExists && (input.Name.IsNullOrWhiteSpace() || "Default".Equals(input.Name, StringComparison.InvariantCultureIgnoreCase))) + //{ + // throw new BusinessException(AbpSaasErrorCodes.DefaultConnectionStringDatabaseExists); + //} } } diff --git a/aspnet-core/modules/saas/LINGYUN.Abp.Saas.DbChecker/FodyWeavers.xml b/aspnet-core/modules/saas/LINGYUN.Abp.Saas.DbChecker/FodyWeavers.xml new file mode 100644 index 000000000..1715698cc --- /dev/null +++ b/aspnet-core/modules/saas/LINGYUN.Abp.Saas.DbChecker/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/aspnet-core/modules/saas/LINGYUN.Abp.Saas.DbChecker/FodyWeavers.xsd b/aspnet-core/modules/saas/LINGYUN.Abp.Saas.DbChecker/FodyWeavers.xsd new file mode 100644 index 000000000..3f3946e28 --- /dev/null +++ b/aspnet-core/modules/saas/LINGYUN.Abp.Saas.DbChecker/FodyWeavers.xsd @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed. + + + + + A comma-separated list of error codes that can be safely ignored in assembly verification. + + + + + 'false' to turn off automatic generation of the XML Schema file. + + + + + \ No newline at end of file diff --git a/aspnet-core/modules/saas/LINGYUN.Abp.Saas.DbChecker/LINGYUN.Abp.Saas.DbChecker.csproj b/aspnet-core/modules/saas/LINGYUN.Abp.Saas.DbChecker/LINGYUN.Abp.Saas.DbChecker.csproj new file mode 100644 index 000000000..fd82b2d2c --- /dev/null +++ b/aspnet-core/modules/saas/LINGYUN.Abp.Saas.DbChecker/LINGYUN.Abp.Saas.DbChecker.csproj @@ -0,0 +1,28 @@ + + + + + + + net9.0 + LINGYUN.Abp.Saas.DbChecker + LINGYUN.Abp.Saas.DbChecker + false + false + false + + + + + + + + + + + + + + + + diff --git a/aspnet-core/modules/saas/LINGYUN.Abp.Saas.DbChecker/LINGYUN/Abp/Saas/AbpSaasDbCheckerModule.cs b/aspnet-core/modules/saas/LINGYUN.Abp.Saas.DbChecker/LINGYUN/Abp/Saas/AbpSaasDbCheckerModule.cs new file mode 100644 index 000000000..d080185c3 --- /dev/null +++ b/aspnet-core/modules/saas/LINGYUN.Abp.Saas.DbChecker/LINGYUN/Abp/Saas/AbpSaasDbCheckerModule.cs @@ -0,0 +1,24 @@ +using LINGYUN.Abp.Saas.MySql; +using LINGYUN.Abp.Saas.Oracle; +using LINGYUN.Abp.Saas.PostgreSql; +using LINGYUN.Abp.Saas.Sqlite; +using LINGYUN.Abp.Saas.SqlServer; +using Volo.Abp.Modularity; + +namespace LINGYUN.Abp.Saas; + +[DependsOn(typeof(AbpSaasDomainModule))] +public class AbpSaasDbCheckerModule : AbpModule +{ + public override void ConfigureServices(ServiceConfigurationContext context) + { + Configure(options => + { + options.ConnectionStringCheckers["mysql"] = new MySqlConnectionStringChecker(); + options.ConnectionStringCheckers["oracle"] = new OracleConnectionStringChecker(); + options.ConnectionStringCheckers["postgres"] = new NpgsqlConnectionStringChecker(); + options.ConnectionStringCheckers["sqlite"] = new SqliteConnectionStringChecker(); + options.ConnectionStringCheckers["sqlserver"] = new SqlServerConnectionStringChecker(); + }); + } +} diff --git a/aspnet-core/modules/saas/LINGYUN.Abp.Saas.DbChecker/LINGYUN/Abp/Saas/MySql/MySqlConnectionStringChecker.cs b/aspnet-core/modules/saas/LINGYUN.Abp.Saas.DbChecker/LINGYUN/Abp/Saas/MySql/MySqlConnectionStringChecker.cs new file mode 100644 index 000000000..1fd6d1887 --- /dev/null +++ b/aspnet-core/modules/saas/LINGYUN.Abp.Saas.DbChecker/LINGYUN/Abp/Saas/MySql/MySqlConnectionStringChecker.cs @@ -0,0 +1,39 @@ +using LINGYUN.Abp.Saas.Tenants; +using MySqlConnector; +using System; +using System.Threading.Tasks; + +namespace LINGYUN.Abp.Saas.MySql; + +public class MySqlConnectionStringChecker : IDataBaseConnectionStringChecker +{ + public virtual async Task CheckAsync(string connectionString) + { + var result = new DataBaseConnectionStringCheckResult(); + var connString = new MySqlConnectionStringBuilder(connectionString) + { + ConnectionLifeTime = 1 + }; + + var oldDatabaseName = connString.Database; + connString.Database = "mysql"; + + try + { + await using var conn = new MySqlConnection(connString.ConnectionString); + await conn.OpenAsync(); + result.Connected = true; + await conn.ChangeDatabaseAsync(oldDatabaseName); + result.DatabaseExists = true; + + await conn.CloseAsync(); + + return result; + } + catch (Exception e) + { + result.Error = e; + return result; + } + } +} diff --git a/aspnet-core/modules/saas/LINGYUN.Abp.Saas.DbChecker/LINGYUN/Abp/Saas/Oracle/OracleConnectionStringChecker.cs b/aspnet-core/modules/saas/LINGYUN.Abp.Saas.DbChecker/LINGYUN/Abp/Saas/Oracle/OracleConnectionStringChecker.cs new file mode 100644 index 000000000..2651598bc --- /dev/null +++ b/aspnet-core/modules/saas/LINGYUN.Abp.Saas.DbChecker/LINGYUN/Abp/Saas/Oracle/OracleConnectionStringChecker.cs @@ -0,0 +1,35 @@ +using LINGYUN.Abp.Saas.Tenants; +using Oracle.ManagedDataAccess.Client; +using System; +using System.Threading.Tasks; + +namespace LINGYUN.Abp.Saas.Oracle; + +public class OracleConnectionStringChecker : IDataBaseConnectionStringChecker +{ + public virtual async Task CheckAsync(string connectionString) + { + var result = new DataBaseConnectionStringCheckResult(); + var connString = new OracleConnectionStringBuilder(connectionString) + { + ConnectionTimeout = 1 + }; + + try + { + await using var conn = new OracleConnection(connString.ConnectionString); + await conn.OpenAsync(); + result.Connected = true; + result.DatabaseExists = true; + + await conn.CloseAsync(); + + return result; + } + catch (Exception e) + { + result.Error = e; + return result; + } + } +} diff --git a/aspnet-core/modules/saas/LINGYUN.Abp.Saas.DbChecker/LINGYUN/Abp/Saas/PostgreSql/NpgsqlConnectionStringChecker.cs b/aspnet-core/modules/saas/LINGYUN.Abp.Saas.DbChecker/LINGYUN/Abp/Saas/PostgreSql/NpgsqlConnectionStringChecker.cs new file mode 100644 index 000000000..89c4cf444 --- /dev/null +++ b/aspnet-core/modules/saas/LINGYUN.Abp.Saas.DbChecker/LINGYUN/Abp/Saas/PostgreSql/NpgsqlConnectionStringChecker.cs @@ -0,0 +1,40 @@ +using LINGYUN.Abp.Saas.Tenants; +using Npgsql; +using System; +using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; + +namespace LINGYUN.Abp.Saas.PostgreSql; + +public class NpgsqlConnectionStringChecker : IDataBaseConnectionStringChecker, ITransientDependency +{ + public virtual async Task CheckAsync(string connectionString) + { + var result = new DataBaseConnectionStringCheckResult(); + var connString = new NpgsqlConnectionStringBuilder(connectionString) + { + Timeout = 1 + }; + + var oldDatabaseName = connString.Database; + connString.Database = "postgres"; + + try + { + await using var conn = new NpgsqlConnection(connString.ConnectionString); + await conn.OpenAsync(); + result.Connected = true; + await conn.ChangeDatabaseAsync(oldDatabaseName!); + result.DatabaseExists = true; + + await conn.CloseAsync(); + + return result; + } + catch (Exception e) + { + result.Error = e; + return result; + } + } +} diff --git a/aspnet-core/modules/saas/LINGYUN.Abp.Saas.DbChecker/LINGYUN/Abp/Saas/SqlServer/SqlServerConnectionStringChecker.cs b/aspnet-core/modules/saas/LINGYUN.Abp.Saas.DbChecker/LINGYUN/Abp/Saas/SqlServer/SqlServerConnectionStringChecker.cs new file mode 100644 index 000000000..52f3d07f7 --- /dev/null +++ b/aspnet-core/modules/saas/LINGYUN.Abp.Saas.DbChecker/LINGYUN/Abp/Saas/SqlServer/SqlServerConnectionStringChecker.cs @@ -0,0 +1,40 @@ +using LINGYUN.Abp.Saas.Tenants; +using Microsoft.Data.SqlClient; +using System; +using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; + +namespace LINGYUN.Abp.Saas.SqlServer; + +public class SqlServerConnectionStringChecker : IDataBaseConnectionStringChecker, ITransientDependency +{ + public virtual async Task CheckAsync(string connectionString) + { + var result = new DataBaseConnectionStringCheckResult(); + var connString = new SqlConnectionStringBuilder(connectionString) + { + ConnectTimeout = 1 + }; + + var oldDatabaseName = connString.InitialCatalog; + connString.InitialCatalog = "master"; + + try + { + await using var conn = new SqlConnection(connString.ConnectionString); + await conn.OpenAsync(); + result.Connected = true; + await conn.ChangeDatabaseAsync(oldDatabaseName); + result.DatabaseExists = true; + + await conn.CloseAsync(); + + return result; + } + catch (Exception e) + { + result.Error = e; + return result; + } + } +} diff --git a/aspnet-core/modules/saas/LINGYUN.Abp.Saas.DbChecker/LINGYUN/Abp/Saas/Sqlite/SqliteConnectionStringChecker.cs b/aspnet-core/modules/saas/LINGYUN.Abp.Saas.DbChecker/LINGYUN/Abp/Saas/Sqlite/SqliteConnectionStringChecker.cs new file mode 100644 index 000000000..747309900 --- /dev/null +++ b/aspnet-core/modules/saas/LINGYUN.Abp.Saas.DbChecker/LINGYUN/Abp/Saas/Sqlite/SqliteConnectionStringChecker.cs @@ -0,0 +1,33 @@ +using LINGYUN.Abp.Saas.Tenants; +using Microsoft.Data.Sqlite; +using System; +using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; + +namespace LINGYUN.Abp.Saas.Sqlite; + +public class SqliteConnectionStringChecker : IDataBaseConnectionStringChecker, ITransientDependency +{ + public virtual async Task CheckAsync(string connectionString) + { + var result = new DataBaseConnectionStringCheckResult(); + + try + { + await using var conn = new SqliteConnection(connectionString); + await conn.OpenAsync(); + result.Connected = true; + result.DatabaseExists = true; + + await conn.CloseAsync(); + + return result; + } + catch (Exception e) + { + result.Error = e; + return result; + } + } +} + diff --git a/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain.Shared/LINGYUN/Abp/Saas/AbpSaasErrorCodes.cs b/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain.Shared/LINGYUN/Abp/Saas/AbpSaasErrorCodes.cs index ed946d9a7..4103cbb9c 100644 --- a/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain.Shared/LINGYUN/Abp/Saas/AbpSaasErrorCodes.cs +++ b/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain.Shared/LINGYUN/Abp/Saas/AbpSaasErrorCodes.cs @@ -20,7 +20,7 @@ public static class AbpSaasErrorCodes /// public const string TenantIdOrNameNotFound = Namespace + ":020002"; /// - /// 无效的默认连接字符串 + /// 无法打开默认连接字符串指向的数据库连接 /// public const string InvalidDefaultConnectionString = Namespace + ":020101"; /// @@ -31,4 +31,8 @@ public static class AbpSaasErrorCodes /// {Name} 的连接字符串无效 /// public const string InvalidConnectionString = Namespace + ":020103"; + /// + /// 不支持 {Name} 类型的数据库连接检查 + /// + public const string ConnectionStringProviderNotSupport = Namespace + ":020104"; } diff --git a/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain.Shared/LINGYUN/Abp/Saas/Localization/Resources/en.json b/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain.Shared/LINGYUN/Abp/Saas/Localization/Resources/en.json index 8d13828e7..8d976749b 100644 --- a/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain.Shared/LINGYUN/Abp/Saas/Localization/Resources/en.json +++ b/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain.Shared/LINGYUN/Abp/Saas/Localization/Resources/en.json @@ -8,6 +8,7 @@ "Saas:020101": "The default connection string cannot open a connection to the database!", "Saas:020102": "The database pointed to by the default connection string already exists!", "Saas:020103": "Unable to open the database connection pointed to by {Name}!", + "Saas:020104": "Database connection check of the {Name} type is not supported!", "Volo.AbpIo.MultiTenancy:010001": "The tenant is unavailable or restricted!", "Volo.AbpIo.MultiTenancy:010002": "Tenant unavailable!", "Menu:Saas": "Saas", @@ -25,6 +26,7 @@ "ConnectionStrings:AddNew": "New Connection", "DisplayName:DefaultConnectionString": "Default Connection String", "DisplayName:UseSharedDatabase": "Use the Shared Database", + "DisplayName:DataBaseProvider": "Data Base Provider", "DisplayName:Name": "Name", "DisplayName:Value": "Value", "DisplayName:IsActive": "Active", diff --git a/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain.Shared/LINGYUN/Abp/Saas/Localization/Resources/zh-Hans.json b/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain.Shared/LINGYUN/Abp/Saas/Localization/Resources/zh-Hans.json index 26caa8a45..21dba4be6 100644 --- a/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain.Shared/LINGYUN/Abp/Saas/Localization/Resources/zh-Hans.json +++ b/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain.Shared/LINGYUN/Abp/Saas/Localization/Resources/zh-Hans.json @@ -8,6 +8,7 @@ "Saas:020101": "无法打开默认连接字符串指向的数据库连接!", "Saas:020102": "默认连接字符串指向的数据库已经存在!", "Saas:020103": "无法打开 {Name} 指向的数据库连接!", + "Saas:020104": "不支持 {Name} 类型的数据库连接检查!", "Volo.AbpIo.MultiTenancy:010001": "租户不可用或受限制!", "Volo.AbpIo.MultiTenancy:010002": "租户不可用!", "Menu:Saas": "Saas", @@ -25,6 +26,7 @@ "ConnectionStrings:AddNew": "添加新连接", "DisplayName:DefaultConnectionString": "默认连接字符串", "DisplayName:UseSharedDatabase": "使用共享数据库", + "DisplayName:DataBaseProvider": "数据库提供者", "DisplayName:Name": "名称", "DisplayName:Value": "值", "DisplayName:IsActive": "启用", diff --git a/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain/LINGYUN/Abp/Saas/AbpSaasConnectionStringCheckOptions.cs b/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain/LINGYUN/Abp/Saas/AbpSaasConnectionStringCheckOptions.cs new file mode 100644 index 000000000..10c287eb9 --- /dev/null +++ b/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain/LINGYUN/Abp/Saas/AbpSaasConnectionStringCheckOptions.cs @@ -0,0 +1,15 @@ +using LINGYUN.Abp.Saas.Tenants; +using System; +using System.Collections.Generic; + +namespace LINGYUN.Abp.Saas; + +public class AbpSaasConnectionStringCheckOptions +{ + public IDictionary ConnectionStringCheckers { get; } + + public AbpSaasConnectionStringCheckOptions() + { + ConnectionStringCheckers = new Dictionary(StringComparer.InvariantCultureIgnoreCase); + } +} diff --git a/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain/LINGYUN/Abp/Saas/Tenants/DataBaseConnectionStringCheckResult.cs b/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain/LINGYUN/Abp/Saas/Tenants/DataBaseConnectionStringCheckResult.cs new file mode 100644 index 000000000..e79456841 --- /dev/null +++ b/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain/LINGYUN/Abp/Saas/Tenants/DataBaseConnectionStringCheckResult.cs @@ -0,0 +1,9 @@ +using System; +using Volo.Abp.Data; + +namespace LINGYUN.Abp.Saas.Tenants; + +public class DataBaseConnectionStringCheckResult : AbpConnectionStringCheckResult +{ + public Exception Error { get; set; } +} diff --git a/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain/LINGYUN/Abp/Saas/Tenants/IDataBaseConnectionStringChecker.cs b/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain/LINGYUN/Abp/Saas/Tenants/IDataBaseConnectionStringChecker.cs new file mode 100644 index 000000000..f2ce72c51 --- /dev/null +++ b/aspnet-core/modules/saas/LINGYUN.Abp.Saas.Domain/LINGYUN/Abp/Saas/Tenants/IDataBaseConnectionStringChecker.cs @@ -0,0 +1,8 @@ +using System.Threading.Tasks; + +namespace LINGYUN.Abp.Saas.Tenants; + +public interface IDataBaseConnectionStringChecker +{ + Task CheckAsync(string connectionString); +} diff --git a/aspnet-core/modules/saas/LINGYUN.Abp.Saas.HttpApi/LINGYUN/Abp/Saas/Tenants/TenantController.cs b/aspnet-core/modules/saas/LINGYUN.Abp.Saas.HttpApi/LINGYUN/Abp/Saas/Tenants/TenantController.cs index 9e29feaa9..34120729a 100644 --- a/aspnet-core/modules/saas/LINGYUN.Abp.Saas.HttpApi/LINGYUN/Abp/Saas/Tenants/TenantController.cs +++ b/aspnet-core/modules/saas/LINGYUN.Abp.Saas.HttpApi/LINGYUN/Abp/Saas/Tenants/TenantController.cs @@ -95,4 +95,11 @@ public class TenantController : AbpSaasControllerBase, ITenantAppService { return TenantAppService.DeleteConnectionStringAsync(id, name); } + [HttpPost] + [Route("connection-string/check")] + [Authorize(AbpSaasPermissions.Tenants.ManageConnectionStrings)] + public virtual Task CheckConnectionStringAsync(TenantConnectionStringCheckInput input) + { + return TenantAppService.CheckConnectionStringAsync(input); + } } From c7febe00fa04ac084730b116a0a6ab39e53f17d8 Mon Sep 17 00:00:00 2001 From: colin Date: Wed, 2 Apr 2025 08:38:42 +0800 Subject: [PATCH 4/4] feat(quartz): References the MySql initialization module --- .../LINGYUN.MicroService.SingleProject.sln | 21 +++++++++++++ .../LINGYUN.MicroService.TaskManagement.sln | 14 +++++++++ ...INGYUN.MicroService.WebhooksManagement.sln | 14 +++++++++ aspnet-core/LINGYUN.MicroService.Workflow.sln | 14 +++++++++ .../FodyWeavers.xsd | 30 +++++++++++++++++++ .../AbpQuartzMySqlInstallerModule.cs | 15 ++++++---- .../MySqlInstaller/QuartzMySqlInstaller.cs | 3 +- .../AbpQuartzSqlServerInstallerModule.cs | 15 ++++++---- .../QuartzSqlServerInstaller.cs | 3 +- ...LY.MicroService.Applications.Single.csproj | 3 +- .../MicroServiceApplicationsSingleModule.cs | 5 ++++ ...Service.TaskManagement.HttpApi.Host.csproj | 1 + .../TaskManagementHttpApiHostModule.cs | 2 ++ ...ice.WebhooksManagement.HttpApi.Host.csproj | 1 + .../WebhooksManagementHttpApiHostModule.cs | 2 ++ ...ice.WorkflowManagement.HttpApi.Host.csproj | 1 + .../WorkflowManagementHttpApiHostModule.cs | 2 ++ 17 files changed, 133 insertions(+), 13 deletions(-) create mode 100644 aspnet-core/modules/task-management/LINGYUN.Abp.Quartz.MySqlInstaller/FodyWeavers.xsd diff --git a/aspnet-core/LINGYUN.MicroService.SingleProject.sln b/aspnet-core/LINGYUN.MicroService.SingleProject.sln index 6f95fc248..a88b87efa 100644 --- a/aspnet-core/LINGYUN.MicroService.SingleProject.sln +++ b/aspnet-core/LINGYUN.MicroService.SingleProject.sln @@ -666,6 +666,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.WeChat.Work.Asp EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.Identity.WeChat.Work", "framework\wechat\LINGYUN.Abp.Identity.WeChat.Work\LINGYUN.Abp.Identity.WeChat.Work.csproj", "{CCC8A29C-1FC1-044F-895A-EC6894CDC8E5}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.Saas.DbChecker", "modules\saas\LINGYUN.Abp.Saas.DbChecker\LINGYUN.Abp.Saas.DbChecker.csproj", "{32F0884D-DA64-4659-AEB7-2717B977855F}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.Quartz.MySqlInstaller", "modules\task-management\LINGYUN.Abp.Quartz.MySqlInstaller\LINGYUN.Abp.Quartz.MySqlInstaller.csproj", "{B6452D3F-E58C-C433-E52A-F65EE2657E01}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.Quartz.SqlServerInstaller", "modules\task-management\LINGYUN.Abp.Quartz.SqlServerInstaller\LINGYUN.Abp.Quartz.SqlServerInstaller.csproj", "{D613F393-9CEE-2D3B-33C9-90630F8348E7}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -1768,6 +1774,18 @@ Global {CCC8A29C-1FC1-044F-895A-EC6894CDC8E5}.Debug|Any CPU.Build.0 = Debug|Any CPU {CCC8A29C-1FC1-044F-895A-EC6894CDC8E5}.Release|Any CPU.ActiveCfg = Release|Any CPU {CCC8A29C-1FC1-044F-895A-EC6894CDC8E5}.Release|Any CPU.Build.0 = Release|Any CPU + {32F0884D-DA64-4659-AEB7-2717B977855F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {32F0884D-DA64-4659-AEB7-2717B977855F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {32F0884D-DA64-4659-AEB7-2717B977855F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {32F0884D-DA64-4659-AEB7-2717B977855F}.Release|Any CPU.Build.0 = Release|Any CPU + {B6452D3F-E58C-C433-E52A-F65EE2657E01}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B6452D3F-E58C-C433-E52A-F65EE2657E01}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B6452D3F-E58C-C433-E52A-F65EE2657E01}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B6452D3F-E58C-C433-E52A-F65EE2657E01}.Release|Any CPU.Build.0 = Release|Any CPU + {D613F393-9CEE-2D3B-33C9-90630F8348E7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D613F393-9CEE-2D3B-33C9-90630F8348E7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D613F393-9CEE-2D3B-33C9-90630F8348E7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D613F393-9CEE-2D3B-33C9-90630F8348E7}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -2092,6 +2110,9 @@ Global {C9266D5D-3860-09C3-F566-489BBB57A534} = {D94D6AFE-20BD-4F21-8708-03F5E34F49FC} {40DC9A79-2E8A-4C6F-A637-5C09D6F26B0E} = {91867618-0D86-4410-91C6-B1166A9ACDF9} {CCC8A29C-1FC1-044F-895A-EC6894CDC8E5} = {91867618-0D86-4410-91C6-B1166A9ACDF9} + {32F0884D-DA64-4659-AEB7-2717B977855F} = {0DF5AD76-AEEA-4052-A6CA-A44C24879F11} + {B6452D3F-E58C-C433-E52A-F65EE2657E01} = {D9C65C9D-8591-46DA-A3EE-419393E607AB} + {D613F393-9CEE-2D3B-33C9-90630F8348E7} = {D9C65C9D-8591-46DA-A3EE-419393E607AB} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {711A43C0-A2F8-4E5C-9B9F-F2551E4B3FF1} diff --git a/aspnet-core/LINGYUN.MicroService.TaskManagement.sln b/aspnet-core/LINGYUN.MicroService.TaskManagement.sln index 57236d16e..84f9888fd 100644 --- a/aspnet-core/LINGYUN.MicroService.TaskManagement.sln +++ b/aspnet-core/LINGYUN.MicroService.TaskManagement.sln @@ -170,6 +170,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.Sms.Platform", EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.Telemetry.SkyWalking", "framework\telemetry\LINGYUN.Abp.Telemetry.SkyWalking\LINGYUN.Abp.Telemetry.SkyWalking.csproj", "{7CF83493-6AF5-9C6D-01A7-AC7FC11BC2CE}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.Quartz.MySqlInstaller", "modules\task-management\LINGYUN.Abp.Quartz.MySqlInstaller\LINGYUN.Abp.Quartz.MySqlInstaller.csproj", "{B6452D3F-E58C-C433-E52A-F65EE2657E01}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.Quartz.SqlServerInstaller", "modules\task-management\LINGYUN.Abp.Quartz.SqlServerInstaller\LINGYUN.Abp.Quartz.SqlServerInstaller.csproj", "{D613F393-9CEE-2D3B-33C9-90630F8348E7}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -436,6 +440,14 @@ Global {7CF83493-6AF5-9C6D-01A7-AC7FC11BC2CE}.Debug|Any CPU.Build.0 = Debug|Any CPU {7CF83493-6AF5-9C6D-01A7-AC7FC11BC2CE}.Release|Any CPU.ActiveCfg = Release|Any CPU {7CF83493-6AF5-9C6D-01A7-AC7FC11BC2CE}.Release|Any CPU.Build.0 = Release|Any CPU + {B6452D3F-E58C-C433-E52A-F65EE2657E01}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B6452D3F-E58C-C433-E52A-F65EE2657E01}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B6452D3F-E58C-C433-E52A-F65EE2657E01}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B6452D3F-E58C-C433-E52A-F65EE2657E01}.Release|Any CPU.Build.0 = Release|Any CPU + {D613F393-9CEE-2D3B-33C9-90630F8348E7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D613F393-9CEE-2D3B-33C9-90630F8348E7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D613F393-9CEE-2D3B-33C9-90630F8348E7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D613F393-9CEE-2D3B-33C9-90630F8348E7}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -506,6 +518,8 @@ Global {8BAB6A91-865C-A599-BE2A-7C487129D83A} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} {8298C4A6-5275-D7A2-9A5C-99B5F2D0E7A0} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} {7CF83493-6AF5-9C6D-01A7-AC7FC11BC2CE} = {5A41C31A-B966-418B-B446-5BA1D7E61A62} + {B6452D3F-E58C-C433-E52A-F65EE2657E01} = {385578CC-C0F1-4377-A7A2-682B8F416234} + {D613F393-9CEE-2D3B-33C9-90630F8348E7} = {385578CC-C0F1-4377-A7A2-682B8F416234} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {E1FD1F4C-D344-408B-97CF-B6F1F6D7D293} diff --git a/aspnet-core/LINGYUN.MicroService.WebhooksManagement.sln b/aspnet-core/LINGYUN.MicroService.WebhooksManagement.sln index cc5c8e797..e30af9fe4 100644 --- a/aspnet-core/LINGYUN.MicroService.WebhooksManagement.sln +++ b/aspnet-core/LINGYUN.MicroService.WebhooksManagement.sln @@ -167,6 +167,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.Telemetry.SkyWa EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "telemetry", "telemetry", "{CE07B9F4-54E8-4E74-BE14-8E5C1FB7AFC8}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.Quartz.MySqlInstaller", "modules\task-management\LINGYUN.Abp.Quartz.MySqlInstaller\LINGYUN.Abp.Quartz.MySqlInstaller.csproj", "{B6452D3F-E58C-C433-E52A-F65EE2657E01}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.Quartz.SqlServerInstaller", "modules\task-management\LINGYUN.Abp.Quartz.SqlServerInstaller\LINGYUN.Abp.Quartz.SqlServerInstaller.csproj", "{D613F393-9CEE-2D3B-33C9-90630F8348E7}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -429,6 +433,14 @@ Global {7CF83493-6AF5-9C6D-01A7-AC7FC11BC2CE}.Debug|Any CPU.Build.0 = Debug|Any CPU {7CF83493-6AF5-9C6D-01A7-AC7FC11BC2CE}.Release|Any CPU.ActiveCfg = Release|Any CPU {7CF83493-6AF5-9C6D-01A7-AC7FC11BC2CE}.Release|Any CPU.Build.0 = Release|Any CPU + {B6452D3F-E58C-C433-E52A-F65EE2657E01}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B6452D3F-E58C-C433-E52A-F65EE2657E01}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B6452D3F-E58C-C433-E52A-F65EE2657E01}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B6452D3F-E58C-C433-E52A-F65EE2657E01}.Release|Any CPU.Build.0 = Release|Any CPU + {D613F393-9CEE-2D3B-33C9-90630F8348E7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D613F393-9CEE-2D3B-33C9-90630F8348E7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D613F393-9CEE-2D3B-33C9-90630F8348E7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D613F393-9CEE-2D3B-33C9-90630F8348E7}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -512,6 +524,8 @@ Global {8BAB6A91-865C-A599-BE2A-7C487129D83A} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} {7CF83493-6AF5-9C6D-01A7-AC7FC11BC2CE} = {CE07B9F4-54E8-4E74-BE14-8E5C1FB7AFC8} {CE07B9F4-54E8-4E74-BE14-8E5C1FB7AFC8} = {03B4B0AA-83CE-4E4B-9CE2-47369BF88B97} + {B6452D3F-E58C-C433-E52A-F65EE2657E01} = {8C3DF571-BAC3-48C4-B46A-AC0E0EAA9871} + {D613F393-9CEE-2D3B-33C9-90630F8348E7} = {8C3DF571-BAC3-48C4-B46A-AC0E0EAA9871} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {80ED12A5-C899-459F-A181-ADCC9D680DE5} diff --git a/aspnet-core/LINGYUN.MicroService.Workflow.sln b/aspnet-core/LINGYUN.MicroService.Workflow.sln index e26f6f05c..aced25869 100644 --- a/aspnet-core/LINGYUN.MicroService.Workflow.sln +++ b/aspnet-core/LINGYUN.MicroService.Workflow.sln @@ -189,6 +189,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LY.MicroService.WorkflowMan EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.Telemetry.SkyWalking", "framework\telemetry\LINGYUN.Abp.Telemetry.SkyWalking\LINGYUN.Abp.Telemetry.SkyWalking.csproj", "{7CF83493-6AF5-9C6D-01A7-AC7FC11BC2CE}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.Quartz.MySqlInstaller", "modules\task-management\LINGYUN.Abp.Quartz.MySqlInstaller\LINGYUN.Abp.Quartz.MySqlInstaller.csproj", "{B5C96536-6387-44F4-A2E2-D4D683588AF5}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.Quartz.SqlServerInstaller", "modules\task-management\LINGYUN.Abp.Quartz.SqlServerInstaller\LINGYUN.Abp.Quartz.SqlServerInstaller.csproj", "{52F5A9DE-50B8-42C6-9980-E908DC6A4B52}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -495,6 +499,14 @@ Global {7CF83493-6AF5-9C6D-01A7-AC7FC11BC2CE}.Debug|Any CPU.Build.0 = Debug|Any CPU {7CF83493-6AF5-9C6D-01A7-AC7FC11BC2CE}.Release|Any CPU.ActiveCfg = Release|Any CPU {7CF83493-6AF5-9C6D-01A7-AC7FC11BC2CE}.Release|Any CPU.Build.0 = Release|Any CPU + {B5C96536-6387-44F4-A2E2-D4D683588AF5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B5C96536-6387-44F4-A2E2-D4D683588AF5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B5C96536-6387-44F4-A2E2-D4D683588AF5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B5C96536-6387-44F4-A2E2-D4D683588AF5}.Release|Any CPU.Build.0 = Release|Any CPU + {52F5A9DE-50B8-42C6-9980-E908DC6A4B52}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {52F5A9DE-50B8-42C6-9980-E908DC6A4B52}.Debug|Any CPU.Build.0 = Debug|Any CPU + {52F5A9DE-50B8-42C6-9980-E908DC6A4B52}.Release|Any CPU.ActiveCfg = Release|Any CPU + {52F5A9DE-50B8-42C6-9980-E908DC6A4B52}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -581,6 +593,8 @@ Global {9CD04B74-AA10-4253-BEEC-4837D48AD3EB} = {6CB521FC-AC40-49A6-B9A5-91399CAA59AB} {09CDA563-DE16-41F6-B61C-56102E7D9B2E} = {9CD04B74-AA10-4253-BEEC-4837D48AD3EB} {7CF83493-6AF5-9C6D-01A7-AC7FC11BC2CE} = {6DA78E72-BA55-4ECF-97DB-6258174D3E2A} + {B5C96536-6387-44F4-A2E2-D4D683588AF5} = {7844FF58-7DBF-46E1-88B7-9764382A4EE9} + {52F5A9DE-50B8-42C6-9980-E908DC6A4B52} = {7844FF58-7DBF-46E1-88B7-9764382A4EE9} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {6BB7A5DE-DA12-44DC-BC9B-0F6CA524346F} diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.Quartz.MySqlInstaller/FodyWeavers.xsd b/aspnet-core/modules/task-management/LINGYUN.Abp.Quartz.MySqlInstaller/FodyWeavers.xsd new file mode 100644 index 000000000..3f3946e28 --- /dev/null +++ b/aspnet-core/modules/task-management/LINGYUN.Abp.Quartz.MySqlInstaller/FodyWeavers.xsd @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed. + + + + + A comma-separated list of error codes that can be safely ignored in assembly verification. + + + + + 'false' to turn off automatic generation of the XML Schema file. + + + + + \ No newline at end of file diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.Quartz.MySqlInstaller/LINGYUN/Abp/Quartz/MySqlInstaller/AbpQuartzMySqlInstallerModule.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.Quartz.MySqlInstaller/LINGYUN/Abp/Quartz/MySqlInstaller/AbpQuartzMySqlInstallerModule.cs index b7878f537..94b8e0422 100644 --- a/aspnet-core/modules/task-management/LINGYUN.Abp.Quartz.MySqlInstaller/LINGYUN/Abp/Quartz/MySqlInstaller/AbpQuartzMySqlInstallerModule.cs +++ b/aspnet-core/modules/task-management/LINGYUN.Abp.Quartz.MySqlInstaller/LINGYUN/Abp/Quartz/MySqlInstaller/AbpQuartzMySqlInstallerModule.cs @@ -1,4 +1,5 @@ -using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; using System.Threading.Tasks; using Volo.Abp; using Volo.Abp.Modularity; @@ -22,9 +23,13 @@ public class AbpQuartzMySqlInstallerModule : AbpModule public async override Task OnPreApplicationInitializationAsync(ApplicationInitializationContext context) { - // 初始化 Quartz Mysql 数据库 - await context.ServiceProvider - .GetRequiredService() - .InstallAsync(); + var configuration = context.ServiceProvider.GetRequiredService(); + if (configuration.GetValue("Quartz:UsePersistentStore", false)) + { + // 初始化 Quartz Mysql 数据库 + await context.ServiceProvider + .GetRequiredService() + .InstallAsync(); + } } } \ No newline at end of file diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.Quartz.MySqlInstaller/LINGYUN/Abp/Quartz/MySqlInstaller/QuartzMySqlInstaller.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.Quartz.MySqlInstaller/LINGYUN/Abp/Quartz/MySqlInstaller/QuartzMySqlInstaller.cs index 40e6dfb22..5358d43da 100644 --- a/aspnet-core/modules/task-management/LINGYUN.Abp.Quartz.MySqlInstaller/LINGYUN/Abp/Quartz/MySqlInstaller/QuartzMySqlInstaller.cs +++ b/aspnet-core/modules/task-management/LINGYUN.Abp.Quartz.MySqlInstaller/LINGYUN/Abp/Quartz/MySqlInstaller/QuartzMySqlInstaller.cs @@ -6,13 +6,14 @@ using MySqlConnector; using System; using System.Data; using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; using Volo.Abp.Quartz; using Volo.Abp.VirtualFileSystem; using static Quartz.SchedulerBuilder; namespace LINGYUN.Abp.Quartz.MySqlInstaller; -public class QuartzMySqlInstaller +public class QuartzMySqlInstaller : ITransientDependency { public ILogger Logger { protected get; set; } diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.Quartz.SqlServerInstaller/LINGYUN/Abp/Quartz/SqlServerInstaller/AbpQuartzSqlServerInstallerModule.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.Quartz.SqlServerInstaller/LINGYUN/Abp/Quartz/SqlServerInstaller/AbpQuartzSqlServerInstallerModule.cs index c3c69701e..0e8eabe51 100644 --- a/aspnet-core/modules/task-management/LINGYUN.Abp.Quartz.SqlServerInstaller/LINGYUN/Abp/Quartz/SqlServerInstaller/AbpQuartzSqlServerInstallerModule.cs +++ b/aspnet-core/modules/task-management/LINGYUN.Abp.Quartz.SqlServerInstaller/LINGYUN/Abp/Quartz/SqlServerInstaller/AbpQuartzSqlServerInstallerModule.cs @@ -1,4 +1,5 @@ -using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; using System.Threading.Tasks; using Volo.Abp; using Volo.Abp.Modularity; @@ -22,9 +23,13 @@ public class AbpQuartzSqlServerInstallerModule : AbpModule public async override Task OnPreApplicationInitializationAsync(ApplicationInitializationContext context) { - // 初始化 Quartz SqlServer 数据库 - await context.ServiceProvider - .GetRequiredService() - .InstallAsync(); + var configuration = context.ServiceProvider.GetRequiredService(); + if (configuration.GetValue("Quartz:UsePersistentStore", false)) + { + // 初始化 Quartz SqlServer 数据库 + await context.ServiceProvider + .GetRequiredService() + .InstallAsync(); + } } } \ No newline at end of file diff --git a/aspnet-core/modules/task-management/LINGYUN.Abp.Quartz.SqlServerInstaller/LINGYUN/Abp/Quartz/SqlServerInstaller/QuartzSqlServerInstaller.cs b/aspnet-core/modules/task-management/LINGYUN.Abp.Quartz.SqlServerInstaller/LINGYUN/Abp/Quartz/SqlServerInstaller/QuartzSqlServerInstaller.cs index 5d4ac3166..ec2d3460e 100644 --- a/aspnet-core/modules/task-management/LINGYUN.Abp.Quartz.SqlServerInstaller/LINGYUN/Abp/Quartz/SqlServerInstaller/QuartzSqlServerInstaller.cs +++ b/aspnet-core/modules/task-management/LINGYUN.Abp.Quartz.SqlServerInstaller/LINGYUN/Abp/Quartz/SqlServerInstaller/QuartzSqlServerInstaller.cs @@ -6,13 +6,14 @@ using Microsoft.Extensions.Options; using System; using System.Data; using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; using Volo.Abp.Quartz; using Volo.Abp.VirtualFileSystem; using static Quartz.SchedulerBuilder; namespace LINGYUN.Abp.Quartz.SqlServerInstaller; -public class QuartzSqlServerInstaller +public class QuartzSqlServerInstaller : ITransientDependency { public ILogger Logger { protected get; set; } diff --git a/aspnet-core/services/LY.MicroService.Applications.Single/LY.MicroService.Applications.Single.csproj b/aspnet-core/services/LY.MicroService.Applications.Single/LY.MicroService.Applications.Single.csproj index 4f18eb613..7a3083599 100644 --- a/aspnet-core/services/LY.MicroService.Applications.Single/LY.MicroService.Applications.Single.csproj +++ b/aspnet-core/services/LY.MicroService.Applications.Single/LY.MicroService.Applications.Single.csproj @@ -15,7 +15,6 @@ - @@ -230,6 +229,7 @@ + @@ -246,6 +246,7 @@ + diff --git a/aspnet-core/services/LY.MicroService.Applications.Single/MicroServiceApplicationsSingleModule.cs b/aspnet-core/services/LY.MicroService.Applications.Single/MicroServiceApplicationsSingleModule.cs index 10dde41f6..c2741f2a5 100644 --- a/aspnet-core/services/LY.MicroService.Applications.Single/MicroServiceApplicationsSingleModule.cs +++ b/aspnet-core/services/LY.MicroService.Applications.Single/MicroServiceApplicationsSingleModule.cs @@ -1,6 +1,7 @@ using LINGYUN.Abp.Identity.WeChat.Work; using LINGYUN.Abp.Notifications.WeChat.Work; using LINGYUN.Abp.OssManagement.Minio; +using LINGYUN.Abp.Quartz.MySqlInstaller; namespace LY.MicroService.Applications.Single; @@ -161,6 +162,8 @@ namespace LY.MicroService.Applications.Single; typeof(AbpSaasHttpApiModule), // Saas模块 实体框架 typeof(AbpSaasEntityFrameworkCoreModule), + // Saas模块 数据库连接检查 + typeof(AbpSaasDbCheckerModule), // 任务管理模块 领域服务 typeof(TaskManagementDomainModule), @@ -261,6 +264,8 @@ namespace LY.MicroService.Applications.Single; typeof(AbpBackgroundTasksNotificationsModule), // 后台任务模块 Quartz集成 typeof(AbpBackgroundTasksQuartzModule), + // Quartz MySql数据库初始化模块 + typeof(AbpQuartzMySqlInstallerModule), // 数据审计模块 应用服务 typeof(AbpDataProtectionManagementApplicationModule), diff --git a/aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/LY.MicroService.TaskManagement.HttpApi.Host.csproj b/aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/LY.MicroService.TaskManagement.HttpApi.Host.csproj index 3443f8310..913a312df 100644 --- a/aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/LY.MicroService.TaskManagement.HttpApi.Host.csproj +++ b/aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/LY.MicroService.TaskManagement.HttpApi.Host.csproj @@ -66,6 +66,7 @@ + diff --git a/aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/TaskManagementHttpApiHostModule.cs b/aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/TaskManagementHttpApiHostModule.cs index b8f6b51f7..6af1ef7f3 100644 --- a/aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/TaskManagementHttpApiHostModule.cs +++ b/aspnet-core/services/LY.MicroService.TaskManagement.HttpApi.Host/TaskManagementHttpApiHostModule.cs @@ -16,6 +16,7 @@ using LINGYUN.Abp.ExceptionHandling.Emailing; using LINGYUN.Abp.Localization.CultureMap; using LINGYUN.Abp.LocalizationManagement.EntityFrameworkCore; using LINGYUN.Abp.OssManagement; +using LINGYUN.Abp.Quartz.MySqlInstaller; using LINGYUN.Abp.Saas.EntityFrameworkCore; using LINGYUN.Abp.Serilog.Enrichers.Application; using LINGYUN.Abp.Serilog.Enrichers.UniqueId; @@ -63,6 +64,7 @@ namespace LY.MicroService.TaskManagement; typeof(AbpBackgroundTasksDistributedLockingModule), typeof(AbpBackgroundTasksExceptionHandlingModule), typeof(AbpBackgroundTasksNotificationsModule), + typeof(AbpQuartzMySqlInstallerModule), typeof(TaskManagementApplicationModule), typeof(TaskManagementHttpApiModule), typeof(TaskManagementEntityFrameworkCoreModule), diff --git a/aspnet-core/services/LY.MicroService.WebhooksManagement.HttpApi.Host/LY.MicroService.WebhooksManagement.HttpApi.Host.csproj b/aspnet-core/services/LY.MicroService.WebhooksManagement.HttpApi.Host/LY.MicroService.WebhooksManagement.HttpApi.Host.csproj index a0e53d6b0..39ecc0cca 100644 --- a/aspnet-core/services/LY.MicroService.WebhooksManagement.HttpApi.Host/LY.MicroService.WebhooksManagement.HttpApi.Host.csproj +++ b/aspnet-core/services/LY.MicroService.WebhooksManagement.HttpApi.Host/LY.MicroService.WebhooksManagement.HttpApi.Host.csproj @@ -60,6 +60,7 @@ + diff --git a/aspnet-core/services/LY.MicroService.WebhooksManagement.HttpApi.Host/WebhooksManagementHttpApiHostModule.cs b/aspnet-core/services/LY.MicroService.WebhooksManagement.HttpApi.Host/WebhooksManagementHttpApiHostModule.cs index 68191fb9e..16ba651bd 100644 --- a/aspnet-core/services/LY.MicroService.WebhooksManagement.HttpApi.Host/WebhooksManagementHttpApiHostModule.cs +++ b/aspnet-core/services/LY.MicroService.WebhooksManagement.HttpApi.Host/WebhooksManagementHttpApiHostModule.cs @@ -14,6 +14,7 @@ using LINGYUN.Abp.ExceptionHandling.Emailing; using LINGYUN.Abp.Http.Client.Wrapper; using LINGYUN.Abp.Identity.Session.AspNetCore; using LINGYUN.Abp.LocalizationManagement.EntityFrameworkCore; +using LINGYUN.Abp.Quartz.MySqlInstaller; using LINGYUN.Abp.Saas.EntityFrameworkCore; using LINGYUN.Abp.Serilog.Enrichers.Application; using LINGYUN.Abp.Serilog.Enrichers.UniqueId; @@ -60,6 +61,7 @@ namespace LY.MicroService.WebhooksManagement; typeof(AbpBackgroundTasksQuartzModule), typeof(AbpBackgroundTasksDistributedLockingModule), typeof(AbpBackgroundTasksExceptionHandlingModule), + typeof(AbpQuartzMySqlInstallerModule), typeof(TaskManagementEntityFrameworkCoreModule), typeof(AbpSaasEntityFrameworkCoreModule), typeof(AbpFeatureManagementEntityFrameworkCoreModule), diff --git a/aspnet-core/services/LY.MicroService.WorkflowManagement.HttpApi.Host/LY.MicroService.WorkflowManagement.HttpApi.Host.csproj b/aspnet-core/services/LY.MicroService.WorkflowManagement.HttpApi.Host/LY.MicroService.WorkflowManagement.HttpApi.Host.csproj index f4e5be3ca..d38cfddea 100644 --- a/aspnet-core/services/LY.MicroService.WorkflowManagement.HttpApi.Host/LY.MicroService.WorkflowManagement.HttpApi.Host.csproj +++ b/aspnet-core/services/LY.MicroService.WorkflowManagement.HttpApi.Host/LY.MicroService.WorkflowManagement.HttpApi.Host.csproj @@ -76,6 +76,7 @@ + diff --git a/aspnet-core/services/LY.MicroService.WorkflowManagement.HttpApi.Host/WorkflowManagementHttpApiHostModule.cs b/aspnet-core/services/LY.MicroService.WorkflowManagement.HttpApi.Host/WorkflowManagementHttpApiHostModule.cs index d9b3a7116..578889b52 100644 --- a/aspnet-core/services/LY.MicroService.WorkflowManagement.HttpApi.Host/WorkflowManagementHttpApiHostModule.cs +++ b/aspnet-core/services/LY.MicroService.WorkflowManagement.HttpApi.Host/WorkflowManagementHttpApiHostModule.cs @@ -20,6 +20,7 @@ using LINGYUN.Abp.Http.Client.Wrapper; using LINGYUN.Abp.Identity.Session.AspNetCore; using LINGYUN.Abp.Localization.CultureMap; using LINGYUN.Abp.LocalizationManagement.EntityFrameworkCore; +using LINGYUN.Abp.Quartz.MySqlInstaller; using LINGYUN.Abp.Saas.EntityFrameworkCore; using LINGYUN.Abp.Serilog.Enrichers.Application; using LINGYUN.Abp.Serilog.Enrichers.UniqueId; @@ -66,6 +67,7 @@ namespace LY.MicroService.WorkflowManagement; typeof(AbpBackgroundTasksQuartzModule), typeof(AbpBackgroundTasksDistributedLockingModule), typeof(AbpBackgroundTasksExceptionHandlingModule), + typeof(AbpQuartzMySqlInstallerModule), typeof(TaskManagementEntityFrameworkCoreModule), typeof(AbpFeatureManagementEntityFrameworkCoreModule), typeof(AbpPermissionManagementEntityFrameworkCoreModule),