From 57557d81a4a5c897f64fb98e6b5719d3ec967289 Mon Sep 17 00:00:00 2001 From: wyw <571921741@qq.com> Date: Tue, 7 Apr 2026 13:47:52 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=BB=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .dockerignore | 25 + .gitignore | 398 ++ APT.API/APT.API.csproj | 36 + APT.API/APT.API.sln | 61 + APT.API/ActionMonitorAttribute.cs | 54 + APT.API/App_Start/DIConfig.cs | 44 + APT.API/CombindedConnectionGenerator.cs | 66 + APT.API/Controllers/AptController.cs | 15 + APT.API/Controllers/ValuesController.cs | 311 ++ APT.API/Dockerfile | 28 + APT.API/ILogTest.cs | 13 + APT.API/LogAttribute.cs | 50 + APT.API/LogInterceptor.cs | 28 + APT.API/Program.cs | 19 + APT.API/Properties/launchSettings.json | 36 + APT.API/Startup.cs | 122 + APT.API/appsettings.Development.json | 9 + APT.API/appsettings.json | 32 + APT.API/log4net.config | 39 + APT.DAL.Data/APT.DAL.Data.csproj | 16 + APT.DAL.Data/CourseMap.cs | 27 + APT.DAL.Data/PhoneMap.cs | 27 + APT.DAL.Data/TestNoneBaseMap.cs | 16 + APT.DAL.Data/UserMap.cs | 40 + APT.Domain/APT.Domain.csproj | 15 + APT.Domain/LDX_Test_Course.cs | 22 + APT.Domain/LDX_Test_Phone.cs | 22 + APT.Domain/LDX_Test_User.cs | 18 + APT.Domain/ModelBase.cs | 15 + APT.Domain/TestNoneBaseModel.cs | 13 + APT.Frame.sln | 73 + .../APT.Infrastructure.Api.csproj | 31 + .../APT.Infrastructure.Api.xml | 3293 ++++++++++++ .../Api/APTApiController.cs | 1009 ++++ .../Api/BaseApiController.cs | 202 + .../Api/CommonApiController.cs | 1861 +++++++ APT.Infrastructure.Api/DI/IDependency.cs | 9 + APT.Infrastructure.Api/DI/ServiceLocator.cs | 74 + .../ConfigurationSectionExtension.cs | 73 + .../Extensions/HttpContextExtensions.cs | 19 + .../Extensions/RootOrgAttribute.cs | 43 + .../Helper/WebSocketServiceHelper.cs | 301 ++ .../LDX.Infrastructure.Api.xml | 1951 ++++++++ .../Model/NeedRetryExceptions.cs | 18 + APT.Infrastructure.Api/Model/TenantInfo.cs | 50 + .../Redis/CsRedisManager.cs | 509 ++ APT.Infrastructure.Api/Redis/RedisConfig.cs | 175 + .../Redis/RedisConfigurationExtensions.cs | 42 + APT.Infrastructure.Api/Redis/RedisManager.cs | 1234 +++++ APT.Infrastructure.Api/Redis/RedisOption.cs | 24 + .../Service/CommonService.cs | 1084 ++++ .../Service/DomainServiceBase.cs | 803 +++ .../Service/ICommonService.cs | 571 +++ .../Service/IDomainService.cs | 215 + APT.Infrastructure.Api/Structs/AppContext.cs | 114 + .../Structs/ConfigurationManager.cs | 93 + .../Structs/DefaultAutofacModuleRegister.cs | 22 + .../Structs/InfluxDbHelper.cs | 86 + .../Structs/InfluxDbOption.cs | 89 + .../Structs/LibMessageUtils.cs | 99 + .../APT.Infrastructure.Core.csproj | 38 + .../APT.Infrastructure.Core.xml | 2477 ++++++++++ APT.Infrastructure.Core/EF/IOrderable.cs | 45 + APT.Infrastructure.Core/EF/IRepository.cs | 222 + .../EF/IRepositoryAsync.cs | 120 + APT.Infrastructure.Core/EF/IRowVersion.cs | 10 + APT.Infrastructure.Core/EF/IUnitOfWork.cs | 221 + APT.Infrastructure.Core/EF/Orderable.cs | 83 + .../Extensions/DateTimeExtension.cs | 30 + .../Extensions/EnumExtensions.cs | 75 + .../Extensions/EnumerableExtension.cs | 34 + .../Extensions/ExpressionExtensions.cs | 80 + .../Extensions/FilterGroupExtensions.cs | 45 + .../Extensions/Int32Extensions.cs | 34 + .../Extensions/JsonExtensions.cs | 37 + .../Extensions/LinqExtensions.cs | 67 + .../Extensions/QueryableOrderExtension.cs | 57 + .../Extensions/RandomExtensions.cs | 78 + .../Extensions/TypeExtensions.cs | 167 + APT.Infrastructure.Core/Helper/ApiHelper.cs | 683 +++ APT.Infrastructure.Core/Helper/DataHelper.cs | 78 + .../Helper/FilterHelper.cs | 369 ++ APT.Infrastructure.Core/Helper/HashUtil.cs | 109 + APT.Infrastructure.Core/Helper/LibUtils.cs | 181 + .../Helper/ReflectHelper.cs | 121 + APT.Infrastructure.Core/Helper/Util.cs | 100 + APT.Infrastructure.Core/Helper/WebUtils.cs | 318 ++ .../Interface/ILibMessageManager.cs | 16 + .../LDX.Infrastructure.Core.xml | 2249 +++++++++ APT.Infrastructure.Core/Logging/ILogger.cs | 105 + .../Logging/Log4netLogger.cs | 96 + .../Logging/LogAttribute.cs | 85 + APT.Infrastructure.Core/Logging/LogHelper.cs | 21 + .../Logging/LoggerManager.cs | 35 + APT.Infrastructure.Core/Structs/Attributes.cs | 891 ++++ APT.Infrastructure.Core/Structs/BaseFilter.cs | 160 + .../Structs/BasePageFilter.cs | 46 + .../Structs/CodeException.cs | 38 + .../Structs/CodeRuleParam.cs | 24 + APT.Infrastructure.Core/Structs/DataOrder.cs | 27 + .../Structs/DomainException.cs | 68 + .../Structs/EFApiActionMessage.cs | 15 + .../Structs/EFApiActionResult.cs | 21 + APT.Infrastructure.Core/Structs/EFModel.cs | 85 + APT.Infrastructure.Core/Structs/Enums.cs | 225 + .../Structs/FilterGroup.cs | 47 + APT.Infrastructure.Core/Structs/FilterRule.cs | 71 + .../Structs/IDependInject.cs | 10 + APT.Infrastructure.Core/Structs/ISession.cs | 52 + .../Structs/ISessionProvider.cs | 7 + .../Structs/JsonActionResult.cs | 75 + .../Structs/JsonContractResolver.cs | 81 + .../Structs/KeywordFilter.cs | 153 + .../Structs/KeywordPageFilter.cs | 55 + .../Structs/LibMessageFormatManager.cs | 90 + .../Structs/LibMessageManager.cs | 44 + .../Structs/MultipleDbPageFilter.cs | 16 + .../Structs/NoSessionException.cs | 24 + .../Structs/PagedActionResult.cs | 72 + .../Structs/PagedResultDto.cs | 46 + .../Structs/ParamDynamicDictionary.cs | 91 + APT.Infrastructure.Core/Structs/Permission.cs | 56 + .../Structs/SimpleSession.cs | 40 + .../Structs/SystemCodeFilter.cs | 31 + APT.Infrastructure.Core/Structs/TreeNode.cs | 33 + .../Structs/UpdateCodeSerialInfo.cs | 28 + .../Structs/WeixinToken.cs | 14 + .../Table/DataUpdateRecord.cs | 40 + APT.Infrastructure.Core/Table/EntityBase.cs | 325 ++ .../Table/T_FM_ORGANIZATION.cs | 58 + .../Table/T_PF_CODE_RULE_SERIAL.cs | 36 + APT.Infrastructure.Core/Table/T_PF_PARAM.cs | 28 + .../Thread/LDXThreadPool.cs | 160 + .../Thread/LDXThreadTimeRule.cs | 155 + .../Thread/LDXThreadWork.cs | 64 + APT.Infrastructure.Core/Utils/InitUtils.cs | 55 + .../APT.Infrastructure.Domain.csproj | 13 + .../Models/DataUpdateRecord.cs | 11 + .../APT.Infrastructure.EF.csproj | 42 + .../APT.Infrastructure.EF.xml | 164 + .../ConnectionResolverType.cs | 13 + APT.Infrastructure.EF/Constans.cs | 15 + .../CustomNpgsqlQuerySqlGenerator.cs | 35 + APT.Infrastructure.EF/DbIntegrationType.cs | 12 + APT.Infrastructure.EF/DbsetProperty.cs | 11 + APT.Infrastructure.EF/EFDbContextLog.cs | 36 + APT.Infrastructure.EF/EfDbContext.cs | 1537 ++++++ .../TenantApplicationBuilderExtension.cs | 26 + .../Extension/TenantCoreExtension.cs | 184 + .../Extensions/DataBaseTypeExtension.cs | 31 + .../Extensions/IQueryableSelectorExtension.cs | 62 + .../Extensions/MySqlTenantExtension.cs | 71 + .../Extensions/PostgreTenantExtension.cs | 93 + .../Extensions/SqlServerTenantExtension.cs | 88 + APT.Infrastructure.EF/Helper/AcronymHelper.cs | 114 + .../Impl/MigrationByTenantAssembly.cs | 42 + .../Impl/NamedConnectionGenerator.cs | 39 + .../Impl/SimpleHeaderTenantInfoGenerator.cs | 30 + .../Impl/TenantConnectionResolver.cs | 58 + .../CombindedConnectionGenerator.cs | 71 + .../Infrastructure/ConnectionResolver.cs | 34 + .../Infrastructure/IConnectionGenerator.cs | 13 + .../Infrastructure/IEntityScaner.cs | 14 + .../ITenantConnectionResolver.cs | 9 + .../Infrastructure/ITenantDbContext.cs | 10 + .../Infrastructure/ITenantEntityBuilder.cs | 15 + .../Infrastructure/ITenantInfoGenerator.cs | 10 + .../Infrastructure/TenantInfo.cs | 11 + .../Infrastructure/TenantInfoMiddleware.cs | 113 + .../Map/DataUpdateRecordMap.cs | 30 + APT.Infrastructure.EF/Map/EntityBaseMap.cs | 29 + .../Map/FMOrganizationMap.cs | 23 + APT.Infrastructure.EF/Map/LDXEntityBaseMap.cs | 20 + .../Map/LDXTreeEntityBaseMap.cs | 26 + .../Map/PFCodeRuleSerialMap.cs | 23 + APT.Infrastructure.EF/Map/PFParamMap.cs | 19 + .../Properties/serviceDependencies.json | 7 + .../Properties/serviceDependencies.local.json | 7 + .../QueryWithNoLockDbCommandInterceptor.cs | 56 + APT.Infrastructure.EF/Repository.cs | 4398 +++++++++++++++++ APT.Infrastructure.EF/SimpleEntityScaner.cs | 53 + APT.Infrastructure.EF/TenantBaseDbContext.cs | 39 + APT.Infrastructure.EF/TenantEntityBuilder.cs | 48 + APT.Infrastructure.EF/TenantModelCacheKey.cs | 34 + .../TenantModelCacheKeyFactory.cs | 21 + APT.Infrastructure.EF/TenantOption.cs | 29 + APT.Infrastructure.EF/TenantSettings.cs | 53 + .../APT.Infrastructure.Redis.csproj | 19 + APT.Infrastructure.Redis/AppConfig.cs | 32 + .../Configurations/RedisConfig.cs | 170 + .../RedisConfigurationExtensions.cs | 42 + .../Configurations/RedisOption.cs | 24 + APT.Infrastructure.Redis/RedisConfig.cs | 170 + APT.Infrastructure.Redis/RedisManager.cs | 1225 +++++ APT.Migrations/APT.Migrations.csproj | 24 + APT.Migrations/MigrationContext.cs | 23 + .../MigrationContextModelSnapshot.cs | 562 +++ .../APT.Infrastructure.Utility.csproj | 20 + .../Kafka/KafkaHelper.cs | 344 ++ .../Redis/CsRedisHelper.cs | 59 + .../Redis/RedisAttributes.cs | 30 + .../Redis/RedisCache.cs | 203 + .../Redis/RedisHanddle.cs | 21 + 203 files changed, 38837 insertions(+) create mode 100644 .dockerignore create mode 100644 .gitignore create mode 100644 APT.API/APT.API.csproj create mode 100644 APT.API/APT.API.sln create mode 100644 APT.API/ActionMonitorAttribute.cs create mode 100644 APT.API/App_Start/DIConfig.cs create mode 100644 APT.API/CombindedConnectionGenerator.cs create mode 100644 APT.API/Controllers/AptController.cs create mode 100644 APT.API/Controllers/ValuesController.cs create mode 100644 APT.API/Dockerfile create mode 100644 APT.API/ILogTest.cs create mode 100644 APT.API/LogAttribute.cs create mode 100644 APT.API/LogInterceptor.cs create mode 100644 APT.API/Program.cs create mode 100644 APT.API/Properties/launchSettings.json create mode 100644 APT.API/Startup.cs create mode 100644 APT.API/appsettings.Development.json create mode 100644 APT.API/appsettings.json create mode 100644 APT.API/log4net.config create mode 100644 APT.DAL.Data/APT.DAL.Data.csproj create mode 100644 APT.DAL.Data/CourseMap.cs create mode 100644 APT.DAL.Data/PhoneMap.cs create mode 100644 APT.DAL.Data/TestNoneBaseMap.cs create mode 100644 APT.DAL.Data/UserMap.cs create mode 100644 APT.Domain/APT.Domain.csproj create mode 100644 APT.Domain/LDX_Test_Course.cs create mode 100644 APT.Domain/LDX_Test_Phone.cs create mode 100644 APT.Domain/LDX_Test_User.cs create mode 100644 APT.Domain/ModelBase.cs create mode 100644 APT.Domain/TestNoneBaseModel.cs create mode 100644 APT.Frame.sln create mode 100644 APT.Infrastructure.Api/APT.Infrastructure.Api.csproj create mode 100644 APT.Infrastructure.Api/APT.Infrastructure.Api.xml create mode 100644 APT.Infrastructure.Api/Api/APTApiController.cs create mode 100644 APT.Infrastructure.Api/Api/BaseApiController.cs create mode 100644 APT.Infrastructure.Api/Api/CommonApiController.cs create mode 100644 APT.Infrastructure.Api/DI/IDependency.cs create mode 100644 APT.Infrastructure.Api/DI/ServiceLocator.cs create mode 100644 APT.Infrastructure.Api/Extensions/ConfigurationSectionExtension.cs create mode 100644 APT.Infrastructure.Api/Extensions/HttpContextExtensions.cs create mode 100644 APT.Infrastructure.Api/Extensions/RootOrgAttribute.cs create mode 100644 APT.Infrastructure.Api/Helper/WebSocketServiceHelper.cs create mode 100644 APT.Infrastructure.Api/LDX.Infrastructure.Api.xml create mode 100644 APT.Infrastructure.Api/Model/NeedRetryExceptions.cs create mode 100644 APT.Infrastructure.Api/Model/TenantInfo.cs create mode 100644 APT.Infrastructure.Api/Redis/CsRedisManager.cs create mode 100644 APT.Infrastructure.Api/Redis/RedisConfig.cs create mode 100644 APT.Infrastructure.Api/Redis/RedisConfigurationExtensions.cs create mode 100644 APT.Infrastructure.Api/Redis/RedisManager.cs create mode 100644 APT.Infrastructure.Api/Redis/RedisOption.cs create mode 100644 APT.Infrastructure.Api/Service/CommonService.cs create mode 100644 APT.Infrastructure.Api/Service/DomainServiceBase.cs create mode 100644 APT.Infrastructure.Api/Service/ICommonService.cs create mode 100644 APT.Infrastructure.Api/Service/IDomainService.cs create mode 100644 APT.Infrastructure.Api/Structs/AppContext.cs create mode 100644 APT.Infrastructure.Api/Structs/ConfigurationManager.cs create mode 100644 APT.Infrastructure.Api/Structs/DefaultAutofacModuleRegister.cs create mode 100644 APT.Infrastructure.Api/Structs/InfluxDbHelper.cs create mode 100644 APT.Infrastructure.Api/Structs/InfluxDbOption.cs create mode 100644 APT.Infrastructure.Api/Structs/LibMessageUtils.cs create mode 100644 APT.Infrastructure.Core/APT.Infrastructure.Core.csproj create mode 100644 APT.Infrastructure.Core/APT.Infrastructure.Core.xml create mode 100644 APT.Infrastructure.Core/EF/IOrderable.cs create mode 100644 APT.Infrastructure.Core/EF/IRepository.cs create mode 100644 APT.Infrastructure.Core/EF/IRepositoryAsync.cs create mode 100644 APT.Infrastructure.Core/EF/IRowVersion.cs create mode 100644 APT.Infrastructure.Core/EF/IUnitOfWork.cs create mode 100644 APT.Infrastructure.Core/EF/Orderable.cs create mode 100644 APT.Infrastructure.Core/Extensions/DateTimeExtension.cs create mode 100644 APT.Infrastructure.Core/Extensions/EnumExtensions.cs create mode 100644 APT.Infrastructure.Core/Extensions/EnumerableExtension.cs create mode 100644 APT.Infrastructure.Core/Extensions/ExpressionExtensions.cs create mode 100644 APT.Infrastructure.Core/Extensions/FilterGroupExtensions.cs create mode 100644 APT.Infrastructure.Core/Extensions/Int32Extensions.cs create mode 100644 APT.Infrastructure.Core/Extensions/JsonExtensions.cs create mode 100644 APT.Infrastructure.Core/Extensions/LinqExtensions.cs create mode 100644 APT.Infrastructure.Core/Extensions/QueryableOrderExtension.cs create mode 100644 APT.Infrastructure.Core/Extensions/RandomExtensions.cs create mode 100644 APT.Infrastructure.Core/Extensions/TypeExtensions.cs create mode 100644 APT.Infrastructure.Core/Helper/ApiHelper.cs create mode 100644 APT.Infrastructure.Core/Helper/DataHelper.cs create mode 100644 APT.Infrastructure.Core/Helper/FilterHelper.cs create mode 100644 APT.Infrastructure.Core/Helper/HashUtil.cs create mode 100644 APT.Infrastructure.Core/Helper/LibUtils.cs create mode 100644 APT.Infrastructure.Core/Helper/ReflectHelper.cs create mode 100644 APT.Infrastructure.Core/Helper/Util.cs create mode 100644 APT.Infrastructure.Core/Helper/WebUtils.cs create mode 100644 APT.Infrastructure.Core/Interface/ILibMessageManager.cs create mode 100644 APT.Infrastructure.Core/LDX.Infrastructure.Core.xml create mode 100644 APT.Infrastructure.Core/Logging/ILogger.cs create mode 100644 APT.Infrastructure.Core/Logging/Log4netLogger.cs create mode 100644 APT.Infrastructure.Core/Logging/LogAttribute.cs create mode 100644 APT.Infrastructure.Core/Logging/LogHelper.cs create mode 100644 APT.Infrastructure.Core/Logging/LoggerManager.cs create mode 100644 APT.Infrastructure.Core/Structs/Attributes.cs create mode 100644 APT.Infrastructure.Core/Structs/BaseFilter.cs create mode 100644 APT.Infrastructure.Core/Structs/BasePageFilter.cs create mode 100644 APT.Infrastructure.Core/Structs/CodeException.cs create mode 100644 APT.Infrastructure.Core/Structs/CodeRuleParam.cs create mode 100644 APT.Infrastructure.Core/Structs/DataOrder.cs create mode 100644 APT.Infrastructure.Core/Structs/DomainException.cs create mode 100644 APT.Infrastructure.Core/Structs/EFApiActionMessage.cs create mode 100644 APT.Infrastructure.Core/Structs/EFApiActionResult.cs create mode 100644 APT.Infrastructure.Core/Structs/EFModel.cs create mode 100644 APT.Infrastructure.Core/Structs/Enums.cs create mode 100644 APT.Infrastructure.Core/Structs/FilterGroup.cs create mode 100644 APT.Infrastructure.Core/Structs/FilterRule.cs create mode 100644 APT.Infrastructure.Core/Structs/IDependInject.cs create mode 100644 APT.Infrastructure.Core/Structs/ISession.cs create mode 100644 APT.Infrastructure.Core/Structs/ISessionProvider.cs create mode 100644 APT.Infrastructure.Core/Structs/JsonActionResult.cs create mode 100644 APT.Infrastructure.Core/Structs/JsonContractResolver.cs create mode 100644 APT.Infrastructure.Core/Structs/KeywordFilter.cs create mode 100644 APT.Infrastructure.Core/Structs/KeywordPageFilter.cs create mode 100644 APT.Infrastructure.Core/Structs/LibMessageFormatManager.cs create mode 100644 APT.Infrastructure.Core/Structs/LibMessageManager.cs create mode 100644 APT.Infrastructure.Core/Structs/MultipleDbPageFilter.cs create mode 100644 APT.Infrastructure.Core/Structs/NoSessionException.cs create mode 100644 APT.Infrastructure.Core/Structs/PagedActionResult.cs create mode 100644 APT.Infrastructure.Core/Structs/PagedResultDto.cs create mode 100644 APT.Infrastructure.Core/Structs/ParamDynamicDictionary.cs create mode 100644 APT.Infrastructure.Core/Structs/Permission.cs create mode 100644 APT.Infrastructure.Core/Structs/SimpleSession.cs create mode 100644 APT.Infrastructure.Core/Structs/SystemCodeFilter.cs create mode 100644 APT.Infrastructure.Core/Structs/TreeNode.cs create mode 100644 APT.Infrastructure.Core/Structs/UpdateCodeSerialInfo.cs create mode 100644 APT.Infrastructure.Core/Structs/WeixinToken.cs create mode 100644 APT.Infrastructure.Core/Table/DataUpdateRecord.cs create mode 100644 APT.Infrastructure.Core/Table/EntityBase.cs create mode 100644 APT.Infrastructure.Core/Table/T_FM_ORGANIZATION.cs create mode 100644 APT.Infrastructure.Core/Table/T_PF_CODE_RULE_SERIAL.cs create mode 100644 APT.Infrastructure.Core/Table/T_PF_PARAM.cs create mode 100644 APT.Infrastructure.Core/Thread/LDXThreadPool.cs create mode 100644 APT.Infrastructure.Core/Thread/LDXThreadTimeRule.cs create mode 100644 APT.Infrastructure.Core/Thread/LDXThreadWork.cs create mode 100644 APT.Infrastructure.Core/Utils/InitUtils.cs create mode 100644 APT.Infrastructure.Domain/APT.Infrastructure.Domain.csproj create mode 100644 APT.Infrastructure.Domain/Models/DataUpdateRecord.cs create mode 100644 APT.Infrastructure.EF/APT.Infrastructure.EF.csproj create mode 100644 APT.Infrastructure.EF/APT.Infrastructure.EF.xml create mode 100644 APT.Infrastructure.EF/ConnectionResolverType.cs create mode 100644 APT.Infrastructure.EF/Constans.cs create mode 100644 APT.Infrastructure.EF/CustomNpgsqlQuerySqlGenerator.cs create mode 100644 APT.Infrastructure.EF/DbIntegrationType.cs create mode 100644 APT.Infrastructure.EF/DbsetProperty.cs create mode 100644 APT.Infrastructure.EF/EFDbContextLog.cs create mode 100644 APT.Infrastructure.EF/EfDbContext.cs create mode 100644 APT.Infrastructure.EF/Extension/TenantApplicationBuilderExtension.cs create mode 100644 APT.Infrastructure.EF/Extension/TenantCoreExtension.cs create mode 100644 APT.Infrastructure.EF/Extensions/DataBaseTypeExtension.cs create mode 100644 APT.Infrastructure.EF/Extensions/IQueryableSelectorExtension.cs create mode 100644 APT.Infrastructure.EF/Extensions/MySqlTenantExtension.cs create mode 100644 APT.Infrastructure.EF/Extensions/PostgreTenantExtension.cs create mode 100644 APT.Infrastructure.EF/Extensions/SqlServerTenantExtension.cs create mode 100644 APT.Infrastructure.EF/Helper/AcronymHelper.cs create mode 100644 APT.Infrastructure.EF/Impl/MigrationByTenantAssembly.cs create mode 100644 APT.Infrastructure.EF/Impl/NamedConnectionGenerator.cs create mode 100644 APT.Infrastructure.EF/Impl/SimpleHeaderTenantInfoGenerator.cs create mode 100644 APT.Infrastructure.EF/Impl/TenantConnectionResolver.cs create mode 100644 APT.Infrastructure.EF/Infrastructure/CombindedConnectionGenerator.cs create mode 100644 APT.Infrastructure.EF/Infrastructure/ConnectionResolver.cs create mode 100644 APT.Infrastructure.EF/Infrastructure/IConnectionGenerator.cs create mode 100644 APT.Infrastructure.EF/Infrastructure/IEntityScaner.cs create mode 100644 APT.Infrastructure.EF/Infrastructure/ITenantConnectionResolver.cs create mode 100644 APT.Infrastructure.EF/Infrastructure/ITenantDbContext.cs create mode 100644 APT.Infrastructure.EF/Infrastructure/ITenantEntityBuilder.cs create mode 100644 APT.Infrastructure.EF/Infrastructure/ITenantInfoGenerator.cs create mode 100644 APT.Infrastructure.EF/Infrastructure/TenantInfo.cs create mode 100644 APT.Infrastructure.EF/Infrastructure/TenantInfoMiddleware.cs create mode 100644 APT.Infrastructure.EF/Map/DataUpdateRecordMap.cs create mode 100644 APT.Infrastructure.EF/Map/EntityBaseMap.cs create mode 100644 APT.Infrastructure.EF/Map/FMOrganizationMap.cs create mode 100644 APT.Infrastructure.EF/Map/LDXEntityBaseMap.cs create mode 100644 APT.Infrastructure.EF/Map/LDXTreeEntityBaseMap.cs create mode 100644 APT.Infrastructure.EF/Map/PFCodeRuleSerialMap.cs create mode 100644 APT.Infrastructure.EF/Map/PFParamMap.cs create mode 100644 APT.Infrastructure.EF/Properties/serviceDependencies.json create mode 100644 APT.Infrastructure.EF/Properties/serviceDependencies.local.json create mode 100644 APT.Infrastructure.EF/QueryWithNoLockDbCommandInterceptor.cs create mode 100644 APT.Infrastructure.EF/Repository.cs create mode 100644 APT.Infrastructure.EF/SimpleEntityScaner.cs create mode 100644 APT.Infrastructure.EF/TenantBaseDbContext.cs create mode 100644 APT.Infrastructure.EF/TenantEntityBuilder.cs create mode 100644 APT.Infrastructure.EF/TenantModelCacheKey.cs create mode 100644 APT.Infrastructure.EF/TenantModelCacheKeyFactory.cs create mode 100644 APT.Infrastructure.EF/TenantOption.cs create mode 100644 APT.Infrastructure.EF/TenantSettings.cs create mode 100644 APT.Infrastructure.Redis/APT.Infrastructure.Redis.csproj create mode 100644 APT.Infrastructure.Redis/AppConfig.cs create mode 100644 APT.Infrastructure.Redis/Configurations/RedisConfig.cs create mode 100644 APT.Infrastructure.Redis/Configurations/RedisConfigurationExtensions.cs create mode 100644 APT.Infrastructure.Redis/Configurations/RedisOption.cs create mode 100644 APT.Infrastructure.Redis/RedisConfig.cs create mode 100644 APT.Infrastructure.Redis/RedisManager.cs create mode 100644 APT.Migrations/APT.Migrations.csproj create mode 100644 APT.Migrations/MigrationContext.cs create mode 100644 APT.Migrations/Migrations/MigrationContextModelSnapshot.cs create mode 100644 Apt.Infrastructure.Utility/APT.Infrastructure.Utility.csproj create mode 100644 Apt.Infrastructure.Utility/Kafka/KafkaHelper.cs create mode 100644 Apt.Infrastructure.Utility/Redis/CsRedisHelper.cs create mode 100644 Apt.Infrastructure.Utility/Redis/RedisAttributes.cs create mode 100644 Apt.Infrastructure.Utility/Redis/RedisCache.cs create mode 100644 Apt.Infrastructure.Utility/Redis/RedisHanddle.cs diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..3729ff0 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,25 @@ +**/.classpath +**/.dockerignore +**/.env +**/.git +**/.gitignore +**/.project +**/.settings +**/.toolstarget +**/.vs +**/.vscode +**/*.*proj.user +**/*.dbmdl +**/*.jfm +**/azds.yaml +**/bin +**/charts +**/docker-compose* +**/Dockerfile* +**/node_modules +**/npm-debug.log +**/obj +**/secrets.dev.yaml +**/values.dev.yaml +LICENSE +README.md \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..426d76d --- /dev/null +++ b/.gitignore @@ -0,0 +1,398 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore + +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Mono auto generated files +mono_crash.* + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Ww][Ii][Nn]32/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ +[Ll]ogs/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUnit +*.VisualState.xml +TestResult.xml +nunit-*.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# ASP.NET Scaffolding +ScaffoldingReadMe.txt + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.log +*.tlog +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Coverlet is a free, cross platform Code Coverage Tool +coverage*.json +coverage*.xml +coverage*.info + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# NuGet Symbol Packages +*.snupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx +*.appxbundle +*.appxupload + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!?*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio 6 auto-generated project file (contains which files were open etc.) +*.vbp + +# Visual Studio 6 workspace and project file (working project files containing files to include in project) +*.dsw +*.dsp + +# Visual Studio 6 technical files +*.ncb +*.aps + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# Visual Studio History (VSHistory) files +.vshistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder +.ionide/ + +# Fody - auto-generated XML schema +FodyWeavers.xsd + +# VS Code files for those working on multiple tools +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +*.code-workspace + +# Local History for Visual Studio Code +.history/ + +# Windows Installer files from build outputs +*.cab +*.msi +*.msix +*.msm +*.msp + +# JetBrains Rider +*.sln.iml diff --git a/APT.API/APT.API.csproj b/APT.API/APT.API.csproj new file mode 100644 index 0000000..8b93573 --- /dev/null +++ b/APT.API/APT.API.csproj @@ -0,0 +1,36 @@ + + + + net6.0 + InProcess + Linux + + + + + + + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + + + + diff --git a/APT.API/APT.API.sln b/APT.API/APT.API.sln new file mode 100644 index 0000000..469acde --- /dev/null +++ b/APT.API/APT.API.sln @@ -0,0 +1,61 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.29806.167 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "APT.API", "APT.API.csproj", "{34B722F6-F94F-4013-A4B1-90883AFD9827}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "APT.DAL.Data", "..\APT.DAL.Data\APT.DAL.Data.csproj", "{416E9E2B-95BC-49FE-8E71-B8D362C5E4A1}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "APT.Domain", "..\APT.Domain\APT.Domain.csproj", "{930AFFDA-4BFE-423F-9F27-62919F09E7F0}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "APT.Infrastructure.Api", "..\APT.Infrastructure.Api\APT.Infrastructure.Api.csproj", "{F6A879CE-7319-479C-BA24-BF9DCB71A9A5}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "APT.Infrastructure.Core", "..\APT.Infrastructure.Core\APT.Infrastructure.Core.csproj", "{E93B3210-F2BC-49F5-91A6-5804839FE1DA}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "APT.Infrastructure.EF", "..\APT.Infrastructure.EF\APT.Infrastructure.EF.csproj", "{AAABC7E2-A68E-4F92-9D96-9E3FD874421B}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "APT.Migrations", "..\APT.Migrations\APT.Migrations.csproj", "{68FD728E-A9FE-4E1F-A4BE-EC0642B9C15B}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {34B722F6-F94F-4013-A4B1-90883AFD9827}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {34B722F6-F94F-4013-A4B1-90883AFD9827}.Debug|Any CPU.Build.0 = Debug|Any CPU + {34B722F6-F94F-4013-A4B1-90883AFD9827}.Release|Any CPU.ActiveCfg = Release|Any CPU + {34B722F6-F94F-4013-A4B1-90883AFD9827}.Release|Any CPU.Build.0 = Release|Any CPU + {416E9E2B-95BC-49FE-8E71-B8D362C5E4A1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {416E9E2B-95BC-49FE-8E71-B8D362C5E4A1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {416E9E2B-95BC-49FE-8E71-B8D362C5E4A1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {416E9E2B-95BC-49FE-8E71-B8D362C5E4A1}.Release|Any CPU.Build.0 = Release|Any CPU + {930AFFDA-4BFE-423F-9F27-62919F09E7F0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {930AFFDA-4BFE-423F-9F27-62919F09E7F0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {930AFFDA-4BFE-423F-9F27-62919F09E7F0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {930AFFDA-4BFE-423F-9F27-62919F09E7F0}.Release|Any CPU.Build.0 = Release|Any CPU + {F6A879CE-7319-479C-BA24-BF9DCB71A9A5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F6A879CE-7319-479C-BA24-BF9DCB71A9A5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F6A879CE-7319-479C-BA24-BF9DCB71A9A5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F6A879CE-7319-479C-BA24-BF9DCB71A9A5}.Release|Any CPU.Build.0 = Release|Any CPU + {E93B3210-F2BC-49F5-91A6-5804839FE1DA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E93B3210-F2BC-49F5-91A6-5804839FE1DA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E93B3210-F2BC-49F5-91A6-5804839FE1DA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E93B3210-F2BC-49F5-91A6-5804839FE1DA}.Release|Any CPU.Build.0 = Release|Any CPU + {AAABC7E2-A68E-4F92-9D96-9E3FD874421B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AAABC7E2-A68E-4F92-9D96-9E3FD874421B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AAABC7E2-A68E-4F92-9D96-9E3FD874421B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AAABC7E2-A68E-4F92-9D96-9E3FD874421B}.Release|Any CPU.Build.0 = Release|Any CPU + {68FD728E-A9FE-4E1F-A4BE-EC0642B9C15B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {68FD728E-A9FE-4E1F-A4BE-EC0642B9C15B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {68FD728E-A9FE-4E1F-A4BE-EC0642B9C15B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {68FD728E-A9FE-4E1F-A4BE-EC0642B9C15B}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {5040CE81-F008-43D7-AEFC-DF1FE1F5CEB6} + EndGlobalSection +EndGlobal diff --git a/APT.API/ActionMonitorAttribute.cs b/APT.API/ActionMonitorAttribute.cs new file mode 100644 index 0000000..80356c2 --- /dev/null +++ b/APT.API/ActionMonitorAttribute.cs @@ -0,0 +1,54 @@ +using APT.Infrastructure.Core; +using Microsoft.AspNetCore.Mvc.Filters; +using System; +using System.Diagnostics; +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; + + + +namespace APT.Infrastructure.Api.WebFilters +{ + + //public class WebApiTrackerAttribute : System.Web.Http.Filters.ActionFilterAttribute + //{ + // public bool AllowMultiple => true; + + // //public Task ExecuteActionFilterAsync(HttpActionContext actionContext, CancellationToken cancellationToken, Func> continuation) + // //{ + // // throw new NotImplementedException(); + // //} + + // //public Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) + // //{ + // // throw new NotImplementedException(); + // // var s = 1; + // //} + + // public override void OnActionExecuting(HttpActionContext actionContext) + // { + // LoggerManager.GetLogger().Info("11111111111"); + // base.OnActionExecuting(actionContext); + // } + + // public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext) + // { + // LoggerManager.GetLogger().Info("2222222222222"); + // base.OnActionExecuted(actionExecutedContext); + // } + + // public override Task OnActionExecutingAsync(HttpActionContext actionContext, CancellationToken cancellationToken) + // { + // LoggerManager.GetLogger().Info("2222222222222"); + // return base.OnActionExecutingAsync(actionContext, cancellationToken); + // } + + // public override Task OnActionExecutedAsync(HttpActionExecutedContext actionExecutedContext, CancellationToken cancellationToken) + // { + // LoggerManager.GetLogger().Info("11111111111"); + // return base.OnActionExecutedAsync(actionExecutedContext, cancellationToken); + // } + + //} +} \ No newline at end of file diff --git a/APT.API/App_Start/DIConfig.cs b/APT.API/App_Start/DIConfig.cs new file mode 100644 index 0000000..fd184b0 --- /dev/null +++ b/APT.API/App_Start/DIConfig.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Autofac; +using APT.Infrastructure.Core; +using APT.Infrastructure.EF; + +using Microsoft.Extensions.Logging; +using APT.Infrastructure.Core.Refctor; +using System.Reflection; +using Autofac.Extras.DynamicProxy; +using APT.Infrastructure.Api; +namespace APT.API +{ + public static class DIConfig + { + public static void RegisterComponents(this ContainerBuilder builder) + { + ReflectHelper.GetClassMethodAttr(typeof(EfDbContext)); + + builder.RegisterType().As().SingleInstance(); + builder.RegisterType().As().SingleInstance(); + builder.RegisterType().PropertiesAutowired(); + //builder.RegisterType().PropertiesAutowired(); + + builder.RegisterType().As().InstancePerLifetimeScope(); + builder.RegisterType().As().InstancePerLifetimeScope(); + + builder.RegisterType(typeof(DomainServiceBase)).As(typeof(IDomainService)).InstancePerLifetimeScope(); + builder.RegisterType().As().InstancePerLifetimeScope() + .PropertiesAutowired(); + //builder.RegisterType().As().InstancePerLifetimeScope() + // .PropertiesAutowired(); + + builder.RegisterType(); + Assembly service = Assembly.Load("APT.API"); + //Assembly iservice = Assembly.Load("APT.API.IService"); + builder.RegisterAssemblyTypes(service).AsImplementedInterfaces() + .InstancePerLifetimeScope() + .EnableInterfaceInterceptors().InterceptedBy(typeof(LogInterceptor)); + } + } +} diff --git a/APT.API/CombindedConnectionGenerator.cs b/APT.API/CombindedConnectionGenerator.cs new file mode 100644 index 0000000..f227849 --- /dev/null +++ b/APT.API/CombindedConnectionGenerator.cs @@ -0,0 +1,66 @@ +using System; +using System.Collections.Generic; +using System.Net.Http; +using APT.Infrastructure.Api; +using APT.Infrastructure.EF; +using Microsoft.Extensions.Configuration; + +namespace APT.API +{ + public class CombindedConnectionGenerator : IConnectionGenerator + { + static Lazy random = new Lazy(); + private readonly IConfiguration configuration; + public string TenantKey => ""; + + public CombindedConnectionGenerator(IConfiguration configuration) + { + this.configuration = configuration; + } + + + public string GetConnection(TenantOption option, TenantInfo tenantInfo) + { + return tenantInfo.Conn; + //var webapiUrl = "http://localhost:5001/api/DbConfigs"; + //var httpResponseMsg = new HttpResponseMessage(); + + //using (var httpClient = new HttpClient()) + //{ + // httpResponseMsg = httpClient.GetAsync(webapiUrl).Result; + + // var retrnUrl = httpResponseMsg.Content.ReadAsStringAsync().Result; + // dynamic urls = Newtonsoft.Json.JsonConvert.DeserializeObject(retrnUrl); + // if (urls != null) + // { + + // List connList = new List(); + // foreach (dynamic url in urls) + // { + // if (url.name == span) + // { + // connList.Add(url.conn); + // } + // } + // if (connList.Count > 0) + // { + // var mod = (random.Value.Next(100) % connList.Count); + // return connList[mod]; + // } + // } + //} + + //if (span.Length > 4 && int.TryParse(span[5].ToString(), out var number)) + //{ + //var mod = (random.Value.Next(1000) % 3)+1; + // return configuration.GetConnectionString($"{option.ConnectionPrefix}{mod}"); + //} + throw new NotSupportedException("Ϣ"); + }// + + public bool MatchTenantKey(string tenantKey) + { + return true; + } + } +} \ No newline at end of file diff --git a/APT.API/Controllers/AptController.cs b/APT.API/Controllers/AptController.cs new file mode 100644 index 0000000..a2736e2 --- /dev/null +++ b/APT.API/Controllers/AptController.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using APT.Infrastructure.Core; +using Microsoft.AspNetCore.Mvc; + +namespace APT.API +{ + [Log] + public class AptController : ControllerBase + { + + } +} diff --git a/APT.API/Controllers/ValuesController.cs b/APT.API/Controllers/ValuesController.cs new file mode 100644 index 0000000..81ef5e9 --- /dev/null +++ b/APT.API/Controllers/ValuesController.cs @@ -0,0 +1,311 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Threading.Tasks; + +using APT.Domain; +using APT.Infrastructure.Api.WebFilters; +using APT.Infrastructure.Core; +using APT.Infrastructure.EF; +using APT.Infrastructure.EF.Infrastructure; +using Microsoft.AspNetCore.Mvc; +using APT.Infrastructure.Api; +namespace APT.API +{ + public class ValuesController : CommonApiController + { + private readonly EfDbContext efDbContext; + + public ValuesController(EfDbContext storeDbContext) + { + this.efDbContext = storeDbContext; + //this.storeDbContext.Database.EnsureCreated(); + + //this.storeDbContext.Database.Migrate(); + } + [HttpGet, Route("api/values")] + + public JsonActionResult> Get() + { + var commonService = ServiceLocator.Instance.GetService(); + ////////return commonService.UnitWork(); + //var param = new CodeRuleParam() + //{ + // CodeType = 1014, + // OrgId = new Guid("b043b28b-bbc3-c452-6052-4fba1457abfa"), + // Count = 1, + //}; + ////var xx = commonService.GetRuleCodes(param); + var codeRule = new T_PF_CODE_RULE_SERIAL() + { + ID = Guid.NewGuid(), + CODE_TYPE = 3500, + ORG_ID = new Guid("b043b28b-bbc3-c452-6052-4fba1457abfa") + + }; + + this.efDbContext.AddEntity(codeRule); + this.efDbContext.SaveChanges(); + + var db = this.efDbContext.GetEntity(t => t.CODE_TYPE == 3500, null); + //EfDbContext dbContext = new EfDbContext("User ID=postgres;Password=123456;Host=localhost;Port=5432;Database=Infracture_Test;CommandTimeout=1024;"); + //var dbs = dbContext.GetEntity(t => t.CODE_TYPE == 3500, null); + ////Expression> expression = t => t.ORG_ID == param.OrgId + //// && t.CODE_TYPE == 1038; + ////expression = expression.And(t => t.DATE_VALUE == "20191016"); + ////var pageFilter = new BasePageFilter(1, 1); + ////pageFilter.Sort = "NUM"; + ////pageFilter.Order = DbOrder.DESC; + ////var maxDbCodeRuleSerial = this.GetOrderPageEntities(expression, pageFilter); + //ServiceLocator serviceLocator = ServiceLocator.Instance; + //var _connectionResolver = serviceLocator.GetService(); + //var x1 = commonService.GetEntity(t => t.CODE_TYPE == 3500); + + //x1.MODIFY_TIME = DateTime.Now; + //this.UpdateEntity(x1); + + ////x1.STATUS = 2; + + ////var x2 = commonService.GetEntity(t => t.CODE_TYPE == 3500 && + //// t.ORG_ID == param.OrgId && t.STATUS == 0 && t.ID != x1.ID); + ////x2.STATUS = 2; + ////this.UpdateEntity(x2); + + ////Dictionary bodyParams = new Dictionary(); + ////bodyParams.Add("sn", "L1002497A000052"); + ////bodyParams.Add("stationId", "FinallyFunctionTest"); + ////Dictionary headParams = new Dictionary(); + ////headParams.Add("Access-Token", "D2B471BAA84582052F9AD2EE49FFB3EE"); + + ////var ret = WebUtils.ExecuteByResolving("http://172.20.8.29:9001/api/TestData/GetTestData", + //// bodyParams, string.Empty, SendType.Get, headParams); + + //var sttr = WitEntities(null, new KeywordFilter()); + //return sttr; + + var entity = new TestNoneBaseModel + { + ID = "Test", + Name = "Test" + }; + + var entities = new List + { + new TestNoneBaseModel + { + ID = "Test1", + Name = "Test1" + }, + new TestNoneBaseModel + { + ID = "Test2", + Name = "Test2" + } + }; + + //var str = commonService.AddAndGetEntity_noneBase(entity); + + //commonService.AddEntities_noneBase(entities); + + var str1 = commonService.GetEntity_noneBase(o => o.ID == "Test"); + var strall = commonService.GetEntities_noneBase(o => o.ID.StartsWith("Test")); + + + return null; + } + [HttpGet, Route("api/asynctest")] + public async Task> asynctest(string id) + { + return await SafeExecuteAsync(async () => + { + await GetAsync(); + return true; + }); + } + + private async Task GetAsync() + { + await this.GetPageEntitiesSync(t => t.CODE_TYPE == 3500, null); + return; + } + + [HttpGet, Route("api/test")] + + public ActionResult test() + { + var commonService = ServiceLocator.Instance.GetService(); + ////////return commonService.UnitWork(); + //var param = new CodeRuleParam() + //{ + // CodeType = 1014, + // OrgId = new Guid("b043b28b-bbc3-c452-6052-4fba1457abfa"), + // Count = 1, + //}; + ////var xx = commonService.GetRuleCodes(param); + var codeRule = new T_PF_CODE_RULE_SERIAL() + { + ID = Guid.NewGuid(), + CODE_TYPE = 3700, + ORG_ID = new Guid("b043b28b-bbc3-c452-6052-4fba1457abfa") + + }; + var codeRule1 = new T_PF_CODE_RULE_SERIAL() + { + ID = Guid.NewGuid(), + CODE_TYPE = 3700, + ORG_ID = new Guid("b043b28b-bbc3-c452-6052-4fba1457abfa") + + }; + commonService.UnifiedCommit(() => + { + commonService.AddEntityNoCommit(codeRule); + commonService.AddEntityNoCommit(codeRule1); + }); + + //this.efDbContext.AddEntity(codeRule); + //this.efDbContext.SaveChanges(); + + var db = this.efDbContext.GetEntity(t => t.ID == codeRule.ID, null); + + + + return true; + } + //[HttpGet] + //[Route("api/testError")] + //public JsonActionResult testError() + //{ + + // return SafeExecute(()=>{ + + // ThrowError("100000",100,200); + // return true; + // }); + //} + ///// + ///// 查询 + ///// + ///// + ///// + //[HttpPost] + //[Route("api/users")] + //public IActionResult Entities([FromBody]KeywordFilter filter) + //{ + // return Ok(WitEntities(null, filter)); + //} + ///// + ///// 查询 + ///// + ///// + ///// + ///// + + //[HttpPost, Route("OrderEntities")] + //public JsonActionResult> OrderEntities([FromBody]KeywordFilter filter) + //{ + // return WitOrderEntities(null, filter); + //} + ///// + ///// 查询 + ///// + ///// + ///// + //[HttpPost, Route("Paged")] + //public PagedActionResult Paged([FromBody]KeywordPageFilter pageFilter) + //{ + // return WitPaged(null, pageFilter); + //} + ///// + ///// 查询 + ///// + ///// + ///// + //[HttpPost, Route("OrderPaged")] + //public async Task> OrderPaged([FromBody]KeywordPageFilter pageFilter) + //{ + // return await WitOrderPagedSync(null, pageFilter); + //} + ///// + ///// 删除 + ///// + ///// + ///// + //[HttpGet, Route("Delete")] + //public JsonActionResult Delete(string id) + //{ + // return WitRealDelete(id); + //} + + ///// + ///// 更新 + ///// + ///// + ///// + //[HttpPost, Route("Update")] + //public JsonActionResult Update([FromBody]APT_Test_User entity) + //{ + // return WitUpdate(entity); + //} + + ///// + ///// 批量删除 + ///// + ///// + ///// + //[HttpGet, Route("BatchDelete")] + //public JsonActionResult BatchDelete(string ids) + //{ + // return WitRealBatchDelete(ids); + //} + + ///// + ///// 获得单条实体数据 + ///// + ///// + ///// + //[HttpPost, Route("Get")] + //public JsonActionResult Get([FromBody] KeywordFilter filter) + //{ + // return WitEntity(null, filter); + //} + } + + public class ExtTestResultModel + { + public int code { get; set; } + public bool success { get; set; } + public string message { get; set; } + + public ICollection data { get; set; } + } + public class ExtTestResultDataModel + { + public string WORKORDER_ID { get; set; } + public string STATION_ID { get; set; } + public ICollection TestDataModels { get; set; } + } + + public class ExtTestResultTestDataModel + { + public string SN { get; set; } + public string MAC { get; set; } + public DateTime TEST_TIME { get; set; } + public string TEST_STATE { get; set; } + public string PRODUCT_ID { get; set; } + public string WORKORDER_ID { get; set; } + public string STATION_ID { get; set; } + + public ICollection ParamList { get; set; } + } + + public class ExtTestResultTestDataParamModel + { + public string PARAM_ID { get; set; } + public string PARAM_NAME { get; set; } + public string PARAM_VALUE { get; set; } + public string LIMIT_MIN_VALUE { get; set; } + public string LIMIT_MAX_VALUE { get; set; } + } + +} diff --git a/APT.API/Dockerfile b/APT.API/Dockerfile new file mode 100644 index 0000000..83b18bb --- /dev/null +++ b/APT.API/Dockerfile @@ -0,0 +1,28 @@ +#See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging. + +FROM mcr.microsoft.com/dotnet/core/aspnet:3.1-buster-slim AS base +WORKDIR /app +EXPOSE 80 + +FROM mcr.microsoft.com/dotnet/core/sdk:3.1-buster AS build +WORKDIR /src +COPY ["APT.API/APT.API.csproj", "APT.API/"] +COPY ["APT.Domain/APT.Domain.csproj", "APT.Domain/"] +COPY ["APT.Infrastructure.EF/APT.Infrastructure.EF.csproj", "APT.Infrastructure.EF/"] +COPY ["APT.Infrastructure.Core/APT.Infrastructure.Core.csproj", "APT.Infrastructure.Core/"] +COPY ["Apt.Infrastructure.Utility/APT.Infrastructure.Utility.csproj", "Apt.Infrastructure.Utility/"] +COPY ["APT.Infrastructure.Api/APT.Infrastructure.Api.csproj", "APT.Infrastructure.Api/"] +COPY ["APT.DAL.Data/APT.DAL.Data.csproj", "APT.DAL.Data/"] +COPY ["APT.Migrations/APT.Migrations.csproj", "APT.Migrations/"] +RUN dotnet restore "APT.API/APT.API.csproj" +COPY . . +WORKDIR "/src/APT.API" +RUN dotnet build "APT.API.csproj" -c Release -o /app/build + +FROM build AS publish +RUN dotnet publish "APT.API.csproj" -c Release -o /app/publish + +FROM base AS final +WORKDIR /app +COPY --from=publish /app/publish . +ENTRYPOINT ["dotnet", "APT.API.dll"] \ No newline at end of file diff --git a/APT.API/ILogTest.cs b/APT.API/ILogTest.cs new file mode 100644 index 0000000..b175651 --- /dev/null +++ b/APT.API/ILogTest.cs @@ -0,0 +1,13 @@ +using Autofac.Extras.DynamicProxy; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace APT.API +{ + [Intercept(typeof(LogInterceptor))] + public interface ILogTest + { + } +} diff --git a/APT.API/LogAttribute.cs b/APT.API/LogAttribute.cs new file mode 100644 index 0000000..9b7449d --- /dev/null +++ b/APT.API/LogAttribute.cs @@ -0,0 +1,50 @@ +using APT.Infrastructure.Core; +using log4net; +using Microsoft.AspNetCore.Mvc.Controllers; +using Microsoft.AspNetCore.Mvc.Filters; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using System.Web.Mvc; + +namespace APT.API +{ + public class LogAttribute : Attribute, IAsyncActionFilter + { + /// + /// 添加操作日志 liyouming + /// + /// + /// + /// + public async Task OnActionExecutionAsync(Microsoft.AspNetCore.Mvc.Filters.ActionExecutingContext context, ActionExecutionDelegate next) + { + string actionArguments = context.ActionArguments.ToJson(); + var resultContext = await next(); + + string url = resultContext.HttpContext.Request.Host + resultContext.HttpContext.Request.Path + resultContext.HttpContext.Request.QueryString; + + string method = resultContext.HttpContext.Request.Method; + + dynamic result = resultContext.Result.GetType().Name == "EmptyResult" ? new { Value = "EmptyResult" } : resultContext.Result as dynamic; + + var userHeads = resultContext.HttpContext.Request.Headers; + var userid = string.Empty; + var username = string.Empty; + if (userHeads.ContainsKey("userid")) + { + userid = userHeads["userid"].ToString(); + } + if (userHeads.ContainsKey("username")) + { + username = userHeads["username"].ToString(); + } + string response = JsonConvert.SerializeObject(result.Value); + var str = $"用户ID:[{userid}],姓名:[{username}],api地址:[{url}],方法:[{method}],接口参数:[{actionArguments}],应答:[{response}]"; + LoggerManager.GetLogger("SQLLog").Info(str); + await next.Invoke(); + } + } +} diff --git a/APT.API/LogInterceptor.cs b/APT.API/LogInterceptor.cs new file mode 100644 index 0000000..a802cf8 --- /dev/null +++ b/APT.API/LogInterceptor.cs @@ -0,0 +1,28 @@ +using Autofac.Extras.DynamicProxy; +using Castle.DynamicProxy; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace APT.API +{ + [Intercept(typeof(LogInterceptor))] + public class LogInterceptor: IInterceptor + { + public void Intercept(IInvocation invocation) + { + try + { + invocation.Proceed(); + var s = invocation.Method.Name; + //LogManager.logger.Info(invocation.Method.Name); + } + catch (Exception ex) + { + var s = invocation.Method.Name; + //Dapper.Logger.LogHelper.logger.Error(invocation.Method.Name + " " + ex.ToString()); + } + } + } +} diff --git a/APT.API/Program.cs b/APT.API/Program.cs new file mode 100644 index 0000000..ecc3594 --- /dev/null +++ b/APT.API/Program.cs @@ -0,0 +1,19 @@ +using Microsoft.AspNetCore; +using Microsoft.AspNetCore.Hosting; +using Autofac.Extensions.DependencyInjection; + +namespace APT.API +{ + public class Program + { + public static void Main(string[] args) + { + CreateWebHostBuilder(args).Build().Run(); + } + + public static IWebHostBuilder CreateWebHostBuilder(string[] args) => + WebHost.CreateDefaultBuilder(args) + .ConfigureServices(services => services.AddAutofac()) + .UseStartup(); + } +} diff --git a/APT.API/Properties/launchSettings.json b/APT.API/Properties/launchSettings.json new file mode 100644 index 0000000..36b5f59 --- /dev/null +++ b/APT.API/Properties/launchSettings.json @@ -0,0 +1,36 @@ +{ + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:57773", + "sslPort": 0 + } + }, + "$schema": "http://json.schemastore.org/launchsettings.json", + "profiles": { + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "launchUrl": "api/values", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "APT.API": { + "commandName": "Project", + "launchBrowser": true, + "launchUrl": "api/values", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "applicationUrl": "http://localhost:5000" + }, + "Docker": { + "commandName": "Docker", + "launchBrowser": true, + "launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}/api/values", + "publishAllPorts": true + } + } +} \ No newline at end of file diff --git a/APT.API/Startup.cs b/APT.API/Startup.cs new file mode 100644 index 0000000..1d29511 --- /dev/null +++ b/APT.API/Startup.cs @@ -0,0 +1,122 @@ +using Autofac; +using APT.Infrastructure.Core; +using APT.Infrastructure.Core.Utils; +using APT.Infrastructure.EF; +using log4net; +using log4net.Config; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; +using System.IO; +using APT.Infrastructure.Api.WebFilters; +using Autofac.Extras.DynamicProxy; +using APT.Infrastructure.EF.Infrastructure; +using APT.Infrastructure.EF.Extensions; +using APT.Infrastructure.Api; +using ConfigurationManager = APT.Infrastructure.Api.ConfigurationManager; + +namespace APT.API +{ + public class Startup + { + public Startup(IConfiguration configuration) + { + Configuration = configuration; + var repository = LogManager.GetRepository + (System.Reflection.Assembly.GetEntryAssembly()); + var fileInfo = new FileInfo("log4net.config"); + if (!fileInfo.Exists) + fileInfo = new FileInfo(Path.Combine(System.AppContext.BaseDirectory, "log4net.config")); + XmlConfigurator.Configure(repository, fileInfo); + ConfigurationManager.Register(configuration); + + InitUtils.Init(); + } + + public IConfiguration Configuration { get; } + + // This method gets called by the runtime. Use this method to add services to the container. + public void ConfigureServices(IServiceCollection services) + { + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + + //services.AddPostgrePerConnection(settings => + //{ + // settings.ConnectionPrefix = "postgre_store"; + //}); + + services.AddMvc(t=> { + t.EnableEndpointRouting = false; + }); + + // services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2); + services.TryAddSingleton(); + //UpdateDatabase(); + } + void setupDb(TenantSettings settings) + { + //settings.ConnectionPrefix = "de"; + //settings.DbContextSetup = (serviceProvider, connectionString, optionsBuilder) => + //{ + // var tenant = serviceProvider.GetService(); + // optionsBuilder + // .UseLazyLoadingProxies(false) + // .UseNpgsql(connectionString, builder => + // { + // // not necessary, if you are not using the table or schema + // builder.TenantBuilderSetup(serviceProvider, settings, tenant); + // }); + //}; + } + // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. + public void Configure(IApplicationBuilder app, IHostingEnvironment env) + { + if (env.IsDevelopment()) + { + app.UseDeveloperExceptionPage(); + } + else + { + // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. + app.UseHsts(); + } + app.UseMiddleware(); + Infrastructure.Api.HttpContext.Register(app.ApplicationServices. + GetRequiredService() + ); + app.Use(next => context => { + context.Request.EnableBuffering(); + return next(context); + }); + + + + app.UseHttpsRedirection(); + app.UseMvc(); + } + + private static void UpdateDatabase() + { + //using (var context = new MigrationContext()) + //{ + // context.Database.Migrate(); + //} + } + + public virtual void ConfigureContainer(ContainerBuilder builder) + { + builder.RegisterComponents(); + //var builders = new ConfigurationBuilder() + //.AddJsonFile("appsettings.json"); + //ConfigurationHelper.Configuration = builders.Build(); + + } + } +} diff --git a/APT.API/appsettings.Development.json b/APT.API/appsettings.Development.json new file mode 100644 index 0000000..e203e94 --- /dev/null +++ b/APT.API/appsettings.Development.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Debug", + "System": "Information", + "Microsoft": "Information" + } + } +} diff --git a/APT.API/appsettings.json b/APT.API/appsettings.json new file mode 100644 index 0000000..57ec4da --- /dev/null +++ b/APT.API/appsettings.json @@ -0,0 +1,32 @@ +{ + "ConnectionStrings": { + //"default": "Data Source=172.20.8.76:1521/DB1;User ID=\"dbo\";Password=mssdev" + //"default": "Database=Test1;Data Source=localhost;Port=3306;User Id=root;Password=123456;TreatTinyAsBoolean=true;", + //"default": "Data Source=172.20.8.76:1521/DB1;User Id=\"dbo\";Password=mssdev;Pooling=false;PERSIST SECURITY INFO=True;" + //"default": "Data Source=172.20.10.173;Initial Catalog=DBTest;User ID=sa;Password=Ldx123456" + + //"default": "User ID=postgres;Password=123456;Host=172.20.8.48;Port=5432;Database=mes;CommandTimeout=1024;", + "default": "User ID=postgres;Password=123456;Host=localhost;Port=5432;Database=Infracture_Test;CommandTimeout=1024;", + + "postgre_store1": "Server=127.0.0.1;Port=5432;Database=testdb1;User Id=postgres;Password=123456;", + "postgre_store2": "Server=127.0.0.1;Port=5432;Database=testdb2;User Id=postgres;Password=123456;", + "postgre_store3": "Server=127.0.0.1;Port=5432;Database=testdb3;User Id=postgres;Password=123456;" + }, + "AppSettings": { + "DataBaseType": "postgresql", + "isSqlLog": "true", + "ConnApiUrl": "http://172.20.8.48/GetConn", + "ConnDataKey": "optenergy" + + }, + "AllowedHosts": "*", + "InflexdbConfig": { + "Url": "http://192.168.2.98:8087/", + "UserName": "optuser", + "PassWord": "optienergy", + "DbName": "opt", + "LogDbName": "OPTiEnergyLog", + "AppOnline": "optAppOnline" + + } +} diff --git a/APT.API/log4net.config b/APT.API/log4net.config new file mode 100644 index 0000000..1c5d484 --- /dev/null +++ b/APT.API/log4net.config @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/APT.DAL.Data/APT.DAL.Data.csproj b/APT.DAL.Data/APT.DAL.Data.csproj new file mode 100644 index 0000000..431b7cb --- /dev/null +++ b/APT.DAL.Data/APT.DAL.Data.csproj @@ -0,0 +1,16 @@ + + + + netstandard2.1 + + + + + + + + + + + + diff --git a/APT.DAL.Data/CourseMap.cs b/APT.DAL.Data/CourseMap.cs new file mode 100644 index 0000000..eb00696 --- /dev/null +++ b/APT.DAL.Data/CourseMap.cs @@ -0,0 +1,27 @@ +using APT.Domain; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; +using System; +using System.Collections.Generic; +using System.Text; + +namespace APT.DAL.Data +{ + public class CourseMap : IEntityTypeConfiguration + { + public CourseMap(ModelBuilder builder) + { + builder.Entity() + .HasOne(o => o.TestUser) + .WithMany() + .HasForeignKey(o => o.UserID); + } + + public virtual void Configure(EntityTypeBuilder builder) + { + builder.HasOne(o => o.TestUser) + .WithMany() + .HasForeignKey(o => o.UserID); + } + } +} diff --git a/APT.DAL.Data/PhoneMap.cs b/APT.DAL.Data/PhoneMap.cs new file mode 100644 index 0000000..018b9f9 --- /dev/null +++ b/APT.DAL.Data/PhoneMap.cs @@ -0,0 +1,27 @@ +using APT.Domain; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; +using System; +using System.Collections.Generic; +using System.Text; + +namespace APT.DAL.Data +{ + public class PhoneMap : IEntityTypeConfiguration + { + //public PhoneMap(ModelBuilder builder) + //{ + // builder.Entity() + // .HasOne(o => o.TestUser) + // .WithMany() + // .HasForeignKey(o => o.TestUser_ID); + //} + + public virtual void Configure(EntityTypeBuilder builder) + { + builder.HasOne(o => o.Nav_TestUser) + .WithMany() + .HasForeignKey(o => o.TestUser_ID); + } + } +} diff --git a/APT.DAL.Data/TestNoneBaseMap.cs b/APT.DAL.Data/TestNoneBaseMap.cs new file mode 100644 index 0000000..cd039d7 --- /dev/null +++ b/APT.DAL.Data/TestNoneBaseMap.cs @@ -0,0 +1,16 @@ +using APT.Domain; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; +using System; +using System.Collections.Generic; +using System.Text; + +namespace APT.DAL.Data +{ + public class TestNoneBaseMap : IEntityTypeConfiguration + { + public virtual void Configure(EntityTypeBuilder builder) + { + } + } +} diff --git a/APT.DAL.Data/UserMap.cs b/APT.DAL.Data/UserMap.cs new file mode 100644 index 0000000..7254d7b --- /dev/null +++ b/APT.DAL.Data/UserMap.cs @@ -0,0 +1,40 @@ +using APT.Domain; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; +using System; +using System.Collections.Generic; +using System.Text; + +namespace APT.DAL.Data +{ + public class UserMap : IEntityTypeConfiguration + { + //public UserMap(ModelBuilder builder) + //{ + // builder.Entity(c => + // { + // c.HasMany(o => o.TestPhones) + // .WithOne(o => o.TestUser) + // .HasForeignKey(o => o.TestUser_ID); + + // c.HasMany(o => o.Courses) + // .WithOne(o => o.TestUser) + // .HasForeignKey(o => o.UserID); + // }); + + // builder.Entity().Property(t => t.IS_DELETED).HasColumnType("bit(1)"); + //} + + public virtual void Configure(EntityTypeBuilder builder) + { + + //builder.HasMany(o => o.TestPhones) + //.WithOne(o => o.Nav_TestUser) + //.HasForeignKey(o => o.TestUser_ID); + + builder.HasMany(o => o.Courses) + .WithOne(o => o.TestUser) + .HasForeignKey(o => o.UserID); + } + } +} diff --git a/APT.Domain/APT.Domain.csproj b/APT.Domain/APT.Domain.csproj new file mode 100644 index 0000000..7c5aab1 --- /dev/null +++ b/APT.Domain/APT.Domain.csproj @@ -0,0 +1,15 @@ + + + + netstandard2.1 + + + + + + + + + + + diff --git a/APT.Domain/LDX_Test_Course.cs b/APT.Domain/LDX_Test_Course.cs new file mode 100644 index 0000000..ddecb37 --- /dev/null +++ b/APT.Domain/LDX_Test_Course.cs @@ -0,0 +1,22 @@ +using APT.Infrastructure.Core; +using System; +using System.Collections.Generic; +using System.Text; + +namespace APT.Domain +{ + public class APT_Test_Course : MesEntityBase + { + public string Name { get; set; } + + public string TeacherName { get; set; } + + public string ClassTime { get; set; } + + public int Score { get; set; } + + public Guid UserID { get; set; } + + public virtual APT_Test_User TestUser { get; set; } + } +} diff --git a/APT.Domain/LDX_Test_Phone.cs b/APT.Domain/LDX_Test_Phone.cs new file mode 100644 index 0000000..f2079e0 --- /dev/null +++ b/APT.Domain/LDX_Test_Phone.cs @@ -0,0 +1,22 @@ +using APT.Infrastructure.Core; +using System; +using System.Collections.Generic; +using System.Text; + +namespace APT.Domain +{ + public class APT_Test_Phone : MesEntityBase + { + public string Brand { get; set; } + + public string Model { get; set; } + + public decimal Price { get; set; } + + public Guid TestUser_ID { get; set; } + + public int? Number { get; set; } + + public virtual APT_Test_User Nav_TestUser { get; set; } + } +} diff --git a/APT.Domain/LDX_Test_User.cs b/APT.Domain/LDX_Test_User.cs new file mode 100644 index 0000000..d949860 --- /dev/null +++ b/APT.Domain/LDX_Test_User.cs @@ -0,0 +1,18 @@ +using APT.Infrastructure.Core; +using System.Collections.Generic; + +namespace APT.Domain +{ + public class APT_Test_User : MesEntityBase + { + public string Country { get; set; } + + public string FirstName { get; set; } + + public string LastName { get; set; } + + /// public virtual ICollection TestPhones { get; set; } + + public virtual ICollection Courses { get; set; } + } +} diff --git a/APT.Domain/ModelBase.cs b/APT.Domain/ModelBase.cs new file mode 100644 index 0000000..9cd2e21 --- /dev/null +++ b/APT.Domain/ModelBase.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace APT.Domain +{ + public class EntityBase + { + public Guid ID { get; set; } = Guid.NewGuid(); + + public DateTime CreatedTime { get; set; } = DateTime.Now; + + public DateTime LastUpdated { get; set; } = DateTime.Now; + } +} diff --git a/APT.Domain/TestNoneBaseModel.cs b/APT.Domain/TestNoneBaseModel.cs new file mode 100644 index 0000000..6d666f3 --- /dev/null +++ b/APT.Domain/TestNoneBaseModel.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace APT.Domain +{ + public class TestNoneBaseModel + { + public string ID { get; set; } + + public string Name { get; set; } + } +} diff --git a/APT.Frame.sln b/APT.Frame.sln new file mode 100644 index 0000000..6cbc23d --- /dev/null +++ b/APT.Frame.sln @@ -0,0 +1,73 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.30011.22 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "APT.API", "APT.API\APT.API.csproj", "{F87A3F72-7E1A-4F63-BE31-6F88199945F0}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "APT.DAL.Data", "APT.DAL.Data\APT.DAL.Data.csproj", "{8A846A4E-70E7-410B-BEC9-DA625E0A0B06}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "APT.Domain", "APT.Domain\APT.Domain.csproj", "{25554D0A-39CA-4E43-B514-ECC66C5A124F}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "APT.Infrastructure.Api", "APT.Infrastructure.Api\APT.Infrastructure.Api.csproj", "{0F778BA2-640D-4DBA-BF17-DBFE40D94C81}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "APT.Infrastructure.Core", "APT.Infrastructure.Core\APT.Infrastructure.Core.csproj", "{783359E8-9993-42E4-8CD9-D6D3C52B0085}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "APT.Infrastructure.EF", "APT.Infrastructure.EF\APT.Infrastructure.EF.csproj", "{AC74146E-9B8D-4B92-8096-E37E13A498E0}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "APT.Migrations", "APT.Migrations\APT.Migrations.csproj", "{CE1F054B-F743-4581-903A-2E5E1D99DC51}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "APT.Infrastructure.Utility", "Apt.Infrastructure.Utility\APT.Infrastructure.Utility.csproj", "{960E5BF4-8B74-4E81-91D8-ADCA8ABED8E1}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "APT.Infrastructure.Redis", "APT.Infrastructure.Redis\APT.Infrastructure.Redis.csproj", "{BD1F2435-9879-4F57-A3B2-5D61D1817CD5}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {F87A3F72-7E1A-4F63-BE31-6F88199945F0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F87A3F72-7E1A-4F63-BE31-6F88199945F0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F87A3F72-7E1A-4F63-BE31-6F88199945F0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F87A3F72-7E1A-4F63-BE31-6F88199945F0}.Release|Any CPU.Build.0 = Release|Any CPU + {8A846A4E-70E7-410B-BEC9-DA625E0A0B06}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8A846A4E-70E7-410B-BEC9-DA625E0A0B06}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8A846A4E-70E7-410B-BEC9-DA625E0A0B06}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8A846A4E-70E7-410B-BEC9-DA625E0A0B06}.Release|Any CPU.Build.0 = Release|Any CPU + {25554D0A-39CA-4E43-B514-ECC66C5A124F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {25554D0A-39CA-4E43-B514-ECC66C5A124F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {25554D0A-39CA-4E43-B514-ECC66C5A124F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {25554D0A-39CA-4E43-B514-ECC66C5A124F}.Release|Any CPU.Build.0 = Release|Any CPU + {0F778BA2-640D-4DBA-BF17-DBFE40D94C81}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0F778BA2-640D-4DBA-BF17-DBFE40D94C81}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0F778BA2-640D-4DBA-BF17-DBFE40D94C81}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0F778BA2-640D-4DBA-BF17-DBFE40D94C81}.Release|Any CPU.Build.0 = Release|Any CPU + {783359E8-9993-42E4-8CD9-D6D3C52B0085}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {783359E8-9993-42E4-8CD9-D6D3C52B0085}.Debug|Any CPU.Build.0 = Debug|Any CPU + {783359E8-9993-42E4-8CD9-D6D3C52B0085}.Release|Any CPU.ActiveCfg = Release|Any CPU + {783359E8-9993-42E4-8CD9-D6D3C52B0085}.Release|Any CPU.Build.0 = Release|Any CPU + {AC74146E-9B8D-4B92-8096-E37E13A498E0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AC74146E-9B8D-4B92-8096-E37E13A498E0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AC74146E-9B8D-4B92-8096-E37E13A498E0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AC74146E-9B8D-4B92-8096-E37E13A498E0}.Release|Any CPU.Build.0 = Release|Any CPU + {CE1F054B-F743-4581-903A-2E5E1D99DC51}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CE1F054B-F743-4581-903A-2E5E1D99DC51}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CE1F054B-F743-4581-903A-2E5E1D99DC51}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CE1F054B-F743-4581-903A-2E5E1D99DC51}.Release|Any CPU.Build.0 = Release|Any CPU + {960E5BF4-8B74-4E81-91D8-ADCA8ABED8E1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {960E5BF4-8B74-4E81-91D8-ADCA8ABED8E1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {960E5BF4-8B74-4E81-91D8-ADCA8ABED8E1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {960E5BF4-8B74-4E81-91D8-ADCA8ABED8E1}.Release|Any CPU.Build.0 = Release|Any CPU + {BD1F2435-9879-4F57-A3B2-5D61D1817CD5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BD1F2435-9879-4F57-A3B2-5D61D1817CD5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BD1F2435-9879-4F57-A3B2-5D61D1817CD5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BD1F2435-9879-4F57-A3B2-5D61D1817CD5}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {309AAC7D-8F7A-4037-A847-A42A651A48B6} + EndGlobalSection +EndGlobal diff --git a/APT.Infrastructure.Api/APT.Infrastructure.Api.csproj b/APT.Infrastructure.Api/APT.Infrastructure.Api.csproj new file mode 100644 index 0000000..45ee91a --- /dev/null +++ b/APT.Infrastructure.Api/APT.Infrastructure.Api.csproj @@ -0,0 +1,31 @@ + + + + netstandard2.1 + 2.0.2.52 + true + 2.0.0.52 + 2.0.0.52 + + + + .\APT.Infrastructure.Api.xml + 3 + + + + + + + + + + + + + + + + + + diff --git a/APT.Infrastructure.Api/APT.Infrastructure.Api.xml b/APT.Infrastructure.Api/APT.Infrastructure.Api.xml new file mode 100644 index 0000000..a10a196 --- /dev/null +++ b/APT.Infrastructure.Api/APT.Infrastructure.Api.xml @@ -0,0 +1,3293 @@ + + + + APT.Infrastructure.Api + + + + + 基类接口 + + + + + + 单元操作 + + + + + 通过获取一条记录 + + ID + + + + + 通过获取一条记录 + + ID + + + + + 通过获取一条记录 + + ID + + + + + 排序后的所有记录 + + 排序方式 + 条件 + 分页参数 + 导航属性 + + + + + 获取所有记录 + + + + + + + + + 分页查询 + + 过滤条件 + 过滤实体fiter + 导航属性 + + + + + 排序后分页查询 + + 排序条件 + 过滤条件 + 过滤实体fiter + 导航属性 + + + + + 排序后分页查询 + + 排序条件 + 过滤条件 + 过滤实体fiter + 导航属性 + + + + + 排序后分页查询 + + 排序条件 + 过滤条件 + 过滤实体fiter + 导航属性 + + + + + 排序后分页查询 + + 排序条件 + 过滤条件 + 过滤实体fiter + 导航属性 + + + + + 提交事务 + + 返回结果 + 数据处理 + 数据提交 + + + + + 提交事务 + + 执行方法 + 提交方法 + + + + 提交事务 + + 提交方法 + + + + + + 返回类型 + 执行 + 返回 + + + + + 统一提交 + + + + + + + + + 统一提交 + + 提交方法 + + + + 基类接口 + + 数据库类型 + + + + 添加一条记录 + + + + + + + 更新一条记录 + + + + + + + 按字段更新数据 + + + + + + + 根据条件删除 + + 条件 + + + + + 删除实体 + + 实体集合 + + + + + 删除实体 + + + + + + + 根据条件删除 + + 条件 + + + + + 删除实体 + + 实体集合 + + + + + 删除实体 + + + + + + + 批量新增数据 + + + + + + + 批量更新数据(效率快) + + + + + + + 获取条数 + + + + + + + + 通过ID删除 + + + + + + + 通过ID删除 + + + + + + + 通过ID字符串删除 + + + + + + + 通过ID数组删除 + + + + + + + 通过ID字符串删除 + + + + + + + 通过ID数组删除 + + + + + + + 树基类接口 + + + + + + 添加一条记录 + + + + + + + 更新一条记录 + + + + + + + 根据条件删除 + + 条件 + + + + + 删除实体 + + 实体集合 + + + + + 删除实体 + + + + + + + 根据条件删除 + + 条件 + + + + + 删除实体 + + 实体集合 + + + + + 删除实体 + + + + + + + 批量新增数据 + + + + + + + 批量更新数据(效率快) + + + + + + + 获取条数 + + + + + + + + 通过ID删除 + + + + + + + 通过ID删除 + + + + + + + 通过ID字符串删除 + + + + + + + 通过ID数组删除 + + + + + + + 通过ID字符串删除 + + + + + + + 通过ID数组删除 + + + + + + + 获取树数据 + + lamble表达式 + 过滤实体 + + + + + + + 抛出错误 + + + + + + 为 基础操作 提供统一的返回格式,包含try / catch操作。 + + 返回值类型 + + + + + + 为 基础操作 提供统一的返回格式,包含try / catch操作。 + + 返回值类型 + + + + + + 为 基础操作 提供统一的返回格式,包含try / catch操作。 + + 返回值类型 + + + + + + 为取 分页数据 提供统一的返回格式,包含try / catch操作。 + + 返回值类型 + + + + + + 根据Request中的QueryString获得Linq表达式 + + 实体对象 + + + + + 获取操作单元 + + + + + + + 查询实体 + + + + + + + + + 查询实体 + + + + + + + + + 查询实体 + + + + + + + + + 查询实体 + + + + + + + + + 获取所有数据 + + + + + + + + + + 获取所有数据 + + 类型 + 排序 + lambd表达式 + 过滤器 + 需要关联查询的数据 + + + + + 获取所有数据 + + 类型 + lambd表达式 + 过滤器 + 需要关联查询的数据 + + + + + 排序获取数据 + + + + + + + + + + + + 排序获取数据 + + + + + + + + + + + + 获取实体集合 + + + + + + + + + + 获取排序的实体集合 + + + + + + + + + + 分页查询 + + + + + + + + + + + + 获取排序的实体集合 + + + + + + + + + + 获取排序的实体集合 + + + + + + + + + + 获取排序的实体集合 + + + + + + + + + + 查询实体 + + + + + + + + + 查询实体 + + + + + + + + + 查询实体 + + + + + + + + + 获取所有数据 + + + + + + + + + + 获取所有数据 + + 类型 + 排序 + lambd表达式 + 过滤器 + 需要关联查询的数据 + + + + + 获取所有数据 + + 类型 + 排序 + lambd表达式 + 过滤器 + 需要关联查询的数据 + + + + + 排序获取数据 + + + + + + + + + + + + 排序获取数据 + + + + + + + + + + + + 获取实体集合 + + + + + + + + + + 获取排序的实体集合 + + + + + + + + + + 获取排序的实体集合 + + + + + + + + + + 获取条数 + + + + + + + + + 添加实体 + + + + + + + 添加实体 + + + + + + + 删除实体 + + + + + + + 删除实体 + + + + + + + 删除实体 + + + + + + + 删除实体 + + + + + + + + 逻辑批量删除 + + + + + + + + 删除实体 + + + + + + + 删除实体 + + + + + + + 删除实体 + + + + + + + + 批量删除实体 + + id集合 + + + + + 更新实体 + + + + + + + 按字段更新实体 + + + + + + + 批量添加实体 + + 实体集合 + + + + + 批量更新实体 + + 实体集 + + + + + 更具字段批量更新实体 + + 实体集 + + + + + 批量保存实体 + + 批量保存 + + + + + 添加实体 + + + + + + + 删除实体 + + + + + + + 删除实体 + + + + + + + 删除实体 + + + + + + + 删除实体 + + + + + + + + 逻辑批量删除 + + + + + + + + 更新实体 + + + + + + + 批量添加实体 + + 实体集合 + + + + + 更新实体 + + + + + + + 批量添加实体 + + 实体集合 + + + + + 批量更新实体 + + 实体集 + + + + + 批量保存实体 + + 批量保存 + + + + + 根据数据库连接新增数据 + + + 实体数据 + 加密连接 + + + + 根据数据库连接更新数据 + + + 实体数据集合 + 加密连接 + + + + 根据数据库连接更新数据 + + + 实体数据 + 加密连接 + 更新字段 + + + + 根据数据库连接删除数据 + + + 表达式 + 加密连接 + + + + 根据数据库连接删除数据 + + + 数据实体 + 加密连接 + + + + 根据数据库连接删除数据 + + + 主键 + 加密连接 + + + + 根据数据库连接删除数据 + + + 数据集合 + 加密连接 + + + + 根据数据库连接新增数据 + + + 数据集合 + 加密连接 + + + + 根据数据库连接新增数据 + + + + + + + + + 根据数据库租户新增数据 + + + 实体数据 + 加密租户 + + + + 根据数据库租户更新数据 + + + 实体数据集合 + 加密租户 + + + + 根据数据库租户更新数据 + + + 实体数据 + 加密租户 + 更新字段 + + + + 根据数据库租户删除数据 + + + 表达式 + 加密租户 + + + + 根据数据库租户删除数据 + + + 数据实体 + 加密租户 + + + + 根据数据库租户删除数据 + + + 主键 + 加密租户 + + + + 根据数据库租户删除数据 + + + 数据集合 + 加密租户 + + + + 根据数据库租户新增数据 + + + 数据集合 + 加密租户 + + + + 根据数据库租户新增数据 + + + + + + + + + 添加实体 + + + + + + + 添加实体 + + + + + + + 删除实体 + + + + + + + 删除实体 + + + + + + + 删除实体 + + + + + + + 删除实体 + + + + + + + + 逻辑批量删除 + + + + + + + + 删除实体 + + + + + + + + 删除实体 + + + + + + + 删除实体 + + + + + + + 删除实体 + + + + + + + + 批量删除实体 + + id集合 + + + + + 更新实体 + + + + + + + 批量添加实体 + + 实体集合 + + + + + 批量更新实体 + + 实体集 + + + + + 批量保存实体 + + 批量保存 + + + + + 添加实体 + + + + + + + 添加实体 + + + + + + + 删除实体 + + + + + + + 删除实体 + + + + + + + 删除实体 + + + + + + + 删除实体 + + + + + + + + 逻辑批量删除 + + + + + + + + 删除实体 + + + + + + + + 删除实体 + + + + + + + 删除实体 + + + + + + + 删除实体 + + + + + + + + 批量删除实体 + + id集合 + + + + + 更新实体 + + + + + + + 批量添加实体 + + 实体集合 + + + + + 批量更新实体 + + 实体集 + + + + + 批量保存实体 + + 批量保存 + + + + + 删除实体 + + + + + + + 对数据库执行给定的 DDL/DML 命令。 + + /// 用于创建服务的实例类型 + 命令字符串 + 参数 + 受影响的行数 + + + + 对数据库执行给定的 DDL/DML 命令。 + + 用于创建服务的实例类型 + 事务行为 + 命令字符串 + 参数 + 受影响的行数 + + + + 对数据库执行给定的 DDL/DML 命令返回reader。 + + 用于创建服务的实例类型 + 命令字符串 + reader委托 + + + + 对数据库执行给定的 DDL/DML 命令返回reader。 + + 用于创建服务的实例类型 + 命令字符串 + 参数 + reader委托 + + + + 对数据库执行给定的 DDL/DML 命令返回reader。 + + 用于创建服务的实例类型 + 命令类型 + 命令字符串 + 参数 + reader委托 + + + + 创建一个原始 SQL 查询,该查询将返回给定类型的元素。 + + 用于创建服务的实例类型 + 查询所返回对象的类型 + SQL 查询字符串 + 要应用于 SQL 查询字符串的参数 + + + + + 对数据库执行给定的 DDL/DML 命令。 + + 命令类型 + 命令字符串 + 参数 + + + + + 根据数据库连接对数据库执行给定的 DDL/DML 命令。 + + 数据库类型 + 连接字符串 + sql 类型 + sql + 参数 + + + + 根据数据库连接对数据库执行给定的 DDL/DML 命令获取Reader。 + + 数据库类型 + 连接字符串 + sql 类型 + sql + 参数 + 执行委托 + + + + 根据数据库连接对数据库执行给定的 DDL/DML 命令获取Reader。 + + 数据库类型 + 连接字符串 + sql 类型 + sql + 参数 + 分页索引 从1开始 + 每页条数 必填 + 执行委托 + + + + 根据数据库连接对数据库执行给定的 DDL/DML 命令获取数据总条数。 + + 数据库类型 + 连接字符串 + sql 类型 + sql + 参数 + 数据总条数 + + + + 获取数据库连接对象 + + 数据库类型 + 连接字符串 + + + + 获取数据库连接对象 + + 数据库类型 + 连接字符串 + + + + 执行查询,并返回查询所返回的结果集中第一行的第一列。 所有其他的列和行将被忽略。 + + 数据库类型 + 连接字符串 + sql 类型 + sql + 参数 + + + + 执行查询,并返回查询所返回的结果集中第一行的第一列。 所有其他的列和行将被忽略。 + + 数据库类型 + 连接字符串 + sql 类型 + sql + 参数 + + + + 执行查询,并返回查询所返回的结果集中第一行的第一列。 所有其他的列和行将被忽略。 + + 数据库类型 + 数据库连接对象 + sql 类型 + sql + 是否自动关闭连接 + 参数 + + + + 执行查询,并返回查询所返回的结果集中第一行的第一列。 所有其他的列和行将被忽略。 + + 数据库类型 + 数据库连接对象 + sql 类型 + sql + 是否自动关闭连接 + 参数 + + + + 根据数据库连接对数据库执行给定的 DDL/DML 命令获取Reader。 + + 数据库类型 + 连接对象 + sql 类型 + sql + 参数 + 分页索引 从1开始 + 每页条数 必填 + 执行委托 + 是否自动关闭连接 + + + + 根据数据库连接对数据库执行给定的 DDL/DML 命令获取Reader。 + + 数据库类型 + 连接对象 + sql 类型 + sql + 参数 + 分页索引 从1开始 + 每页条数 必填 + 执行委托 + 是否自动关闭连接 + + + + 根据数据库连接对数据库执行给定的 DDL/DML 命令获取Reader。 + + 数据库类型 + 连接对象 + 指令类型 + SQL语句 + 参数 + 委托 + 是否自动关闭连接 + + + + 根据数据库连接对数据库执行给定的 DDL/DML 命令获取Reader。 + + 数据库类型 + 连接对象 + 指令类型 + SQL语句 + 参数 + 委托 + 是否自动关闭连接 + + + + 根据数据库连接对数据库执行给定的 DDL/DML 命令获取Reader。 + + 数据库类型 + 连接对象 + 指令类型 + SQL语句 + 参数 + 委托 + 是否自动关闭连接 + + + + 依赖注入接口,只有实现该接口才可以被注册到IoC容器中 + + + + + 服务对象定位器 + + + + + 服务对象定位器实例 + + + + + 获取泛型服务对象 + + 服务对象的类型 + + + + + + 添加根节点过滤 + + + + + + + + webSocket 服务帮助类 + + + + + 初始化WebSocket服务 + + + + + + + + + 发生消息到所有用户 + + + + + + 发生消息到所有用户 + + + 检查客户端有效性 + + + + 发送信息到所有用户 + + + + + + 发送信息到所有用户 + + + 检查客户端有效性 + + + + 发送消息到指定用户 + + + + + + + 发送消息到指定用户 + + + + + + TradeManageMessage 和 TradeManageMessage:MQ队列 + + + + + + TradeManageMessage 和 TradeManageMessage:MQ队列 + + + + + + 设置hash值 + + + + + + + + + 根据表名,键名,获取hash值 + + 表名 + 键名 + + + + + 获取指定key中所有字段 + + + + + + + 根据表名,键名,删除hash值 + + 表名 + 键名 + + + + + + 保存一个对象 + + + + + + + + + + 获取单个key的值 + + Redis Key + + + + + 删除单个key + + redis key + 是否删除成功 + + + + 判断key是否存储 + + redis key + + + + + 获取list的redis + + + + + + + 删除list中的某张表数据 + + + + + + + + 是否存在 + + + + + + + + 获取list中表的rediskey + + + + + + + + 单例获取 + + + + + 缓存获取 + + + + + + + + + + + + + + 配置更改时 + + + + + + + 发生错误时 + + + + + + + 重新建立连接之前的错误 + + + + + + + 连接失败 , 如果重新连接成功你将不会收到这个通知 + + + + + + + 更改集群 + + + + + + + redis类库错误 + + + + + + + 缓存管理 + 1.要可以查看所有的缓存 + 2.要可以管理缓存中的数据,如清空,删除等 + 3.可以预先加载 + + + + + 判断某个数据是否已经被缓存 + + + + + + + + 移除hash中的某值 + + + + + + + + 从hash表获取数据 + + + + + + + + + 获取所有KEY + + + + + + 获取list的redis + + + + + + + 删除list中的某张表数据 + + + + + + + + 是否存在 + + + + + + + + 获取list中表的rediskey + + + + + + + + Redis服务器 + + + + + Redis密码 + + + + + 系统自定义Key前缀 + + + + + 逻辑删除 + + + + + + + 逻辑删除 + + + + + + + 逻辑删除 + + + + + + + 逻辑批量删除 + + + + + + + + 逻辑删除 + + + + + + + 更新 + + 实体 + 是否成功 + + + + 批量更新 + + 实体集合 + 是否成功 + + + + 批量更新(新增和保存一起)速度慢 + + 实体集合 + 是否成功 + + + + 添加实体 + + + + + + + 删除实体 + + + + + + + 删除实体 + + + + + + + 删除实体 + + + + + + + 删除实体 + + + + + + + + 逻辑批量删除 + + + + + + + + 更新实体 + + + + + + + 批量添加实体 + + 实体集合 + + + + + 批量更新实体 + + 实体集 + + + + + 批量保存实体 + + 批量保存 + + + + + 查询实体 + + + + + + + + + 查询实体 + + + + + + + + + 查询实体 + + + + + + + + + 获取所有数据 + + + + + + + + + + 获取所有数据 + + 类型 + 排序 + lambd表达式 + 过滤器 + 需要关联查询的数据 + + + + + 获取所有数据 + + 类型 + lambd表达式 + 过滤器 + 需要关联查询的数据 + + + + + 排序获取数据 + + + + + + + + + + + + 排序获取数据 + + + + + + + + + + + + 提交事务 + + 提交方法 + + + + 逻辑删除 + + + + + + + 逻辑删除 + + + + + + + 逻辑删除 + + + + + + + 逻辑批量删除 + + + + + + + + 逻辑删除 + + + + + + + 更新 + + 实体 + 是否成功 + + + + 批量更新 + + 实体集合 + 是否成功 + + + + 批量更新 + + 实体集合 + 是否成功 + + + + 更新 + + 实体 + 是否成功 + + + + 批量更新(新增和保存一起)速度慢 + + 实体集合 + 是否成功 + + + + 统一提交 + + 数据库方法 + + + + 批量添加实体 + + 实体集合 + + + + + 添加实体 + + + + + + + 删除实体 + + + + + + + 删除实体 + + + + + + + 删除实体 + + + + + + + 删除实体 + + + + + + + + 逻辑批量删除 + + + + + + + + 更新实体 + + + + + + + 批量更新实体 + + 实体集 + + + + + 批量保存实体 + + 批量保存 + + + + + 根据数据库连接新增数据 + + + 实体数据 + 加密连接 + + + + 根据数据库连接更新数据 + + + 实体数据集合 + 加密连接 + + + + 根据数据库连接更新数据 + + + 实体数据 + 加密连接 + 更新字段 + + + + 根据数据库连接删除数据 + + + 表达式 + 加密连接 + + + + 根据数据库连接删除数据 + + + 数据实体 + 加密连接 + + + + 根据数据库连接删除数据 + + + 主键 + 加密连接 + + + + 根据数据库连接删除数据 + + + 数据集合 + 加密连接 + + + + 根据数据库连接新增数据 + + + 数据集合 + 加密连接 + + + + 根据数据库连接新增数据 + + + + + + + + + 根据数据库连接新增数据 + + + 实体数据 + 加密连接 + + + + 根据数据库连接更新数据 + + + 实体数据集合 + 加密连接 + + + + 根据数据库连接更新数据 + + + 实体数据 + 加密连接 + 更新字段 + + + + 根据数据库连接删除数据 + + + 表达式 + 加密连接 + + + + 根据数据库连接删除数据 + + + 数据实体 + 加密连接 + + + + 根据数据库连接删除数据 + + + 主键 + 加密连接 + + + + 根据数据库连接删除数据 + + + 数据集合 + 加密连接 + + + + 根据数据库连接新增数据 + + + 数据集合 + 加密连接 + + + + 根据数据库连接新增数据 + + + + + + + + + 领域服务基类 + + 领域实体仓储对象 + 领域实体 + 领域实体主键类型 + + + + 对数据库执行给定的 DDL/DML 命令。 + + 命令字符串 + 参数 + 受影响的行数 + + + + 对数据库执行给定的 DDL/DML 命令。 + + 事务行为 + 命令字符串 + 参数 + 受影响的行数 + + + + 对数据库执行给定的 DDL/DML 命令返回reader。 + + 命令字符串 + reader委托 + + + + 对数据库执行给定的 DDL/DML 命令返回reader。 + + 命令字符串 + 参数 + reader委托 + + + + 对数据库执行给定的 DDL/DML 命令返回reader。 + + 命令类型 + 命令字符串 + 参数 + reader委托 + + + + 创建一个原始 SQL 查询,该查询将返回给定类型的元素。 + + 查询所返回对象的类型 + SQL 查询字符串 + 要应用于 SQL 查询字符串的参数 + + + + + 获取数据库连接对象 + + 数据库类型 + 连接字符串 + + + + 对数据库执行给定的 DDL/DML 命令。 + + 命令类型 + 命令字符串 + 参数 + + + + + 根据数据库连接对数据库执行给定的 DDL/DML 命令。 + + 数据库类型 + 连接字符串 + sql 类型 + sql + 参数 + + + + 根据数据库连接对数据库执行给定的 DDL/DML 命令获取Reader。 + + 数据库类型 + 连接字符串 + sql 类型 + sql + 参数 + 执行委托 + + + + 执行查询,并返回查询所返回的结果集中第一行的第一列。 所有其他的列和行将被忽略。 + + 数据库类型 + 连接字符串 + sql 类型 + sql + 参数 + + + + 执行查询,并返回查询所返回的结果集中第一行的第一列。 所有其他的列和行将被忽略。 + + 数据库类型 + 数据库连接对象 + sql 类型 + sql + 是否自动关闭连接 + 参数 + + + + 根据数据库连接对数据库执行给定的 DDL/DML 命令获取Reader。 + + 数据库类型 + 连接对象 + 指令类型 + SQL语句 + 参数 + 委托 + 是否自动关闭连接 + + + + 根据数据库连接对数据库执行给定的 DDL/DML 命令获取Reader。 + + 数据库类型 + 连接字符串 + sql 类型 + sql + 参数 + 分页索引 从1开始 + 每页条数 必填 + 执行委托 + + + + 根据数据库连接对数据库执行给定的 DDL/DML 命令获取Reader。 + + 数据库类型 + 连接对象 + sql 类型 + sql + 参数 + 分页索引 从1开始 + 每页条数 必填 + 执行委托 + 是否自动关闭连接 + + + + 根据数据库连接对数据库执行给定的 DDL/DML 命令获取数据总条数。 + + 数据库类型 + 连接字符串 + sql 类型 + sql + 参数 + 数据总条数 + + + + 通用接口,可以调用基类方法 + + + + + + 查询实体 + + + + + + + + + 查询实体 + + + + + + + + + 查询实体 + + + + + + + + + 查询实体 + + + + + + + + + 查询实体 + + + + + + + + + 获取所有数据 + + + + + + + + + + 获取所有数据 + + 类型 + 排序 + lambd表达式 + 过滤器 + 需要关联查询的数据 + + + 获取所有数据 + + 类型 + 排序 + lambd表达式 + 过滤器 + 需要关联查询的数据 + + + + + 获取所有数据 + + 类型 + lambd表达式 + 过滤器 + 需要关联查询的数据 + + + + + 排序获取数据 + + + + + + + + + + + + 排序获取数据 + + + + + + + + + + + + 添加实体 + + + + + + + 删除实体 + + + + + + + 删除实体 + + + + + + + 删除实体 + + + + + + + 删除实体 + + + + + + + + 逻辑批量删除 + + + + + + + + + 按字段更新数据 + + + + + + + + + 根据字段批量更新实体 + + + + + + + + + 批量添加实体 + + 实体集合 + + + + + 批量更新实体 + + 实体集 + + + + + 批量保存实体 + + 批量保存 + + + + + 添加实体 + + + + + + + 删除实体 + + + + + + + 删除实体 + + + + + + + 删除实体 + + + + + + + 删除实体 + + + + + + + + 逻辑批量删除 + + + + + + + + 更新实体 + + + + + + + 批量添加实体 + + 实体集合 + + + + + 批量更新实体 + + 实体集 + + + + + 批量保存实体 + + 批量保存 + + + + + 批量添加实体 + + 实体集合 + + + + + 添加实体 + + + + + + + 删除实体 + + + + + + + 删除实体 + + + + + + + 删除实体 + + + + + + + 删除实体 + + + + + + + + 逻辑批量删除 + + + + + + + + 更新实体 + + + + + + + 批量更新实体 + + 实体集 + + + + + 批量保存实体 + + 批量保存 + + + + + 逻辑删除 + + + + + + + 逻辑删除 + + + + + + + 逻辑删除 + + + + + + + 逻辑批量删除 + + + + + + + + 逻辑删除 + + + + + + + 更新 + + 实体 + 是否成功 + + + + 批量更新 + + 实体集合 + 是否成功 + + + + 更新 + + 实体 + 是否成功 + + + + 批量更新 + + 实体集合 + 是否成功 + + + + 批量更新(新增和保存一起)速度慢 + + 实体集合 + 是否成功 + + + + 统一提交 + + 数据库方法 + + + + 领域服务接口 + + + + + + + + 对数据库执行给定的 DDL/DML 命令。 + + 命令字符串 + 参数 + 受影响的行数 + + + + 对数据库执行给定的 DDL/DML 命令。 + + 事务行为 + 命令字符串 + 参数 + 受影响的行数 + + + + 对数据库执行给定的 DDL/DML 命令返回reader。 + + 命令字符串 + reader委托 + + + + 对数据库执行给定的 DDL/DML 命令返回reader。 + + 命令字符串 + 参数 + reader委托 + + + + 对数据库执行给定的 DDL/DML 命令返回reader。 + + 命令类型 + 命令字符串 + 参数 + reader委托 + + + + 创建一个原始 SQL 查询,该查询将返回给定类型的元素。 + + 查询所返回对象的类型 + SQL 查询字符串 + 要应用于 SQL 查询字符串的参数 + + + + + 对数据库执行给定的 DDL/DML 命令。 + + 命令类型 + 命令字符串 + 参数 + + + + + 获取数据库连接对象 + + 数据库类型 + 连接字符串 + + + + 执行查询,并返回查询所返回的结果集中第一行的第一列。 所有其他的列和行将被忽略。 + + 数据库类型 + 连接字符串 + sql 类型 + sql + 参数 + + + + 执行查询,并返回查询所返回的结果集中第一行的第一列。 所有其他的列和行将被忽略。 + + 数据库类型 + 数据库连接对象 + sql 类型 + sql + 参数 + 是否关闭连接 + + + + 根据数据库连接对数据库执行给定的 DDL/DML 命令获取Reader。 + + 数据库类型 + 连接对象 + sql 类型 + sql + 参数 + 分页索引 从1开始 + 每页条数 必填 + 执行委托 + 是否关闭连接 + + + + 根据数据库连接对数据库执行给定的 DDL/DML 命令获取Reader。 + + 数据库类型 + 连接对象 + 指令类型 + SQL语句 + 参数 + 是否关闭连接 + 委托 + + + + 根据数据库连接对数据库执行给定的 DDL/DML 命令。 + + 数据库类型 + 连接字符串 + sql 类型 + sql + 参数 + + + + 根据数据库连接对数据库执行给定的 DDL/DML 命令。 + + 数据库类型 + 连接字符串 + sql 类型 + sql + 参数 + + + + 根据数据库连接对数据库执行给定的 DDL/DML 命令获取Reader。 + + 数据库类型 + 连接字符串 + sql 类型 + sql + 参数 + 执行委托 + + + + 根据数据库连接对数据库执行给定的 DDL/DML 命令获取Reader。 + + 数据库类型 + 连接字符串 + sql 类型 + sql + 参数 + 分页索引 从1开始 + 每页条数 必填 + 执行委托 + + + + 根据数据库连接对数据库执行给定的 DDL/DML 命令获取数据总条数。 + + 数据库类型 + 连接字符串 + sql 类型 + sql + 参数 + 数据总条数 + + + + 当前会话 + + + + + 日志记录器 + + + + + 是否使用Redis + + + + + 微信Token + + + + + 部门ID + + + + + 自定义变量1 + + + + + 自定义变量2 + + + + + 自定义变量3 + + + + + 自定义变量4 + + + + + 自定义变量5 + + + + + 权限缓存 + + + + + 地址 + + + + + 用户 + + + + + 密码 + + + + + 源标签历史数据 + + + + + 纠错数据表 + + + + + Log + + + + + + + + + + 用量 + + + + + 价格 + + + + + 价格 + + + + diff --git a/APT.Infrastructure.Api/Api/APTApiController.cs b/APT.Infrastructure.Api/Api/APTApiController.cs new file mode 100644 index 0000000..db6bdb6 --- /dev/null +++ b/APT.Infrastructure.Api/Api/APTApiController.cs @@ -0,0 +1,1009 @@ +using Microsoft.EntityFrameworkCore; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Threading.Tasks; +using APT.Infrastructure.Core; +namespace APT.Infrastructure.Api +{ + + /// + /// 基类接口 + /// + /// + public abstract class APTApiControllerBase : CommonApiController where T : MesEntityBase, new() + { + private IUnitOfWork _UnitOfWork; + /// + /// 单元操作 + /// + protected IUnitOfWork UnitOfWork + { + get + { + if (_UnitOfWork == null) + { + _UnitOfWork = GetUnitOfWork(); + } + return _UnitOfWork; + } + } + + /// + /// 通过获取一条记录 + /// + /// ID + /// + protected JsonActionResult WitEntity(string id, params string[] param) + { + + return SafeExecute(() => + { + return base.GetEntity(id, param); + }); + } + /// + /// 通过获取一条记录 + /// + /// ID + /// + protected JsonActionResult WitEntity(Expression> expression, params string[] param) + { + + return SafeExecute(() => + { + return base.GetEntity(expression, param); + }); + } + /// + /// 通过获取一条记录 + /// + /// ID + /// + protected JsonActionResult WitEntity(Expression> expression, BaseFilter filter, params string[] param) + { + + return SafeExecute(() => + { + return base.GetEntity(expression, filter, param); + }); + } + /// + /// 排序后的所有记录 + /// + /// 排序方式 + /// 条件 + /// 分页参数 + /// 导航属性 + /// + protected JsonActionResult> WitActionOrderEntities(Action> orderBy, Expression> expression, BaseFilter fiter, params string[] param) + { + return SafeExecute>(() => + { + return base.ActionOrderEntities(orderBy, expression, fiter, param); + }); + } + /// + /// 获取所有记录 + /// + /// + /// + /// + /// + protected JsonActionResult> WitEntities(Expression> expression, BaseFilter fiter, params string[] param) + { + return SafeExecute>(() => + { + return base.GetEntities(expression, fiter, param); + }); + } + /// + /// 分页查询 + /// + /// 过滤条件 + /// 过滤实体fiter + /// 导航属性 + /// + protected PagedActionResult WitPaged(Expression> expression, BasePageFilter fiter, params string[] param) + { + return SafeGetPagedData((result) => + { + var page = base.GetPageEntities(expression, fiter, param); + result.Data = page.Data; + result.TotalCount = page.TotalCount; + }); + } + /// + /// 排序后分页查询 + /// + /// 排序条件 + /// 过滤条件 + /// 过滤实体fiter + /// 导航属性 + /// + protected async Task> WitActionOrderPagedSync(Action> orderBy, Expression> expression, BasePageFilter fiter, params string[] param) + { + return SafeGetPagedData(async (result) => + { + var page = await base.ActionOrderPageEntitiesSync(orderBy, expression, fiter, param); + result.Data = page.Data; + result.TotalCount = page.TotalCount; + }); + } + /// + /// 排序后分页查询 + /// + /// 排序条件 + /// 过滤条件 + /// 过滤实体fiter + /// 导航属性 + /// + protected async Task> WitOrderPagedSync(Expression> expression, BasePageFilter fiter, params string[] param) + { + return SafeGetPagedData(async (result) => + { + var page = await base.GetOrderPageEntitiesSync(expression, fiter, param); + result.Data = page.Data; + result.TotalCount = page.TotalCount; + }); + } + /// + /// 排序后分页查询 + /// + /// 排序条件 + /// 过滤条件 + /// 过滤实体fiter + /// 导航属性 + /// + protected PagedActionResult WitActionOrderPaged(Action> orderBy, Expression> expression, BasePageFilter fiter, params string[] param) + { + return SafeGetPagedData((result) => + { + var page = base.ActionOrderPageEntities(orderBy, expression, fiter, param); + result.Data = page.Data; + result.TotalCount = page.TotalCount; + }); + } + + protected PagedActionResult WitActionOrderPaged(Expression> expression, BasePageFilter pageFilter, string[] selectField, + params string[] paths) where T : MesEntityBase, new() + { + return SafeGetPagedData((result) => + { + var page = base.GetOrderPageEntities(expression, pageFilter, selectField,paths); + result.Data = page.Data; + result.TotalCount = page.TotalCount; + }); + } + /// + /// 排序后分页查询 + /// + /// 排序条件 + /// 过滤条件 + /// 过滤实体fiter + /// 导航属性 + /// + protected PagedActionResult WitOrderPaged(Expression> expression, BasePageFilter fiter, params string[] param) + { + return SafeGetPagedData((result) => + { + var page = base.GetOrderPageEntities(expression, fiter, param); + result.Data = page.Data; + result.TotalCount = page.TotalCount; + }); + } + + protected JsonActionResult> WitOrderEntities(Expression> expression, string sort, string order, BaseFilter fiter, params string[] param) + { + return SafeExecute>(() => + { + return base.GetOrderEntities(expression, fiter, sort, order, param); + }); + } + protected JsonActionResult> WitOrderEntities(Expression> expression, BaseFilter fiter, params string[] param) + { + return SafeExecute>(() => + { + return base.GetOrderEntities(expression, fiter, param); + }); + } + + /// + /// 提交事务 + /// + /// 返回结果 + /// 数据处理 + /// 数据提交 + /// + protected JsonActionResult WitCommitTransaction(Action execAction, Func comitAction) + { + var result = new JsonActionResult(); + try + { + if (execAction != null) + { + execAction(); + } + UnitOfWork.BeginTransaction(); + result.Data = comitAction(); + UnitOfWork.CommitTransaction(); + } + catch (CodeException ex) + { + try + { + UnitOfWork.RollbackTransaction(); + } + catch (Exception ex1) + { + LoggerManager.GetLogger().Info("rollback Error" + ex1.ToString()); + } + + result.IsSuccessful = false; + result.ErrorMessage = GetErrorMsg(ex); + result.Code = ex.Code; + LoggerManager.GetLogger().Error(result.ErrorMessage); + } + catch (Exception ex) + { + try + { + UnitOfWork.RollbackTransaction(); + } + catch (Exception ex1) + { + LoggerManager.GetLogger().Info("rollback Error" + ex1.ToString()); + } + LoggerManager.GetLogger().Error(ex.ToString()); + result.IsSuccessful = false; + result.ErrorMessage = ex.Message; + } + return result; + } + /// + /// 提交事务 + /// + /// 执行方法 + /// 提交方法 + protected void WitCommitTransaction(Action execAction, Action comitAction) + { + try + { + if (execAction != null) + { + execAction(); + } + UnitOfWork.BeginTransaction(); + comitAction(); + UnitOfWork.CommitTransaction(); + } + catch (CodeException ex) + { + try + { + UnitOfWork.RollbackTransaction(); + } + catch (Exception ex1) + { + LoggerManager.GetLogger().Info("rollback Error" + ex1.ToString()); + } + var exs = GetErrorMsg(ex); + LoggerManager.GetLogger().Info("rollback Error" + exs.ToString()); + } + catch (Exception ex) + { + try + { + UnitOfWork.RollbackTransaction(); + } + catch (Exception ex1) + { + LoggerManager.GetLogger().Info("rollback Error" + ex1.ToString()); + } + throw; + } + } + /// + /// 提交事务 + /// + /// 提交方法 + protected void WitCommitTransaction(Action comitAction) + { + try + { + + UnitOfWork.BeginTransaction(); + comitAction(); + UnitOfWork.CommitTransaction(); + } + catch (CodeException ex) + { + try + { + UnitOfWork.RollbackTransaction(); + } + catch (Exception ex1) + { + LoggerManager.GetLogger().Info("rollback Error" + ex1.ToString()); + } + var exs = GetErrorMsg(ex); + LoggerManager.GetLogger().Info("rollback Error" + exs.ToString()); + } + catch + { + try + { + UnitOfWork.RollbackTransaction(); + } + catch (Exception ex1) + { + LoggerManager.GetLogger().Info("rollback Error" + ex1.ToString()); + } + throw; + } + } + /// + /// + /// + /// 返回类型 + /// 执行 + /// 返回 + /// + protected JsonActionResult WitSafeExecute(Action execAction, Func> comitAction) + { + var result = new JsonActionResult(); + try + { + if (execAction != null) + { + execAction(); + } + result = comitAction(); + } + catch (CodeException ex) + { + result.IsSuccessful = false; + result.ErrorMessage = GetErrorMsg(ex); + result.Code = ex.Code; + LoggerManager.GetLogger().Error(result.ErrorMessage); + } + catch (Exception ex) + { + LoggerManager.GetLogger().Error(ex.ToString()); + result.IsSuccessful = false; + result.ErrorMessage = ex.Message; + } + return result; + } + + protected JsonActionResult WitSafeExecute(Action execAction, Func comitAction) + { + var result = new JsonActionResult(); + try + { + if (execAction != null) + { + execAction(); + } + result.Data = comitAction(); + } + catch (CodeException ex) + { + result.IsSuccessful = false; + result.ErrorMessage = GetErrorMsg(ex); + result.Code = ex.Code; + LoggerManager.GetLogger().Error(result.ErrorMessage); + } + catch (Exception ex) + { + LoggerManager.GetLogger().Error(ex.ToString()); + result.IsSuccessful = false; + result.ErrorMessage = ex.Message; + } + return result; + } + + /// + /// 统一提交 + /// + /// + /// + /// + /// + protected JsonActionResult UnifiedCommit(Action execAction, Func comitAction) + { + var result = new JsonActionResult(); + try + { + if (execAction != null) + { + execAction(); + UnitOfWork.SaveChanges(); + } + result.Data = comitAction(); + } + catch (CodeException ex) + { + result.IsSuccessful = false; + result.ErrorMessage = GetErrorMsg(ex); + result.Code = ex.Code; + LoggerManager.GetLogger().Error(result.ErrorMessage); + } + catch (Exception ex) + { + LoggerManager.GetLogger().Error(ex.ToString()); + result.IsSuccessful = false; + result.ErrorMessage = ex.Message; + } + return result; + } + + /// + /// 统一提交 + /// + /// 提交方法 + protected void UnifiedCommit(Action comitAction) + { + try + { + + comitAction(); + UnitOfWork.SaveChanges(); + } + catch (CodeException ex) + { + var exs = GetErrorMsg(ex); + LoggerManager.GetLogger().Info("rollback Error" + exs.ToString()); + throw; + } + catch (Exception ex1) + { + LoggerManager.GetLogger().Info("rollback Error" + ex1.ToString()); + throw; + } + } + + } + + + /// + /// 基类接口 + /// + /// 数据库类型 + public abstract class APTApiController : APTApiControllerBase where T : MesEntityBase, new() + { + + /// + /// 添加一条记录 + /// + /// + /// + protected JsonActionResult WitAdd(T entity) + { + return SafeExecute(() => + { + return base.AddEntity(entity); + }); + } + /// + /// 更新一条记录 + /// + /// + /// + protected JsonActionResult WitUpdate(T entity) + { + return SafeExecute(() => + { + return base.UpdateEntity(entity); + }); + } + + /// + /// 按字段更新数据 + /// + /// + /// + protected JsonActionResult WitUpdate(T entity, params string[] updateField) + { + return SafeExecute(() => + { + return base.UpdateEntity(entity,updateField); + }); + } + + + /// + /// 根据条件删除 + /// + /// 条件 + /// + protected JsonActionResult WitDelete(Expression> expression) + { + return SafeExecute(() => + { + return base.DeleteEntity(expression); + }); + } + /// + /// 删除实体 + /// + /// 实体集合 + /// + protected JsonActionResult WitDelete(IEnumerable entities) + { + return SafeExecute(() => + { + return base.DeleteEntity(entities); + }); + } + /// + /// 删除实体 + /// + /// + /// + protected JsonActionResult WitDelete(T entity) + { + return SafeExecute(() => + { + return base.DeleteEntity(entity); + }); + } + /// + /// 根据条件删除 + /// + /// 条件 + /// + protected JsonActionResult WitRealDelete(Expression> expression) + { + return SafeExecute(() => + { + return base.RealDeleteEntity(expression); + }); + } + /// + /// 删除实体 + /// + /// 实体集合 + /// + protected JsonActionResult WitRealDelete(IEnumerable entities) + { + return SafeExecute(() => + { + return base.RealDeleteEntity(entities); + }); + } + /// + /// 删除实体 + /// + /// + /// + protected JsonActionResult WitRealDelete(T entity) + { + return SafeExecute(() => + { + return base.RealDeleteEntity(entity); + }); + } + /// + /// 批量新增数据 + /// + /// + /// + protected JsonActionResult WitBantchAdd(IEnumerable entities) + { + return SafeExecute(() => + { + return base.BantchAddEntity(entities); + }); + } + /// + /// 批量更新数据(效率快) + /// + /// + /// + protected JsonActionResult WitBantchUpdate(IEnumerable entities) + { + return SafeExecute(() => + { + return base.BantchUpdateEntity(entities); + }); + } + + /// + /// 获取条数 + /// + /// + /// + /// + protected JsonActionResult WitCount(Expression> expression, BaseFilter filter) + { + return SafeExecute(() => + { + return base.GetCount(expression, filter); + }); + } + + /// + /// 通过ID删除 + /// + /// + /// + protected JsonActionResult WitDelete(string id) + { + return SafeExecute(() => + { + return base.DeleteEntity(id); + }); + } + /// + /// 通过ID删除 + /// + /// + /// + protected JsonActionResult WitRealDelete(string id) + { + return SafeExecute(() => + { + try + { + Guid temp = new Guid(id); + return base.RealDeleteEntity(t => t.ID == temp); + } + catch (Exception ex) + { + if (ex is DbUpdateException) + throw new Exception("该资料已被用,不允许执行此操作"); + else if (ex is DomainException) + { + if (ex.Message.IndexOf("DbUpdateException", StringComparison.OrdinalIgnoreCase) > -1) + throw new Exception("该资料已被用,不允许执行此操作"); + } + throw ex; + } + }); + } + /// + /// 通过ID字符串删除 + /// + /// + /// + protected JsonActionResult WitBatchDelete(string ids) + { + var aryList = ids.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(i => new Guid(i)).ToList(); + //var users = UserService.Query(i => i.NO == userName && i.PASSWORD == passWord).FirstOrDefault(); + return SafeExecute(() => + { + try + { + return base.BantchDeleteEntity(aryList); + } + catch (Exception ex) + { + //if (ex is DbUpdateException) + // throw new Exception("存在资料已被用,不允许执行此操作"); + //else if (ex is DomainException) + //{ + // if (ex.Message.IndexOf("DbUpdateException", StringComparison.OrdinalIgnoreCase) > -1) + // throw new Exception("存在资料已被用,不允许执行此操作"); + //} + throw ex; + } + }); + } + /// + /// 通过ID数组删除 + /// + /// + /// + protected JsonActionResult WitBatchDelete(string[] ids) + { + //var users = UserService.Query(i => i.NO == userName && i.PASSWORD == passWord).FirstOrDefault(); + return SafeExecute(() => + { + var tmp = ids == null ? null : ids.Select(i => new Guid(i)).ToList(); + return base.BantchDeleteEntity(tmp); + }); + } + /// + /// 通过ID字符串删除 + /// + /// + /// + protected JsonActionResult WitRealBatchDelete(string ids) + { + var aryList = ids.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(i => new Guid(i)).ToList(); + //var users = UserService.Query(i => i.NO == userName && i.PASSWORD == passWord).FirstOrDefault(); + return SafeExecute(() => + { + return base.RealBantchDeleteEntity(aryList); + }); + } + /// + /// 通过ID数组删除 + /// + /// + /// + protected JsonActionResult WitRealBatchDelete(string[] ids) + { + //var users = UserService.Query(i => i.NO == userName && i.PASSWORD == passWord).FirstOrDefault(); + return SafeExecute(() => + { + var tmp = ids == null ? null : ids.Select(i => new Guid(i)).ToList(); + return base.RealBantchDeleteEntity(tmp); + }); + } + + } + + /// + /// 树基类接口 + /// + /// + public abstract class APTTreeApiController : APTApiControllerBase where T : TreeEntityBase, new() + { + /// + /// 添加一条记录 + /// + /// + /// + protected JsonActionResult WitAdd(T entity) + { + return SafeExecute(() => + { + return base.TreeAddEntity(entity); + }); + } + /// + /// 更新一条记录 + /// + /// + /// + protected JsonActionResult WitUpdate(T entity) + { + return SafeExecute(() => + { + return base.TreeUpdateEntity(entity); + }); + } + + + + /// + /// 根据条件删除 + /// + /// 条件 + /// + protected JsonActionResult WitDelete(Expression> expression) + { + return SafeExecute(() => + { + return base.TreeDeleteEntity(expression); + }); + } + /// + /// 删除实体 + /// + /// 实体集合 + /// + protected JsonActionResult WitDelete(IEnumerable entities) + { + return SafeExecute(() => + { + return base.TreeDeleteEntity(entities); + }); + } + /// + /// 删除实体 + /// + /// + /// + protected JsonActionResult WitDelete(T entity) + { + return SafeExecute(() => + { + return base.TreeDeleteEntity(entity); + }); + } + /// + /// 根据条件删除 + /// + /// 条件 + /// + protected JsonActionResult WitRealDelete(Expression> expression) + { + return SafeExecute(() => + { + return base.TreeRealDeleteEntity(expression); + }); + } + /// + /// 删除实体 + /// + /// 实体集合 + /// + protected JsonActionResult WitRealDelete(IEnumerable entities) + { + return SafeExecute(() => + { + return base.TreeRealDeleteEntity(entities); + }); + } + /// + /// 删除实体 + /// + /// + /// + protected JsonActionResult WitRealDelete(T entity) + { + return SafeExecute(() => + { + return base.TreeRealDeleteEntity(entity); + }); + } + /// + /// 批量新增数据 + /// + /// + /// + protected JsonActionResult WitBantchAdd(IEnumerable entities) + { + return SafeExecute(() => + { + return base.TreeBantchAddEntity(entities); + }); + } + /// + /// 批量更新数据(效率快) + /// + /// + /// + protected JsonActionResult WitBantchUpdate(IEnumerable entities) + { + return SafeExecute(() => + { + return base.TreeBantchUpdateEntity(entities); + }); + } + + /// + /// 获取条数 + /// + /// + /// + /// + protected JsonActionResult WitCount(Expression> expression, BaseFilter filter) + { + return SafeExecute(() => + { + return base.GetCount(expression, filter); + }); + } + + /// + /// 通过ID删除 + /// + /// + /// + protected JsonActionResult WitDelete(string id) + { + return SafeExecute(() => + { + return base.TreeDeleteEntity(id); + }); + } + /// + /// 通过ID删除 + /// + /// + /// + protected JsonActionResult WitRealDelete(string id) + { + return SafeExecute(() => + { + try + { + return base.TreeRealDeleteEntity(id); + } + catch (Exception ex) + { + if (ex is DbUpdateException) + throw new Exception("该资料已被用,不允许执行此操作"); + else if (ex is DomainException) + { + if (ex.Message.IndexOf("DbUpdateException", StringComparison.OrdinalIgnoreCase) > -1) + throw new Exception("该资料已被用,不允许执行此操作"); + } + throw ex; + } + }); + } + /// + /// 通过ID字符串删除 + /// + /// + /// + protected JsonActionResult WitBatchDelete(string ids) + { + return SafeExecute(() => + { + try + { + var aryList = ids.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(t => new Guid(t)).ToList(); + return base.TreeBantchDeleteEntity(aryList); + } + catch (Exception ex) + { + if (ex is DbUpdateException) + throw new Exception("存在资料已被用,不允许执行此操作"); + else if (ex is DomainException) + { + if (ex.Message.IndexOf("DbUpdateException", StringComparison.OrdinalIgnoreCase) > -1) + throw new Exception("存在资料已被用,不允许执行此操作"); + } + throw ex; + } + }); + } + /// + /// 通过ID数组删除 + /// + /// + /// + protected JsonActionResult WitBatchDelete(string[] ids) + { + //var users = UserService.Query(i => i.NO == userName && i.PASSWORD == passWord).FirstOrDefault(); + return SafeExecute(() => + { + var aryList = ids == null ? null : ids.Select(t => new Guid(t)).ToList(); + return base.TreeBantchDeleteEntity(aryList); + }); + } + /// + /// 通过ID字符串删除 + /// + /// + /// + protected JsonActionResult WitRealBatchDelete(string ids) + { + //var users = UserService.Query(i => i.NO == userName && i.PASSWORD == passWord).FirstOrDefault(); + return SafeExecute(() => + { + + var aryList = string.IsNullOrEmpty(ids) ? null : ids.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(t => new Guid(t)).ToList(); + return base.TreeRealBantchDeleteEntity(aryList); + }); + } + /// + /// 通过ID数组删除 + /// + /// + /// + protected JsonActionResult WitRealBatchDelete(string[] ids) + { + //var users = UserService.Query(i => i.NO == userName && i.PASSWORD == passWord).FirstOrDefault(); + return SafeExecute(() => + { + var aryList = ids == null ? null : ids.Select(t => new Guid(t)).ToList(); + return base.TreeRealBantchDeleteEntity(aryList); + }); + } + /// + /// 获取树数据 + /// + /// lamble表达式 + /// 过滤实体 + /// + /// + /// + protected JsonActionResult>> WitTreeOrderEntities(Expression> expression, BaseFilter filter, bool isTracking = false, + params string[] paths) + { + return SafeExecute(() => + { + return base.TreeOrderEntities(expression, filter, isTracking, paths); + }); + } + + } +} diff --git a/APT.Infrastructure.Api/Api/BaseApiController.cs b/APT.Infrastructure.Api/Api/BaseApiController.cs new file mode 100644 index 0000000..c4d6521 --- /dev/null +++ b/APT.Infrastructure.Api/Api/BaseApiController.cs @@ -0,0 +1,202 @@ +using APT.Infrastructure.Api.Model; +using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Mvc; +using System; +using System.Linq; +using System.Linq.Expressions; +using System.Security.Claims; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using APT.Infrastructure.Core; +namespace APT.Infrastructure.Api +{ + //[Log] + public abstract class BaseApiController : ControllerBase + { + /// + /// 抛出错误 + /// + /// + protected void ThrowError(string code, params object [] objs) + { + LibMessageUtils.ThrowError(code,objs); + } + /// + /// 为 基础操作 提供统一的返回格式,包含try / catch操作。 + /// + /// 返回值类型 + /// + /// + protected virtual JsonActionResult SafeExecute(Func execAction, int retryTime = 0) + { + var result = new JsonActionResult(); + try + { + result.Data = execAction(); + } + catch (CodeException ex) + { + LoggerManager.GetLogger().Error(ex.ToString()); + result.IsSuccessful = false; + result.ErrorMessage = GetErrorMsg(ex); + result.Code = ex.Code; + } + catch (Exception ex) + { + if (NeedRetryExceptions.RetryExceptions().Any(o => ex.Message.Contains(o)) && retryTime <= 3 && retryTime > 0) + { + retryTime += 1; + Thread.Sleep(5000); + return this.SafeExecute(execAction, retryTime); + } + var errMsg = LogHelper.GetCurSourceFileName() + " - " + LogHelper.GetLineNum() + ":" + ex.Message; + LoggerManager.GetLogger().Error(errMsg); + result.IsSuccessful = false; + result.ErrorMessage = errMsg; + + } + return result; + } + + /// + /// 为 基础操作 提供统一的返回格式,包含try / catch操作。 + /// + /// 返回值类型 + /// + /// + protected virtual async Task> SafeExecuteAsync(Func> execAction, int retryTime = 0) + { + var result = new JsonActionResult(); + try + { + result.Data = await execAction(); + } + catch (CodeException ex) + { + LoggerManager.GetLogger().Error(ex.ToString()); + result.IsSuccessful = false; + result.ErrorMessage = GetErrorMsg(ex); + result.Code = ex.Code; + } + catch (Exception ex) + { + if (NeedRetryExceptions.RetryExceptions().Any(o => ex.Message.Contains(o)) && retryTime <= 3 && retryTime >0) + { + retryTime += 1; + Thread.Sleep(5000); + return await this.SafeExecuteAsync(execAction, retryTime); + } + var errMsg = LogHelper.GetCurSourceFileName() + " - " + LogHelper.GetLineNum() + ":" + ex.Message; + LoggerManager.GetLogger().Error(errMsg); + result.IsSuccessful = false; + result.ErrorMessage = errMsg; + + } + return result; + } + + + protected string GetErrorMsg(Exception ex) + { + string innerError = string.Empty; + GetInnerErrorMsg(ex.InnerException, ref innerError); + return ex.Message + (!string.IsNullOrEmpty(innerError) ? (",报错明细:" + innerError) : string.Empty); + } + + private void GetInnerErrorMsg(Exception ex, ref string error) + { + if (ex == null) return; + error = ex.Message; + GetInnerErrorMsg(ex.InnerException, ref error); + } + + + + /// + /// 为 基础操作 提供统一的返回格式,包含try / catch操作。 + /// + /// 返回值类型 + /// + /// + protected JsonActionResult SafeJsonExecute(Action> execAction) + { + var result = new JsonActionResult(); + try + { + execAction(result); + } + catch (CodeException ex) + { + LoggerManager.GetLogger().Error(ex.ToString()); + result.IsSuccessful = false; + result.ErrorMessage = GetErrorMsg(ex); + result.Code = ex.Code; + } + catch (Exception ex) + { + var errMsg = LogHelper.GetCurSourceFileName() + " - " + LogHelper.GetLineNum() + ":" + ex.Message; + LoggerManager.GetLogger().Error(errMsg); + result.IsSuccessful = false; + result.ErrorMessage = errMsg; + + } + return result; + } + + /// + /// 为取 分页数据 提供统一的返回格式,包含try / catch操作。 + /// + /// 返回值类型 + /// + /// + protected PagedActionResult SafeGetPagedData(Action> execAction) + { + var result = new PagedActionResult(); + try + { + execAction(result); + } + catch (CodeException ex) + { + LoggerManager.GetLogger().Error(ex.ToString()); + result.IsSuccessful = false; + result.ErrorMessage = GetErrorMsg(ex); + result.Code = ex.Code; + } + catch (Exception ex) + { + var errMsg = LogHelper.GetCurSourceFileName() + " - " + LogHelper.GetLineNum() + ":" + ex.Message; + LoggerManager.GetLogger().Error(errMsg); + result.IsSuccessful = false; + result.ErrorMessage = errMsg; + } + return result; + } + + + + /// + /// 根据Request中的QueryString获得Linq表达式 + /// + /// 实体对象 + /// + protected Expression> GetExpressionFromQueryString() + { + Expression> expr = null; + var queryPairs = Request.Query.ToDictionary(q => q.Key, q => q.Value).Where(q => q.Key.Equals("$format") == false); + if (queryPairs.Count() > 0) + { + var filterGroup = new FilterGroup(); + foreach (var pairItem in queryPairs) + { + filterGroup.Rules.Add(new FilterRule(pairItem.Key, pairItem.Value)); + } + expr = filterGroup.BuildExpression(null); + } + return expr; + } + + + } +} diff --git a/APT.Infrastructure.Api/Api/CommonApiController.cs b/APT.Infrastructure.Api/Api/CommonApiController.cs new file mode 100644 index 0000000..39538a6 --- /dev/null +++ b/APT.Infrastructure.Api/Api/CommonApiController.cs @@ -0,0 +1,1861 @@ +using Microsoft.EntityFrameworkCore.Storage; +using System; +using System.Collections; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Data; +using System.Data.Common; +using System.Linq; +using System.Linq.Expressions; +using System.Threading.Tasks; +using APT.Infrastructure.Core; +namespace APT.Infrastructure.Api +{ + public abstract class CommonApiController : BaseApiController + { + /// + /// 获取操作单元 + /// + /// + /// + public IUnitOfWork GetUnitOfWork() where T : MesEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + return commonService.UnitWork(); + } + readonly ServiceLocator _serviceLocator = ServiceLocator.Instance; + + + + #region old query + /// + /// 查询实体 + /// + /// + /// + /// + /// + public T GetEntity(string id, params string[] paths) where T : MesEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + + return commonService.GetEntity(id, paths); + + } + + /// + /// 查询实体 + /// + /// + /// + /// + /// + public T GetEntity(Guid id, params string[] paths) where T : MesEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + + return commonService.GetEntity(id, paths); + + } + /// + /// 查询实体 + /// + /// + /// + /// + /// + public T GetEntity(Expression> expression, params string[] paths) where T : MesEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + return commonService.GetEntity(expression, paths); + } + /// + /// 查询实体 + /// + /// + /// + /// + /// + public T GetEntity(Expression> expression, BaseFilter fiter, params string[] paths) where T : MesEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + return commonService.GetEntity(expression, fiter, paths); + } + + /// + /// 获取所有数据 + /// + /// + /// + /// + /// + /// + public IEnumerable GetEntities(Expression> expression, BaseFilter filter, params string[] paths) where T : MesEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + return commonService.GetEntities(expression, filter, paths); + } + + /// + /// 获取所有数据 + /// + /// 类型 + /// 排序 + /// lambd表达式 + /// 过滤器 + /// 需要关联查询的数据 + /// + public IEnumerable ActionOrderEntities(Action> orderBy, Expression> expression, BaseFilter filter, params string[] paths) where T : MesEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + return commonService.GetOrderEntities(expression, filter, orderBy, paths); + } + + /// + /// 获取所有数据 + /// + /// 类型 + /// lambd表达式 + /// 过滤器 + /// 需要关联查询的数据 + /// + public IEnumerable GetOrderEntities(Expression> expression, BaseFilter filter, params string[] paths) where T : MesEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + return commonService.GetOrderEntities(expression, filter, paths); + } + /// + /// 排序获取数据 + /// + /// + /// + /// + /// + /// + /// + /// + public IEnumerable GetOrderEntities(Expression> expression, BaseFilter filter, string sort, string order, params string[] paths) where T : MesEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + return commonService.GetOrderEntities(expression, filter, sort, order, paths); + } + /// + /// 排序获取数据 + /// + /// + /// + /// + /// + /// + /// + /// + public IEnumerable GetOrderEntities(Expression> expression, Dictionary orders, BaseFilter filter, params string[] paths) where T : MesEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + return commonService.GetOrderEntities(expression, filter, orders, paths); + } + ///// + ///// 获取实体集合 + ///// + ///// + ///// + //public PagedActionResult GetPageEntities(CommonPageFilter filter) where T : MesEntityBase, new() + //{ + // _serviceLocator.RegisterType(typeof(CommonService), typeof(ICommonService)); + // var commonService = _serviceLocator.GetService>(); + // Expression> expression = t => true; + // if (!string.IsNullOrEmpty(filter.Cid)) + // expression.And(i => i.CID == filter.Cid); + // var page = commonService.GetPagerIEnumerable(expression, filter.Start, filter.Limit); + // return new PagedActionResult(page.Items, page.TotalCount); + //} + + /// + ///获取实体集合 + /// + /// + /// + /// + /// + /// + public PagedActionResult GetPageEntities(Expression> expression, BasePageFilter filter, params string[] paths) where T : MesEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + filter.Sort = "ID"; + var page = commonService.GetPageEntities(expression, filter, paths); + return new PagedActionResult(page.Items, page.TotalCount); + } + + public IEnumerable> GetTreeOrderEntities(Expression> expression, BaseFilter filter, params string[] paths) where T : TreeEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + return commonService.GetTreeOrderEntities(expression, filter, (!filter?.IsNoTranking) ?? true, paths); + } + + /// + ///获取排序的实体集合 + /// + /// + /// + /// + /// + /// + public PagedActionResult ActionOrderPageEntities(Action> orderBy, Expression> expression, BasePageFilter filter, params string[] paths) where T : MesEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + var page = commonService.GetOrderPageEntities(expression, filter, null, 0, 0, orderBy, (!filter?.IsNoTranking) ?? true, paths); + return new PagedActionResult(page.Items, page.TotalCount); + } + /// + /// 分页查询 + /// + /// + /// + /// + /// + /// + /// + /// + public PagedActionResult GetOrderPageEntities(Expression> expression, BasePageFilter pageFilter, string[] selectField, + params string[] paths) where T : MesEntityBase, new() + { + + var commonService = _serviceLocator.GetService(); + var page = commonService.GetOrderPageEntities(expression, pageFilter, selectField, paths); + return new PagedActionResult(page.Items, page.TotalCount); + } + + + /// + ///获取排序的实体集合 + /// + /// + /// + /// + /// + /// + public PagedActionResult GetOrderPageEntities(Expression> expression, BasePageFilter filter, params string[] paths) where T : MesEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + var page = commonService.GetOrderPageEntities(expression, filter, paths); + return new PagedActionResult(page.Items, page.TotalCount); + } + + /// + ///获取排序的实体集合 + /// + /// + /// + /// + /// + /// + public async Task> ActionOrderPageEntitiesSync(Action> orderBy, Expression> expression, BasePageFilter filter, params string[] paths) where T : MesEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + var page = await commonService.GetOrderPageEntitiesSync(expression, filter, null, 0, 0, orderBy, (!filter?.IsNoTranking) ?? true, paths); + return new PagedActionResult(page.Items, page.TotalCount); + } + + /// + ///获取排序的实体集合 + /// + /// + /// + /// + /// + /// + public async Task> GetOrderPageEntitiesSync(Expression> expression, BasePageFilter filter, params string[] paths) where T : MesEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + var page = await commonService.GetOrderPageEntitiesSync(expression, filter, paths); + return new PagedActionResult(page.Items, page.TotalCount); + } + + + #endregion + + #region notraking query + /// + /// 查询实体 + /// + /// + /// + /// + /// + public T GetEntity(string id, bool notraking = false, params string[] paths) where T : MesEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + return commonService.GetEntity(t => t.ID == new Guid(id), null, notraking, paths); + + } + + /// + /// 查询实体 + /// + /// + /// + /// + /// + public T GetEntity(Expression> expression, bool notraking = false, params string[] paths) where T : MesEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + return commonService.GetEntity(expression, null, notraking, paths); + } + /// + /// 查询实体 + /// + /// + /// + /// + /// + public T GetEntity(Expression> expression, BaseFilter fiter, bool notraking = false, params string[] paths) where T : MesEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + return commonService.GetEntity(expression, fiter, notraking, paths); + } + + public T GetEntityByRedis(string key, Guid orgid) where T : MesEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + return commonService.GetEntityByRedis(key, orgid); + } + + public T GetEntityByRedis(Guid key, Guid orgid) where T : MesEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + return commonService.GetEntityByRedis(key, orgid); + } + + public List GetEntitiesByRedis(BaseFilter filter) where T : MesEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + return commonService.GetEntitiesByRedis(filter); + } + + List GetEntitiesByGroupRedis(BaseFilter filter, string groupValue) where T : MesEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + return commonService.GetEntitiesByGroupRedis(filter, groupValue); + } + + public List GetEntitiesByRedis(Expression> expression, BaseFilter filter) where T : MesEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + return commonService.GetEntitiesByRedis(expression, filter); + } + + public List GetEntitiesByRedis(Expression> expression, BaseFilter filter, + params string[] paths) where T : MesEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + return commonService.GetEntitiesTableByRedis(expression, filter, paths); + } + + public List GetEntitiesByRedis(Expression> expression, BaseFilter filter, string groupValue, + params string[] paths) where T : MesEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + return commonService.GetEntitiesByRedis(expression, filter, groupValue, paths); + } + public PagedResultDto GetOrderPageByRedis(Expression> expression, BasePageFilter pageFilter, + params string[] paths) where T : MesEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + return commonService.GetOrderPageByRedis(expression, pageFilter, paths); + } + + /// + /// 获取所有数据 + /// + /// + /// + /// + /// + /// + public IEnumerable GetEntities(Expression> expression, BaseFilter filter, bool notraking = false, params string[] paths) where T : MesEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + return commonService.GetEntities(expression, filter, notraking, paths); + } + + /// + /// 获取所有数据 + /// + /// 类型 + /// 排序 + /// lambd表达式 + /// 过滤器 + /// 需要关联查询的数据 + /// + public IEnumerable ActionOrderEntities(Action> orderBy, Expression> expression, BaseFilter filter, bool notraking = false, params string[] paths) where T : MesEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + return commonService.GetOrderEntities(expression, filter, orderBy, notraking, paths); + } + + /// + /// 获取所有数据 + /// + /// 类型 + /// 排序 + /// lambd表达式 + /// 过滤器 + /// 需要关联查询的数据 + /// + public IEnumerable GetOrderEntities(Expression> expression, BaseFilter filter, bool notraking = false, params string[] paths) where T : MesEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + return commonService.GetOrderEntities(expression, filter, notraking, paths); + } + /// + /// 排序获取数据 + /// + /// + /// + /// + /// + /// + /// + /// + public IEnumerable GetOrderEntities(Expression> expression, string sort, string order, BaseFilter filter, bool notraking = false, params string[] paths) where T : MesEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + Dictionary orders = new Dictionary(); + orders[sort] = order; + return commonService.GetOrderEntities(expression, filter, orders, null, notraking, paths); + } + /// + /// 排序获取数据 + /// + /// + /// + /// + /// + /// + /// + /// + public IEnumerable GetOrderEntities(Expression> expression, Dictionary orders, BaseFilter filter, bool notraking = false, params string[] paths) where T : MesEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + return commonService.GetOrderEntities(expression, filter, orders, null, notraking, paths); + } + + + /// + ///获取实体集合 + /// + /// + /// + /// + /// + /// + public async Task> GetPageEntitiesSync(Expression> expression, BasePageFilter filter, bool notraking = false, params string[] paths) where T : MesEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + filter.Sort = "ID"; + var page = await commonService.GetOrderPageEntitiesSync(expression, filter, 0, 0, notraking, paths); + return new PagedActionResult(page.Items, page.TotalCount); + } + + /// + ///获取排序的实体集合 + /// + /// + /// + /// + /// + /// + public async Task> ActionOrderPageEntitiesSync(Action> orderBy, Expression> expression, BasePageFilter filter, bool notraking = false, params string[] paths) where T : MesEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + var page = await commonService.GetOrderPageEntitiesSync(expression, filter, null, 0, 0, orderBy, notraking, paths); + return new PagedActionResult(page.Items, page.TotalCount); + } + + /// + ///获取排序的实体集合 + /// + /// + /// + /// + /// + /// + public async Task> GetOrderPageEntitiesSync(Expression> expression, BasePageFilter filter, bool notraking = false, params string[] paths) where T : MesEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + var page = await commonService.GetOrderPageEntitiesSync(expression, filter, null, 0, 0, null, notraking, paths); + return new PagedActionResult(page.Items, page.TotalCount); + } + + + #endregion + + /// + /// 获取条数 + /// + /// + /// + /// + /// + public int GetCount(Expression> expression, BaseFilter filter) where T : MesEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + return commonService.Count(expression, filter); + } + + public bool IsAny(Expression> expression, BaseFilter filter) where T : MesEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + return commonService.IsAny(expression, filter); + } + + /// + /// 添加实体 + /// + /// + /// + public bool AddEntity(T entity) where T : MesEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + return commonService.AddEntity(entity); + } + + /// + /// 添加实体 + /// + /// + /// + public T AddAndGetEntity(T entity) where T : MesEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + return commonService.AddAndGetEntity(entity); + } + + /// + /// 删除实体 + /// + /// + /// + public bool DeleteEntity(string id) where T : MesEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + return commonService.DeleteEntity(new Guid(id)); + + } + + + + /// + /// 删除实体 + /// + /// + /// + public bool DeleteEntity(Expression> expression) where T : MesEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + return commonService.DeleteEntity(expression); + } + /// + /// 删除实体 + /// + /// + /// + public bool DeleteEntity(IEnumerable entity) where T : MesEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + return commonService.DeleteEntity(entity); + } + /// + /// 删除实体 + /// + /// + /// + /// + public bool DeleteEntity(T entity) where T : MesEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + return commonService.DeleteEntity(entity); + } + + /// + /// 逻辑批量删除 + /// + /// + /// + /// + public bool BantchDeleteEntity(List ids) where T : MesEntityBase, new() + { + if (ids == null || !ids.Any()) return false; + var commonService = _serviceLocator.GetService(); + + return commonService.DeleteEntity(i => ids.Contains(i.ID)); + + } + + /// + /// 删除实体 + /// + /// + /// + public bool RealDeleteEntity(Expression> expression) where T : MesEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + return commonService.DeleteEntity(expression); + } + /// + /// 删除实体 + /// + /// + /// + public bool RealDeleteEntity(IEnumerable entity) where T : MesEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + return commonService.DeleteEntity(entity); + } + /// + /// 删除实体 + /// + /// + /// + /// + public bool RealDeleteEntity(T entity) where T : MesEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + return commonService.DeleteEntity(entity); + } + /// + /// 批量删除实体 + /// + /// id集合 + /// + public bool RealBantchDeleteEntity(List ids) where T : MesEntityBase, new() + { + if (ids == null || !ids.Any()) return false; + var commonService = _serviceLocator.GetService(); + + return commonService.DeleteEntity(i => ids.Contains(i.ID)); + + } + /// + /// 更新实体 + /// + /// + /// + public bool UpdateEntity(T entity) where T : MesEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + return commonService.UpdateEntity(entity); + } + + /// + /// 按字段更新实体 + /// + /// + /// + public bool UpdateEntity(T entity, params string[] updateField) where T : MesEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + return commonService.UpdateEntity(entity, updateField); + } + + /// + /// 批量添加实体 + /// + /// 实体集合 + /// + public bool BantchAddEntity(IEnumerable entities) where T : MesEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + return commonService.BantchAddEntity(entities); + } + + /// + /// 批量更新实体 + /// + /// 实体集 + /// + public bool BantchUpdateEntity(IEnumerable entities) where T : MesEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + return commonService.BantchUpdateEntity(entities); + } + + /// + /// 更具字段批量更新实体 + /// + /// 实体集 + /// + public bool BantchUpdateEntity(IEnumerable entities, params string[] updateField) where T : MesEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + return commonService.BantchUpdateEntity(entities, updateField); + } + /// + /// 批量保存实体 + /// + /// 批量保存 + /// + public bool BantchSaveEntity(IEnumerable entities) where T : MesEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + return commonService.BantchSaveEntity(entities); + } + + + #region nocommit + /// + /// 添加实体 + /// + /// + /// + public bool AddEntityNoCommit(T entity) where T : MesEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + return commonService.AddEntityNoCommit(entity); + } + /// + /// 删除实体 + /// + /// + /// + public bool DeleteEntityNoCommit(string id) where T : MesEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + return commonService.DeleteEntityNoCommit(new Guid(id)); + + } + + /// + /// 删除实体 + /// + /// + /// + public bool DeleteEntityNoCommit(Expression> expression) where T : MesEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + return commonService.DeleteEntityNoCommit(expression); + } + /// + /// 删除实体 + /// + /// + /// + public bool DeleteEntityNoCommit(IEnumerable entity) where T : MesEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + return commonService.DeleteEntityNoCommit(entity); + } + /// + /// 删除实体 + /// + /// + /// + /// + public bool DeleteEntityNoCommit(T entity) where T : MesEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + return commonService.DeleteEntityNoCommit(entity); + } + + /// + /// 逻辑批量删除 + /// + /// + /// + /// + public bool BantchDeleteEntityNoCommit(List ids) where T : MesEntityBase, new() + { + if (ids == null || !ids.Any()) return false; + var commonService = _serviceLocator.GetService(); + + return commonService.DeleteEntityNoCommit(i => ids.Contains(i.ID)); + + } + + /// + /// 更新实体 + /// + /// + /// + public bool UpdateEntityNoCommit(T entity) where T : MesEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + return commonService.UpdateEntityNoCommit(entity); + } + + /// + /// 批量添加实体 + /// + /// 实体集合 + /// + public bool BantchAddEntityNoCommit(IEnumerable entities) where T : MesEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + return commonService.BantchAddEntityNoCommit(entities); + } + + /// + /// 更新实体 + /// + /// + /// + public bool UpdateEntityNoCommit(T entity, params string[] updateField) where T : MesEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + return commonService.UpdateEntityNoCommit(entity, updateField); + } + + /// + /// 批量添加实体 + /// + /// 实体集合 + /// + public bool BantchUpdateEntityNoCommit(IEnumerable entities, params string[] updateField) where T : MesEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + return commonService.BantchUpdateEntityNoCommit(entities, updateField); + } + + /// + /// 批量更新实体 + /// + /// 实体集 + /// + public bool BantchUpdateEntityNoCommit(IEnumerable entities) where T : MesEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + return commonService.BantchUpdateEntityNoCommit(entities); + } + /// + /// 批量保存实体 + /// + /// 批量保存 + /// + public bool BantchSaveEntityNoCommit(IEnumerable entities) where T : MesEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + return commonService.BantchSaveEntityNoCommit(entities); + } + + #region 根据连接更新数据 + + + /// + /// 根据数据库连接新增数据 + /// + /// + /// 实体数据 + /// 加密连接 + public void AddEntityByConn(T entity, string conn) where T : MesEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + commonService.AddEntityByConn(entity, conn); + } + + /// + /// 根据数据库连接更新数据 + /// + /// + /// 实体数据集合 + /// 加密连接 + public void UpdateEntitiesByConn(IEnumerable entities, string conn) where T : MesEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + commonService.UpdateEntitiesByConn(entities, conn); + } + + /// + /// 根据数据库连接更新数据 + /// + /// + /// 实体数据 + /// 加密连接 + /// 更新字段 + public void UpdateEntityByConn(T entity, string conn, params string[] updateField) where T : MesEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + commonService.UpdateEntityByConn(entity, conn, updateField); + } + + /// + /// 根据数据库连接删除数据 + /// + /// + /// 表达式 + /// 加密连接 + public void DeleteEntityByConn(Expression> expression, string conn) where T : MesEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + commonService.DeleteEntityByConn(expression, conn); + } + /// + /// 根据数据库连接删除数据 + /// + /// + /// 数据实体 + /// 加密连接 + public void DeleteEntityByConn(T entity, string conn) where T : MesEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + commonService.DeleteEntityByConn(entity, conn); + } + + /// + /// 根据数据库连接删除数据 + /// + /// + /// 主键 + /// 加密连接 + public void DeleteEntityByConn(Guid id, string conn) where T : MesEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + commonService.DeleteEntityByConn(id, conn); + } + /// + /// 根据数据库连接删除数据 + /// + /// + /// 数据集合 + /// 加密连接 + public void DeleteEntitiesByConn(IEnumerable entities, string conn) where T : MesEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + commonService.DeleteEntitiesByConn(entities, conn); + } + /// + /// 根据数据库连接新增数据 + /// + /// + /// 数据集合 + /// 加密连接 + public void AddEntitiesByConn(IEnumerable entities, string conn) where T : MesEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + commonService.AddEntitiesByConn(entities, conn); + } + + /// + /// 根据数据库连接新增数据 + /// + /// + /// + /// + /// + public void UpdateEntitiesByConn(IEnumerable entities, string conn, params string[] updateField) where T : MesEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + commonService.UpdateEntitiesByConn(entities, conn, updateField); + } + + + #endregion + + #region 根据租户更新数据 + + + /// + /// 根据数据库租户新增数据 + /// + /// + /// 实体数据 + /// 加密租户 + public void AddEntityByTenant(T entity, string Tenant) where T : MesEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + commonService.AddEntityByTenant(entity, Tenant); + } + + /// + /// 根据数据库租户更新数据 + /// + /// + /// 实体数据集合 + /// 加密租户 + public void UpdateEntitiesByTenant(IEnumerable entities, string Tenant) where T : MesEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + commonService.UpdateEntitiesByTenant(entities, Tenant); + } + + /// + /// 根据数据库租户更新数据 + /// + /// + /// 实体数据 + /// 加密租户 + /// 更新字段 + public void UpdateEntityByTenant(T entity, string Tenant, params string[] updateField) where T : MesEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + commonService.UpdateEntityByTenant(entity, Tenant, updateField); + } + + /// + /// 根据数据库租户删除数据 + /// + /// + /// 表达式 + /// 加密租户 + public void DeleteEntityByTenant(Expression> expression, string Tenant) where T : MesEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + commonService.DeleteEntityByTenant(expression, Tenant); + } + /// + /// 根据数据库租户删除数据 + /// + /// + /// 数据实体 + /// 加密租户 + public void DeleteEntityByTenant(T entity, string Tenant) where T : MesEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + commonService.DeleteEntityByTenant(entity, Tenant); + } + + /// + /// 根据数据库租户删除数据 + /// + /// + /// 主键 + /// 加密租户 + public void DeleteEntityByTenant(Guid id, string Tenant) where T : MesEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + commonService.DeleteEntityByTenant(id, Tenant); + } + /// + /// 根据数据库租户删除数据 + /// + /// + /// 数据集合 + /// 加密租户 + public void DeleteEntitiesByTenant(IEnumerable entities, string Tenant) where T : MesEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + commonService.DeleteEntitiesByTenant(entities, Tenant); + } + /// + /// 根据数据库租户新增数据 + /// + /// + /// 数据集合 + /// 加密租户 + public void AddEntitiesByTenant(IEnumerable entities, string Tenant) where T : MesEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + commonService.AddEntitiesByTenant(entities, Tenant); + } + + /// + /// 根据数据库租户新增数据 + /// + /// + /// + /// + /// + public void UpdateEntitiesByTenant(IEnumerable entities, string Tenant, params string[] updateField) where T : MesEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + commonService.UpdateEntitiesByTenant(entities, Tenant, updateField); + } + + + #endregion + + #region 树实体 + /// + /// 添加实体 + /// + /// + /// + public bool TreeAddEntityNoCommit(T entity) where T : TreeEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + return commonService.TreeAddEntityNoCommit(entity); + } + /// + /// 添加实体 + /// + /// + /// + public T TreeAddAndGetEntityNoCommit(T entity) where T : TreeEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + return commonService.TreeAddAndGetEntityNoCommit(entity); + } + + /// + /// 删除实体 + /// + /// + /// + public bool TreeDeleteEntityNoCommit(string id) where T : TreeEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + return commonService.TreeDeleteEntityNoCommit(new Guid(id)); + + } + + /// + /// 删除实体 + /// + /// + /// + public bool TreeDeleteEntityNoCommit(Expression> expression) where T : TreeEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + return commonService.TreeDeleteEntityNoCommit(expression); + } + /// + /// 删除实体 + /// + /// + /// + public bool TreeDeleteEntityNoCommit(IEnumerable entity) where T : TreeEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + return commonService.TreeDeleteEntityNoCommit(entity); + } + /// + /// 删除实体 + /// + /// + /// + /// + public bool TreeDeleteEntityNoCommit(T entity) where T : TreeEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + return commonService.TreeDeleteEntityNoCommit(entity); + } + + /// + /// 逻辑批量删除 + /// + /// + /// + /// + public bool TreeBantchDeleteEntityNoCommit(List ids) where T : TreeEntityBase, new() + { + if (ids == null || !ids.Any()) return false; + var commonService = _serviceLocator.GetService(); + + return commonService.TreeDeleteEntityNoCommit(i => ids.Contains(i.ID)); + + } + /// + /// 删除实体 + /// + /// + /// + /// + public bool TreeRealDeleteEntityNoCommit(string id) where T : TreeEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + return commonService.TreeDeleteEntityNoCommit(new Guid(id)); + + } + /// + /// 删除实体 + /// + /// + /// + public bool TreeRealDeleteEntityNoCommit(Expression> expression) where T : TreeEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + return commonService.TreeDeleteEntityNoCommit(expression); + } + /// + /// 删除实体 + /// + /// + /// + public bool TreeRealDeleteEntityNoCommit(IEnumerable entity) where T : TreeEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + return commonService.TreeDeleteEntityNoCommit(entity); + } + /// + /// 删除实体 + /// + /// + /// + /// + public bool TreeRealDeleteEntityNoCommit(T entity) where T : TreeEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + return commonService.TreeDeleteEntityNoCommit(entity); + } + /// + /// 批量删除实体 + /// + /// id集合 + /// + public bool TreeRealBantchDeleteEntityNoCommit(List ids) where T : TreeEntityBase, new() + { + if (ids == null || !ids.Any()) return false; + var commonService = _serviceLocator.GetService(); + return commonService.TreeDeleteEntityNoCommit(i => ids.Contains(i.ID)); + } + /// + /// 更新实体 + /// + /// + /// + public bool TreeUpdateEntityNoCommit(T entity) where T : TreeEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + return commonService.TreeUpdateEntityNoCommit(entity); + + } + + /// + /// 批量添加实体 + /// + /// 实体集合 + /// + public bool TreeBantchAddEntityNoCommit(IEnumerable entities) where T : TreeEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + return commonService.TreeBantchAddEntityNoCommit(entities); + } + + /// + /// 批量更新实体 + /// + /// 实体集 + /// + public bool TreeBantchUpdateEntityNoCommit(IEnumerable entities) where T : TreeEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + return commonService.TreeBantchUpdateEntityNoCommit(entities); + } + /// + /// 批量保存实体 + /// + /// 批量保存 + /// + public bool TreeBantchSaveEntityNoCommit(IEnumerable entities) where T : TreeEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + return commonService.TreeBantchSaveEntityNoCommit(entities); + } + + + #endregion + #endregion + + + + #region 树实体 + /// + /// 添加实体 + /// + /// + /// + public bool TreeAddEntity(T entity) where T : TreeEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + return commonService.TreeAddEntity(entity); + } + /// + /// 添加实体 + /// + /// + /// + public T TreeAddAndGetEntity(T entity) where T : TreeEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + return commonService.TreeAddAndGetEntity(entity); + } + + /// + /// 删除实体 + /// + /// + /// + public bool TreeDeleteEntity(string id) where T : TreeEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + return commonService.TreeDeleteEntity(new Guid(id)); + + } + + /// + /// 删除实体 + /// + /// + /// + public bool TreeDeleteEntity(Expression> expression) where T : TreeEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + return commonService.TreeDeleteEntity(expression); + } + /// + /// 删除实体 + /// + /// + /// + public bool TreeDeleteEntity(IEnumerable entity) where T : TreeEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + return commonService.TreeDeleteEntity(entity); + } + /// + /// 删除实体 + /// + /// + /// + /// + public bool TreeDeleteEntity(T entity) where T : TreeEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + return commonService.TreeDeleteEntity(entity); + } + + /// + /// 逻辑批量删除 + /// + /// + /// + /// + public bool TreeBantchDeleteEntity(List ids) where T : TreeEntityBase, new() + { + if (ids == null || !ids.Any()) return false; + var commonService = _serviceLocator.GetService(); + + return commonService.TreeDeleteEntity(i => ids.Contains(i.ID)); + + } + /// + /// 删除实体 + /// + /// + /// + /// + public bool TreeRealDeleteEntity(string id) where T : TreeEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + return commonService.TreeDeleteEntity(new Guid(id)); + + } + /// + /// 删除实体 + /// + /// + /// + public bool TreeRealDeleteEntity(Expression> expression) where T : TreeEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + return commonService.TreeDeleteEntity(expression); + } + /// + /// 删除实体 + /// + /// + /// + public bool TreeRealDeleteEntity(IEnumerable entity) where T : TreeEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + return commonService.TreeDeleteEntity(entity); + } + /// + /// 删除实体 + /// + /// + /// + /// + public bool TreeRealDeleteEntity(T entity) where T : TreeEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + return commonService.TreeDeleteEntity(entity); + } + /// + /// 批量删除实体 + /// + /// id集合 + /// + public bool TreeRealBantchDeleteEntity(List ids) where T : TreeEntityBase, new() + { + if (ids == null || !ids.Any()) return false; + var commonService = _serviceLocator.GetService(); + return commonService.TreeDeleteEntity(i => ids.Contains(i.ID)); + } + /// + /// 更新实体 + /// + /// + /// + public bool TreeUpdateEntity(T entity) where T : TreeEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + return commonService.TreeUpdateEntity(entity); + + } + + /// + /// 批量添加实体 + /// + /// 实体集合 + /// + public bool TreeBantchAddEntity(IEnumerable entities) where T : TreeEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + return commonService.TreeBantchAddEntity(entities); + } + + /// + /// 批量更新实体 + /// + /// 实体集 + /// + public bool TreeBantchUpdateEntity(IEnumerable entities) where T : TreeEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + return commonService.TreeBantchUpdateEntity(entities); + } + /// + /// 批量保存实体 + /// + /// 批量保存 + /// + public bool TreeBantchSaveEntity(IEnumerable entities) where T : TreeEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + return commonService.TreeBantchSaveEntity(entities); + } + + /// + /// 删除实体 + /// + /// + /// + public IEnumerable> TreeOrderEntities(Expression> expression, BaseFilter filter, bool isTracking, + params string[] paths) where T : TreeEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + return commonService.GetTreeOrderEntities(expression, filter, isTracking, paths); + } + + public IEnumerable GetTree(string id, bool containCurrent = true, BaseFilter filter = null, + params string[] paths) where T : TreeEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + return commonService.GetTree(id, containCurrent, filter, paths); + } + #endregion + + + #region 执行SQL + + + /// + /// 对数据库执行给定的 DDL/DML 命令。 + /// + /// /// 用于创建服务的实例类型 + /// 命令字符串 + /// 参数 + /// 受影响的行数 + public int ExecuteSqlCommand(string sql, params object[] parameters) where T : MesEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + return commonService.ExecuteSqlCommand(sql, parameters); + } + /// + /// 对数据库执行给定的 DDL/DML 命令。 + /// + /// 用于创建服务的实例类型 + /// 事务行为 + /// 命令字符串 + /// 参数 + /// 受影响的行数 + public int ExecuteSqlCommand(TransactionalBehavior transactionalBehavior, string sql, params object[] parameters) where T : MesEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + return commonService.ExecuteSqlCommand(transactionalBehavior, sql, parameters); + } + + /// + /// 对数据库执行给定的 DDL/DML 命令返回reader。 + /// + /// 用于创建服务的实例类型 + /// 命令字符串 + /// reader委托 + public void ExecuteReader(string sql, ReaderColumn[] readerColumns, Action readerAction) where T : MesEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + commonService.ExecuteReader(sql, readerColumns, readerAction); + } + + /// + /// 对数据库执行给定的 DDL/DML 命令返回reader。 + /// + /// 用于创建服务的实例类型 + /// 命令字符串 + /// 参数 + /// reader委托 + public void ExecuteReader(string sql, ReaderColumn[] readerColumns, DbParameter[] parameters, Action readerAction) where T : MesEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + commonService.ExecuteReader(sql, readerColumns, parameters, readerAction); + } + + /// + /// 对数据库执行给定的 DDL/DML 命令返回reader。 + /// + /// 用于创建服务的实例类型 + /// 命令类型 + /// 命令字符串 + /// 参数 + /// reader委托 + public void ExecuteReader(CommandType commandType, string sql, ReaderColumn[] readerColumns, DbParameter[] parameters, Action readerAction) where T : MesEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + commonService.ExecuteReader(commandType, sql, readerColumns, parameters, readerAction); + } + + + + /// + /// 创建一个原始 SQL 查询,该查询将返回给定泛型类型的元素。 + /// + /// 查询所返回对象的类型 + /// 用于创建服务的实例类型 + /// SQL 查询字符串 + /// 要应用于 SQL 查询字符串的参数 + /// + //public IEnumerable SqlQuery(string sql, params object[] parameters) where T : MesEntityBase, new() + //{ + // _serviceLocator.RegisterType(typeof(CommonService), typeof(ICommonService)); + // var commonService = _serviceLocator.GetService>(); + // return commonService.SqlQuery(sql, parameters); + //} + + /// + /// 创建一个原始 SQL 查询,该查询将返回给定类型的元素。 + /// + /// 用于创建服务的实例类型 + /// 查询所返回对象的类型 + /// SQL 查询字符串 + /// 要应用于 SQL 查询字符串的参数 + /// + public IEnumerable SqlQuery(Type elementType, string sql, ReaderColumn[] readerColumns, params Object[] parameters) where T : MesEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + return commonService.SqlQuery(elementType, sql, readerColumns, parameters); + } + + + /// + /// 对数据库执行给定的 DDL/DML 命令。 + /// + /// 命令类型 + /// 命令字符串 + /// 参数 + /// + public int ExecuteNonQuery(CommandType commandType, string sql, ReaderColumn[] readerColumns, DbParameter[] parameters) where T : MesEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + return commonService.ExecuteNonQuery(commandType, sql, readerColumns, parameters); + } + + + /// + /// 根据数据库连接对数据库执行给定的 DDL/DML 命令。 + /// + /// 数据库类型 + /// 连接字符串 + /// sql 类型 + /// sql + /// 参数 + public void ExecuteNonQueryByConn(DataBaseType dataBaseType, string connString, CommandType commandType, string sql, DbParameter[] dbParameters) where T : MesEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + commonService.ExecuteNonQueryByConn(dataBaseType, connString, commandType, sql, dbParameters); + } + + + /// + /// 根据数据库连接对数据库执行给定的 DDL/DML 命令获取Reader。 + /// + /// 数据库类型 + /// 连接字符串 + /// sql 类型 + /// sql + /// 参数 + /// 执行委托 + public void ExecuteReaderByConn(DataBaseType dataBaseType, string connString, CommandType commandType, + string sql, DbParameter[] dbParameters, Action readerAction) where T : MesEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + commonService.ExecuteReaderByConn(dataBaseType, connString, commandType, sql, dbParameters, readerAction); + } + + + + /// + /// 根据数据库连接对数据库执行给定的 DDL/DML 命令获取Reader。 + /// + /// 数据库类型 + /// 连接字符串 + /// sql 类型 + /// sql + /// 参数 + /// 分页索引 从1开始 + /// 每页条数 必填 + /// 执行委托 + public void ExecuteReaderPageByConn(DataBaseType dataBaseType, string connString, CommandType commandType, + string sql, DbParameter[] dbParameters, int pageIndex, int pageLimit, Action readerAction) + where T : MesEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + commonService.ExecuteReaderPageByConn(dataBaseType, connString, commandType, sql, + dbParameters, pageIndex, pageLimit, readerAction); + } + + + /// + /// 根据数据库连接对数据库执行给定的 DDL/DML 命令获取数据总条数。 + /// + /// 数据库类型 + /// 连接字符串 + /// sql 类型 + /// sql + /// 参数 + /// 数据总条数 + public int GetSqlCountByConn(DataBaseType dataBaseType, string connString, CommandType commandType, + string sql, DbParameter[] dbParameters) + where T : MesEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + return commonService.GetSqlCountByConn(dataBaseType, connString, commandType, sql, dbParameters); + } + + + /// + /// 获取数据库连接对象 + /// + /// 数据库类型 + /// 连接字符串 + public DbConnection InitDbConnection(DataBaseType dataBaseType, string connString) + where T : MesEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + return commonService.InitDbConnection(dataBaseType, connString); + } + + /// + /// 获取数据库连接对象 + /// + /// 数据库类型 + /// 连接字符串 + public DbConnection InitDbConnection(DataBaseType dataBaseType, string connString) + { + var commonService = _serviceLocator.GetService(); + return commonService.InitDbConnection(dataBaseType, connString); + } + + + /// + /// 执行查询,并返回查询所返回的结果集中第一行的第一列。 所有其他的列和行将被忽略。 + /// + /// 数据库类型 + /// 连接字符串 + /// sql 类型 + /// sql + /// 参数 + public object ExecuteScalarByConn(DataBaseType dataBaseType, string connString, CommandType commandType, string sql, DbParameter[] dbParameters) + where T : MesEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + return commonService.ExecuteScalarByConn(dataBaseType, connString, commandType, sql, dbParameters); + + } + + /// + /// 执行查询,并返回查询所返回的结果集中第一行的第一列。 所有其他的列和行将被忽略。 + /// + /// 数据库类型 + /// 连接字符串 + /// sql 类型 + /// sql + /// 参数 + public object ExecuteScalarByConn(DataBaseType dataBaseType, string connString, CommandType commandType, string sql, DbParameter[] dbParameters) + { + var commonService = _serviceLocator.GetService(); + return commonService.ExecuteScalarByConn(dataBaseType, connString, commandType, sql, dbParameters); + + } + + /// + /// 执行查询,并返回查询所返回的结果集中第一行的第一列。 所有其他的列和行将被忽略。 + /// + /// 数据库类型 + /// 数据库连接对象 + /// sql 类型 + /// sql + /// 是否自动关闭连接 + /// 参数 + public object ExecuteScalarByConn(DataBaseType dataBaseType, DbConnection conn, CommandType commandType, + string sql, bool close = true, params DbParameter[] dbParameters) + { + var commonService = _serviceLocator.GetService(); + return commonService.ExecuteScalarByConn(dataBaseType, conn, commandType, sql, close, dbParameters); + + } + + /// + /// 执行查询,并返回查询所返回的结果集中第一行的第一列。 所有其他的列和行将被忽略。 + /// + /// 数据库类型 + /// 数据库连接对象 + /// sql 类型 + /// sql + /// 是否自动关闭连接 + /// 参数 + public object ExecuteScalarByConn(DataBaseType dataBaseType, DbConnection conn, CommandType commandType, + string sql, bool close = true, params DbParameter[] dbParameters) + where T : MesEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + return commonService.ExecuteScalarByConn(dataBaseType, conn, commandType, sql, close, dbParameters); + + } + + /// + /// 根据数据库连接对数据库执行给定的 DDL/DML 命令获取Reader。 + /// + /// 数据库类型 + /// 连接对象 + /// sql 类型 + /// sql + /// 参数 + /// 分页索引 从1开始 + /// 每页条数 必填 + /// 执行委托 + /// 是否自动关闭连接 + public void ExecuteReaderPageByConn(DataBaseType dataBaseType, DbConnection conn, CommandType commandType, + string sql, DbParameter[] dbParameters, int pageIndex, int pageLimit, Action readerAction, + bool close = true) + { + var commonService = _serviceLocator.GetService(); + commonService.ExecuteReaderPageByConn(dataBaseType, conn, commandType, sql, + dbParameters, pageIndex, pageLimit, readerAction, close); + } + + /// + /// 根据数据库连接对数据库执行给定的 DDL/DML 命令获取Reader。 + /// + /// 数据库类型 + /// 连接对象 + /// sql 类型 + /// sql + /// 参数 + /// 分页索引 从1开始 + /// 每页条数 必填 + /// 执行委托 + /// 是否自动关闭连接 + public void ExecuteReaderPageByConn(DataBaseType dataBaseType, DbConnection conn, CommandType commandType, + string sql, DbParameter[] dbParameters, int pageIndex, int pageLimit, Action readerAction, + bool close = true) + where T : MesEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + commonService.ExecuteReaderPageByConn(dataBaseType, conn, commandType, sql, + dbParameters, pageIndex, pageLimit, readerAction, close); + } + + /// + /// 根据数据库连接对数据库执行给定的 DDL/DML 命令获取Reader。 + /// + /// 数据库类型 + /// 连接对象 + /// 指令类型 + /// SQL语句 + /// 参数 + /// 委托 + /// 是否自动关闭连接 + public void ExecuteReaderByConn(DataBaseType dataBaseType, DbConnection conn, CommandType commandType, string sql, + DbParameter[] dbParameters, Action readerAction, bool close = true) where T : MesEntityBase, new() + { + var commonService = _serviceLocator.GetService(); + commonService.ExecuteReaderByConn(dataBaseType, conn, commandType, sql, + dbParameters, readerAction); + } + + /// + /// 根据数据库连接对数据库执行给定的 DDL/DML 命令获取Reader。 + /// + /// 数据库类型 + /// 连接对象 + /// 指令类型 + /// SQL语句 + /// 参数 + /// 委托 + /// 是否自动关闭连接 + public void ExecuteReaderByConn(DataBaseType dataBaseType, DbConnection conn, CommandType commandType, string sql, + DbParameter[] dbParameters, Action readerAction, bool close = true) + { + var commonService = _serviceLocator.GetService(); + commonService.ExecuteReaderByConn(dataBaseType, conn, commandType, sql, + dbParameters, readerAction); + } + + /// + /// 根据数据库连接对数据库执行给定的 DDL/DML 命令获取Reader。 + /// + /// 数据库类型 + /// 连接对象 + /// 指令类型 + /// SQL语句 + /// 参数 + /// 委托 + /// 是否自动关闭连接 + public void ExecuteNonQueryByConn(DataBaseType dataBaseType, DbConnection conn, CommandType commandType, string sql, DbParameter[] dbParameters, bool close = true) + { + var commonService = _serviceLocator.GetService(); + commonService.ExecuteNonQueryByConn(dataBaseType, conn, commandType, sql, + dbParameters, close); + } + + public T AddAndGetEntity_noneBase(T entity) where T : class + { + var commonService = _serviceLocator.GetService(); + return commonService.AddAndGetEntity_noneBase(entity); + } + + public void BantchAddEntity_noneBase(IEnumerable entities) where T : class + { + var commonService = _serviceLocator.GetService(); + commonService.AddEntities_noneBase(entities); + } + + public void BantchUpdateEntity_noneBase(IEnumerable entities) where T : class + { + var commonService = _serviceLocator.GetService(); + commonService.UpdateEntities_noneBase(entities); + } + + + + public T GetEntity_noneBase(Expression> expressions) where T : class + { + var commonService = _serviceLocator.GetService(); + return commonService.GetEntity_noneBase(expressions); + } + + public List GetEntities_noneBase(Expression> expressions) where T : class + { + var commonService = _serviceLocator.GetService(); + return commonService.GetEntities_noneBase(expressions); + } + + public bool DeleteEntity_noneBase(Expression> expression) where T : class + { + var commonService = _serviceLocator.GetService(); + return commonService.DeleteEntity_noneBase(expression); + } + + #endregion + } +} diff --git a/APT.Infrastructure.Api/DI/IDependency.cs b/APT.Infrastructure.Api/DI/IDependency.cs new file mode 100644 index 0000000..379be55 --- /dev/null +++ b/APT.Infrastructure.Api/DI/IDependency.cs @@ -0,0 +1,9 @@ +namespace APT.Infrastructure.Api +{ + /// + /// 依赖注入接口,只有实现该接口才可以被注册到IoC容器中 + /// + public interface IDependency + { + } +} diff --git a/APT.Infrastructure.Api/DI/ServiceLocator.cs b/APT.Infrastructure.Api/DI/ServiceLocator.cs new file mode 100644 index 0000000..6aa3411 --- /dev/null +++ b/APT.Infrastructure.Api/DI/ServiceLocator.cs @@ -0,0 +1,74 @@ +using Autofac; +using Autofac.Extensions.DependencyInjection; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using APT.Infrastructure.Core; +namespace APT.Infrastructure.Api +{ + /// + /// 服务对象定位器 + /// + public sealed class ServiceLocator + { + #region fields + #endregion + private IServiceProvider _autofacServiceProvider = null; + #region ctor. + + private ServiceLocator() + { + ContainerBuilder builder = new ContainerBuilder(); + builder.RegisterModule(); + var AutofacContainer = builder.Build(); + _autofacServiceProvider = new AutofacServiceProvider(AutofacContainer); + } + + #endregion + + #region properties + + #region Instance + private static readonly ServiceLocator s_Instance = new ServiceLocator(); + + /// + /// 服务对象定位器实例 + /// + public static ServiceLocator Instance + { + get { return s_Instance; } + } + #endregion + + + + #endregion + + #region methods + + + + /// + /// 获取泛型服务对象 + /// + /// 服务对象的类型 + /// + /// + public T GetService() + { + if (HttpContext.Current != null && HttpContext.Current.RequestServices != null) + return (T)HttpContext.Current.RequestServices.GetService(typeof(T)); + if (_autofacServiceProvider != null) + return (T)_autofacServiceProvider.GetService(typeof(T)); + return default(T); + } + + + #endregion + + + } + + +} diff --git a/APT.Infrastructure.Api/Extensions/ConfigurationSectionExtension.cs b/APT.Infrastructure.Api/Extensions/ConfigurationSectionExtension.cs new file mode 100644 index 0000000..526a04d --- /dev/null +++ b/APT.Infrastructure.Api/Extensions/ConfigurationSectionExtension.cs @@ -0,0 +1,73 @@ +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Primitives; +using System; +using System.Collections.Generic; + +namespace APT.Infrastructure.Api +{ + public class ConfigurationSectionExtension : IConfigurationSection, IConfiguration + { + private readonly string sectionKey; + + private IConfiguration configuration; + + public string Key + { + get; + } + + public string Path + { + get; + } + + public string Value + { + get; + set; + } + + public string this[string key] + { + get + { + string enviromentValue = GetEnviromentValue(key); + if (string.IsNullOrEmpty(enviromentValue)) + { + return configuration.GetSection(sectionKey)[key]; + } + return enviromentValue; + } + set + { + configuration.GetSection(sectionKey)[key] = value; + } + } + + public ConfigurationSectionExtension(string sectionKey, IConfiguration configuration) + { + this.sectionKey = sectionKey; + this.configuration = configuration; + } + + public IEnumerable GetChildren() + { + throw new NotImplementedException(); + } + + public IChangeToken GetReloadToken() + { + throw new NotImplementedException(); + } + + public IConfigurationSection GetSection(string key) + { + throw new NotImplementedException(); + } + + protected virtual string GetEnviromentValue(string key) + { + return System.Environment.GetEnvironmentVariable(key); + } + } +} diff --git a/APT.Infrastructure.Api/Extensions/HttpContextExtensions.cs b/APT.Infrastructure.Api/Extensions/HttpContextExtensions.cs new file mode 100644 index 0000000..a00ca15 --- /dev/null +++ b/APT.Infrastructure.Api/Extensions/HttpContextExtensions.cs @@ -0,0 +1,19 @@ +using Microsoft.AspNetCore.Http; +using System; +using System.Collections.Generic; +using System.Text; + +namespace APT.Infrastructure.Api +{ + public static class HttpContext + { + private static IHttpContextAccessor contextAccessor; + + public static Microsoft.AspNetCore.Http.HttpContext Current => contextAccessor?.HttpContext; + + public static void Register(IHttpContextAccessor httpContextAccessor) + { + contextAccessor = httpContextAccessor; + } + } +} diff --git a/APT.Infrastructure.Api/Extensions/RootOrgAttribute.cs b/APT.Infrastructure.Api/Extensions/RootOrgAttribute.cs new file mode 100644 index 0000000..cf2135c --- /dev/null +++ b/APT.Infrastructure.Api/Extensions/RootOrgAttribute.cs @@ -0,0 +1,43 @@ +using APT.Infrastructure.Core; +using log4net; +using Microsoft.AspNetCore.Mvc.Filters; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +namespace APT.Infrastructure.Api +{ + public class RootOrgAttribute : Attribute, IAsyncActionFilter + { + /// + /// 添加根节点过滤 + /// + /// + /// + /// + public async Task OnActionExecutionAsync(Microsoft.AspNetCore.Mvc.Filters.ActionExecutingContext context, ActionExecutionDelegate next) + { + + try + { + var s = context.HttpContext.Request.Headers["RootOrgId"].ToString(); + if (!string.IsNullOrEmpty(s)) + { + AppContext.CurrentSession.RootOrgId = new Guid(s); + } + } + catch (Exception ex) + { + LoggerManager.GetLogger().Error(Infrastructure.Core.LogHelper.GetCurSourceFileName() + " - " + LogHelper.GetLineNum() + ":" + ex.Message); + //throw; + } + finally + { + await next.Invoke(); + } + + } + + } +} diff --git a/APT.Infrastructure.Api/Helper/WebSocketServiceHelper.cs b/APT.Infrastructure.Api/Helper/WebSocketServiceHelper.cs new file mode 100644 index 0000000..468236d --- /dev/null +++ b/APT.Infrastructure.Api/Helper/WebSocketServiceHelper.cs @@ -0,0 +1,301 @@ +using APT.Infrastructure.Api.Redis; +using APT.Infrastructure.Core; +using Fleck; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace APT.Infrastructure.Api +{ + /// + /// webSocket 服务帮助类 + /// + public static class WebSocketServiceHelper + { + private static List _clientInfos; + + public static List ClintInfos + { + get + { + if (_clientInfos == null) + _clientInfos = new List(); + return _clientInfos; + } + } + + public static List UserIds + { + get + { + return ClintInfos.Where(t => t.UserId != null).Select(t => t.UserId.Value).ToList(); + } + } + + /// + /// 初始化WebSocket服务 + /// + /// + /// + /// + /// + public static void InitService(int port, + Func + onOpen, + Func + onMessage, + Action + onClose) + { + FleckLog.Level = LogLevel.Debug; + var server = new WebSocketServer("ws://0.0.0.0:" + (port == 0 ? 8181 : port)); + server.Start(socket => + { + socket.OnOpen = () => + { + WebSocketClientInfo webSocketClientInfo = new WebSocketClientInfo(); + webSocketClientInfo.WebSocketConnection = socket; + ClintInfos.Add(webSocketClientInfo); + if (onOpen != null) + { + var ret = onOpen(webSocketClientInfo); + if (ret != null) + socket.Send(JsonConvert.SerializeObject(ret)); + } + }; + socket.OnClose = () => + { + var info = ClintInfos.FirstOrDefault(t => t.WebSocketConnection == socket); + if (info != null) + ClintInfos.Remove(info); + if (onClose != null && info?.UserId != null) + onClose(info.UserId.Value, info); + }; + socket.OnMessage = message => + { + var info = ClintInfos.FirstOrDefault(t => t.WebSocketConnection == socket); + if (info != null) + { + try + { + var requestInfo = JsonConvert.DeserializeObject(message); + if (requestInfo != null) + { + + if (string.Compare(requestInfo.TypeCode, "P0001", true) == 0)//登入 + { + if (!string.IsNullOrEmpty(requestInfo.Data)) + { + var loginInfo = JsonConvert.DeserializeObject(requestInfo.Data); + if (loginInfo != null) + { + info.Tenant = loginInfo.Tenant; + info.UserId = loginInfo.UserId; + info.DbConn = GetDbConn(info.Tenant); + info.UserName = loginInfo.UserName; + info.ClientType = (WebSocketClientTypeEnum)loginInfo.ClientType; + } + } + } + if (onMessage != null) + { + var ret = onMessage(info, requestInfo); + if (ret != null) + socket.Send(JsonConvert.SerializeObject(ret)); + } + } + } + catch (Exception ex) + { + Console.WriteLine(ex.Message); + } + } + }; + }); + } + /// + /// 发生消息到所有用户 + /// + /// + public static void SendToAll(WebSocketResponseInfo responseInfo) + { + SendToAll(responseInfo, null); + } + + /// + /// 发生消息到所有用户 + /// + /// + /// 检查客户端有效性 + public static void SendToAll(WebSocketResponseInfo responseInfo, Func checkClientInfoFunc = null) + { + if (responseInfo == null) return; + List webSocketResponseInfos = new List(); + webSocketResponseInfos.Add(responseInfo); + SendToAll(webSocketResponseInfos, checkClientInfoFunc); + } + /// + /// 发送信息到所有用户 + /// + /// + public static void SendToAll(List responseInfos) + { + SendToAll(responseInfos, null); + } + /// + /// 发送信息到所有用户 + /// + /// + /// 检查客户端有效性 + public static void SendToAll(List responseInfos, Func checkClientInfoFunc = null) + { + if (responseInfos == null || !responseInfos.Any() || !ClintInfos.Any()) return; + ClintInfos.ForEach(t => + { + if (checkClientInfoFunc != null) + { + if (!checkClientInfoFunc(t)) + return; + } + if (t.WebSocketConnection != null) + { + responseInfos.ForEach(t1 => + { + t.WebSocketConnection.Send(JsonConvert.SerializeObject(t1)); + }); + } + }); + } + /// + /// 发送消息到指定用户 + /// + /// + /// + public static void SendToUser(Guid userId, WebSocketResponseInfo responseInfo) + { + if (responseInfo == null) return; + List responseUseInfos = new List(); + WebSocketResponseUserInfo info = new WebSocketResponseUserInfo(); + info.UserId = userId; + info.Data = responseInfo.Data; + info.TypeCode = responseInfo.TypeCode; + responseUseInfos.Add(info); + SendToUser(responseUseInfos); + } + /// + /// 发送消息到指定用户 + /// + /// + public static void SendToUser(List responseUseInfos) + { + if (responseUseInfos == null || !responseUseInfos.Any()) return; + responseUseInfos.ForEach(t => + { + if (t.UserId != null) + { + var userClientInfo = ClintInfos?.Where(t1 => t1.UserId == t.UserId && t1.WebSocketConnection != null).ToList(); + userClientInfo.ForEach(t1 => + { + t1.WebSocketConnection.Send(JsonConvert.SerializeObject(t)); + }); + } + }); + } + + public static string GetDbConn(string tenantName) + { + //redis取數據 + var deskey = ConfigurationManager.AppSettings["ConnDataKey"]; + if (string.IsNullOrEmpty(deskey)) + deskey = "optenergy2021001"; + var tenantKey = ConfigurationManager.AppSettings["TenantConnKey"] + tenantName; + if (CsRedisManager.KeyExists(tenantKey)) + { + var conns = CsRedisManager.StringGet(tenantKey); + var retConn = conns == "null" ? null : EncryptHelper.AesDecrypt(conns, deskey); ; + return retConn; + } + else + { + var url = ConfigurationManager.AppSettings["ConnApiUrl"]; + if (!string.IsNullOrEmpty(url)) + { + var deData = WebUtils.Get(url, "code", tenantName, ""); + //LoggerManager.GetLogger().Info($"TenantData:{deData}"); + return EncryptHelper.AesDecrypt(deData, deskey); + } + } + return ConfigurationManager.ConnectionStrings["default"]; + } + + + } + + public enum WebSocketClientTypeEnum + { + WEB后台 = 0, + 客户端 = 1, + APP = 2, + 默认 = 99, + } + + public class WebSocketClientInfo + { + public IWebSocketConnection WebSocketConnection { get; set; } + + public Guid? UserId { get; set; } + + public string UserName { get; set; } + + public string Tenant { get; set; } + + public string DbConn { get; set; } + public Guid? OrgId { get; set; } + + public WebSocketClientTypeEnum ClientType { get; set; } + } + + public class WebSocketRequestInfo + { + public WebSocketRequestInfo() + { + this.TypeCode = "U0000"; + } + + public string TypeCode { get; set; } + + public string Tenant { get; set; } + + public string Data { get; set; } + } + + public class WebSocketResponseInfo + { + public WebSocketResponseInfo() + { + this.TypeCode = "U0000"; + } + public string TypeCode { get; set; } + + public object Data { get; set; } + } + + public class WebSocketResponseUserInfo : WebSocketResponseInfo + { + public Guid? UserId { get; set; } + } + + + public class WebSocketRequestLoginInfo + { + public Guid? UserId { get; set; } + + public string UserName { get; set; } + public string Tenant { get; set; } + public string DbConn { get; set; } + public Guid? OrgId { get; set; } + + public int ClientType { get; set; } + } +} diff --git a/APT.Infrastructure.Api/LDX.Infrastructure.Api.xml b/APT.Infrastructure.Api/LDX.Infrastructure.Api.xml new file mode 100644 index 0000000..1de0324 --- /dev/null +++ b/APT.Infrastructure.Api/LDX.Infrastructure.Api.xml @@ -0,0 +1,1951 @@ + + + + APT.Infrastructure.Api + + + + + 抛出错误 + + + + + + 为 基础操作 提供统一的返回格式,包含try / catch操作。 + + 返回值类型 + + + + + + 为 基础操作 提供统一的返回格式,包含try / catch操作。 + + 返回值类型 + + + + + + 为取 分页数据 提供统一的返回格式,包含try / catch操作。 + + 返回值类型 + + + + + + 根据Request中的QueryString获得Linq表达式 + + 实体对象 + + + + + 获取操作单元 + + + + + + + 查询实体 + + + + + + + + + 查询实体 + + + + + + + + + 查询实体 + + + + + + + + + 获取所有数据 + + + + + + + + + + 获取所有数据 + + 类型 + 排序 + lambd表达式 + 过滤器 + 需要关联查询的数据 + + + + + 获取所有数据 + + 类型 + lambd表达式 + 过滤器 + 需要关联查询的数据 + + + + + 排序获取数据 + + + + + + + + + + + + 排序获取数据 + + + + + + + + + + + + 获取实体集合 + + + + + + + + + + 获取排序的实体集合 + + + + + + + + + + 获取排序的实体集合 + + + + + + + + + + 查询实体 + + + + + + + + + 查询实体 + + + + + + + + + 查询实体 + + + + + + + + + 获取所有数据 + + + + + + + + + + 获取所有数据 + + 类型 + 排序 + lambd表达式 + 过滤器 + 需要关联查询的数据 + + + + + 获取所有数据 + + 类型 + 排序 + lambd表达式 + 过滤器 + 需要关联查询的数据 + + + + + 排序获取数据 + + + + + + + + + + + + 排序获取数据 + + + + + + + + + + + + 获取实体集合 + + + + + + + + + + 获取排序的实体集合 + + + + + + + + + + 获取排序的实体集合 + + + + + + + + + + 获取条数 + + + + + + + + + 添加实体 + + + + + + + 添加实体 + + + + + + + 删除实体 + + + + + + + 删除实体 + + + + + + + 删除实体 + + + + + + + 删除实体 + + + + + + + + 逻辑批量删除 + + + + + + + + 删除实体 + + + + + + + 删除实体 + + + + + + + 删除实体 + + + + + + + + 批量删除实体 + + id集合 + + + + + 更新实体 + + + + + + + 批量添加实体 + + 实体集合 + + + + + 批量更新实体 + + 实体集 + + + + + 批量保存实体 + + 批量保存 + + + + + 添加实体 + + + + + + + 添加实体 + + + + + + + 删除实体 + + + + + + + 删除实体 + + + + + + + 删除实体 + + + + + + + 删除实体 + + + + + + + + 逻辑批量删除 + + + + + + + + 删除实体 + + + + + + + + 删除实体 + + + + + + + 删除实体 + + + + + + + 删除实体 + + + + + + + + 批量删除实体 + + id集合 + + + + + 更新实体 + + + + + + + 批量添加实体 + + 实体集合 + + + + + 批量更新实体 + + 实体集 + + + + + 批量保存实体 + + 批量保存 + + + + + 对数据库执行给定的 DDL/DML 命令。 + + /// 用于创建服务的实例类型 + 命令字符串 + 参数 + 受影响的行数 + + + + 对数据库执行给定的 DDL/DML 命令。 + + 用于创建服务的实例类型 + 事务行为 + 命令字符串 + 参数 + 受影响的行数 + + + + 对数据库执行给定的 DDL/DML 命令返回reader。 + + 用于创建服务的实例类型 + 命令字符串 + reader委托 + + + + 对数据库执行给定的 DDL/DML 命令返回reader。 + + 用于创建服务的实例类型 + 命令字符串 + 参数 + reader委托 + + + + 对数据库执行给定的 DDL/DML 命令返回reader。 + + 用于创建服务的实例类型 + 命令类型 + 命令字符串 + 参数 + reader委托 + + + + 创建一个原始 SQL 查询,该查询将返回给定类型的元素。 + + 用于创建服务的实例类型 + 查询所返回对象的类型 + SQL 查询字符串 + 要应用于 SQL 查询字符串的参数 + + + + + 对数据库执行给定的 DDL/DML 命令。 + + 命令类型 + 命令字符串 + 参数 + + + + + 根据数据库连接对数据库执行给定的 DDL/DML 命令。 + + 数据库类型 + 连接字符串 + sql 类型 + sql + 参数 + + + + 根据数据库连接对数据库执行给定的 DDL/DML 命令获取Reader。 + + 数据库类型 + 连接字符串 + sql 类型 + sql + 参数 + 执行委托 + + + + 根据数据库连接对数据库执行给定的 DDL/DML 命令获取Reader。 + + 数据库类型 + 连接字符串 + sql 类型 + sql + 参数 + 分页索引 从1开始 + 每页条数 必填 + 执行委托 + + + + 根据数据库连接对数据库执行给定的 DDL/DML 命令获取数据总条数。 + + 数据库类型 + 连接字符串 + sql 类型 + sql + 参数 + 数据总条数 + + + + 获取数据库连接对象 + + 数据库类型 + 连接字符串 + + + + 执行查询,并返回查询所返回的结果集中第一行的第一列。 所有其他的列和行将被忽略。 + + 数据库类型 + 连接字符串 + sql 类型 + sql + 参数 + + + + 执行查询,并返回查询所返回的结果集中第一行的第一列。 所有其他的列和行将被忽略。 + + 数据库类型 + 数据库连接对象 + sql 类型 + sql + 是否自动关闭连接 + 参数 + + + + 根据数据库连接对数据库执行给定的 DDL/DML 命令获取Reader。 + + 数据库类型 + 连接对象 + sql 类型 + sql + 参数 + 分页索引 从1开始 + 每页条数 必填 + 执行委托 + 是否自动关闭连接 + + + + 根据数据库连接对数据库执行给定的 DDL/DML 命令获取Reader。 + + 数据库类型 + 连接对象 + 指令类型 + SQL语句 + 参数 + 委托 + 是否自动关闭连接 + + + + 基类接口 + + + + + + 单元操作 + + + + + 通过获取一条记录 + + ID + + + + + 通过获取一条记录 + + ID + + + + + 通过获取一条记录 + + ID + + + + + 排序后的所有记录 + + 排序方式 + 条件 + 分页参数 + 导航属性 + + + + + 获取所有记录 + + + + + + + + + 分页查询 + + 过滤条件 + 过滤实体fiter + 导航属性 + + + + + 排序后分页查询 + + 排序条件 + 过滤条件 + 过滤实体fiter + 导航属性 + + + + + 排序后分页查询 + + 排序条件 + 过滤条件 + 过滤实体fiter + 导航属性 + + + + + 提交事务 + + 返回结果 + 数据处理 + 数据提交 + + + + + 提交事务 + + 执行方法 + 提交方法 + + + + 提交事务 + + 提交方法 + + + + + + 返回类型 + 执行 + 返回 + + + + + 基类接口 + + 数据库类型 + + + + 添加一条记录 + + + + + + + 更新一条记录 + + + + + + + 根据条件删除 + + 条件 + + + + + 删除实体 + + 实体集合 + + + + + 删除实体 + + + + + + + 根据条件删除 + + 条件 + + + + + 删除实体 + + 实体集合 + + + + + 删除实体 + + + + + + + 批量新增数据 + + + + + + + 批量更新数据(效率快) + + + + + + + 获取条数 + + + + + + + + 通过ID删除 + + + + + + + 通过ID删除 + + + + + + + 通过ID字符串删除 + + + + + + + 通过ID数组删除 + + + + + + + 通过ID字符串删除 + + + + + + + 通过ID数组删除 + + + + + + + 树基类接口 + + + + + + 添加一条记录 + + + + + + + 更新一条记录 + + + + + + + 根据条件删除 + + 条件 + + + + + 删除实体 + + 实体集合 + + + + + 删除实体 + + + + + + + 根据条件删除 + + 条件 + + + + + 删除实体 + + 实体集合 + + + + + 删除实体 + + + + + + + 批量新增数据 + + + + + + + 批量更新数据(效率快) + + + + + + + 获取条数 + + + + + + + + 通过ID删除 + + + + + + + 通过ID删除 + + + + + + + 通过ID字符串删除 + + + + + + + 通过ID数组删除 + + + + + + + 通过ID字符串删除 + + + + + + + 通过ID数组删除 + + + + + + + 依赖注入接口,只有实现该接口才可以被注册到IoC容器中 + + + + + 服务对象定位器 + + + + + 服务对象定位器实例 + + + + + 获取泛型服务对象 + + 服务对象的类型 + + + + + + webSocket 服务帮助类 + + + + + 初始化WebSocket服务 + + + + + + + + + 发生消息到所有用户 + + + + + + 发生消息到所有用户 + + + 检查客户端有效性 + + + + 发送信息到所有用户 + + + + + + 发送信息到所有用户 + + + 检查客户端有效性 + + + + 发送消息到指定用户 + + + + + + + 发送消息到指定用户 + + + + + + 逻辑删除 + + + + + + + 逻辑删除 + + + + + + + 逻辑删除 + + + + + + + 逻辑批量删除 + + + + + + + + 逻辑删除 + + + + + + + 更新 + + 实体 + 是否成功 + + + + 批量更新 + + 实体集合 + 是否成功 + + + + 批量更新(新增和保存一起)速度慢 + + 实体集合 + 是否成功 + + + + 添加实体 + + + + + + + 删除实体 + + + + + + + 删除实体 + + + + + + + 删除实体 + + + + + + + 删除实体 + + + + + + + + 逻辑批量删除 + + + + + + + + 更新实体 + + + + + + + 批量添加实体 + + 实体集合 + + + + + 批量更新实体 + + 实体集 + + + + + 批量保存实体 + + 批量保存 + + + + + 查询实体 + + + + + + + + + 查询实体 + + + + + + + + + 查询实体 + + + + + + + + + 获取所有数据 + + + + + + + + + + 获取所有数据 + + 类型 + 排序 + lambd表达式 + 过滤器 + 需要关联查询的数据 + + + + + 获取所有数据 + + 类型 + lambd表达式 + 过滤器 + 需要关联查询的数据 + + + + + 排序获取数据 + + + + + + + + + + + + 排序获取数据 + + + + + + + + + + + + 提交事务 + + 提交方法 + + + + 领域服务基类 + + 领域实体仓储对象 + 领域实体 + 领域实体主键类型 + + + + 对数据库执行给定的 DDL/DML 命令。 + + 命令字符串 + 参数 + 受影响的行数 + + + + 对数据库执行给定的 DDL/DML 命令。 + + 事务行为 + 命令字符串 + 参数 + 受影响的行数 + + + + 对数据库执行给定的 DDL/DML 命令返回reader。 + + 命令字符串 + reader委托 + + + + 对数据库执行给定的 DDL/DML 命令返回reader。 + + 命令字符串 + 参数 + reader委托 + + + + 对数据库执行给定的 DDL/DML 命令返回reader。 + + 命令类型 + 命令字符串 + 参数 + reader委托 + + + + 创建一个原始 SQL 查询,该查询将返回给定类型的元素。 + + 查询所返回对象的类型 + SQL 查询字符串 + 要应用于 SQL 查询字符串的参数 + + + + + 获取数据库连接对象 + + 数据库类型 + 连接字符串 + + + + 对数据库执行给定的 DDL/DML 命令。 + + 命令类型 + 命令字符串 + 参数 + + + + + 根据数据库连接对数据库执行给定的 DDL/DML 命令。 + + 数据库类型 + 连接字符串 + sql 类型 + sql + 参数 + + + + 根据数据库连接对数据库执行给定的 DDL/DML 命令获取Reader。 + + 数据库类型 + 连接字符串 + sql 类型 + sql + 参数 + 执行委托 + + + + 执行查询,并返回查询所返回的结果集中第一行的第一列。 所有其他的列和行将被忽略。 + + 数据库类型 + 连接字符串 + sql 类型 + sql + 参数 + + + + 执行查询,并返回查询所返回的结果集中第一行的第一列。 所有其他的列和行将被忽略。 + + 数据库类型 + 数据库连接对象 + sql 类型 + sql + 是否自动关闭连接 + 参数 + + + + 根据数据库连接对数据库执行给定的 DDL/DML 命令获取Reader。 + + 数据库类型 + 连接对象 + 指令类型 + SQL语句 + 参数 + 委托 + 是否自动关闭连接 + + + + 根据数据库连接对数据库执行给定的 DDL/DML 命令获取Reader。 + + 数据库类型 + 连接字符串 + sql 类型 + sql + 参数 + 分页索引 从1开始 + 每页条数 必填 + 执行委托 + + + + 根据数据库连接对数据库执行给定的 DDL/DML 命令获取Reader。 + + 数据库类型 + 连接对象 + sql 类型 + sql + 参数 + 分页索引 从1开始 + 每页条数 必填 + 执行委托 + 是否自动关闭连接 + + + + 根据数据库连接对数据库执行给定的 DDL/DML 命令获取数据总条数。 + + 数据库类型 + 连接字符串 + sql 类型 + sql + 参数 + 数据总条数 + + + + 通用接口,可以调用基类方法 + + + + + + 查询实体 + + + + + + + + + 查询实体 + + + + + + + + + 查询实体 + + + + + + + + + 查询实体 + + + + + + + + + 获取所有数据 + + + + + + + + + + 获取所有数据 + + 类型 + 排序 + lambd表达式 + 过滤器 + 需要关联查询的数据 + + + 获取所有数据 + + 类型 + 排序 + lambd表达式 + 过滤器 + 需要关联查询的数据 + + + + + 获取所有数据 + + 类型 + lambd表达式 + 过滤器 + 需要关联查询的数据 + + + + + 排序获取数据 + + + + + + + + + + + + 排序获取数据 + + + + + + + + + + + + 添加实体 + + + + + + + 删除实体 + + + + + + + 删除实体 + + + + + + + 删除实体 + + + + + + + 删除实体 + + + + + + + + 逻辑批量删除 + + + + + + + + + 批量添加实体 + + 实体集合 + + + + + 批量更新实体 + + 实体集 + + + + + 批量保存实体 + + 批量保存 + + + + + 添加实体 + + + + + + + 删除实体 + + + + + + + 删除实体 + + + + + + + 删除实体 + + + + + + + 删除实体 + + + + + + + + 逻辑批量删除 + + + + + + + + 更新实体 + + + + + + + 批量添加实体 + + 实体集合 + + + + + 批量更新实体 + + 实体集 + + + + + 批量保存实体 + + 批量保存 + + + + + 领域服务接口 + + + + + + + + 对数据库执行给定的 DDL/DML 命令。 + + 命令字符串 + 参数 + 受影响的行数 + + + + 对数据库执行给定的 DDL/DML 命令。 + + 事务行为 + 命令字符串 + 参数 + 受影响的行数 + + + + 对数据库执行给定的 DDL/DML 命令返回reader。 + + 命令字符串 + reader委托 + + + + 对数据库执行给定的 DDL/DML 命令返回reader。 + + 命令字符串 + 参数 + reader委托 + + + + 对数据库执行给定的 DDL/DML 命令返回reader。 + + 命令类型 + 命令字符串 + 参数 + reader委托 + + + + 创建一个原始 SQL 查询,该查询将返回给定类型的元素。 + + 查询所返回对象的类型 + SQL 查询字符串 + 要应用于 SQL 查询字符串的参数 + + + + + 对数据库执行给定的 DDL/DML 命令。 + + 命令类型 + 命令字符串 + 参数 + + + + + 获取数据库连接对象 + + 数据库类型 + 连接字符串 + + + + 执行查询,并返回查询所返回的结果集中第一行的第一列。 所有其他的列和行将被忽略。 + + 数据库类型 + 连接字符串 + sql 类型 + sql + 参数 + + + + 执行查询,并返回查询所返回的结果集中第一行的第一列。 所有其他的列和行将被忽略。 + + 数据库类型 + 数据库连接对象 + sql 类型 + sql + 参数 + 是否关闭连接 + + + + 根据数据库连接对数据库执行给定的 DDL/DML 命令获取Reader。 + + 数据库类型 + 连接对象 + sql 类型 + sql + 参数 + 分页索引 从1开始 + 每页条数 必填 + 执行委托 + 是否关闭连接 + + + + 根据数据库连接对数据库执行给定的 DDL/DML 命令获取Reader。 + + 数据库类型 + 连接对象 + 指令类型 + SQL语句 + 参数 + 是否关闭连接 + 委托 + + + + 根据数据库连接对数据库执行给定的 DDL/DML 命令。 + + 数据库类型 + 连接字符串 + sql 类型 + sql + 参数 + + + + 根据数据库连接对数据库执行给定的 DDL/DML 命令获取Reader。 + + 数据库类型 + 连接字符串 + sql 类型 + sql + 参数 + 执行委托 + + + + 根据数据库连接对数据库执行给定的 DDL/DML 命令获取Reader。 + + 数据库类型 + 连接字符串 + sql 类型 + sql + 参数 + 分页索引 从1开始 + 每页条数 必填 + 执行委托 + + + + 根据数据库连接对数据库执行给定的 DDL/DML 命令获取数据总条数。 + + 数据库类型 + 连接字符串 + sql 类型 + sql + 参数 + 数据总条数 + + + + 当前会话 + + + + + 日志记录器 + + + + + 部门ID + + + + + 自定义变量1 + + + + + 自定义变量2 + + + + + 自定义变量3 + + + + + 自定义变量4 + + + + + 自定义变量5 + + + + + 权限缓存 + + + + diff --git a/APT.Infrastructure.Api/Model/NeedRetryExceptions.cs b/APT.Infrastructure.Api/Model/NeedRetryExceptions.cs new file mode 100644 index 0000000..c66e421 --- /dev/null +++ b/APT.Infrastructure.Api/Model/NeedRetryExceptions.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace APT.Infrastructure.Api.Model +{ + public static class NeedRetryExceptions + { + public static List RetryExceptions() + { + return new List() + { + "transient failure", + "EntityFrameworkCore" + }; + } + } +} diff --git a/APT.Infrastructure.Api/Model/TenantInfo.cs b/APT.Infrastructure.Api/Model/TenantInfo.cs new file mode 100644 index 0000000..cdb9ce0 --- /dev/null +++ b/APT.Infrastructure.Api/Model/TenantInfo.cs @@ -0,0 +1,50 @@ +using System; +using System.Collections.Generic; +using System.Dynamic; + +namespace APT.Infrastructure.Api +{ + public class TenantInfo: DynamicObject + { + public string Name { get; set; } + + public string Conn { get; set; } + + public bool IsPresent { get; set; } + + public bool IsWrite { get; set; } + public object Generator { get; set; } + + public dynamic Container { get; set; } = new ExpandoObject(); + + Dictionary dictionary = new Dictionary(); + + public override bool TryGetMember(GetMemberBinder binder, out object result) + { + return dictionary.TryGetValue(binder.Name, out result); + } + + public override bool TrySetMember(SetMemberBinder binder, object value) + { + dictionary[binder.Name] = value; + return true; + } + + public override bool TrySetIndex(SetIndexBinder binder, object[] indexes, object value) + { + if (!(indexes?.Length > 0)) + return false; + dictionary[indexes[0].ToString()] = value; + return true; + } + + public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result) + { + result = null; + if (!(indexes?.Length > 0)) + return false; + result = dictionary[indexes[0].ToString()]; + return true; + } + } +} diff --git a/APT.Infrastructure.Api/Redis/CsRedisManager.cs b/APT.Infrastructure.Api/Redis/CsRedisManager.cs new file mode 100644 index 0000000..45d5db0 --- /dev/null +++ b/APT.Infrastructure.Api/Redis/CsRedisManager.cs @@ -0,0 +1,509 @@ +using APT.Infrastructure.Core; +using CSRedis; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading.Tasks; + +namespace APT.Infrastructure.Api.Redis +{ + public class CsRedisManager + { + static CSRedisClient redisManger = null; + public static CSRedisClient GetClient() + { + return redisManger; + } + static JsonSerializerSettings _jsonSetting; + public static string ConvertJson(T value) + { + string result = value is string ? value.ToString() : JsonConvert.SerializeObject(value, _jsonSetting); + return result; + } + static CsRedisManager() + { + _jsonSetting = new JsonSerializerSettings(); + _jsonSetting.ReferenceLoopHandling = ReferenceLoopHandling.Ignore; + RedisOption option = ConfigurationManager.RedisOption; + if (option != null) + { + //SysCustomKey = option.RedisPrefixKey; + //RedisConnectionString = option.RedisConnectionString; + //RedisPwd = option.RedisConnectionPwd; + } + else + { + throw new Exception($"未加载redis.json文件"); + } + redisManger = new CSRedisClient(option.RedisConnectionString); //Redis的连接字符串 + } + + /// + /// TradeManageMessage 和 TradeManageMessage:MQ队列 + /// + /// + public static bool EnQeenTradeManageMessage(string value) + { + try + { + LoggerManager.GetLogger("redis").Info("yinzhou--EnQeenTradeManageMessage:" + value); + //从头部插入 + GetClient().LPush("TradeManageMessage", value); + GetClient().LPush("TradeManageMessage:MQ", value); + return true; + } + catch (Exception e) + { + LoggerManager.GetLogger("redis").Error($"EnQeenTradeManageMessage:key=TradeManageMessage:MQ,value={value},错误信息:{e}"); + return false; + } + } + /// + /// TradeManageMessage 和 TradeManageMessage:MQ队列 + /// + /// + public static bool EnQeenTradeManageMessage(T value) + { + try + { + //从头部插入 + GetClient().LPush("TradeManageMessage", value); + GetClient().LPush("TradeManageMessage:MQ", value); + return true; + } + catch (Exception e) + { + LoggerManager.GetLogger("redis").Error($"EnQeenTradeManageMessage:key=TradeManageMessage:MQ,value={value},错误信息:{e}"); + return false; + } + } + + public static bool EnQueen(string key, string value) + { + try + { + //从头部插入 + GetClient().LPush(key, value); + return true; + } + catch (Exception e) + { + LoggerManager.GetLogger("redis").Error($"EnQueen:key={key},value={value},错误信息:{e}"); + return false; + } + } + + public static string DeQueen(string key) + { + string result = ""; + try + { + //从尾部取值 + result = GetClient().RPop(key); + return result; + } + catch (Exception e) + { + LoggerManager.GetLogger("redis").Error($"DeQueen:key={key},错误信息:{e}"); + return result; + } + } + //redis订阅模式 + public static void Sub(string key, Action action) + { + GetClient().Subscribe((key, msg => action(msg.Body))); + } + + public static string[] DeQueenAll(string key) + { + string[] result = { }; + try + { + long len = GetClient().LLen(key); + + //取出指定数量数据 + result = GetClient().LRange(key, 0, len - 1); + //删除指定数据 + bool res = GetClient().LTrim(key, len, -1); + + return result; + } + catch (Exception e) + { + LoggerManager.GetLogger("redis").Error($"DeQueen:key={key},错误信息:{e}"); + return result; + } + } + + public static bool EnQueen(string key, T value) + { + try + { + //从头部插入 + long len = GetClient().LPush(key, value); + if (len > 0) + return true; + else + return false; + } + catch (Exception e) + { + LoggerManager.GetLogger("redis").Error($"EnQueenObj:key={key},value={value},错误信息:{e}"); + return false; + } + } + + public static T DeQueen(string key) + { + T result = default(T); + try + { + //从尾部取值 + result = GetClient().RPop(key); + return result; + } + catch (Exception e) + { + LoggerManager.GetLogger("redis").Error($"DeQueen:key={key},错误信息:{e}"); + return result; + } + } + + /// + /// 设置hash值 + /// + /// + /// + /// + /// + public static bool SetHash(string key, string field, string value) + { + try + { + GetClient().HSet(key, field, value); + return true; + } + catch (Exception e) + { + LoggerManager.GetLogger("redis").Error($"SetHash:key={key},value={value},错误信息:{e}"); + return false; + } + } + + /// + /// 根据表名,键名,获取hash值 + /// + /// 表名 + /// 键名 + /// + public static string GetHash(string key, string field) + { + string result = ""; + try + { + + result = GetClient().HGet(key, field); + return result; + } + catch (Exception e) + { + LoggerManager.GetLogger("redis").Error($"GetHash:key={key},错误信息:{e}"); + return result; + } + } + + /// + /// 获取指定key中所有字段 + /// + /// + /// + public static Dictionary GetHashAll(string key) + { + try + { + + var result = GetClient().HGetAll(key); + return result; + } + catch (Exception e) + { + LoggerManager.GetLogger("redis").Error($"GetHash:key={key},错误信息:{e}"); + return new Dictionary(); + } + } + + /// + /// 根据表名,键名,删除hash值 + /// + /// 表名 + /// 键名 + /// + public static long DeleteHash(string key, string field) + { + long result = 0; + try + { + result = GetClient().HDel(key, field); + return result; + } + catch (Exception e) + { + LoggerManager.GetLogger("redis").Error($"GetHash:key={key}", e); + throw new Exception($"redis error:DeleteHash: key ={ key },错误信息:{e}"); + } + } + // + /// 保存单个key value + /// + /// Redis Key + /// 保存的值 + /// 过期时间 + /// + public static async Task StringSetAsync(string key, T value, int expiry = -1) + { + try + { + string json = ConvertJson(value); + var result = await GetClient().SetAsync(key, json, expiry); + return result; + } + catch (Exception e) + { + LoggerManager.GetLogger("redis").Error($"StringSetAsync:key={key}", e); + throw new Exception($"redis error:StringSetAsync: key ={ key },错误信息:{e}"); + } + } + + + + /// + /// 保存一个对象 + /// + /// + /// + /// + /// + /// + public static bool StringSet(string key, T obj, int expiry = -1) + { + try + { + string json = ConvertJson(obj); + var result = GetClient().Set(key, json, expiry); + return result; + } + catch (Exception e) + { + LoggerManager.GetLogger("redis").Error($"StringSet:key={key},错误信息:{e}"); + throw new Exception($"redis error:StringSet: key ={ key },错误信息:{e}"); + } + } + + /// + /// 获取单个key的值 + /// + /// Redis Key + /// + public static async Task StringGetAsync(string key) + { + try + { + var result = await GetClient().GetAsync(key); + return result; + } + catch (Exception e) + { + LoggerManager.GetLogger("redis").Error($"StringGetAsync:key={key},错误信息:{e}"); + throw new Exception($"redis error:StringGetAsync: key ={ key },错误信息:{e}"); + } + } + + public static string StringGet(string key) + { + try + { + var result = GetClient().Get(key); + return result; + } + catch (Exception e) + { + LoggerManager.GetLogger("redis").Error($"StringGet:key={key},错误信息:{e}"); + throw new Exception($"redis error:StringGet: key ={ key },错误信息:{e}"); + } + } + + public static async Task StringGetAsync(string key) + { + try + { + var result = await GetClient().GetAsync(key); + return result; + } + catch (Exception e) + { + LoggerManager.GetLogger("redis").Error($"StringGetAsync:key={key},错误信息:{e}"); + throw new Exception($"redis error:StringGetAsync: key ={ key },错误信息:{e}"); + } + } + + public static T StringGet(string key) + { + try + { + var result = GetClient().Get(key); + return result; + } + catch (Exception e) + { + LoggerManager.GetLogger("redis").Error($"StringGet:key={key},错误信息:{e}"); + throw new Exception($"redis error:StringGet: key ={ key },错误信息:{e}"); + } + } + + + /// + /// 删除单个key + /// + /// redis key + /// 是否删除成功 + public static bool KeyDelete(string key) + { + try + { + var result = GetClient().Del(key); + return true; + } + catch (Exception e) + { + LoggerManager.GetLogger("redis").Error($"StringGet:key={key},错误信息:{e}"); + throw new Exception($"redis error:KeyDelete: key ={ key },错误信息:{e}"); + } + } + public static async Task KeyDeleteAsync(string key) + { + try + { + var result = await GetClient().DelAsync(key); + return true; + } + catch (Exception e) + { + LoggerManager.GetLogger("redis").Error($"StringGet:key={key},错误信息:{e}"); + throw new Exception($"redis error:KeyDeleteAsync: key ={ key },错误信息:{e}"); + } + } + + + /// + /// 判断key是否存储 + /// + /// redis key + /// + public static bool KeyExists(string key) + { + return GetClient().Exists(key); + } + public static async Task KeyExistsAsync(string key) + { + return await GetClient().ExistsAsync(key); + } + + /// + /// 获取list的redis + /// + /// + /// + public static Dictionary GetListKeys(Guid orgid) + { + return GetClient().HGetAll("opt_list_" + orgid); + } + /// + /// 删除list中的某张表数据 + /// + /// + /// + /// + public static bool DeleteListKeys(Guid orgid, string name) + { + if (GetClient().HExists("opt_list_" + orgid, name)) + { + GetClient().HDel("opt_list_" + orgid, name); + } + return true; + } + /// + /// 是否存在 + /// + /// + /// + /// + public static bool ExistsListKeys(Guid orgid, string name) + { + return GetClient().HExists("opt_list_" + orgid, name); + } + /// + /// 获取list中表的rediskey + /// + /// + /// + /// + public static string GetListKey(Guid orgid, string name) + { + return GetClient().HGet("opt_list_" + orgid, name); + } + //private object deleteCache( Method method, Object[] args) + //{ + // object flag = false; + + // String fieldkey = parseKey(method, args); + // try + // { + // if (fieldkey.equals("")) + // { + // cacheClient.del(cache.key()); + // } + // else + // { + // cacheClient.hdel(cache.key(), fieldkey); + // } + // flag = true; + // } + // catch (Exception e) + // { + // //System.out.println(e.getMessage()); + // flag = false; + // } + // return flag; + //} + + + /** + * 获取值field + * @param key + * @param method + * @param args + * @return + * @throws Exception + */ + // public string parseKey(Method method, Object[] args) + // { + // string fieldKey = ""; + // for (int i = 0; i < method.getParameters().length; i++) + // { + // Parameter p = method.getParameters()[i]; + // FieldAnnotation f = p.getAnnotation(FieldAnnotation.class); + // if(f!=null) { + // fieldKey+=args[i].toString()+":"; + // }else { + // FieldOnlyKeyAnnotation fo = p.getAnnotation(FieldOnlyKeyAnnotation.class); + // if(fo != null) { + // fieldKey+=args[i].toString(); + //} + // } + // } + + // return fieldKey; + // } + } +} diff --git a/APT.Infrastructure.Api/Redis/RedisConfig.cs b/APT.Infrastructure.Api/Redis/RedisConfig.cs new file mode 100644 index 0000000..fd0c503 --- /dev/null +++ b/APT.Infrastructure.Api/Redis/RedisConfig.cs @@ -0,0 +1,175 @@ +using StackExchange.Redis; +using System; +using System.Collections.Concurrent; +using System.Threading; + +namespace APT.Infrastructure.Api +{ + public class RedisConfig + { + //系统自定义Key前缀 + public static string SysCustomKey = ""; + //"127.0.0.1:6379,allowadmin=true + private static string RedisConnectionString = "192.168.0.167:6340,allowadmin=true"; + private static string RedisPwd = "redis123"; + + private static readonly ConcurrentDictionary ConnectionCache = new ConcurrentDictionary(); + private static readonly object Locker = new object(); + private static ConnectionMultiplexer _instance; + + static RedisConfig() + { + RedisOption option = ConfigurationManager.RedisOption; + if (option != null) + { + SysCustomKey = option.RedisPrefixKey; + RedisConnectionString = option.RedisConnectionString; + RedisPwd = option.RedisConnectionPwd; + } + else + { + throw new Exception($"未加载redis.json文件"); + } + } + + /// + /// 单例获取 + /// + public static ConnectionMultiplexer Instance + { + get + { + + if (_instance == null) + { + lock (Locker) + { + if (_instance == null || !_instance.IsConnected) + { + try + { + _instance = GetManager(); + } + catch (Exception ex) + { + throw new Exception("初始化Redis缓存错误," + ex.Message); + } + } + } + } + return _instance; + + } + } + + /// + /// 缓存获取 + /// + /// + /// + public static ConnectionMultiplexer GetConnectionMultiplexer(string connectionString) + { + if (!ConnectionCache.ContainsKey(connectionString)) + { + ConnectionCache[connectionString] = GetManager(connectionString); + } + return ConnectionCache[connectionString]; + } + + /// + /// + /// + /// + /// + private static ConnectionMultiplexer GetManager(string connectionString = null) + { + connectionString = connectionString ?? RedisConnectionString; + + var options = ConfigurationOptions.Parse(connectionString); + //options.ClientName = "root"; + //options.AbortOnConnectFail = false; + options.Password = RedisPwd; + options.ConnectTimeout = 15000; + options.SyncTimeout = 5000; + options.ResponseTimeout = 15000; + options.AbortOnConnectFail = false; + options.AllowAdmin = true; + var connect = ConnectionMultiplexer.Connect(options); + + //注册如下事件 + connect.ConnectionFailed += MuxerConnectionFailed; + connect.ConnectionRestored += MuxerConnectionRestored; + connect.ErrorMessage += MuxerErrorMessage; + connect.ConfigurationChanged += MuxerConfigurationChanged; + connect.HashSlotMoved += MuxerHashSlotMoved; + connect.InternalError += MuxerInternalError; + return connect; + } + + + #region 事件 + /// + /// 配置更改时 + /// + /// + /// + private static void MuxerConfigurationChanged(object sender, EndPointEventArgs e) + { + System.Console.WriteLine("Configuration changed: " + e.EndPoint); + } + + /// + /// 发生错误时 + /// + /// + /// + private static void MuxerErrorMessage(object sender, RedisErrorEventArgs e) + { + System.Console.WriteLine("ErrorMessage: " + e.Message); + } + + /// + /// 重新建立连接之前的错误 + /// + /// + /// + private static void MuxerConnectionRestored(object sender, ConnectionFailedEventArgs e) + { + System.Console.WriteLine("ConnectionRestored: " + e.EndPoint); + } + + /// + /// 连接失败 , 如果重新连接成功你将不会收到这个通知 + /// + /// + /// + private static void MuxerConnectionFailed(object sender, ConnectionFailedEventArgs e) + { + System.Console.WriteLine("重新连接:Endpoint failed: " + e.EndPoint + ", " + e.FailureType + (e.Exception == null ? "" : (", " + e.Exception.Message))); + } + + /// + /// 更改集群 + /// + /// + /// + private static void MuxerHashSlotMoved(object sender, HashSlotMovedEventArgs e) + { + System.Console.WriteLine("HashSlotMoved:NewEndPoint" + e.NewEndPoint + ", OldEndPoint" + e.OldEndPoint); + } + + /// + /// redis类库错误 + /// + /// + /// + private static void MuxerInternalError(object sender, InternalErrorEventArgs e) + { + System.Console.WriteLine("InternalError:Message" + e.Exception.Message); + } + + #endregion 事件 + + + } +} diff --git a/APT.Infrastructure.Api/Redis/RedisConfigurationExtensions.cs b/APT.Infrastructure.Api/Redis/RedisConfigurationExtensions.cs new file mode 100644 index 0000000..f08b7a1 --- /dev/null +++ b/APT.Infrastructure.Api/Redis/RedisConfigurationExtensions.cs @@ -0,0 +1,42 @@ +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Configuration.Json; +using Microsoft.Extensions.FileProviders; +using System; +using System.Collections.Generic; +using System.Text; + +namespace APT.Infrastructure.Api +{ + public static class RedisConfigurationExtensions + { + public static IConfigurationBuilder AddRedisFile(this IConfigurationBuilder builder, string path) + { + return AddRedisFile(builder, provider: null, path: path, optional: false, reloadOnChange: false); + } + + public static IConfigurationBuilder AddRedisFile(this IConfigurationBuilder builder, string path, bool optional) + { + return AddRedisFile(builder, provider: null, path: path, optional: optional, reloadOnChange: false); + } + + public static IConfigurationBuilder AddRedisFile(this IConfigurationBuilder builder, string path, bool optional, bool reloadOnChange) + { + return AddRedisFile(builder, provider: null, path: path, optional: optional, reloadOnChange: reloadOnChange); + } + + public static IConfigurationBuilder AddRedisFile(this IConfigurationBuilder builder, IFileProvider provider, string path, bool optional, bool reloadOnChange) + { + var source = new JsonConfigurationSource() + { + FileProvider = provider, + Path = path, + Optional = optional, + ReloadOnChange = reloadOnChange + }; + builder.Add(source); + //AppConfig.Configuration = builder.Build(); + //AppConfig.RedisOption = AppConfig.Configuration.GetSection("RedisConfig").Get(); + return builder; + } + } +} diff --git a/APT.Infrastructure.Api/Redis/RedisManager.cs b/APT.Infrastructure.Api/Redis/RedisManager.cs new file mode 100644 index 0000000..3b19550 --- /dev/null +++ b/APT.Infrastructure.Api/Redis/RedisManager.cs @@ -0,0 +1,1234 @@ + +using Newtonsoft.Json; +using StackExchange.Redis; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Threading.Tasks; + +namespace APT.Infrastructure.Api +{ + /// + /// 缓存管理 + /// 1.要可以查看所有的缓存 + /// 2.要可以管理缓存中的数据,如清空,删除等 + /// 3.可以预先加载 + /// + public class RedisManager + { + public int DbNum { get; } + public ConnectionMultiplexer _conn; + + JsonSerializerSettings _jsonSetting; + + #region 构造函数 + + public RedisManager(int dbNum = 0) + { + DbNum = dbNum; + _conn = RedisConfig.Instance; + _jsonSetting = new JsonSerializerSettings(); + _jsonSetting.ReferenceLoopHandling = ReferenceLoopHandling.Ignore; + } + #endregion 构造函数 + + #region String + #region 同步方法 + + ///// + ///// 保存单个key value + ///// + ///// Redis Key + ///// 保存的值 + ///// 过期时间 + ///// + //public bool StringSet(string key, string value, TimeSpan? expiry = default(TimeSpan?)) + //{ + // key = AddSysCustomKey(key); + // return Do(db => db.StringSet(key, value, expiry)); + //} + + ///// + ///// 保存多个key value + ///// + ///// 键值对 + ///// + //public bool StringSet(List> keyValues) + //{ + // List> newkeyValues = + // keyValues.Select(p => new KeyValuePair(AddSysCustomKey(p.Key), p.Value)).ToList(); + // return Do(db => db.StringSet(newkeyValues.ToArray())); + //} + + ///// + ///// 保存一个对象 + ///// + ///// + ///// + ///// + ///// + ///// + //public bool StringSet(string key, T obj, TimeSpan? expiry = default(TimeSpan?)) + //{ + // key = AddSysCustomKey(key); + // string json = ConvertJson(obj); + // return Do(db => db.StringSet(key, json, expiry)); + //} + + ///// + ///// 保存一个对象 + ///// + ///// + ///// + ///// + ///// + ///// + //public bool StringSet(string key, T obj, DateTime expiry) + //{ + // key = AddSysCustomKey(key); + // string json = ConvertJson(obj); + // return Do(db => db.StringSet(key, json, expiry - DateTime.Now)); + //} + + ///// + ///// 获取单个key的值 + ///// + ///// Redis Key + ///// + //public string StringGet(string key) + //{ + // key = AddSysCustomKey(key); + // return Do(db => db.StringGet(key)); + //} + + ///// + ///// 获取多个Key + ///// + ///// Redis Key集合 + ///// + //public RedisValue[] StringGet(List listKey) + //{ + // List newKeys = listKey.Select(AddSysCustomKey).ToList(); + // return Do(db => db.StringGet(ConvertRedisKeys(newKeys))); + //} + + ///// + ///// 获取一个key的对象 + ///// + ///// + ///// + ///// + //public T StringGet(string key) + //{ + // key = AddSysCustomKey(key); + // return Do(db => ConvertObj(db.StringGet(key))); + //} + + ///// + ///// 为数字增长val + ///// + ///// + ///// 可以为负 + ///// 增长后的值 + //public double StringIncrement(string key, double val = 1) + //{ + // key = AddSysCustomKey(key); + // return Do(db => db.StringIncrement(key, val)); + //} + + ///// + ///// 为数字减少val + ///// + ///// + ///// 可以为负 + ///// 减少后的值 + //public double StringDecrement(string key, double val = 1) + //{ + // key = AddSysCustomKey(key); + // return Do(db => db.StringDecrement(key, val)); + //} + + //#endregion 同步方法 + + //#region 异步方法 + + ///// + ///// 保存单个key value + ///// + ///// Redis Key + ///// 保存的值 + ///// 过期时间 + ///// + //public async Task StringSetAsync(string key, string value, TimeSpan? expiry = default(TimeSpan?)) + //{ + // key = AddSysCustomKey(key); + // return await Do(db => db.StringSetAsync(key, value, expiry)); + //} + + ///// + ///// 保存多个key value + ///// + ///// 键值对 + ///// + //public async Task StringSetAsync(List> keyValues) + //{ + // List> newkeyValues = + // keyValues.Select(p => new KeyValuePair(AddSysCustomKey(p.Key), p.Value)).ToList(); + // return await Do(db => db.StringSetAsync(newkeyValues.ToArray())); + //} + + ///// + ///// 保存一个对象 + ///// + ///// + ///// + ///// + ///// + ///// + //public async Task StringSetAsync(string key, T obj, TimeSpan? expiry = default(TimeSpan?)) + //{ + // key = AddSysCustomKey(key); + // string json = ConvertJson(obj); + // return await Do(db => db.StringSetAsync(key, json, expiry)); + //} + + ///// + ///// 获取单个key的值 + ///// + ///// Redis Key + ///// + //public async Task StringGetAsync(string key) + //{ + // key = AddSysCustomKey(key); + // return await Do(db => db.StringGetAsync(key)); + //} + + ///// + ///// 获取多个Key + ///// + ///// Redis Key集合 + ///// + //public async Task StringGetAsync(List listKey) + //{ + // List newKeys = listKey.Select(AddSysCustomKey).ToList(); + // return await Do(db => db.StringGetAsync(ConvertRedisKeys(newKeys))); + //} + + ///// + ///// 获取一个key的对象 + ///// + ///// + ///// + ///// + //public async Task StringGetAsync(string key) + //{ + // key = AddSysCustomKey(key); + // string result = await Do(db => db.StringGetAsync(key)); + // return ConvertObj(result); + + //} + + ///// + ///// 为数字增长val + ///// + ///// + ///// 可以为负 + ///// 增长后的值 + //public async Task StringIncrementAsync(string key, double val = 1) + //{ + // key = AddSysCustomKey(key); + // return await Do(db => db.StringIncrementAsync(key, val)); + //} + + ///// + ///// 为数字减少val + ///// + ///// + ///// 可以为负 + ///// 减少后的值 + //public async Task StringDecrementAsync(string key, double val = 1) + //{ + // key = AddSysCustomKey(key); + // return await Do(db => db.StringDecrementAsync(key, val)); + //} + + //#endregion 异步方法 + + //#endregion String + + //#region Hash + + //#region 同步方法 + + /// + /// 判断某个数据是否已经被缓存 + /// + /// + /// + /// + public bool HashExists(string key, string dataKey) + { + if (string.IsNullOrEmpty(key) || string.IsNullOrEmpty(dataKey)) + return false; + key = AddSysCustomKey(key); + return Do(db => db.HashExists(key, dataKey)); + } + + ///// + ///// 存储数据到hash表 + ///// + ///// + ///// + ///// + ///// + ///// + //public bool HashSet(string key, string dataKey, T t) + //{ + // key = AddSysCustomKey(key); + // return Do(db => + // { + // string json = ConvertJson(t); + // return db.HashSet(key, dataKey, json); + // }); + //} + + /// + /// 移除hash中的某值 + /// + /// + /// + /// + public bool HashDelete(string key, string dataKey) + { + if (string.IsNullOrEmpty(key) || string.IsNullOrEmpty(dataKey)) + return false; + key = AddSysCustomKey(key); + return Do(db => db.HashDelete(key, dataKey)); + } + + ///// + ///// 移除hash中的多个值 + ///// + ///// + ///// + ///// + //public long HashDelete(string key, List dataKeys) + //{ + // key = AddSysCustomKey(key); + // //List dataKeys1 = new List() {"1","2"}; + // return Do(db => db.HashDelete(key, dataKeys.ToArray())); + //} + + /// + /// 从hash表获取数据 + /// + /// + /// + /// + /// + public T HashGet(string key, string dataKey) + { + if (string.IsNullOrEmpty(key) || string.IsNullOrEmpty(dataKey)) + return default(T); + key = AddSysCustomKey(key); + return Do(db => + { + string value = db.HashGet(key, dataKey); + if (!string.IsNullOrEmpty(value)) + return ConvertObj(value); + else + return default(T); + }); + } + + ///// + ///// 为数字增长val + ///// + ///// + ///// + ///// 可以为负 + ///// 增长后的值 + //public double HashIncrement(string key, string dataKey, double val = 1) + //{ + // key = AddSysCustomKey(key); + // return Do(db => db.HashIncrement(key, dataKey, val)); + //} + + ///// + ///// 为数字减少val + ///// + ///// + ///// + ///// 可以为负 + ///// 减少后的值 + //public double HashDecrement(string key, string dataKey, double val = 1) + //{ + // key = AddSysCustomKey(key); + // return Do(db => db.HashDecrement(key, dataKey, val)); + //} + + ///// + ///// 获取hashkey所有Redis key + ///// + ///// + ///// + ///// + //public List HashKeys(string key) + //{ + // key = AddSysCustomKey(key); + // return Do(db => + // { + // RedisValue[] values = db.HashKeys(key); + // return ConvetList(values); + // }); + //} + + ///// + ///// + ///// + ///// + ///// + ///// + //public List HashValues(string key) + //{ + // var result = new List(); + // key = AddSysCustomKey(key); + // return Do(db => + // { + // HashEntry[] arr = db.HashGetAll(key); + // foreach (var item in arr) + // { + // if (!item.Value.IsNullOrEmpty) + // { + // result.Add(JsonConvert.DeserializeObject(item.Value)); + // } + // } + // return result; + // }); + //} + + public HashEntry[] HashValueAll(string key) + { + key = AddSysCustomKey(key); + return Do(db => + { + HashEntry[] arr = db.HashGetAll(key); + return arr; + }); + } + + //#endregion 同步方法 + + //#region 异步方法 + + ///// + ///// 判断某个数据是否已经被缓存 + ///// + ///// + ///// + ///// + //public async Task HashExistsAsync(string key, string dataKey) + //{ + // key = AddSysCustomKey(key); + // return await Do(db => db.HashExistsAsync(key, dataKey)); + //} + + ///// + ///// 存储数据到hash表 + ///// + ///// + ///// + ///// + ///// + ///// + //public async Task HashSetAsync(string key, string dataKey, T t) + //{ + // key = AddSysCustomKey(key); + // return await Do(db => + // { + // string json = ConvertJson(t); + // return db.HashSetAsync(key, dataKey, json); + // }); + //} + + ///// + ///// 移除hash中的某值 + ///// + ///// + ///// + ///// + //public async Task HashDeleteAsync(string key, string dataKey) + //{ + // key = AddSysCustomKey(key); + // return await Do(db => db.HashDeleteAsync(key, dataKey)); + //} + + ///// + ///// 移除hash中的多个值 + ///// + ///// + ///// + ///// + //public async Task HashDeleteAsync(string key, List dataKeys) + //{ + // key = AddSysCustomKey(key); + // //List dataKeys1 = new List() {"1","2"}; + // return await Do(db => db.HashDeleteAsync(key, dataKeys.ToArray())); + //} + + ///// + ///// 从hash表获取数据 + ///// + ///// + ///// + ///// + ///// + //public async Task HashGetAsync(string key, string dataKey) + //{ + // key = AddSysCustomKey(key); + // string value = await Do(db => db.HashGetAsync(key, dataKey)); + // return ConvertObj(value); + + //} + + ///// + ///// 为数字增长val + ///// + ///// + ///// + ///// 可以为负 + ///// 增长后的值 + //public async Task HashIncrementAsync(string key, string dataKey, double val = 1) + //{ + // key = AddSysCustomKey(key); + // return await Do(db => db.HashIncrementAsync(key, dataKey, val)); + //} + + ///// + ///// 为数字减少val + ///// + ///// + ///// + ///// 可以为负 + ///// 减少后的值 + //public async Task HashDecrementAsync(string key, string dataKey, double val = 1) + //{ + // key = AddSysCustomKey(key); + // return await Do(db => db.HashDecrementAsync(key, dataKey, val)); + //} + + ///// + ///// 获取hashkey所有Redis key + ///// + ///// + ///// + ///// + //public async Task> HashKeysAsync(string key) + //{ + // key = AddSysCustomKey(key); + // RedisValue[] values = await Do(db => db.HashKeysAsync(key)); + // return ConvetList(values); + //} + + ///// + ///// + ///// + ///// + ///// + ///// + //public async Task> HashValuesAsync(string key) + //{ + // var result = new List(); + // key = AddSysCustomKey(key); + // HashEntry[] arr = await Do(db => db.HashGetAllAsync(key)); + // foreach (var item in arr) + // { + // string values = item.Name; + // if (!item.Value.IsNullOrEmpty) + // { + // result.Add(JsonConvert.DeserializeObject(item.Value)); + // } + // } + // return result; + //} + ///// + ///// + ///// + ///// + ///// + ///// + //public async Task HashValueAllAsync(string key) + //{ + // key = AddSysCustomKey(key); + // HashEntry[] arr = await Do(db => db.HashGetAllAsync(key)); + // return arr; + //} + #endregion 异步方法 + + #endregion Hash + + //#region List + + //#region 同步方法 + + ///// + ///// 移除指定ListId的内部List的值 + ///// + ///// + ///// + //public void ListRemove(string key, T value) + //{ + // key = AddSysCustomKey(key); + // Do(db => db.ListRemove(key, ConvertJson(value))); + //} + + ///// + ///// 获取指定key的List + ///// + ///// + ///// + //public List ListRange(string key) + //{ + // key = AddSysCustomKey(key); + // return Do(redis => + // { + // var values = redis.ListRange(key); + // return ConvetList(values); + // }); + //} + + ///// + ///// 入队 + ///// + ///// + ///// + //public void ListRightPush(string key, T value) + //{ + // key = AddSysCustomKey(key); + // Do(db => db.ListRightPush(key, ConvertJson(value))); + //} + + ///// + ///// 出队 + ///// + ///// + ///// + ///// + //public T ListRightPop(string key) + //{ + // key = AddSysCustomKey(key); + // return Do(db => + // { + // var value = db.ListRightPop(key); + // return ConvertObj(value); + // }); + //} + + ///// + ///// 入栈 + ///// + ///// + ///// + ///// + //public void ListLeftPush(string key, T value) + //{ + // key = AddSysCustomKey(key); + // Do(db => db.ListLeftPush(key, ConvertJson(value))); + //} + + ///// + ///// 出栈 + ///// + ///// + ///// + ///// + //public T ListLeftPop(string key) + //{ + // key = AddSysCustomKey(key); + // return Do(db => + // { + // var value = db.ListLeftPop(key); + // return ConvertObj(value); + // }); + //} + + ///// + ///// 获取集合中的数量 + ///// + ///// + ///// + //public long ListLength(string key) + //{ + // key = AddSysCustomKey(key); + // return Do(redis => redis.ListLength(key)); + //} + + //#endregion 同步方法 + + //#region 异步方法 + + ///// + ///// 移除指定ListId的内部List的值 + ///// + ///// + ///// + //public async Task ListRemoveAsync(string key, T value) + //{ + // key = AddSysCustomKey(key); + // return await Do(db => db.ListRemoveAsync(key, ConvertJson(value))); + //} + + ///// + ///// 获取指定key的List + ///// + ///// + ///// + //public async Task> ListRangeAsync(string key) + //{ + // key = AddSysCustomKey(key); + // var values = await Do(redis => redis.ListRangeAsync(key)); + // return ConvetList(values); + //} + + ///// + ///// 入队 + ///// + ///// + ///// + //public async Task ListRightPushAsync(string key, T value) + //{ + // key = AddSysCustomKey(key); + // return await Do(db => db.ListRightPushAsync(key, ConvertJson(value))); + //} + + ///// + ///// 出队 + ///// + ///// + ///// + ///// + //public async Task ListRightPopAsync(string key) + //{ + // key = AddSysCustomKey(key); + // var value = await Do(db => db.ListRightPopAsync(key)); + // return ConvertObj(value); + //} + + ///// + ///// 入栈 + ///// + ///// + ///// + ///// + //public async Task ListLeftPushAsync(string key, T value) + //{ + // key = AddSysCustomKey(key); + // return await Do(db => db.ListLeftPushAsync(key, ConvertJson(value))); + //} + + ///// + ///// 出栈 + ///// + ///// + ///// + ///// + //public async Task ListLeftPopAsync(string key) + //{ + // key = AddSysCustomKey(key); + // var value = await Do(db => db.ListLeftPopAsync(key)); + // return ConvertObj(value); + //} + + ///// + ///// 获取集合中的数量 + ///// + ///// + ///// + //public async Task ListLengthAsync(string key) + //{ + // key = AddSysCustomKey(key); + // return await Do(redis => redis.ListLengthAsync(key)); + //} + + //#endregion 异步方法 + + //#endregion List + + //#region SortedSet 有序集合 + + //#region 同步方法 + + ///// + ///// 添加 + ///// + ///// + ///// + ///// + //public bool SortedSetAdd(string key, T value, double score) + //{ + // key = AddSysCustomKey(key); + + // return Do(redis => redis.SortedSetAdd(key, ConvertJson(value), score)); + //} + + ///// + ///// 添加???????? + ///// + ///// + ///// + ///// + //public double SortedSetIncrement(string key, T value, double score) + //{ + // key = AddSysCustomKey(key); + + // return Do(redis => redis.SortedSetIncrement(key, ConvertJson(value), score)); + //} + + //public bool SortedSetAdd(string key, SortedSetEntry[] values) + //{ + // key = AddSysCustomKey(key); + // Do(redis => redis.SortedSetAdd(key, values, CommandFlags.None)); + // return true; + //} + //public async Task SortedSetAddAsync(string key, SortedSetEntry[] values) + //{ + // key = AddSysCustomKey(key); + // await Do(redis => redis.SortedSetAddAsync(key, values)); + // return true; + //} + ///// + ///// 删除 + ///// + ///// + ///// + //public bool SortedSetRemove(string key, T value) + //{ + // key = AddSysCustomKey(key); + // return Do(redis => redis.SortedSetRemove(key, ConvertJson(value))); + //} + + ///// + ///// 获取全部 + ///// + ///// + ///// + //public List SortedSetRangeByRank(string key) + //{ + // key = AddSysCustomKey(key); + // return Do(redis => + // { + // var values = redis.SortedSetRangeByRank(key); + // return ConvetList(values); + // }); + //} + + ///// + ///// 获取全部 + ///// + ///// + ///// + //public RedisValue[] SortedSetRangeByRank(string key) + //{ + // key = AddSysCustomKey(key); + // return Do(redis => + // { + // return redis.SortedSetRangeByRank(key); + + // }); + //} + + //public IEnumerable SortedSetScan(string key, RedisValue pattern = default) + //{ + // key = AddSysCustomKey(key); + // return Do(redis => + // { + // return redis.SortedSetScan(key, pattern); + // }); + //} + //public async Task> SortedSetScanAsync(string key, RedisValue pattern = default) + //{ + // key = AddSysCustomKey(key); + // return Do(redis => + // { + // return redis.SortedSetScanAsync(key,pattern); + // }); + //} + + + ///// + ///// 获取集合中的数量 + ///// + ///// + ///// + //public long SortedSetLength(string key) + //{ + // key = AddSysCustomKey(key); + // return Do(redis => redis.SortedSetLength(key)); + //} + + //#endregion 同步方法 + + //#region 异步方法 + + ///// + ///// 添加 + ///// + ///// + ///// + ///// + //public async Task SortedSetAddAsync(string key, T value, double score) + //{ + // key = AddSysCustomKey(key); + // return await Do(redis => redis.SortedSetAddAsync(key, ConvertJson(value), score)); + //} + + ///// + ///// 删除 + ///// + ///// + ///// + //public async Task SortedSetRemoveAsync(string key, T value) + //{ + // key = AddSysCustomKey(key); + // return await Do(redis => redis.SortedSetRemoveAsync(key, ConvertJson(value))); + //} + + ///// + ///// 获取全部 + ///// + ///// + ///// + //public async Task> SortedSetRangeByRankAsync(string key) + //{ + // key = AddSysCustomKey(key); + // var values = await Do(redis => redis.SortedSetRangeByRankAsync(key)); + // return ConvetList(values); + //} + + ///// + ///// 获取集合中的数量 + ///// + ///// + ///// + //public async Task SortedSetLengthAsync(string key) + //{ + // key = AddSysCustomKey(key); + // return await Do(redis => redis.SortedSetLengthAsync(key)); + //} + + //#endregion 异步方法 + + //#endregion SortedSet 有序集合 + + //#region key + + ///// + ///// 删除单个key + ///// + ///// redis key + ///// 是否删除成功 + //public bool KeyDelete(string key) + //{ + // key = AddSysCustomKey(key); + // return Do(db => db.KeyDelete(key)); + //} + //public async Task KeyDeleteAsync(string key) + //{ + // key = AddSysCustomKey(key); + // return await Do(db => db.KeyDeleteAsync(key)); + //} + ///// + ///// 删除多个key + ///// + ///// rediskey + ///// 成功删除的个数 + //public long KeyDelete(List keys) + //{ + // List newKeys = keys.Select(AddSysCustomKey).ToList(); + // return Do(db => db.KeyDelete(ConvertRedisKeys(newKeys))); + //} + + ///// + ///// 判断key是否存储 + ///// + ///// redis key + ///// + //public bool KeyExists(string key) + //{ + // key = AddSysCustomKey(key); + // return Do(db => db.KeyExists(key)); + //} + + ///// + ///// 重新命名key + ///// + ///// 就的redis key + ///// 新的redis key + ///// + //public bool KeyRename(string key, string newKey) + //{ + // key = AddSysCustomKey(key); + // return Do(db => db.KeyRename(key, newKey)); + //} + + ///// + ///// 设置Key的时间 + ///// + ///// redis key + ///// + ///// + //public bool KeyExpire(string key, TimeSpan? expiry = default(TimeSpan?)) + //{ + // key = AddSysCustomKey(key); + // return Do(db => db.KeyExpire(key, expiry)); + //} + + /// + /// 获取所有KEY + /// + /// + public List GetAllCacheKeys() + { + try + { + var result = new List(); + var endpoints = _conn.GetEndPoints(true); + foreach (var endpoint in endpoints) + { + var server = _conn.GetServer(endpoint); + result.AddRange(server.Keys(DbNum).Select(x => x.ToString())); + } + return result.Distinct().ToList(); + } + catch + { + return null; + } + } + + ///// + ///// 获取所有KEY-Value + ///// + ///// + //public IDictionary GetAll() + //{ + // try + // { + // var result = new Dictionary(); + // IDatabase idb = _conn.GetDatabase(DbNum); + // var endpoints = _conn.GetEndPoints(true); + // foreach (var endpoint in endpoints) + // { + // var server = _conn.GetServer(endpoint); + // foreach (var item in server.Keys(DbNum)) + // { + // result.Add(item.ToString(), idb.StringGet(item.ToString())); + // } + // } + // return result; + // } + // catch + // { + // return null; + // } + //} + + + //#endregion key + + //#region 发布订阅 + + ///// + ///// Redis发布订阅 订阅 + ///// + ///// + ///// + //public void Subscribe(string subChannel, Action handler = null) + //{ + // ISubscriber sub = _conn.GetSubscriber(); + // sub.Subscribe(subChannel, (channel, message) => + // { + // if (handler == null) + // { + // Console.WriteLine(subChannel + " 订阅收到消息:" + message); + // } + // else + // { + // handler(channel, message); + // } + // }); + //} + + ///// + ///// Redis发布订阅 发布 + ///// + ///// + ///// + ///// + ///// + //public long Publish(string channel, T msg) + //{ + // ISubscriber sub = _conn.GetSubscriber(); + // return sub.Publish(channel, ConvertJson(msg)); + //} + + ///// + ///// Redis发布订阅 取消订阅 + ///// + ///// + //public void Unsubscribe(string channel) + //{ + // ISubscriber sub = _conn.GetSubscriber(); + // sub.Unsubscribe(channel); + //} + + ///// + ///// Redis发布订阅 取消全部订阅 + ///// + //public void UnsubscribeAll() + //{ + // ISubscriber sub = _conn.GetSubscriber(); + // sub.UnsubscribeAll(); + //} + + //#endregion 发布订阅 + + #region 其他 + /// + /// 获取list的redis + /// + /// + /// + public List GetListKeys(Guid orgid) + { + return this.HashValueAll("opt_list_" + orgid).ToList(); + } + /// + /// 删除list中的某张表数据 + /// + /// + /// + /// + public bool DeleteListKeys(Guid orgid, string name) + { + if (this.HashExists("opt_list_" + orgid, name)) + { + return this.HashDelete("opt_list_" + orgid, name); + } + return true; + } + /// + /// 是否存在 + /// + /// + /// + /// + public bool ExistsListKeys(Guid orgid, string name) + { + return this.HashExists("opt_list_" + orgid, name); + } + /// + /// 获取list中表的rediskey + /// + /// + /// + /// + public string GetListKey(Guid orgid, string name) + { + return this.HashGet("opt_list_" + orgid, name); + } + + public ITransaction CreateTransaction() + { + return GetDatabase().CreateTransaction(); + } + + public IDatabase GetDatabase() + { + return _conn.GetDatabase(DbNum); + } + + public IServer GetServer(string hostAndPort) + { + return _conn.GetServer(hostAndPort); + } + #endregion 其他 + + #region 辅助方法 + + private string AddSysCustomKey(string oldKey) + { + var prefixKey = RedisConfig.SysCustomKey; + return prefixKey + oldKey; + } + + private T Do(Func func) + { + try + { + var database = _conn.GetDatabase(DbNum); + return func(database); + } + catch (Exception ex) + { + Console.WriteLine($"reids.do:{ex.Message}"); + return default(T); + } + } + + public string ConvertJson(T value) + { + string result = value is string ? value.ToString() : JsonConvert.SerializeObject(value, _jsonSetting); + return result; + } + + //private T ConvertObj(RedisValue value) + //{ + // if (value.HasValue) + // { + // // return SerializerJson.DeserializeObject(value); + // return Newtonsoft.Json.JsonConvert.DeserializeObject(value); + // //return SerializerJson.DeserializeObject(value); + // } + // return default(T); + //} + + private T ConvertObj(RedisValue value) + { + if (typeof(T).Name.Equals(typeof(string).Name)) + { + return JsonConvert.DeserializeObject($"'{value}'"); + } + else + { + T t = JsonConvert.DeserializeObject(value); + if (t == null) + { + Console.WriteLine($"reids.ConvertObj.t:{null}"); + } + return t; + } + } + + + private List ConvetList(RedisValue[] values) + { + List result = new List(); + foreach (var item in values) + { + var model = ConvertObj(item); + result.Add(model); + } + return result; + } + + private RedisKey[] ConvertRedisKeys(List redisKeys) + { + return redisKeys.Select(redisKey => (RedisKey)redisKey).ToArray(); + } + + #endregion 辅助方法 + + } +} diff --git a/APT.Infrastructure.Api/Redis/RedisOption.cs b/APT.Infrastructure.Api/Redis/RedisOption.cs new file mode 100644 index 0000000..54823bf --- /dev/null +++ b/APT.Infrastructure.Api/Redis/RedisOption.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace APT.Infrastructure.Api +{ + public class RedisOption + { + /// + /// Redis服务器 + /// + public string RedisConnectionString { get; set; } + + /// + /// Redis密码 + /// + public string RedisConnectionPwd { get; set; } + + /// + /// 系统自定义Key前缀 + /// + public string RedisPrefixKey { get; set; } + } +} diff --git a/APT.Infrastructure.Api/Service/CommonService.cs b/APT.Infrastructure.Api/Service/CommonService.cs new file mode 100644 index 0000000..79574ab --- /dev/null +++ b/APT.Infrastructure.Api/Service/CommonService.cs @@ -0,0 +1,1084 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Threading.Tasks; +using APT.Infrastructure.Core; +namespace APT.Infrastructure.Api +{ + public partial class CommonService : DomainServiceBase, ICommonService + { + private IRepository _repository; + public IRepository Repository { get { return _repository; } } + public CommonService(IRepository repository) : base(repository.UnitOfWork) + { + _repository = repository; + } + + public IUnitOfWork UnitWork() + { + return Repository.UnitOfWork; + } + public virtual bool AddEntity(T entity) where T : MesEntityBase, new() + { + this.Repository.AddEntity(entity); + return true; + } + public virtual T AddAndGetEntity(T entity) where T : MesEntityBase, new() + { + return this.Repository.AddAndGetEntity(entity); + } + + public virtual bool BantchAddEntity(IEnumerable entities) where T : MesEntityBase, new() + { + this.Repository.AddEntities(entities); + return true; + } + /// + /// 逻辑删除 + /// + /// + /// + public virtual bool DeleteEntity(Guid id) where T : MesEntityBase, new() + { + this.Repository.DeleteEntity(id); + return true; + } + /// + /// 逻辑删除 + /// + /// + /// + public virtual bool DeleteEntity(Expression> predicate) where T : MesEntityBase, new() + { + this.Repository.DeleteEntity(predicate); + return true; + } + /// + /// 逻辑删除 + /// + /// + /// + public virtual bool DeleteEntity(IEnumerable entities) where T : MesEntityBase, new() + { + this.Repository.DeleteEntities(entities); + return true; + } + + /// + /// 逻辑批量删除 + /// + /// + /// + /// + public bool BantchDeleteEntity(List ids) where T : MesEntityBase, new() + { + if (ids == null || !ids.Any()) return false; + this.Repository.DeleteEntity(t => ids.Contains(t.ID)); + return true; + } + + /// + /// 逻辑删除 + /// + /// + /// + public virtual bool DeleteEntity(T entity) where T : MesEntityBase, new() + { + this.Repository.DeleteEntity(entity); + return true; + } + + /// + /// 更新 + /// + /// 实体 + /// 是否成功 + public virtual bool UpdateEntity(T entity) where T : MesEntityBase, new() + { + this.Repository.UpdateEntity(entity); + return true; + } + public virtual bool UpdateEntity(T entity, params string[] updateField) where T : MesEntityBase, new() + { + this.Repository.UpdateEntity(entity, true, updateField); + return true; + } + public virtual bool BantchUpdateEntity(IEnumerable entities, params string[] updateField) where T : MesEntityBase, new() + { + this.Repository.UpdateEntities(entities, true, updateField); + return true; + } + + /// + /// 批量更新 + /// + /// 实体集合 + /// 是否成功 + public virtual bool BantchUpdateEntity(IEnumerable entities) where T : MesEntityBase, new() + { + this.Repository.UpdateEntities(entities); + return true; + } + + /// + /// 批量更新(新增和保存一起)速度慢 + /// + /// 实体集合 + /// 是否成功 + public virtual bool BantchSaveEntity(IEnumerable entities) where T : MesEntityBase, new() + { + //entities.ForEach(i => i.MODIFICATION_TIME = DateTime.Now); + this.Repository.SaveEntities(entities); + return true; + } + + + + #region 树实体 + /// + /// 添加实体 + /// + /// + /// + public bool TreeAddEntity(T entity) where T : TreeEntityBase, new() + { + return this.AddEntity(entity); + } + + public T TreeAddAndGetEntity(T entity) where T : MesEntityBase, new() + { + return this.AddAndGetEntity(entity); + } + + /// + /// 删除实体 + /// + /// + /// + public bool TreeDeleteEntity(Guid id) where T : TreeEntityBase, new() + { + return this.DeleteEntity(id); + + } + + /// + /// 删除实体 + /// + /// + /// + public bool TreeDeleteEntity(Expression> expression) where T : TreeEntityBase, new() + { + return this.DeleteEntity(expression); + } + /// + /// 删除实体 + /// + /// + /// + public bool TreeDeleteEntity(IEnumerable entity) where T : TreeEntityBase, new() + { + return this.DeleteEntity(entity); + } + /// + /// 删除实体 + /// + /// + /// + /// + public bool TreeDeleteEntity(T entity) where T : TreeEntityBase, new() + { + return this.DeleteEntity(entity); + } + + /// + /// 逻辑批量删除 + /// + /// + /// + /// + public bool TreeBantchDeleteEntity(List ids) where T : TreeEntityBase, new() + { + return this.BantchDeleteEntity(ids); + } + /// + /// 更新实体 + /// + /// + /// + public bool TreeUpdateEntity(T entity) where T : TreeEntityBase, new() + { + return this.UpdateEntity(entity); + } + + /// + /// 批量添加实体 + /// + /// 实体集合 + /// + public bool TreeBantchAddEntity(IEnumerable entities) where T : TreeEntityBase, new() + { + return this.BantchAddEntity(entities); + + } + + /// + /// 批量更新实体 + /// + /// 实体集 + /// + public bool TreeBantchUpdateEntity(IEnumerable entities) where T : TreeEntityBase, new() + { + return this.BantchUpdateEntity(entities); + } + /// + /// 批量保存实体 + /// + /// 批量保存 + /// + public bool TreeBantchSaveEntity(IEnumerable entities) where T : TreeEntityBase, new() + { + return this.BantchSaveEntity(entities); + } + #endregion + + + + + + /// + /// 查询实体 + /// + /// + /// + /// + /// + public T GetEntity(string id, params string[] paths) where T : MesEntityBase, new() + { + var gId = new Guid(id); + return this.GetEntity(t => t.ID == gId, paths); + } + + public T GetEntity(Guid id, params string[] paths) where T : MesEntityBase, new() + { + return this.GetEntity(t => t.ID == id, paths); + } + /// + /// 查询实体 + /// + /// + /// + /// + /// + public T GetEntity(Expression> expression, params string[] paths) where T : MesEntityBase, new() + { + return this.GetEntity(expression, null, paths); + } + + + + /// + /// 查询实体 + /// + /// + /// + /// + /// + public T GetEntity(Expression> expression, BaseFilter filter, params string[] paths) + where T : MesEntityBase, new() + { + return this.GetEntity(expression, filter, (!filter?.IsNoTranking) ?? true, paths); + } + public T GetEntity(Expression> expression, BaseFilter filter, bool isTracking = true, params string[] paths) + where T : MesEntityBase, new() + { + return this.Repository.GetEntity(expression, filter, isTracking, paths); + } + public int GetCount(Expression> expression, BaseFilter filter) + where T : MesEntityBase, new() + { + return this.GetCount(expression, filter); + } + public T GetEntityByRedis(string key, Guid orgid) + where T : MesEntityBase, new() + { + return this.Repository.GetEntityByRedis(key, orgid); + } + + public List GetEntitiesByRedis(BaseFilter filter) where T : MesEntityBase, new() + { + return this.Repository.GetEntitiesByRedis(filter).Result; + } + + public List GetEntitiesByGroupRedis(BaseFilter filter, string groupValue) where T : MesEntityBase, new() + { + return this.Repository.GetEntitiesByGroupRedis(filter, groupValue).Result; + } + public List GetEntitiesByRedis(Expression> expression, BaseFilter filter) where T : MesEntityBase, new() + { + return this.Repository.GetEntitiesByRedis(expression, filter); + } + + public List GetEntitiesTableByRedis(Expression> expression, BaseFilter filter, + params string[] paths) where T : MesEntityBase, new() + { + return this.Repository.GetEntitiesTableByRedis(expression, filter, paths).Result; + } + + public List GetEntitiesByRedis(Expression> expression, BaseFilter filter, string groupValue, + params string[] paths) where T : MesEntityBase, new() + { + return this.Repository.GetEntitiesByRedis(expression, filter, groupValue, paths).Result; + } + + public PagedResultDto GetOrderPageByRedis(Expression> expression, BasePageFilter pageFilter, + params string[] paths) where T : MesEntityBase, new() + { + return this.Repository.GetOrderPageByRedis(expression, pageFilter, paths); + } + public T GetEntityByRedis(Guid key, Guid orgid) + where T : MesEntityBase, new() + { + return this.Repository.GetEntityByRedis(key, orgid); + } + + + public IEnumerable GetEntities(Expression> expression, + params string[] paths) where T : MesEntityBase, new() + { + return this.GetEntities(expression, false, paths); + } + public IEnumerable GetEntities(Expression> expression, + bool isTracking = false, params string[] paths) where T : MesEntityBase, new() + { + return this.Repository.GetEntities(expression, null, isTracking, paths); + } + /// + /// 获取所有数据 + /// + /// + /// + /// + /// + /// + public IEnumerable GetEntities(Expression> expression, + BaseFilter filter, params string[] paths) where T : MesEntityBase, new() + { + return this.Repository.GetEntities(expression, filter, false, paths); + } + public IEnumerable GetEntities(Expression> expression, BaseFilter filter, + bool isTracking = false, params string[] paths) where T : MesEntityBase, new() + { + return this.Repository.GetEntities(expression, filter, isTracking, paths); + } + + /// + /// 获取所有数据 + /// + /// 类型 + /// 排序 + /// lambd表达式 + /// 过滤器 + /// 需要关联查询的数据 + /// + public IEnumerable GetOrderEntities(Expression> expression, + BaseFilter filter, Action> orderBy, params string[] paths) + where T : MesEntityBase, new() + { + return this.Repository.GetOrderEntities(expression, filter, null, orderBy, false, paths); + } + + /// + /// 获取所有数据 + /// + /// 类型 + /// lambd表达式 + /// 过滤器 + /// 需要关联查询的数据 + /// + public IEnumerable GetOrderEntities + (Expression> expression, BaseFilter filter, params string[] paths) where T : MesEntityBase, new() + { + return this.GetOrderEntities(expression, filter, new Dictionary(), paths); + } + + public IEnumerable GetOrderEntities(Expression> expression, + BaseFilter filter, Action> orderBy, bool isTracking = false, params string[] paths) where T : MesEntityBase, new() + { + return this.Repository.GetOrderEntities(expression, filter, null, orderBy, isTracking, paths); + } + + /// + /// 排序获取数据 + /// + /// + /// + /// + /// + /// + /// + /// + public IEnumerable GetOrderEntities(Expression> expression, BaseFilter filter, + string sort, string order, params string[] paths) where T : MesEntityBase, new() + { + Dictionary orders = new Dictionary(); + if (!string.IsNullOrEmpty(sort)) + orders[sort] = order; + return this.GetOrderEntities(expression, filter, orders, paths); + } + /// + /// 排序获取数据 + /// + /// + /// + /// + /// + /// + /// + /// + public IEnumerable GetOrderEntities(Expression> expression, BaseFilter filter, + Dictionary orders, params string[] paths) where T : MesEntityBase, new() + { + return this.GetOrderEntities(expression, filter, orders, null, false, paths); + } + public IEnumerable GetOrderEntities(Expression> expression, BaseFilter filter, + bool isTracking = false, params string[] paths) where T : MesEntityBase, new() + { + return this.GetOrderEntities(expression, filter, null, null, isTracking, paths); + } + + public IEnumerable GetOrderEntities(Expression> expression, + BaseFilter filter, Dictionary orders, Action> orderBy, bool isTracking = false, params string[] paths) where T : MesEntityBase, new() + { + return this.Repository.GetOrderEntities(expression, filter, orders, orderBy, isTracking, paths); + } + + public PagedResultDto GetOrderPageEntities(Expression> expression, BasePageFilter pageFilter, + Action> orderBy, + params string[] paths) where T : MesEntityBase, new() + { + return this.GetOrderPageEntities(expression, pageFilter, null, 0, 0, orderBy, false, paths); + } + public PagedResultDto GetPageEntities(Expression> expression, BasePageFilter pageFilter, + params string[] paths) where T : MesEntityBase, new() + { + return this.Repository.GetPageEntities(expression, pageFilter, paths); + } + + public PagedResultDto GetOrderPageEntities(Expression> expression, BasePageFilter pageFilter, + params string[] paths) where T : MesEntityBase, new() + { + return this.GetOrderPageEntities(expression, pageFilter, 0, 0, paths); + } + public PagedResultDto GetOrderPageEntities(Expression> expression, BasePageFilter pageFilter, + int pageSize, int startIndex, + params string[] paths) where T : MesEntityBase, new() + { + return this.GetOrderPageEntities(expression, pageFilter, pageSize, startIndex, (!pageFilter?.IsNoTranking) ?? true, paths); + } + public PagedResultDto GetOrderPageEntities(Expression> expression, BasePageFilter pageFilter, + int pageSize, int startIndex, bool isTracking = false, + params string[] paths) where T : MesEntityBase, new() + { + return this.Repository.GetOrderPageEntities(expression, pageFilter, pageSize, startIndex, isTracking, paths); + } + + public IEnumerable> GetTreeOrderEntities(Expression> expression, BaseFilter filter, bool isTracking = false, + params string[] paths) where T : TreeEntityBase, new() + { + return this.Repository.GetTreeOrderEntities(expression, filter, isTracking, paths); + + } + + public IEnumerable GetTree(string id, bool containCurrent = true, BaseFilter filter = null, + params string[] paths) where T : TreeEntityBase, new() + { + return this.Repository.GetTree(id, containCurrent, filter, paths); + } + public PagedResultDto GetOrderPageEntities(Expression> expression, BasePageFilter pageFilter, + Dictionary orders, + int pageSize, int startIndex, bool isTracking = false, + params string[] paths) where T : MesEntityBase, new() + { + return this.Repository.GetOrderPageEntities(expression, pageFilter, orders, pageSize, startIndex, isTracking, paths); + } + public PagedResultDto GetOrderPageEntities(Expression> expression, BasePageFilter pageFilter, + Dictionary orders, + int pageSize, int startIndex, Action> orderBy, bool isTracking = false, + params string[] paths) where T : MesEntityBase, new() + { + return this.Repository.GetOrderPageEntities(expression, pageFilter, orders, 0, 0, orderBy, isTracking, paths); + } + + public PagedResultDto GetOrderPageEntities(Expression> expression, BasePageFilter pageFilter, string[] selectField, + params string[] paths) where T : MesEntityBase, new() + { + return this.Repository.GetOrderPageEntities(expression, pageFilter, selectField, paths); + } + + + + + public async Task> GetOrderPageEntitiesSync(Expression> expression, BasePageFilter pageFilter, + params string[] paths) where T : MesEntityBase, new() + { + return await this.GetOrderPageEntitiesSync(expression, pageFilter, 0, 0, paths); + } + public async Task> GetOrderPageEntitiesSync(Expression> expression, BasePageFilter pageFilter, + int pageSize, int startIndex, + params string[] paths) where T : MesEntityBase, new() + { + return await this.GetOrderPageEntitiesSync(expression, pageFilter, pageSize, startIndex, false, paths); + } + public async Task> GetOrderPageEntitiesSync(Expression> expression, BasePageFilter pageFilter, + int pageSize, int startIndex, bool isTracking = false, + params string[] paths) where T : MesEntityBase, new() + { + return await this.Repository.GetOrderPageEntitiesSync(expression, pageFilter, pageSize, startIndex, isTracking, paths); + } + public async Task> GetOrderPageEntitiesSync(Expression> expression, BasePageFilter pageFilter, + Dictionary orders, + int pageSize, int startIndex, bool isTracking = false, + params string[] paths) where T : MesEntityBase, new() + { + return await this.Repository.GetOrderPageEntitiesSync(expression, pageFilter, orders, pageSize, startIndex, isTracking, paths); + } + public async Task> GetOrderPageEntitiesSync(Expression> expression, BasePageFilter pageFilter, + Dictionary orders, + int pageSize, int startIndex, Action> orderBy, bool isTracking = false, + params string[] paths) where T : MesEntityBase, new() + { + return await this.Repository.GetOrderPageEntitiesSync(expression, pageFilter, orders, pageSize, startIndex, orderBy, isTracking, paths); + } + public async Task> GetOrderPageEntitiesSync(Expression> expression, BasePageFilter pageFilter, + Action> orderBy, + params string[] paths) where T : MesEntityBase, new() + { + + return await this.Repository.GetOrderPageEntitiesSync(expression, pageFilter, null, 0, 0, orderBy, false, paths); + } + + public int Count(Expression> expression, BaseFilter filter) where T : MesEntityBase, new() + { + return this.Repository.GetCount(expression, filter); + } + + public bool IsAny(Expression> expression, BaseFilter filter) where T : MesEntityBase, new() + { + return this.Repository.IsAny(expression, filter); + } + public int Count(Expression> expression) where T : MesEntityBase, new() + { + return this.Count(expression, null); + } + + + /// + /// 提交事务 + /// + /// 提交方法 + protected void WitCommitTransaction(Action comitAction) + { + try + { + + UnitOfWork.BeginTransaction(); + comitAction(); + UnitOfWork.CommitTransaction(); + } + catch + { + try + { + UnitOfWork.RollbackTransaction(); + } + catch (Exception ex) + { + LoggerManager.GetLogger().Info("rollback Error" + ex.ToString()); + } + throw; + } + } + + public T AddAndGetEntity_noneBase(T entity) where T : class + { + return this.Repository.AddAndGetEntity_noneBase(entity); + } + + public void AddEntities_noneBase(IEnumerable entities) where T : class + { + this.Repository.AddEntities_noneBase(entities); + } + + public void UpdateEntities_noneBase(IEnumerable entities) where T : class + { + if (entities != null && entities.Any()) + this.Repository.UpdateEntities_noneBase(entities); + } + + public T GetEntity_noneBase(Expression> expressions) where T : class + { + return this.Repository.GetEntity_noneBase(expressions); + } + + public List GetEntities_noneBase(Expression> expressions) where T : class + { + return this.Repository.GetEntities_noneBase(expressions); + } + + public bool DeleteEntity_noneBase(Expression> expression) where T : class + { + Repository.DeleteEntity_noneBase(expression); + return true; + } + + #region nocomit + public bool AddEntityNoCommit(T entity) where T : MesEntityBase, new() + { + this.Repository.AddEntityNoCommit(entity); + return true; + } + + public bool BantchAddEntityNoCommit(IEnumerable entities) where T : MesEntityBase, new() + { + this.Repository.AddEntitiesNoCommit(entities); + return true; + } + /// + /// 逻辑删除 + /// + /// + /// + public bool DeleteEntityNoCommit(Guid id) where T : MesEntityBase, new() + { + this.Repository.DeleteEntityNoCommit(id); + return true; + } + /// + /// 逻辑删除 + /// + /// + /// + public bool DeleteEntityNoCommit(Expression> predicate) where T : MesEntityBase, new() + { + this.Repository.DeleteEntityNoCommit(predicate); + return true; + } + /// + /// 逻辑删除 + /// + /// + /// + public bool DeleteEntityNoCommit(IEnumerable entities) where T : MesEntityBase, new() + { + this.Repository.DeleteEntitiesNoCommit(entities); + return true; + } + + /// + /// 逻辑批量删除 + /// + /// + /// + /// + public bool BantchDeleteEntityNoCommit(List ids) where T : MesEntityBase, new() + { + if (ids == null || !ids.Any()) return false; + this.Repository.DeleteEntityNoCommit(t => ids.Contains(t.ID)); + return true; + } + + /// + /// 逻辑删除 + /// + /// + /// + public bool DeleteEntityNoCommit(T entity) where T : MesEntityBase, new() + { + this.Repository.DeleteEntityNoCommit(entity); + return true; + } + + /// + /// 更新 + /// + /// 实体 + /// 是否成功 + public bool UpdateEntityNoCommit(T entity) where T : MesEntityBase, new() + { + this.Repository.UpdateEntityNoCommit(entity); + return true; + } + + /// + /// 批量更新 + /// + /// 实体集合 + /// 是否成功 + public bool BantchUpdateEntityNoCommit(IEnumerable entities) where T : MesEntityBase, new() + { + this.Repository.UpdateEntitiesNoCommit(entities); + return true; + } + + /// + /// 批量更新 + /// + /// 实体集合 + /// 是否成功 + public bool BantchUpdateEntityNoCommit(IEnumerable entities, params string[] updateField) where T : MesEntityBase, new() + { + this.Repository.UpdateEntitiesNoCommit(entities, updateField); + return true; + } + + /// + /// 更新 + /// + /// 实体 + /// 是否成功 + public bool UpdateEntityNoCommit(T entity, params string[] updateField) where T : MesEntityBase, new() + { + this.Repository.UpdateEntityNoCommit(entity, updateField); + return true; + } + + + /// + /// 批量更新(新增和保存一起)速度慢 + /// + /// 实体集合 + /// 是否成功 + public bool BantchSaveEntityNoCommit(IEnumerable entities) where T : MesEntityBase, new() + { + this.Repository.SaveEntitiesNoCommit(entities); + return true; + } + /// + /// 统一提交 + /// + /// 数据库方法 + public void UnifiedCommit(Action comitAction) + { + try + { + + comitAction(); + UnitOfWork.SaveChanges(); + } + catch (Exception ex) + { + LoggerManager.GetLogger().Info("rollback Error" + ex.ToString()); + throw; + } + } + /// + /// 批量添加实体 + /// + /// 实体集合 + /// + public bool TreeBantchAddEntityNoCommit(IEnumerable entities) where T : TreeEntityBase, new() + { + return this.BantchAddEntityNoCommit(entities); + + } + /// + /// 添加实体 + /// + /// + /// + public bool TreeAddEntityNoCommit(T entity) where T : TreeEntityBase, new() + { + return this.AddEntityNoCommit(entity); + } + + public T TreeAddAndGetEntityNoCommit(T entity) where T : MesEntityBase, new() + { + return this.AddAndGetEntityNoCommit(entity); + } + public T AddAndGetEntityNoCommit(T entity) where T : MesEntityBase, new() + { + return this.Repository.AddAndGetEntityNoCommit(entity); + } + /// + /// 删除实体 + /// + /// + /// + public bool TreeDeleteEntityNoCommit(Guid id) where T : TreeEntityBase, new() + { + return this.DeleteEntityNoCommit(id); + + } + + /// + /// 删除实体 + /// + /// + /// + public bool TreeDeleteEntityNoCommit(Expression> expression) where T : TreeEntityBase, new() + { + return this.DeleteEntityNoCommit(expression); + } + /// + /// 删除实体 + /// + /// + /// + public bool TreeDeleteEntityNoCommit(IEnumerable entity) where T : TreeEntityBase, new() + { + return this.DeleteEntityNoCommit(entity); + } + /// + /// 删除实体 + /// + /// + /// + /// + public bool TreeDeleteEntityNoCommit(T entity) where T : TreeEntityBase, new() + { + return this.DeleteEntityNoCommit(entity); + } + + /// + /// 逻辑批量删除 + /// + /// + /// + /// + public bool TreeBantchDeleteEntityNoCommit(List ids) where T : TreeEntityBase, new() + { + return this.BantchDeleteEntityNoCommit(ids); + } + /// + /// 更新实体 + /// + /// + /// + public bool TreeUpdateEntityNoCommit(T entity) where T : TreeEntityBase, new() + { + return this.UpdateEntityNoCommit(entity); + } + + /// + /// 批量更新实体 + /// + /// 实体集 + /// + public bool TreeBantchUpdateEntityNoCommit(IEnumerable entities) where T : TreeEntityBase, new() + { + return this.BantchUpdateEntityNoCommit(entities); + } + /// + /// 批量保存实体 + /// + /// 批量保存 + /// + public bool TreeBantchSaveEntityNoCommit(IEnumerable entities) where T : TreeEntityBase, new() + { + return this.BantchSaveEntityNoCommit(entities); + } + + /// + /// 根据数据库连接新增数据 + /// + /// + /// 实体数据 + /// 加密连接 + public void AddEntityByConn(T entity, string conn) where T : MesEntityBase, new() + { + this.Repository.AddEntityByConn(entity, conn); + } + + /// + /// 根据数据库连接更新数据 + /// + /// + /// 实体数据集合 + /// 加密连接 + public void UpdateEntitiesByConn(IEnumerable entities, string conn) where T : MesEntityBase, new() + { + this.Repository.UpdateEntitiesByConn(entities, conn); + } + + /// + /// 根据数据库连接更新数据 + /// + /// + /// 实体数据 + /// 加密连接 + /// 更新字段 + public void UpdateEntityByConn(T entity, string conn, params string[] updateField) where T : MesEntityBase, new() + { + this.Repository.UpdateEntityByConn(entity, conn, updateField); + } + + /// + /// 根据数据库连接删除数据 + /// + /// + /// 表达式 + /// 加密连接 + public void DeleteEntityByConn(Expression> expression, string conn) where T : MesEntityBase, new() + { + this.Repository.DeleteEntityByConn(expression, conn); + } + /// + /// 根据数据库连接删除数据 + /// + /// + /// 数据实体 + /// 加密连接 + public void DeleteEntityByConn(T entity, string conn) where T : MesEntityBase, new() + { + this.Repository.DeleteEntityByConn(entity, conn); + } + + /// + /// 根据数据库连接删除数据 + /// + /// + /// 主键 + /// 加密连接 + public void DeleteEntityByConn(Guid id, string conn) where T : MesEntityBase, new() + { + this.Repository.DeleteEntityByConn(id, conn); + } + /// + /// 根据数据库连接删除数据 + /// + /// + /// 数据集合 + /// 加密连接 + public void DeleteEntitiesByConn(IEnumerable entities, string conn) where T : MesEntityBase, new() + { + this.Repository.DeleteEntitiesByConn(entities, conn); + } + /// + /// 根据数据库连接新增数据 + /// + /// + /// 数据集合 + /// 加密连接 + public void AddEntitiesByConn(IEnumerable entities, string conn) where T : MesEntityBase, new() + { + this.Repository.AddEntitiesByConn(entities, conn); + } + + /// + /// 根据数据库连接新增数据 + /// + /// + /// + /// + /// + public void UpdateEntitiesByConn(IEnumerable entities, string conn, params string[] updateField) where T : MesEntityBase, new() + { + this.Repository.UpdateEntitiesByConn(entities, conn, updateField); + } + + //Tenant + + /// + /// 根据数据库连接新增数据 + /// + /// + /// 实体数据 + /// 加密连接 + public void AddEntityByTenant(T entity, string Tenant) where T : MesEntityBase, new() + { + this.Repository.AddEntityByTenant(entity, Tenant); + } + + /// + /// 根据数据库连接更新数据 + /// + /// + /// 实体数据集合 + /// 加密连接 + public void UpdateEntitiesByTenant(IEnumerable entities, string Tenant) where T : MesEntityBase, new() + { + this.Repository.UpdateEntitiesByTenant(entities, Tenant); + } + + /// + /// 根据数据库连接更新数据 + /// + /// + /// 实体数据 + /// 加密连接 + /// 更新字段 + public void UpdateEntityByTenant(T entity, string Tenant, params string[] updateField) where T : MesEntityBase, new() + { + this.Repository.UpdateEntityByTenant(entity, Tenant, updateField); + } + + /// + /// 根据数据库连接删除数据 + /// + /// + /// 表达式 + /// 加密连接 + public void DeleteEntityByTenant(Expression> expression, string Tenant) where T : MesEntityBase, new() + { + this.Repository.DeleteEntityByTenant(expression, Tenant); + } + /// + /// 根据数据库连接删除数据 + /// + /// + /// 数据实体 + /// 加密连接 + public void DeleteEntityByTenant(T entity, string Tenant) where T : MesEntityBase, new() + { + this.Repository.DeleteEntityByTenant(entity, Tenant); + } + + /// + /// 根据数据库连接删除数据 + /// + /// + /// 主键 + /// 加密连接 + public void DeleteEntityByTenant(Guid id, string Tenant) where T : MesEntityBase, new() + { + this.Repository.DeleteEntityByTenant(id, Tenant); + } + /// + /// 根据数据库连接删除数据 + /// + /// + /// 数据集合 + /// 加密连接 + public void DeleteEntitiesByTenant(IEnumerable entities, string Tenant) where T : MesEntityBase, new() + { + this.Repository.DeleteEntitiesByTenant(entities, Tenant); + } + /// + /// 根据数据库连接新增数据 + /// + /// + /// 数据集合 + /// 加密连接 + public void AddEntitiesByTenant(IEnumerable entities, string Tenant) where T : MesEntityBase, new() + { + this.Repository.AddEntitiesByTenant(entities, Tenant); + } + + /// + /// 根据数据库连接新增数据 + /// + /// + /// + /// + /// + public void UpdateEntitiesByTenant(IEnumerable entities, string Tenant, params string[] updateField) where T : MesEntityBase, new() + { + this.Repository.UpdateEntitiesByTenant(entities, Tenant, updateField); + } + + #endregion + } + +} diff --git a/APT.Infrastructure.Api/Service/DomainServiceBase.cs b/APT.Infrastructure.Api/Service/DomainServiceBase.cs new file mode 100644 index 0000000..9d74321 --- /dev/null +++ b/APT.Infrastructure.Api/Service/DomainServiceBase.cs @@ -0,0 +1,803 @@ +using APT.Infrastructure.Core; +using Microsoft.Data.SqlClient; +using Microsoft.EntityFrameworkCore.Storage; +//using MySql.Data.MySqlClient; +//using Npgsql; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Data; +using System.Data.Common; +using System.Linq; +using System.Text; +namespace APT.Infrastructure.Api +{ + + /// + /// 领域服务基类 + /// + /// 领域实体仓储对象 + /// 领域实体 + /// 领域实体主键类型 + public class DomainServiceBase : IDomainService + { + private IUnitOfWork _unitOfWork; + public DomainServiceBase(IUnitOfWork unitOfWork) + { + _unitOfWork = unitOfWork; + } + + #region properties + + protected IUnitOfWork UnitOfWork { get { return _unitOfWork; } } + + + #endregion + + #region methods + + public void ThrowError(string code, params object[] objs) + { + LibMessageUtils.ThrowError(code, objs); + } + /// + /// 对数据库执行给定的 DDL/DML 命令。 + /// + /// 命令字符串 + /// 参数 + /// 受影响的行数 + public int ExecuteSqlCommand(string sql, params object[] parameters) + { + return this.UnitOfWork.ExecuteSqlCommand(sql, parameters); + } + /// + /// 对数据库执行给定的 DDL/DML 命令。 + /// + /// 事务行为 + /// 命令字符串 + /// 参数 + /// 受影响的行数 + public int ExecuteSqlCommand(TransactionalBehavior transactionalBehavior, string sql, params object[] parameters) + { + return this.UnitOfWork.ExecuteSqlCommand(transactionalBehavior, sql, parameters); + } + + /// + /// 对数据库执行给定的 DDL/DML 命令返回reader。 + /// + /// 命令字符串 + /// reader委托 + public void ExecuteReader(string sql, ReaderColumn[] readerColumns, Action readerAction) + { + this.UnitOfWork.ExecuteReader(sql, readerColumns, readerAction); + } + + /// + /// 对数据库执行给定的 DDL/DML 命令返回reader。 + /// + /// 命令字符串 + /// 参数 + /// reader委托 + public void ExecuteReader(string sql, ReaderColumn[] readerColumns, DbParameter[] parameters, Action readerAction) + { + this.UnitOfWork.ExecuteReader(sql, readerColumns,parameters, readerAction); + } + + /// + /// 对数据库执行给定的 DDL/DML 命令返回reader。 + /// + /// 命令类型 + /// 命令字符串 + /// 参数 + /// reader委托 + public void ExecuteReader(CommandType commandType, string sql, ReaderColumn[] readerColumns, DbParameter[] parameters, Action readerAction) + { + this.UnitOfWork.ExecuteReader(commandType, sql,readerColumns, parameters, readerAction); + } + + + + /// + /// 创建一个原始 SQL 查询,该查询将返回给定泛型类型的元素。 + /// + /// 查询所返回对象的类型 + /// SQL 查询字符串 + /// 要应用于 SQL 查询字符串的参数 + /// + //public IEnumerable SqlQuery(string sql, params object[] parameters) + //{ + // return this.UnitOfWork.SqlQuery(sql, parameters); + //} + + /// + /// 创建一个原始 SQL 查询,该查询将返回给定类型的元素。 + /// + /// 查询所返回对象的类型 + /// SQL 查询字符串 + /// 要应用于 SQL 查询字符串的参数 + /// + public IEnumerable SqlQuery(Type elementType, string sql, ReaderColumn[] readerColumns, params Object[] parameters) + { + return this.UnitOfWork.SqlQuery(elementType, sql, readerColumns, parameters); + } + + /// + /// 获取数据库连接对象 + /// + /// 数据库类型 + /// 连接字符串 + public DbConnection InitDbConnection(DataBaseType dataBaseType, string connString) + { + var conn = GetDbConnection(dataBaseType, connString); + if (conn == null) + throw new Exception("连接失败"); + return conn; + } + /// + /// 对数据库执行给定的 DDL/DML 命令。 + /// + /// 命令类型 + /// 命令字符串 + /// 参数 + /// + public int ExecuteNonQuery(CommandType commandType, string sql, ReaderColumn[] readerColumns, DbParameter[] parameters) + { + return this.UnitOfWork.ExecuteNonQuery(commandType, sql, readerColumns, parameters); + } + + /// + /// 根据数据库连接对数据库执行给定的 DDL/DML 命令。 + /// + /// 数据库类型 + /// 连接字符串 + /// sql 类型 + /// sql + /// 参数 + public void ExecuteNonQueryByConn(DataBaseType dataBaseType, string connString, CommandType commandType, string sql, DbParameter[] dbParameters) + { + var conn = GetDbConnection(dataBaseType, connString); + ExecuteNonQueryByConn(dataBaseType, conn, commandType, sql, dbParameters); + + } + + + public void ExecuteNonQueryByConn(DataBaseType dataBaseType, DbConnection conn, CommandType commandType, string sql, DbParameter[] dbParameters, bool close = true) + { + try + { + if (conn.State == ConnectionState.Closed) + conn.Open(); + if (conn != null) + { + var cmd = GetDbCommand(dataBaseType, conn, sql, dbParameters); + if (cmd != null) + { + cmd.CommandType = commandType; + cmd.ExecuteNonQuery(); + } + } + } + finally + { + if (close && conn != null) + conn.Dispose(); + } + } + + /// + /// 根据数据库连接对数据库执行给定的 DDL/DML 命令获取Reader。 + /// + /// 数据库类型 + /// 连接字符串 + /// sql 类型 + /// sql + /// 参数 + /// 执行委托 + public void ExecuteReaderByConn(DataBaseType dataBaseType, string connString, CommandType commandType, + string sql, DbParameter[] dbParameters, Action readerAction) + { + var conn = GetDbConnection(dataBaseType, connString); + try + { + conn.Open(); + if (conn != null) + { + var cmd = GetDbCommand(dataBaseType, conn, sql, dbParameters); + if (cmd != null) + { + cmd.CommandType = commandType; + using (var reader = cmd.ExecuteReader()) + { + if (readerAction != null) + readerAction(reader); + } + } + } + } + finally + { + if (conn != null) + conn.Dispose(); + } + } + + /// + /// 执行查询,并返回查询所返回的结果集中第一行的第一列。 所有其他的列和行将被忽略。 + /// + /// 数据库类型 + /// 连接字符串 + /// sql 类型 + /// sql + /// 参数 + public object ExecuteScalarByConn(DataBaseType dataBaseType, string connString, CommandType commandType, string sql, DbParameter[] dbParameters) + { + var conn = GetDbConnection(dataBaseType, connString); + try + { + + conn.Open(); + if (conn != null) + { + var cmd = GetDbCommand(dataBaseType, conn, sql, dbParameters); + if (cmd != null) + { + cmd.CommandType = commandType; + var ret = cmd.ExecuteScalar(); + return ret; + } + } + } + finally + { + if (conn != null) + conn.Dispose(); + } + return null; + } + + /// + /// 执行查询,并返回查询所返回的结果集中第一行的第一列。 所有其他的列和行将被忽略。 + /// + /// 数据库类型 + /// 数据库连接对象 + /// sql 类型 + /// sql + /// 是否自动关闭连接 + /// 参数 + public object ExecuteScalarByConn(DataBaseType dataBaseType, DbConnection conn, CommandType commandType, + string sql, bool close = true, params DbParameter[] dbParameters) + { + //var conn = GetDbConnection(dataBaseType, connString); + if (conn == null) + throw new Exception("数据库连接对象不能为空"); + try + { + if (conn.State == ConnectionState.Closed) + conn.Open(); + if (conn != null) + { + var cmd = GetDbCommand(dataBaseType, conn, sql, dbParameters); + if (cmd != null) + { + cmd.CommandType = commandType; + var ret = cmd.ExecuteScalar(); + return ret; + } + } + } + finally + { + if (close) + { + if (conn != null) + conn.Dispose(); + } + + } + return null; + } + + /// + /// 根据数据库连接对数据库执行给定的 DDL/DML 命令获取Reader。 + /// + /// 数据库类型 + /// 连接对象 + /// 指令类型 + /// SQL语句 + /// 参数 + /// 委托 + /// 是否自动关闭连接 + public void ExecuteReaderByConn(DataBaseType dataBaseType, DbConnection conn, CommandType commandType, + string sql, DbParameter[] dbParameters, Action readerAction, bool close = true) + { + //var conn = GetDbConnection(dataBaseType, connString); + try + { + if (conn.State == ConnectionState.Closed) + conn.Open(); + if (conn != null) + { + var cmd = GetDbCommand(dataBaseType, conn, sql, dbParameters); + if (cmd != null) + { + cmd.CommandType = commandType; + using (var reader = cmd.ExecuteReader()) + { + if (readerAction != null) + readerAction(reader); + } + } + } + } + finally + { + if (close) + { + if (conn != null) + conn.Dispose(); + } + } + } + + + /// + /// 根据数据库连接对数据库执行给定的 DDL/DML 命令获取Reader。 + /// + /// 数据库类型 + /// 连接字符串 + /// sql 类型 + /// sql + /// 参数 + /// 分页索引 从1开始 + /// 每页条数 必填 + /// 执行委托 + public void ExecuteReaderPageByConn(DataBaseType dataBaseType, string connString, CommandType commandType, + string sql, DbParameter[] dbParameters, int pageIndex, int pageLimit, Action readerAction) + { + if (pageLimit == 0) + throw new Exception("请填写每页条数"); + if (pageIndex <= 0) + pageIndex = 1; + + int start = (pageIndex - 1) * pageLimit; + int end = pageIndex * pageLimit; + if (dataBaseType == DataBaseType.Oracle) + { + sql = string.Format(@"SELECT* FROM(SELECT A.*, ROWNUM RN FROM({0}) A WHERE ROWNUM <= {2}) WHERE RN >= {1}", sql, start, end); + } + else if (dataBaseType == DataBaseType.Postgresql) + { + sql = $"{sql} LIMIT {pageLimit} OFFSET {start}"; + } + else + { + throw new Exception("不支持的数据库类型"); + } + + var conn = GetDbConnection(dataBaseType, connString); + try + { + conn.Open(); + if (conn != null) + { + + var cmd = GetDbCommand(dataBaseType, conn, sql, dbParameters); + if (cmd != null) + { + cmd.CommandType = commandType; + using (var reader = cmd.ExecuteReader()) + { + if (readerAction != null) + readerAction(reader); + } + } + } + } + finally + { + if (conn != null) + conn.Dispose(); + } + } + + + /// + /// 根据数据库连接对数据库执行给定的 DDL/DML 命令获取Reader。 + /// + /// 数据库类型 + /// 连接对象 + /// sql 类型 + /// sql + /// 参数 + /// 分页索引 从1开始 + /// 每页条数 必填 + /// 执行委托 + /// 是否自动关闭连接 + public void ExecuteReaderPageByConn(DataBaseType dataBaseType, DbConnection conn, CommandType commandType, + string sql, DbParameter[] dbParameters, int pageIndex, int pageLimit, Action readerAction + , bool close = true) + { + if (conn == null) + throw new Exception("数据库连接对象不能为空"); + if (pageLimit == 0) + throw new Exception("请填写每页条数"); + if (pageIndex <= 0) + pageIndex = 1; + int start = (pageIndex - 1) * pageLimit; + int end = pageIndex * pageLimit; + if (dataBaseType == DataBaseType.Oracle) + { + if (pageIndex <= 0) + pageIndex = 1; + + sql = string.Format(@"SELECT* FROM(SELECT A.*, ROWNUM RN FROM({0}) A WHERE ROWNUM <= {2}) WHERE RN >= {1}", sql, start, end); + } + + else if (dataBaseType == DataBaseType.Postgresql) + { + sql = $"{sql} LIMIT {pageLimit} OFFSET {start}"; + } + else + { + throw new Exception("不支持的数据库类型"); + } + //var conn = GetDbConnection(dataBaseType, connString); + try + { + if (conn.State == ConnectionState.Closed) + conn.Open(); + if (conn != null) + { + var cmd = GetDbCommand(dataBaseType, conn, sql, dbParameters); + if (cmd != null) + { + cmd.CommandType = commandType; + using (var reader = cmd.ExecuteReader()) + { + if (readerAction != null) + readerAction(reader); + } + } + } + } + finally + { + if (close) + { + if (conn != null) + conn.Dispose(); + } + } + } + + + /// + /// 根据数据库连接对数据库执行给定的 DDL/DML 命令获取数据总条数。 + /// + /// 数据库类型 + /// 连接字符串 + /// sql 类型 + /// sql + /// 参数 + /// 数据总条数 + public int GetSqlCountByConn(DataBaseType dataBaseType, string connString, CommandType commandType, + string sql, DbParameter[] dbParameters) + { + if (dataBaseType == DataBaseType.Oracle) + { + sql = string.Format(@"SELECT Max(RN) As SQLCOUNT FROM(SELECT A.*, ROWNUM RN FROM({0}) A )", sql); + } + + else if (dataBaseType == DataBaseType.Postgresql) + { + sql = $"SELECT COUNT(1) FROM({sql}) A"; + } + else + { + throw new Exception("不支持的数据库类型"); + } + int result = 0; + var conn = GetDbConnection(dataBaseType, connString); + try + { + conn.Open(); + if (conn != null) + { + + var cmd = GetDbCommand(dataBaseType, conn, sql, dbParameters); + if (cmd != null) + { + cmd.CommandType = commandType; + using (var reader = cmd.ExecuteReader()) + { + while (reader.Read()) + { + object tmp = reader.GetValue(0); + if (tmp != null) + result = Convert.ToInt32(tmp); + } + } + } + } + } + finally + { + if (conn != null) + conn.Dispose(); + } + return result; + } + + private const string RuleCode_ORACLE_SQL = @"select a.ID,a.serial,b.TAKE_RETAIN_MIN,a.ROW_VERSION from t_pf_code_rule_serial a +inner join T_PF_CODE_RULE b on a.code_type = b.code_type and a.org_id = b.org_id +and b.ENABLE_STATUS = 0 + where a.CODE_TYPE = '{0}' and rownum <= '{1}' and (b.IS_IGNORE_DATE = 1 or(b.IS_IGNORE_DATE = 0 and a.DATE_VALUE = '{2}')) + and a.Org_Id = '{3}' and + a.STATUS = 0 + order by a.num "; + + private const string RuleCode_MYSQL_SQL = @"select a.ID,a.serial,b.TAKE_RETAIN_MIN,a.ROW_VERSION from t_pf_code_rule_serial a +inner join T_PF_CODE_RULE b on a.code_type = b.code_type and a.org_id = b.org_id +and b.ENABLE_STATUS = 0 + where a.CODE_TYPE = '{0}' and (b.IS_IGNORE_DATE = 1 or(b.IS_IGNORE_DATE = 0 and a.DATE_VALUE = '{2}')) + and a.Org_Id = '{3}' and + a.STATUS = 0 + order by a.num limit {1}"; + + private const string RuleCode_SQL_SERVER_SQL = @"select top {1} a.ID,a.serial,b.TAKE_RETAIN_MIN,a.ROW_VERSION from t_pf_code_rule_serial a +inner join T_PF_CODE_RULE b on a.code_type = b.code_type and a.org_id = b.org_id +and b.ENABLE_STATUS = 0 + where a.CODE_TYPE = '{0}' and (b.IS_IGNORE_DATE = 1 or(b.IS_IGNORE_DATE = 0 and a.DATE_VALUE = '{2}')) + and a.Org_Id = '{3}' and + a.STATUS = 0 + order by a.num "; + private const string RuleCode_POSTGRESQL_SQL = @"select a.""ID"",a.""SERIAL"",b.""TAKE_RETAIN_MIN"",a.""ROW_VERSION"" +from ""T_PF_CODE_RULE_SERIAL"" a +inner join ""T_PF_CODE_RULE"" b on a.""CODE_TYPE""=b.""CODE_TYPE"" and a.""ORG_ID""=b.""ORG_ID"" +and b.""ENABLE_STATUS""=0 + where a.""CODE_TYPE""='{0}' and (b.""IS_IGNORE_DATE"" =true or (b.""IS_IGNORE_DATE""=false and a.""DATE_VALUE""='{2}')) + and a.""ORG_ID""='{3}' and + a.""STATUS""='0' + order by a.""NUM"" Limit {1};"; + + public string GetRuleCodes(CodeRuleParam param) + { + if (param == null || param.Count == 0) return null; + var dataBaseType = this.UnitOfWork.GetDataBaseType(); + string orgId = string.Empty; + string codeRuleSql = string.Empty; + string updateSql = string.Empty; + if (param.OrgId.HasValue) + { + switch (dataBaseType) + { + case DataBaseType.Oracle: + { + orgId = BitConverter.ToString(param.OrgId.Value.ToByteArray()).Replace("-", ""); + codeRuleSql = RuleCode_ORACLE_SQL; + } + break; + case DataBaseType.MySQL: + { + codeRuleSql = RuleCode_MYSQL_SQL; + orgId = param.OrgId.Value.ToString().ToLower(); + } + break; + case DataBaseType.Postgresql: + { + codeRuleSql = RuleCode_POSTGRESQL_SQL; + orgId = param.OrgId.Value.ToString().ToLower(); + } + break; + default: + { + codeRuleSql = RuleCode_SQL_SERVER_SQL; + orgId = param.OrgId.Value.ToString().ToUpper(); + } + break; + } + } + var conn = GetDbConnection(dataBaseType, this.UnitOfWork.ConnectionString); + try + { + string date = param.Time.ToString("yyyyMMdd"); + string sql = string.Format(codeRuleSql, param.CodeType, param.Count, date, orgId); + List ruleCodeInfos = new List(); + this.ExecuteReaderByConn(dataBaseType, conn, CommandType.Text, sql, null, (reader) => + { + while (reader.Read()) + { + RuleCodeInfo info = new RuleCodeInfo(); + var obj = reader.GetValue(0); + if (obj != null && obj != DBNull.Value) + { + if (obj is byte[]) + { + var blob = obj as byte[]; + info.ID = BitConverter.ToString(blob).Replace("-", ""); + } + else + { + info.ID = Convert.ToString(obj); + } + } + info.Serial = LibUtils.ToString(reader.GetValue(1));// reader.GetString(0); + info.TaskTimeMin = LibUtils.ToInt(reader.GetValue(2)); + info.RowVersion = LibUtils.ToInt(reader.GetValue(3)); + ruleCodeInfos.Add(info); + } + }, false); + if (ruleCodeInfos.Count < param.Count) + throw new Exception("流水码[" + param.CodeType + "]不足,请联系系统管理员"); + + if (param.IsUpdate) + { + List updateSqls = new List(); + List tempInfos = new List(); + + if (dataBaseType == DataBaseType.Postgresql) + { + + StringBuilder updates = new StringBuilder(); + foreach (var item in ruleCodeInfos) + updates.Append(string.Format(" ('{0}',{1}),", item.ID, item.RowVersion)); + updates.Length--; + updateSqls.Add("create temp table \"T_PF_CODE_RULE_SERIAL_TEMP\" (\"ID\" uuid,\"ROW_VERSION\" integer) ;"); + updateSqls.Add(string.Format("insert into \"T_PF_CODE_RULE_SERIAL_TEMP\" values {0}; ", updates.ToString())); + + + var firstItem = ruleCodeInfos.FirstOrDefault(); + var takeTime = DateTime.Now; + var releaseTime = DateTime.Now.AddMinutes(firstItem.TaskTimeMin == 0 ? 20 : firstItem.TaskTimeMin); + var takeTimeStr = dataBaseType == DataBaseType.Oracle ? + ("to_date('" + takeTime.ToString("yyyy/MM/dd HH:mm:ss") + "','yyyy-mm-dd hh24-mi-ss')") : + ("'" + takeTime.ToString("yyyy-MM-dd HH:mm:ss") + "'"); + var releaseTimeStr = dataBaseType == DataBaseType.Oracle ? + ("to_date('" + releaseTime.ToString("yyyy/MM/dd HH:mm:ss") + "','yyyy-mm-dd hh24-mi-ss')") : + ("'" + releaseTime.ToString("yyyy-MM-dd HH:mm:ss") + "'"); + updateSqls.Add(string.Format(@"Update {4}T_PF_CODE_RULE_SERIAL{4} set {4}STATUS{4}='{0}',{4}TAKE_TIME{4}={1}, +{4}ROW_VERSION{4}={4}ROW_VERSION{4}+1, + {4}RELEASE_TIME{4}={2} where exists (select 1 from ""T_PF_CODE_RULE_SERIAL_TEMP"" a where a.""ID""= ""T_PF_CODE_RULE_SERIAL"".""ID"" + and a.""ROW_VERSION""=""T_PF_CODE_RULE_SERIAL"".""ROW_VERSION"") and {4}STATUS{4}='0';", + 1, takeTimeStr, releaseTimeStr, string.Empty, (dataBaseType == DataBaseType.Postgresql ? "\"" : string.Empty))); + + } + else if (dataBaseType == DataBaseType.Oracle) + { + //创建临时表 + //CREATE GLOBAL TEMPORARY TABLE T_PF_CODE_RULE_SERIAL_TEMP + //(ID RAW(16),ROW_VERSION NUMBER(10)) + //ON COMMIT PRESERVE ROWS; + + StringBuilder updates = new StringBuilder(); + foreach (var item in ruleCodeInfos) + updates.Append(string.Format(" into T_PF_CODE_RULE_SERIAL_TEMP(ID,ROW_VERSION) values ('{0}')", item.ID, item.RowVersion)); + updateSqls.Add(string.Format("insert /*+ nologging */ all {0} SELECT 1 FROM DUAL; ", updates.ToString())); + + var firstItem = ruleCodeInfos.FirstOrDefault(); + var takeTime = DateTime.Now; + var releaseTime = DateTime.Now.AddMinutes(firstItem.TaskTimeMin == 0 ? 20 : firstItem.TaskTimeMin); + var takeTimeStr = "to_date('" + takeTime.ToString("yyyy/MM/dd HH:mm:ss") + "','yyyy-mm-dd hh24-mi-ss')"; + var releaseTimeStr = "to_date('" + releaseTime.ToString("yyyy/MM/dd HH:mm:ss") + "','yyyy-mm-dd hh24-mi-ss')"; + updateSqls.Add(string.Format(@"Update T_PF_CODE_RULE_SERIAL set STATUS={0},TAKE_TIME={1},RELEASE_TIME={2},ROW_VERSION=ROW_VERSION+1 where exists (select 1 from T_PF_CODE_RULE_SERIAL_TEMP a where a.Id= T_PF_CODE_RULE_SERIAL.Id and a.ROW_VERSION=T_PF_CODE_RULE_SERIAL.ROW_VERSION) and STATUS='0';", + 1, takeTimeStr, releaseTimeStr)); + + } + else + { + foreach (var item in ruleCodeInfos) + { + tempInfos.Add(item); + if (tempInfos.Count >= 100) + { + DoGetUpdateCodeRuleSql(dataBaseType, tempInfos, updateSqls); + tempInfos.Clear(); + } + } + DoGetUpdateCodeRuleSql(dataBaseType, tempInfos, updateSqls); + } + StringBuilder sb = new StringBuilder(); + if (dataBaseType != DataBaseType.Postgresql) + sb.AppendLine("begin"); + foreach (var str in updateSqls) + sb.AppendLine(str); + if (dataBaseType != DataBaseType.Postgresql) + sb.AppendLine("end;"); + this.ExecuteNonQueryByConn(dataBaseType, conn, CommandType.Text, sb.ToString(), null, false); + //this.ExecuteNonQuery(CommandType.Text, sb.ToString(), null); + } + return string.Join(",", ruleCodeInfos.Select(t => t.Serial).ToList()); + } + finally + { + if (conn != null) + conn.Dispose(); + } + } + + private void DoGetUpdateCodeRuleSql(DataBaseType dataBaseType, List infos, List updateSqls) + { + if (!infos.Any()) return; + StringBuilder stringBuilder = new StringBuilder(); + foreach (var item in infos) + { + stringBuilder.Append("'" + item.ID + "'"); + stringBuilder.Append(","); + } + stringBuilder.Length--; + var firstItem = infos.FirstOrDefault(); + var takeTime = DateTime.Now; + var releaseTime = DateTime.Now.AddMinutes(firstItem.TaskTimeMin == 0 ? 20 : firstItem.TaskTimeMin); + var takeTimeStr = dataBaseType == DataBaseType.Oracle ? + ("to_date('" + takeTime.ToString("yyyy/MM/dd HH:mm:ss") + "','yyyy-mm-dd hh24-mi-ss')") : + ("'" + takeTime.ToString("yyyy-MM-dd HH:mm:ss") + "'"); + var releaseTimeStr = dataBaseType == DataBaseType.Oracle ? + ("to_date('" + releaseTime.ToString("yyyy/MM/dd HH:mm:ss") + "','yyyy-mm-dd hh24-mi-ss')") : + ("'" + releaseTime.ToString("yyyy-MM-dd HH:mm:ss") + "'"); + updateSqls.Add(string.Format(@"Update {4}T_PF_CODE_RULE_SERIAL{4} set {4}STATUS{4}='{0}',{4}TAKE_TIME{4}={1}, +{4}ROW_VERSION{4}={4}ROW_VERSION{4}+1, + {4}RELEASE_TIME{4}={2} where {4}ID{4} in ({3}) and {4}STATUS{4}='0';", + 1, takeTimeStr, releaseTimeStr, stringBuilder.ToString(), (dataBaseType == DataBaseType.Postgresql ? "\"" : string.Empty))); + } + + class RuleCodeInfo + { + public string ID { get; set; } + public string Serial { get; set; } + public int TaskTimeMin { get; set; } + public int RowVersion { get; set; } + } + + #endregion + + + #region 私有函数 + private DbConnection GetDbConnection(DataBaseType dataBaseType, string connString) + { + switch (dataBaseType) + { + //case DataBaseType.Oracle: + // return new OracleConnection(connString); + //case DataBaseType.MySQL: + // return new MySqlConnection(connString); + //case DataBaseType.Postgresql: + // return new NpgsqlConnection(connString); + } + return new SqlConnection(connString); + } + + private DbCommand GetDbCommand(DataBaseType dataBaseType, DbConnection conn, string sql, DbParameter[] dbParameters) + { + DbCommand command = null; + switch (dataBaseType) + { + case DataBaseType.Oracle: + //command = new OracleCommand(sql, conn as OracleConnection); + break; + //case DataBaseType.MySQL: + // command = new MySqlCommand(sql, conn as MySqlConnection); + // break; + case DataBaseType.SQL: + command = new SqlCommand(sql, conn as SqlConnection); + break; + case DataBaseType.Postgresql: + //command = new NpgsqlCommand(sql, conn as NpgsqlConnection); + break; + } + if (dbParameters != null && dbParameters.Length > 0) + { + foreach (var item in dbParameters) + { + if (item.Value == null) + item.Value = DBNull.Value; + command.Parameters.Add(item); + } + } + return command; + } + + #endregion + + } + +} diff --git a/APT.Infrastructure.Api/Service/ICommonService.cs b/APT.Infrastructure.Api/Service/ICommonService.cs new file mode 100644 index 0000000..fa711ea --- /dev/null +++ b/APT.Infrastructure.Api/Service/ICommonService.cs @@ -0,0 +1,571 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq.Expressions; +using System.Threading.Tasks; +using APT.Infrastructure.Core; +namespace APT.Infrastructure.Api +{ + /// + /// 通用接口,可以调用基类方法 + /// + /// + public partial interface ICommonService : IDomainService + { + IUnitOfWork UnitWork(); + + #region 实体 + /// + /// 查询实体 + /// + /// + /// + /// + /// + T GetEntity(string id, params string[] paths) where T : MesEntityBase, new(); + /// + /// 查询实体 + /// + /// + /// + /// + /// + T GetEntity(Guid id, params string[] paths) where T : MesEntityBase, new(); + /// + /// 查询实体 + /// + /// + /// + /// + /// + T GetEntity(Expression> expression, params string[] paths) where T : MesEntityBase, new(); + /// + /// 查询实体 + /// + /// + /// + /// + /// + T GetEntity(Expression> expression, BaseFilter fiter, params string[] paths) where T : MesEntityBase, new(); + + /// + /// 查询实体 + /// + /// + /// + /// + /// + T GetEntity(Expression> expression, BaseFilter fiter, bool isTracking = false, params string[] paths) where T : MesEntityBase, new(); + + T GetEntityByRedis(string key, Guid orgid) + where T : MesEntityBase, new(); + + T GetEntityByRedis(Guid key, Guid orgid) + where T : MesEntityBase, new(); + + List GetEntitiesByRedis(BaseFilter filter) where T : MesEntityBase, new(); + + List GetEntitiesByGroupRedis(BaseFilter filter, string groupValue) where T : MesEntityBase, new(); + + + List GetEntitiesByRedis(Expression> expression, BaseFilter filter) where T : MesEntityBase, new(); + + List GetEntitiesTableByRedis(Expression> expression, BaseFilter filter, + params string[] paths) where T : MesEntityBase, new(); + + List GetEntitiesByRedis(Expression> expression, BaseFilter filter, string groupValue, + params string[] paths) where T : MesEntityBase, new(); + + PagedResultDto GetOrderPageByRedis(Expression> expression, BasePageFilter pageFilter, + params string[] paths) where T : MesEntityBase, new(); + + IEnumerable GetEntities(Expression> expression, + params string[] paths) where T : MesEntityBase, new(); + IEnumerable GetEntities(Expression> expression, +bool isTracking = false, params string[] paths) where T : MesEntityBase, new(); + IEnumerable GetEntities(Expression> expression, BaseFilter filter, +bool isTracking = false, params string[] paths) where T : MesEntityBase, new(); + /// + /// 获取所有数据 + /// + /// + /// + /// + /// + /// + IEnumerable GetEntities(Expression> expression, BaseFilter filter, params string[] paths) where T : MesEntityBase, new(); + /// + /// 获取所有数据 + /// + /// 类型 + /// 排序 + /// lambd表达式 + /// 过滤器 + /// 需要关联查询的数据 + /// + /// + /// 获取所有数据 + /// + /// 类型 + /// 排序 + /// lambd表达式 + /// 过滤器 + /// 需要关联查询的数据 + /// + IEnumerable GetOrderEntities(Expression> expression, + BaseFilter filter, Action> orderBy, params string[] paths) where T : MesEntityBase, new(); + /// + /// 获取所有数据 + /// + /// 类型 + /// lambd表达式 + /// 过滤器 + /// 需要关联查询的数据 + /// + IEnumerable GetOrderEntities(Expression> expression, BaseFilter filter, params string[] paths) where T : MesEntityBase, new(); + /// + /// 排序获取数据 + /// + /// + /// + /// + /// + /// + /// + /// + IEnumerable GetOrderEntities(Expression> expression, BaseFilter filter, string sort, string order, params string[] paths) where T : MesEntityBase, new(); + /// + /// 排序获取数据 + /// + /// + /// + /// + /// + /// + /// + /// + IEnumerable GetOrderEntities(Expression> expression, BaseFilter filter, Dictionary orders, params string[] paths) where T : MesEntityBase, new(); + + IEnumerable GetOrderEntities(Expression> expression, BaseFilter filter, + bool isTracking = false, params string[] paths) where T : MesEntityBase, new(); + + IEnumerable GetOrderEntities(Expression> expression, + BaseFilter filter, Action> orderBy, bool isTracking = false, params string[] paths) where T : MesEntityBase, new(); + IEnumerable GetOrderEntities(Expression> expression, + BaseFilter filter, Dictionary orders, Action> orderBy, bool isTracking = false, params string[] paths) where T : MesEntityBase, new(); + + PagedResultDto GetPageEntities(Expression> expression, BasePageFilter pageFilter, + params string[] paths) where T : MesEntityBase, new(); + + IEnumerable> GetTreeOrderEntities(Expression> expression, BaseFilter filter, bool isTracking, + params string[] paths) where T : TreeEntityBase, new(); + + PagedResultDto GetOrderPageEntities(Expression> expression, BasePageFilter pageFilter, + params string[] paths) where T : MesEntityBase, new(); + + PagedResultDto GetOrderPageEntities(Expression> expression, BasePageFilter pageFilter, +int pageSize, int startIndex, + params string[] paths) where T : MesEntityBase, new(); + PagedResultDto GetOrderPageEntities(Expression> expression, BasePageFilter pageFilter, +int pageSize, int startIndex, bool isTracking = false, + params string[] paths) where T : MesEntityBase, new(); + PagedResultDto GetOrderPageEntities(Expression> expression, BasePageFilter pageFilter, +Dictionary orders, +int pageSize, int startIndex, bool isTracking = false, + params string[] paths) where T : MesEntityBase, new(); + + IEnumerable GetTree(string id, bool containCurrent = true, BaseFilter filter = null, + params string[] paths) where T : TreeEntityBase, new(); + PagedResultDto GetOrderPageEntities(Expression> expression, BasePageFilter pageFilter, +Dictionary orders, +int pageSize, int startIndex, Action> orderBy, bool isTracking = false, +params string[] paths) where T : MesEntityBase, new(); + + PagedResultDto GetOrderPageEntities(Expression> expression, BasePageFilter pageFilter, string[] selectField, + params string[] paths) where T : MesEntityBase, new(); + // + + Task> GetOrderPageEntitiesSync(Expression> expression, BasePageFilter pageFilter, + params string[] paths) where T : MesEntityBase, new(); + + Task> GetOrderPageEntitiesSync(Expression> expression, BasePageFilter pageFilter, +int pageSize, int startIndex, + params string[] paths) where T : MesEntityBase, new(); + Task> GetOrderPageEntitiesSync(Expression> expression, BasePageFilter pageFilter, +int pageSize, int startIndex, bool isTracking = false, + params string[] paths) where T : MesEntityBase, new(); + Task> GetOrderPageEntitiesSync(Expression> expression, BasePageFilter pageFilter, +Dictionary orders, +int pageSize, int startIndex, bool isTracking = false, + params string[] paths) where T : MesEntityBase, new(); + Task> GetOrderPageEntitiesSync(Expression> expression, BasePageFilter pageFilter, +Dictionary orders, +int pageSize, int startIndex, Action> orderBy, bool isTracking = false, +params string[] paths) where T : MesEntityBase, new(); + + int Count(Expression> expression, BaseFilter filter) where T : MesEntityBase, new(); + bool IsAny(Expression> expression, BaseFilter filter) where T : MesEntityBase, new(); + + int Count(Expression> expression) where T : MesEntityBase, new(); + #endregion + /// + /// 添加实体 + /// + /// + /// + bool AddEntity(T entity) where T : MesEntityBase, new(); + + T AddAndGetEntity(T entity) where T : MesEntityBase, new(); + + /// + /// 删除实体 + /// + /// + /// + bool DeleteEntity(Guid id) where T : MesEntityBase, new(); + + /// + /// 删除实体 + /// + /// + /// + bool DeleteEntity(Expression> expression) where T : MesEntityBase, new(); + /// + /// 删除实体 + /// + /// + /// + bool DeleteEntity(IEnumerable entity) where T : MesEntityBase, new(); + /// + /// 删除实体 + /// + /// + /// + /// + bool DeleteEntity(T entity) where T : MesEntityBase, new(); + + /// + /// 逻辑批量删除 + /// + /// + /// + /// + bool BantchDeleteEntity(List ids) where T : MesEntityBase, new(); + + /// 更新实体 + /// + /// + /// + bool UpdateEntity(T entity) where T : MesEntityBase, new(); + + /// + /// 按字段更新数据 + /// + /// + /// + /// + /// + bool UpdateEntity(T entity, params string[] updateField) where T : MesEntityBase, new(); + /// + ///根据字段批量更新实体 + /// + /// + /// + /// + /// + bool BantchUpdateEntity(IEnumerable entities, params string[] updateField) where T : MesEntityBase, new(); + /// + /// 批量添加实体 + /// + /// 实体集合 + /// + bool BantchAddEntity(IEnumerable entities) where T : MesEntityBase, new(); + + /// + /// 批量更新实体 + /// + /// 实体集 + /// + bool BantchUpdateEntity(IEnumerable entities) where T : MesEntityBase, new(); + /// + /// 批量保存实体 + /// + /// 批量保存 + /// + bool BantchSaveEntity(IEnumerable entities) where T : MesEntityBase, new(); + + + + #region 树实体 + /// + /// 添加实体 + /// + /// + /// + bool TreeAddEntity(T entity) where T : TreeEntityBase, new(); + T TreeAddAndGetEntity(T entity) where T : MesEntityBase, new(); + /// + /// 删除实体 + /// + /// + /// + bool TreeDeleteEntity(Guid id) where T : TreeEntityBase, new(); + + /// + /// 删除实体 + /// + /// + /// + bool TreeDeleteEntity(Expression> expression) where T : TreeEntityBase, new(); + /// + /// 删除实体 + /// + /// + /// + bool TreeDeleteEntity(IEnumerable entity) where T : TreeEntityBase, new(); + /// + /// 删除实体 + /// + /// + /// + /// + bool TreeDeleteEntity(T entity) where T : TreeEntityBase, new(); + + /// + /// 逻辑批量删除 + /// + /// + /// + /// + bool TreeBantchDeleteEntity(List ids) where T : TreeEntityBase, new(); + + + /// + /// 更新实体 + /// + /// + /// + bool TreeUpdateEntity(T entity) where T : TreeEntityBase, new(); + + /// + /// 批量添加实体 + /// + /// 实体集合 + /// + bool TreeBantchAddEntity(IEnumerable entities) where T : TreeEntityBase, new(); + + /// + /// 批量更新实体 + /// + /// 实体集 + /// + bool TreeBantchUpdateEntity(IEnumerable entities) where T : TreeEntityBase, new(); + /// + /// 批量保存实体 + /// + /// 批量保存 + /// + bool TreeBantchSaveEntity(IEnumerable entities) where T : TreeEntityBase, new(); + + /// + /// 批量添加实体 + /// + /// 实体集合 + /// + public bool TreeBantchAddEntityNoCommit(IEnumerable entities) where T : TreeEntityBase, new() + { + return this.BantchAddEntityNoCommit(entities); + + } + /// + /// 添加实体 + /// + /// + /// + public bool TreeAddEntityNoCommit(T entity) where T : TreeEntityBase, new() + { + return this.AddEntityNoCommit(entity); + } + + public T TreeAddAndGetEntityNoCommit(T entity) where T : MesEntityBase, new() + { + return this.AddAndGetEntityNoCommit(entity); + } + T AddAndGetEntityNoCommit(T entity) where T : MesEntityBase, new(); + /// + /// 删除实体 + /// + /// + /// + bool TreeDeleteEntityNoCommit(Guid id) where T : TreeEntityBase, new(); + + + /// + /// 删除实体 + /// + /// + /// + bool TreeDeleteEntityNoCommit(Expression> expression) where T : TreeEntityBase, new(); + /// + /// 删除实体 + /// + /// + /// + bool TreeDeleteEntityNoCommit(IEnumerable entity) where T : TreeEntityBase, new(); + /// + /// 删除实体 + /// + /// + /// + /// + bool TreeDeleteEntityNoCommit(T entity) where T : TreeEntityBase, new(); + + /// + /// 逻辑批量删除 + /// + /// + /// + /// + bool TreeBantchDeleteEntityNoCommit(List ids) where T : TreeEntityBase, new(); + /// + /// 更新实体 + /// + /// + /// + bool TreeUpdateEntityNoCommit(T entity) where T : TreeEntityBase, new(); + + /// + /// 批量更新实体 + /// + /// 实体集 + /// + bool TreeBantchUpdateEntityNoCommit(IEnumerable entities) where T : TreeEntityBase, new(); + /// + /// 批量保存实体 + /// + /// 批量保存 + /// + bool TreeBantchSaveEntityNoCommit(IEnumerable entities) where T : TreeEntityBase, new(); + #endregion + + T AddAndGetEntity_noneBase(T entity) where T : class; + + void AddEntities_noneBase(IEnumerable entities) where T : class; + + void UpdateEntities_noneBase(IEnumerable entities) where T : class; + + T GetEntity_noneBase(Expression> expressions) where T : class; + + List GetEntities_noneBase(Expression> expressions) where T : class; + + bool DeleteEntity_noneBase(Expression> expression) where T : class; + + bool AddEntityNoCommit(T entity) where T : MesEntityBase, new(); + + bool BantchAddEntityNoCommit(IEnumerable entities) where T : MesEntityBase, new(); + /// + /// 逻辑删除 + /// + /// + /// + bool DeleteEntityNoCommit(Guid id) where T : MesEntityBase, new(); + /// + /// 逻辑删除 + /// + /// + /// + bool DeleteEntityNoCommit(Expression> predicate) where T : MesEntityBase, new(); + /// + /// 逻辑删除 + /// + /// + /// + bool DeleteEntityNoCommit(IEnumerable entities) where T : MesEntityBase, new(); + /// + /// 逻辑批量删除 + /// + /// + /// + /// + bool BantchDeleteEntityNoCommit(List ids) where T : MesEntityBase, new(); + /// + /// 逻辑删除 + /// + /// + /// + bool DeleteEntityNoCommit(T entity) where T : MesEntityBase, new(); + /// + /// 更新 + /// + /// 实体 + /// 是否成功 + bool UpdateEntityNoCommit(T entity) where T : MesEntityBase, new(); + /// + /// 批量更新 + /// + /// 实体集合 + /// 是否成功 + bool BantchUpdateEntityNoCommit(IEnumerable entities) where T : MesEntityBase, new(); + /// + /// 更新 + /// + /// 实体 + /// 是否成功 + bool UpdateEntityNoCommit(T entity, params string[] updateField) where T : MesEntityBase, new(); + /// + /// 批量更新 + /// + /// 实体集合 + /// 是否成功 + bool BantchUpdateEntityNoCommit(IEnumerable entities, params string[] updateField) where T : MesEntityBase, new(); + /// + /// 批量更新(新增和保存一起)速度慢 + /// + /// 实体集合 + /// 是否成功 + bool BantchSaveEntityNoCommit(IEnumerable entities) where T : MesEntityBase, new(); + /// + /// 统一提交 + /// + /// 数据库方法 + void UnifiedCommit(Action comitAction); + + #region 根据Db连接提交 + + void AddEntityByConn(T entity, string conn) where T : MesEntityBase, new(); + + void UpdateEntitiesByConn(IEnumerable entities, string conn) where T : MesEntityBase, new(); + + void UpdateEntityByConn(T entity, string conn, params string[] updateField) where T : MesEntityBase, new(); + + void DeleteEntityByConn(Expression> expression, string conn) where T : MesEntityBase, new(); + + void DeleteEntityByConn(T entity, string conn) where T : MesEntityBase, new(); + void DeleteEntityByConn(Guid id, string conn) where T : MesEntityBase, new(); + void DeleteEntitiesByConn(IEnumerable entities, string conn) where T : MesEntityBase, new(); + void AddEntitiesByConn(IEnumerable entities, string conn) where T : MesEntityBase, new(); + void UpdateEntitiesByConn(IEnumerable entities, string conn, params string[] updateField) where T : MesEntityBase, new(); + + #endregion + + #region 根据租户提交 + void AddEntityByTenant(T entity, string Tenant) where T : MesEntityBase, new(); + + void UpdateEntitiesByTenant(IEnumerable entities, string Tenant) where T : MesEntityBase, new(); + + void UpdateEntityByTenant(T entity, string Tenant, params string[] updateField) where T : MesEntityBase, new(); + + void DeleteEntityByTenant(Expression> expression, string Tenant) where T : MesEntityBase, new(); + + void DeleteEntityByTenant(T entity, string Tenant) where T : MesEntityBase, new(); + void DeleteEntityByTenant(Guid id, string Tenant) where T : MesEntityBase, new(); + void DeleteEntitiesByTenant(IEnumerable entities, string Tenant) where T : MesEntityBase, new(); + void AddEntitiesByTenant(IEnumerable entities, string Tenant) where T : MesEntityBase, new(); + void UpdateEntitiesByTenant(IEnumerable entities, string Tenant, params string[] updateField) where T : MesEntityBase, new(); + + #endregion + + + } + +} diff --git a/APT.Infrastructure.Api/Service/IDomainService.cs b/APT.Infrastructure.Api/Service/IDomainService.cs new file mode 100644 index 0000000..f352eee --- /dev/null +++ b/APT.Infrastructure.Api/Service/IDomainService.cs @@ -0,0 +1,215 @@ +using Microsoft.EntityFrameworkCore.Storage; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Data; +using System.Data.Common; +using System.Linq.Expressions; +using APT.Infrastructure.Core; +namespace APT.Infrastructure.Api +{ + /// + /// 领域服务接口 + /// + /// + /// + /// + public interface IDomainService : IDependInject + { + + /// + /// 对数据库执行给定的 DDL/DML 命令。 + /// + /// 命令字符串 + /// 参数 + /// 受影响的行数 + int ExecuteSqlCommand(string sql, params object[] parameters); + /// + /// 对数据库执行给定的 DDL/DML 命令。 + /// + /// 事务行为 + /// 命令字符串 + /// 参数 + /// 受影响的行数 + int ExecuteSqlCommand(TransactionalBehavior transactionalBehavior, string sql, params object[] parameters); + + /// + /// 对数据库执行给定的 DDL/DML 命令返回reader。 + /// + /// 命令字符串 + /// reader委托 + void ExecuteReader(string sql, ReaderColumn[] readerColumns, Action readerAction); + + /// + /// 对数据库执行给定的 DDL/DML 命令返回reader。 + /// + /// 命令字符串 + /// 参数 + /// reader委托 + void ExecuteReader(string sql, ReaderColumn[] readerColumns, DbParameter[] parameters, Action readerAction); + + /// + /// 对数据库执行给定的 DDL/DML 命令返回reader。 + /// + /// 命令类型 + /// 命令字符串 + /// 参数 + /// reader委托 + void ExecuteReader(CommandType commandType, string sql, ReaderColumn[] readerColumns, DbParameter[] parameters, Action readerAction); + + + + /// + /// 创建一个原始 SQL 查询,该查询将返回给定泛型类型的元素。 + /// + /// 查询所返回对象的类型 + /// SQL 查询字符串 + /// 要应用于 SQL 查询字符串的参数 + /// + //IEnumerable SqlQuery(string sql, params object[] parameters); + + /// + /// 创建一个原始 SQL 查询,该查询将返回给定类型的元素。 + /// + /// 查询所返回对象的类型 + /// SQL 查询字符串 + /// 要应用于 SQL 查询字符串的参数 + /// + IEnumerable SqlQuery(Type elementType, string sql, ReaderColumn[] readerColumns, params Object[] parameters); + + /// + /// 对数据库执行给定的 DDL/DML 命令。 + /// + /// 命令类型 + /// 命令字符串 + /// 参数 + /// + int ExecuteNonQuery(CommandType commandType, string sql, ReaderColumn[] readerColumns, DbParameter[] parameters); + + + + /// + /// 获取数据库连接对象 + /// + /// 数据库类型 + /// 连接字符串 + DbConnection InitDbConnection(DataBaseType dataBaseType, string connString); + + + /// + /// 执行查询,并返回查询所返回的结果集中第一行的第一列。 所有其他的列和行将被忽略。 + /// + /// 数据库类型 + /// 连接字符串 + /// sql 类型 + /// sql + /// 参数 + object ExecuteScalarByConn(DataBaseType dataBaseType, string connString, CommandType commandType, + string sql, DbParameter[] dbParameters); + + /// + /// 执行查询,并返回查询所返回的结果集中第一行的第一列。 所有其他的列和行将被忽略。 + /// + /// 数据库类型 + /// 数据库连接对象 + /// sql 类型 + /// sql + /// 参数 + /// 是否关闭连接 + object ExecuteScalarByConn(DataBaseType dataBaseType, DbConnection conn, CommandType commandType, + string sql, bool close = true, params DbParameter[] dbParameters); + + /// + /// 根据数据库连接对数据库执行给定的 DDL/DML 命令获取Reader。 + /// + /// 数据库类型 + /// 连接对象 + /// sql 类型 + /// sql + /// 参数 + /// 分页索引 从1开始 + /// 每页条数 必填 + /// 执行委托 + /// 是否关闭连接 + void ExecuteReaderPageByConn(DataBaseType dataBaseType, DbConnection conn, CommandType commandType, + string sql, DbParameter[] dbParameters, int pageIndex, int pageLimit, Action readerAction + , bool close = true); + /// + /// 根据数据库连接对数据库执行给定的 DDL/DML 命令获取Reader。 + /// + /// 数据库类型 + /// 连接对象 + /// 指令类型 + /// SQL语句 + /// 参数 + /// 是否关闭连接 + /// 委托 + void ExecuteReaderByConn(DataBaseType dataBaseType, DbConnection conn, CommandType commandType, string sql, + DbParameter[] dbParameters, Action readerAction, bool close = true); + /// + /// 根据数据库连接对数据库执行给定的 DDL/DML 命令。 + /// + /// 数据库类型 + /// 连接字符串 + /// sql 类型 + /// sql + /// 参数 + void ExecuteNonQueryByConn(DataBaseType dataBaseType, string connString, CommandType commandType, + string sql, DbParameter[] dbParameters); + + /// + /// 根据数据库连接对数据库执行给定的 DDL/DML 命令。 + /// + /// 数据库类型 + /// 连接字符串 + /// sql 类型 + /// sql + /// 参数 + void ExecuteNonQueryByConn(DataBaseType dataBaseType, DbConnection conn, CommandType commandType, string sql, + DbParameter[] dbParameters, bool close = true); + + /// + /// 根据数据库连接对数据库执行给定的 DDL/DML 命令获取Reader。 + /// + /// 数据库类型 + /// 连接字符串 + /// sql 类型 + /// sql + /// 参数 + /// 执行委托 + void ExecuteReaderByConn(DataBaseType dataBaseType, string connString, CommandType commandType, string sql, + DbParameter[] dbParameters, Action readerAction); + + + /// + /// 根据数据库连接对数据库执行给定的 DDL/DML 命令获取Reader。 + /// + /// 数据库类型 + /// 连接字符串 + /// sql 类型 + /// sql + /// 参数 + /// 分页索引 从1开始 + /// 每页条数 必填 + /// 执行委托 + void ExecuteReaderPageByConn(DataBaseType dataBaseType, string connString, CommandType commandType, + string sql, DbParameter[] dbParameters, int pageIndex, int pageLimit, Action readerAction); + + /// + /// 根据数据库连接对数据库执行给定的 DDL/DML 命令获取数据总条数。 + /// + /// 数据库类型 + /// 连接字符串 + /// sql 类型 + /// sql + /// 参数 + /// 数据总条数 + int GetSqlCountByConn(DataBaseType dataBaseType, string connString, CommandType commandType, + string sql, DbParameter[] dbParameters); + + string GetRuleCodes(CodeRuleParam param); + + } + + +} diff --git a/APT.Infrastructure.Api/Structs/AppContext.cs b/APT.Infrastructure.Api/Structs/AppContext.cs new file mode 100644 index 0000000..4baf31f --- /dev/null +++ b/APT.Infrastructure.Api/Structs/AppContext.cs @@ -0,0 +1,114 @@ +using System; +using APT.Infrastructure.Core; +namespace APT.Infrastructure.Api +{ + [Serializable] + public static class AppContext + { + #region fields + + private static SysPermission _sysPermission = new SysPermission(); + + #endregion + + #region ctor. + static AppContext() + { + + } + #endregion + + #region properties + + private static ISessionProvider GetSessionProvider() + { + ISessionProvider sessionProvider =null; + try + { + sessionProvider = ServiceLocator.Instance.GetService(); + } + catch { } + if (null == sessionProvider) + { + sessionProvider = new SimpleSession(); + } + return sessionProvider; + } + + + /// + /// 当前会话 + /// + public static ISession CurrentSession + { + get + { + var session= GetSessionProvider(); + return session.GetSession(); + } + } + + /// + /// 日志记录器 + /// + public static ILog4netLogger Logger + { + get + { + return LoggerManager.GetLogger(); + } + } + + /// + /// 是否使用Redis + /// + public static bool IsRedis + { + get;set; + } + + /// + /// 微信Token + /// + public static WeixinToken WxToken { get; set; } + + /// + /// 部门ID + /// + public static Guid? DepartmentID { get; set; } + + + /// + ///自定义变量1 + /// + public static string CustomVariable1 { get; set; } + /// + /// 自定义变量2 + /// + public static string CustomVariable2 { get; set; } + /// + /// 自定义变量3 + /// + public static string CustomVariable3 { get; set; } + /// + /// 自定义变量4 + /// + public static string CustomVariable4{ get; set; } + /// + /// 自定义变量5 + /// + public static string CustomVariable5 { get; set; } + + + + /// + /// 权限缓存 + /// + public static SysPermission SysPermission + { + get { return _sysPermission; } + set { _sysPermission = value; } + } + #endregion + } +} diff --git a/APT.Infrastructure.Api/Structs/ConfigurationManager.cs b/APT.Infrastructure.Api/Structs/ConfigurationManager.cs new file mode 100644 index 0000000..7083bb3 --- /dev/null +++ b/APT.Infrastructure.Api/Structs/ConfigurationManager.cs @@ -0,0 +1,93 @@ +using Microsoft.EntityFrameworkCore.Internal; +using Microsoft.Extensions.Configuration; +using System.Linq; +using APT.Infrastructure.Core; + +namespace APT.Infrastructure.Api +{ + public static class ConfigurationManager + { + public static IConfiguration Configuration + { + get; + private set; + } + + public static IConfigurationSection AppSettings { get; set; } + public static IConfigurationSection WexinSettings { get; set; } + + public static IConfigurationSection ConnectionStrings { get; set; } + + public static IConfigurationSection RedisStrings { get; set; } + + public static IConfigurationSection InfluxDbStrings { get; set; } + + public static void Register(IConfiguration configuration) + { + Configuration = configuration; + AppSettings = Configuration.GetSection("AppSettings"); + RedisStrings = Configuration.GetSection("RedisConfig"); + InfluxDbStrings = Configuration.GetSection("InflexdbConfig"); + ConnectionStrings = Configuration.GetSection("ConnectionStrings"); + WexinSettings = Configuration.GetSection("WexinSettings"); + } + + public static bool IsRedis + { + get + { + return LibUtils.ToBoolean(RedisStrings["IsRedis"]); + } + } + + private static InfluxDbOption _option; + public static InfluxDbOption InfluxDbOption + { + get + { + if (_option == null) + { + _option = new InfluxDbOption(); + var s = InfluxDbStrings.GetChildren(); + _option.Url = s.Any(i => i.Key == "Url") ? s.FirstOrDefault(i => i.Key == "Url").Value : ""; + _option.UserName = s.Any(i => i.Key == "UserName") ? s.FirstOrDefault(i => i.Key == "UserName").Value : ""; + _option.PassWord = s.Any(i => i.Key == "PassWord") ? s.FirstOrDefault(i => i.Key == "PassWord").Value : ""; + _option.SrcTagDbName = s.Any(i => i.Key == "SrcTagDbName") ? s.FirstOrDefault(i => i.Key == "SrcTagDbName").Value : ""; + _option.CorrectWaring = s.Any(i => i.Key == "CorrectWaring") ? s.FirstOrDefault(i => i.Key == "CorrectWaring").Value : ""; + _option.LogDbName = s.Any(i => i.Key == "LogDbName") ? s.FirstOrDefault(i => i.Key == "LogDbName").Value : ""; + _option.MaxDemandDbName = s.Any(i => i.Key == "MaxDemandDbName") ? s.FirstOrDefault(i => i.Key == "MaxDemandDbName").Value : ""; + _option.DosageDbName = s.Any(i => i.Key == "DosageDbName") ? s.FirstOrDefault(i => i.Key == "DosageDbName").Value : ""; + _option.EnergyValDbName = s.Any(i => i.Key == "EnergyValDbName") ? s.FirstOrDefault(i => i.Key == "EnergyValDbName").Value : ""; + _option.AppOnline = s.Any(i => i.Key == "AppOnline") ? s.FirstOrDefault(i => i.Key == "AppOnline").Value : ""; + + } + return _option; + } + } + + private static RedisOption _redisPotion; + + public static RedisOption RedisOption + { + get + { + if (_redisPotion == null) + { + var s = RedisStrings.GetChildren(); + var conn = s.Any(i => i.Key == "RedisConnectionString") ? s.FirstOrDefault(i => i.Key == "RedisConnectionString").Value : ""; + var pwd = s.Any(i => i.Key == "RedisConnectionPwd") ? s.FirstOrDefault(i => i.Key == "RedisConnectionPwd").Value : ""; + var pKey = s.Any(i => i.Key == "RedisPrefixKey") ? s.FirstOrDefault(i => i.Key == "RedisPrefixKey").Value : ""; + _redisPotion= new RedisOption() + { + RedisConnectionString = conn, + RedisConnectionPwd = pwd, + RedisPrefixKey = pKey + }; + } + return _redisPotion; + } + } + + + } +} diff --git a/APT.Infrastructure.Api/Structs/DefaultAutofacModuleRegister.cs b/APT.Infrastructure.Api/Structs/DefaultAutofacModuleRegister.cs new file mode 100644 index 0000000..ac7cda0 --- /dev/null +++ b/APT.Infrastructure.Api/Structs/DefaultAutofacModuleRegister.cs @@ -0,0 +1,22 @@ +using Autofac; +using System; +using System.Linq; +using System.Collections.Generic; +using System.Reflection; +using System.Text; +using APT.Infrastructure.Core; +namespace APT.Infrastructure.Api +{ + public class DefaultAutofacModuleRegister : Autofac.Module + { + protected override void Load(ContainerBuilder builder) + { + Assembly[] assemblies = System.IO.Directory.GetFiles( + System.AppContext.BaseDirectory, "APT.*.dll"). + Select(m => Assembly.LoadFrom(m)).ToArray(); + builder.RegisterAssemblyTypes(assemblies). + Where(t => typeof(IDependInject).IsAssignableFrom(t)).AsImplementedInterfaces(). + InstancePerLifetimeScope(); + } + } +} diff --git a/APT.Infrastructure.Api/Structs/InfluxDbHelper.cs b/APT.Infrastructure.Api/Structs/InfluxDbHelper.cs new file mode 100644 index 0000000..871ce69 --- /dev/null +++ b/APT.Infrastructure.Api/Structs/InfluxDbHelper.cs @@ -0,0 +1,86 @@ +using System; +using System.Collections.Generic; +using System.Dynamic; +using System.Linq; +using System.Text; +using Microsoft.Extensions.Configuration; +namespace APT.Infrastructure.Api +{ + public static class InfluxDbHelper + { + + + //private static InfluxDbClient _influxDbClient; + //public static InfluxDbClient InfluxDbClient + //{ + // get + // { + // if (_influxDbClient == null) + // { + // _influxDbClient = new InfluxDbClient(ConfigurationManager.InfluxDbOption.Url, + // ConfigurationManager.InfluxDbOption.UserName, ConfigurationManager.InfluxDbOption.PassWord, InfluxDbVersion.Latest); + + // } + // return _influxDbClient; + // } + //} + + public static string SrcTagDbName + { + get + { + return ConfigurationManager.InfluxDbOption.SrcTagDbName; + } + } + + public static string CorrectWaring + { + get + { + return ConfigurationManager.InfluxDbOption.CorrectWaring; + } + } + + public static string InfluxLogDbName + { + get + { + return ConfigurationManager.InfluxDbOption.LogDbName; + } + } + public static string MaxDemandDbName + { + get + { + return ConfigurationManager.InfluxDbOption.MaxDemandDbName; + } + } + + public static string DosageDbName + { + get + { + return ConfigurationManager.InfluxDbOption.DosageDbName; + } + } + + public static string EnergyValDbName + { + get + { + return ConfigurationManager.InfluxDbOption.EnergyValDbName; + } + } + + public static string AppOnline + { + get + { + return ConfigurationManager.InfluxDbOption.AppOnline; + } + } + } + + + +} diff --git a/APT.Infrastructure.Api/Structs/InfluxDbOption.cs b/APT.Infrastructure.Api/Structs/InfluxDbOption.cs new file mode 100644 index 0000000..206eb64 --- /dev/null +++ b/APT.Infrastructure.Api/Structs/InfluxDbOption.cs @@ -0,0 +1,89 @@ +using System; +using System.Collections.Generic; +using System.Dynamic; +using System.Linq; +using System.Text; +using Microsoft.Extensions.Configuration; +namespace APT.Infrastructure.Api +{ + //public static class ConfigurationHelper + //{ + // public static IConfigurationRoot Configuration { get; set; } + + // private static InfluxDbOption _option; + // public static InfluxDbOption InfluxDbOption + // { + // get + // { + // if (_option == null) + // { + // _option = new InfluxDbOption(); + // var s = Configuration.GetSection("InflexdbConfig").GetChildren(); + // _option.Url= s.Any(i => i.Key == "Url") ? s.FirstOrDefault(i => i.Key == "Url").Value : ""; + // _option.UserName = s.Any(i => i.Key == "UserName") ? s.FirstOrDefault(i => i.Key == "UserName").Value : ""; + // _option.PassWord = s.Any(i => i.Key == "PassWord") ? s.FirstOrDefault(i => i.Key == "PassWord").Value : ""; + // _option. = s.Any(i => i.Key == "") ? s.FirstOrDefault(i => i.Key == "").Value : ""; + // _option.LogDbName = s.Any(i => i.Key == "LogDbName") ? s.FirstOrDefault(i => i.Key == "LogDbName").Value : ""; + // _option.DosageDbName = s.Any(i => i.Key == "DosageDbName") ? s.FirstOrDefault(i => i.Key == "DosageDbName").Value : ""; + // _option. = s.Any(i => i.Key == "EnergyValDbName") ? s.FirstOrDefault(i => i.Key == "EnergyValDbName").Value : ""; + + // } + // return _option; + // } + // } + //} + + + public class InfluxDbOption + { + /// + /// 地址 + /// + public string Url { get; set; } + + /// + /// 用户 + /// + public string UserName { get; set; } + + /// + /// 密码 + /// + public string PassWord { get; set; } + + + /// + /// 源标签历史数据 + /// + public string SrcTagDbName { get; set; } + /// + /// 纠错数据表 + /// + public string CorrectWaring { get; set; } + + /// + /// Log + /// + public string LogDbName { get; set; } + + /// + /// + /// + public string MaxDemandDbName { get; set; } + /// + /// 用量 + /// + public string DosageDbName { get; set; } + /// + /// 价格 + /// + public string EnergyValDbName { get; set; } + + /// + /// 价格 + /// + public string AppOnline { get; set; } + + + } +} diff --git a/APT.Infrastructure.Api/Structs/LibMessageUtils.cs b/APT.Infrastructure.Api/Structs/LibMessageUtils.cs new file mode 100644 index 0000000..d095083 --- /dev/null +++ b/APT.Infrastructure.Api/Structs/LibMessageUtils.cs @@ -0,0 +1,99 @@ +using System; +using APT.Infrastructure.Core; +namespace APT.Infrastructure.Api +{ + public static class LibMessageUtils + { + public static void AddError(string message) + { + AddMessage(EFMessageType.Error, string.Empty, message); + } + public static void AddError(string code, params object[] objs) + { + AddMessage(EFMessageType.Error, code, GetMessage(code, objs)); + } + + public static void AddWarning(string message) + { + AddMessage(EFMessageType.Warning, string.Empty, message); + } + public static void AddWarning(string code, params object[] objs) + { + AddMessage(EFMessageType.Warning, code, GetMessage(code, objs)); + } + + + public static void AddInfo(string message) + { + AddMessage(EFMessageType.Info, string.Empty, message); + } + public static void AddInfo(string code, params object[] objs) + { + AddMessage(EFMessageType.Info, code, GetMessage(code, objs)); + } + + public static string GetMessage(string code,params object[] objs) + { + var foramt = LibMessageFormatManager.Instance. + GetMessageFormat(code, "");//多语言暂不支持 + return string.Format(foramt, objs); + } + + + + + public static void AddMessage(EFMessageType type, string message) + { + AddMessage(type, string.Empty, message); + } + + public static void ThrowError(string code, params object[] objs) + { + string m = GetMessage(code, objs); + throw new CodeException(code, m); + } + //public static void ThrowUpdateRowVersionError(string code, params object[] objs) + //{ + // string m = GetMessage(code, objs); + // throw new EFUpdateRowVersionException(code, m); + //} + //public static void ThrowFieldUniqueError(string code, string field, params object[] objs) + //{ + // string m = GetMessage(code, objs); + // throw new EFFieldUniqueException(code, field, m); + //} + + public static void AddMessage(EFMessageType type, string code, string message) + { + var messageM = GetMessageManage(); + if (messageM == null) throw new Exception("ILibMessageManager is null"); + messageM.AddMessage(type, code, message); + } + + public static void AddMessage(EFApiActionMessage message) + { + var messageM = GetMessageManage(); + if (messageM == null) throw new Exception("ILibMessageManager is null"); + messageM.AddMessage(message); + } + + public static void StoreMessage(EFApiActionResult ret) + { + var messageM = GetMessageManage(); + if (messageM == null) return; + messageM.StoreMessage(ret); + } + + private static ILibMessageManager GetMessageManage() + { + ILibMessageManager clientFactory = null; + try + { + if (HttpContext.Current != null && HttpContext.Current.RequestServices != null) + clientFactory = (ILibMessageManager)HttpContext.Current.RequestServices.GetService(typeof(ILibMessageManager)); + } + catch { } + return clientFactory; + } + } +} diff --git a/APT.Infrastructure.Core/APT.Infrastructure.Core.csproj b/APT.Infrastructure.Core/APT.Infrastructure.Core.csproj new file mode 100644 index 0000000..d7d2ed2 --- /dev/null +++ b/APT.Infrastructure.Core/APT.Infrastructure.Core.csproj @@ -0,0 +1,38 @@ + + + + netstandard2.1 + 2.1.2.65 + true + 2.1.2.65 + 2.1.2.65 + + + + .\APT.Infrastructure.Core.xml + + + + + + + + + + + + + + + + + + + + + + C:\Program Files\dotnet\sdk\NuGetFallbackFolder\microsoft.extensions.configuration.abstractions\2.2.0\lib\netstandard2.0\Microsoft.Extensions.Configuration.Abstractions.dll + + + + diff --git a/APT.Infrastructure.Core/APT.Infrastructure.Core.xml b/APT.Infrastructure.Core/APT.Infrastructure.Core.xml new file mode 100644 index 0000000..cd441c3 --- /dev/null +++ b/APT.Infrastructure.Core/APT.Infrastructure.Core.xml @@ -0,0 +1,2477 @@ + + + + APT.Infrastructure.Core + + + + + 排序规范 + + + + + + 递增 + + + + + + + + 然后递增 + + + + + + + + 递减 + + + + + + + + 然后递减 + + + + + + + + 排序后的结果集 + + + + + 获取 当前单元操作对象 + + + + + 填充系统参数 + + + + + + + + 异步泛型主键实体仓储接口 + + 实体类型 + 实体主键类型 + + + + 异步插入实体 + + 实体对象 + 操作影响的行数 + + + + 异步批量插入实体 + + 实体对象集合 + 操作影响的行数 + + + + 异步删除实体 + + 实体对象 + 操作影响的行数 + + + + 异步删除指定编号的实体 + + 实体编号 + 操作影响的行数 + + + + 异步删除所有符合特定条件的实体 + + 查询条件谓语表达式 + 操作影响的行数 + + + + 异步批量删除删除实体 + + 实体对象集合 + 操作影响的行数 + + + + 异步更新实体对象 + + 实体对象 + 操作影响的行数 + + + + 异步批量更新实体对象 + + 实体对象集合 + 操作影响的行数 + + + + 批量更新 + + 查询条件谓语表达式 + 更新表达式 + 操作影响的行数 + + + + 异步获取指定主键的实体 + + 实体主键 + 符合主键的实体,不存在时返回null + + + + 异步获取符合条件的实体 + + 查询条件谓语表达式 + 符合条件的实体,不存在时返回null + + + + 异步获取记录数 + + + + + + 异步获取符合条件的记录数 + + 查询条件谓语表达式 + + + + + 异步是否存在符合条件的记录 + + 查询条件谓语表达式 + + + + + 泛型时间戳接口 + + + + + 对数据库执行给定的 DDL/DML 命令。 + + 命令字符串 + 参数 + 受影响的行数 + + + + 对数据库执行给定的 DDL/DML 命令。 + + 事务行为 + 命令字符串 + 参数 + 受影响的行数 + + + + 对数据库执行给定的 DDL/DML 命令返回reader。 + + 命令字符串 + reader委托 + + + + 对数据库执行给定的 DDL/DML 命令返回reader。 + + 命令字符串 + 参数 + reader委托 + + + + 对数据库执行给定的 DDL/DML 命令返回reader。 + + 命令类型 + 命令字符串 + 参数 + reader委托 + + + + 对数据库执行给定的 DDL/DML 命令。 + + 命令类型 + 命令字符串 + 参数 + + + + + 创建一个原始 SQL 查询,该查询将返回给定类型的元素。 + + 查询所返回对象的类型 + SQL 查询字符串 + 要应用于 SQL 查询字符串的参数 + + + + + 提交当前单元操作的更改。 + + 操作影响的行数 + + + + 执行数据sql语句 + + 执行数据sql语句 + + + + 异步提交当前单元操作的更改。 + + 操作影响的行数 + + + + 开启事务 + + + + + 提交事务 + + + + + 回滚事务 + + + + + 根据表名获取表数据结构 + + + + + + + 根据表名、字段名称获取字段结构 + + + + + + + + 根据表名,导航名称获取外键信息 + + + + + + + + 获取所有外键信息 + + + + + + + 根据表名,ID字段名称获取外键信息 + + + + + + + + Linq架构里对集合排序实现 + + + + + + 排序后的结果集 + + + + + + 排序之后的结果集 + + + + + 递增 + + + + + + + + 然后递增 + + + + + + + + 递减 + + + + + + + + 然后递减 + + + + + + + + DateTime 扩展类 + + + + + 将当前DateTime值转换成yyyy-MM-dd字符串。 + + + + + + + 将当前DateTime值星期几中文字符串。 + + + + + + + 类型扩展方法类 + + + + + 获取枚举值值 + + 枚举值 + + + + + 将一个或多个枚举常数的名称或数字值的字符串表示转换成等效的枚举对象。 用于指示转换是否成功的返回值。 + + 要将 value 转换为的枚举类型。 + 要转换的枚举名称或基础值的字符串表示形式。 + 默认值 + 如果 value 参数成功转换,则返回类型为 TEnum 的一个对象,其值由 value 表示;否则为 defaultValue。 + + + + Expression表达式扩展操作类 + + + + + 以特定的条件运行组合两个Expression表达式 + + 表达式的主实体类型 + 第一个Expression表达式 + 要组合的Expression表达式 + 组合条件运算方式 + 组合后的表达式 + + + + 以 Expression.AndAlso 组合两个Expression表达式 + + 表达式的主实体类型 + 第一个Expression表达式 + 要组合的Expression表达式 + 组合后的表达式 + + + + 以 Expression.OrElse 组合两个Expression表达式 + + 表达式的主实体类型 + 第一个Expression表达式 + 要组合的Expression表达式 + 组合后的表达式 + + + + 类型扩展方法类 + + + + + 生成条件表达式 + + 类型 + 条件组 + + + + + 生成条件表达式 + + + + + + + + 生成条件表达式 + + 类型 + 条件组 + + + + + 类型扩展方法类 + + + + + 返回一个新字符串,该字符串通过在此实例中的字符左侧填充指定的 Unicode 字符来达到指定的总长度,从而使这些字符右对齐。 + + + + + + + + + 返回一个新字符串,该字符串通过在此字符串中的字符右侧填充指定的 Unicode 字符来达到指定的总长度,从而使这些字符左对齐。 + + + + + + + + + 把对象序列化成Json字符串格式 + + + + + + + 把Json字符串转换为强类型对象 + + + + + Linq 拓展方法类 + + + + + 类型扩展方法类 + + + + + 获取指定的长度的随机数字字符串 + + + 要获取随机数长度 + 指定长度的随机数字符串 + + + + 获取指定的长度的随机字母字符串 + + + 要获取随机数长度 + 指定长度的随机字母组成字符串 + + + + 获取指定的长度的随机字母和数字字符串 + + + 要获取随机数长度 + 指定长度的随机字母和数字组成字符串 + + + + 类型扩展方法类 + + + + + 判断类型是否为Nullable类型 + + 要处理的类型 + 是返回True,不是返回False + + + + 由类型的Nullable类型返回实际类型 + + 要处理的类型对象 + + + + + 通过类型转换器获取Nullable类型的基础类型 + + 要处理的类型对象 + + + + + 获取成员元数据的Description特性描述信息 + + 成员元数据对象 + 是否搜索成员的继承链以查找描述特性 + 返回Description特性描述信息,如不存在则返回成员的名称 + + + + 检查指定指定类型成员中是否存在指定的Attribute特性 + + 要检查的Attribute特性类型 + 要检查的类型成员 + 是否从继承中查找 + 是否存在 + + + + 从类型成员获取指定Attribute特性 + + Attribute特性类型 + 类型类型成员 + 是否从继承中查找 + 存在返回第一个,不存在返回null + + + + 从类型成员获取指定Attribute特性 + + Attribute特性类型 + 类型类型成员 + 是否从继承中查找 + 返回所有指定Attribute特性的数组 + + + + 判断类型是否为集合类型 + + 要处理的类型 + 是返回True,不是返回False + + + + 判断当前泛型类型是否可由指定类型的实例填充 + + 泛型类型 + 指定类型 + + + + + 创建GET方式的HTTP请求 + + 请求的URL + 请求的超时时间 + 请求的客户端浏览器信息,可以为空 + 随同HTTP请求发送的Cookie信息,如果不需要身份验证可以为空 + + + + + 创建GET方式的HTTP请求 + + 请求的URL + 请求的超时时间 + 请求的客户端浏览器信息,可以为空 + 随同HTTP请求发送的Cookie信息,如果不需要身份验证可以为空 + + + + + 创建POST方式的HTTP请求 + + 请求的URL + 随同请求POST的参数名称及参数值字典 + 请求的超时时间 + 请求的客户端浏览器信息,可以为空 + 发送HTTP请求时所用的编码 + 随同HTTP请求发送的Cookie信息,如果不需要身份验证可以为空 + + + + + 创建POST方式的HTTP请求 + + 请求的URL + 随同请求POST的参数名称及参数值字典 + 请求的超时时间 + 请求的客户端浏览器信息,可以为空 + 发送HTTP请求时所用的编码 + 随同HTTP请求发送的Cookie信息,如果不需要身份验证可以为空 + + + + + AES 加密 + + 明文(待加密) + 密文 + + + + + AES 解密 + + 明文(待解密) + 密文 + + + + + 查询表达式辅助操作类 + + + + + 获取指定查询条件组的查询表达式 + + 表达式实体类型 + 查询条件组,如果为null,则直接返回 true 表达式 + + + + 获取指定查询条件的查询表达式 + + 表达式实体类型 + 查询条件,如果为null,则直接返回 true 表达式 + + + + + Hash工具类 + + + + + 计算字符串MD5值 + + 要计算的值 + + + + + 计算byte数组MD5值 + + 要计算的byte数组 + + + + + 产生随机字串,可用来自动生成密码,默认长度8位16进制 + + 长度 + 字串类型 0 字母 1 数字 2 大写字母 3 小写字母 4 十六进制字母 5 混合 + 额外字符 + + + + + 随机数类型 + + + + + 转为字符串 + + + + + + + 转为整数 + + + + + + + 转为Decimal + + + + + + + 转为日期 + + + + + + + 转为Guid + + + + + + + 转为布尔类型 + + + + + + + 比较两个指定的 System.String 对象(其中忽略或考虑其大小写),并返回一个整数 + + + + 是否忽略大小写 + + + + + 保留指定小数点位数 + + + + + + + + + 工具类 + + + + + 新建一个 混合构成的适用于DB的可排序的 + + Comb Guid数据 + + + + 加密密码 + + + + + + 获取指定日期,在为一年中为第几周 + + 指定时间 + 返回第几周 + + + + + + + + + + + 判断byte数组是否相等 + + + + + + + + 通过唯一编号获得数据表 + + + + + + + + + 通过过滤条件获取一条数据 + + + + + 是否直接转换对象 + + + + + 执行某个接口 + + + + + + + + + + + + + + + + + 通过过滤条件获取一条数据 + + + + + + + + + 获取二进制图片 + + + + + + + + + + + + + isResolvingResult=true + + + + + + + + + + + + + + + + + + + + + + + + + isResolvingResult=true + + + + + + + + + + + + 日志记录器 + + + + + 写入日志消息 + + 日志消息 + + + + 写入格式化日志消息 + + 日志消息格式 + 格式化参数 + + + + 写入日志消息 + + 日志消息 + + + + 写入格式化日志消息 + + 日志消息格式 + 格式化参数 + + + + 写入日志消息 + + 日志消息 + + + + 写入格式化日志消息 + + 日志消息格式 + 格式化参数 + + + + 写入日志消息 + + 日志消息 + + + + 写入格式化日志消息 + + 日志消息格式 + 格式化参数 + + + + 写入日志消息,并记录异常 + + 日志消息 + 异常 + + + + 写入格式化日志消息,并记录异常 + + 日志消息格式 + 异常 + 格式化参数 + + + + 写入日志消息 + + 日志消息 + + + + 写入格式化日志消息 + + 日志消息格式 + 格式化参数 + + + + 写入日志消息,并记录异常 + + 日志消息 + 异常 + + + + 写入格式化日志消息,并记录异常 + + 日志消息格式 + 异常 + 格式化参数 + + + + log4net日志记录器 + + + + + 添加操作日志 liyouming + + + + + + + + Logger管理器 + + + + /// 取得当前源码的哪一行 /// /// + + + /// 取当前源码的源文件名 /// /// + + + + 枚举属性 + + + + + 枚举项排序索引小标 属性 + + + + + 枚举项排序索引小标 属性 + + + + + 枚举属性 + + + + + 数据记录 + + + + + 数据记录 + + 数据方向 + + + + 数据方向 + + + + + 初始化一个类型的新实例 + + + + + 获取 操作符 + + + + + 首字母简称属性 + + + + + 编辑表单显示字段属性 + 用于定义字段是否显示在编辑表单中 + + + + + 字段显示文本 + + + + + 顺序索引 + + + + + + + 字段显示文本 + 顺序索引 + + + + + + 字段显示文本 + + + + 列表表单显示字段属性 + 用于定义字段是否显示在列表表单中 + + + + + 字段显示文本 + + + + + 顺序索引 + + + + + + + 字段显示文本 + 顺序索引 + + + + + + 字段显示文本 + + + + 树表单显示字段属性 + 用于定义字段是否显示在树表单中 + + + + + 字段显示文本 + + + + + 顺序索引 + + + + + + + 字段显示文本 + 顺序索引 + + + + + + 字段显示文本 + + + + 列表单显示查询字段属性 + 用于定义字段是否显示在列表表单查询中 + + + + + 字段显示文本 + + + + + 顺序索引 + + + + + + + 字段显示文本 + + + + + + 字段显示文本 + + + + 编辑表单显示字段属性 + 用于定义字段是否显示在编辑表单中 + + + + + 字段显示文本 + + + + + + + 字段显示文本 + + + + 列表表单显示字段属性 + 用于定义字段是否显示在列表表单中 + + + + + 字段显示文本 + + + + + + + 字段显示文本 + + + + 树表单显示字段属性 + 用于定义字段是否显示在树表单中 + + + + + 字段显示文本 + + + + + + + 字段显示文本 + + + + 字段长度属性 + + + + + 字段长度 + + + + + + + 字段长度 + + + + 字段忽略属性 + + + + + 类索引属性 + 用于联合索引 + + + + + 索引字段列表 + + + + + 是否唯一索引 + + + + + + + 索引字段列表 + 是否唯一索引 + + + + + + 索引字段列表 + + + + 字段索引属性 + + + + + 是否唯一索引 + + + + + + + 是否唯一索引 + + + + 字段必填属性 + + + + + 是否必填 + + + + + + + 是否必填 + + + + 字段外键属性 + 在外键ID字段上使用 + + + + + 导航字段名称 + + + + + 主表导航字段名称 + + + + + 主表导航字段名称 + + + + + + + 导航字段名称 + 主表导航字段名称 + 是否1对1 + + + + + + 导航字段名称 + 是否1对1 + + + + 字段外键属性 + 在主表的外键导航属性上使用 + + + + + 导航字段名称 + + + + + ID字段名称 + + + + + 主表导航字段名称 + + + + + + + ID字段名称 + 导航字段名称 + 是否一对一 + + + + + + ID字段名称 + 是否一对一 + + + + 获取方法的描述 + + + + + 导航字段名称 + + + + + 参数说明 + + + + + 构造函数 + + 方法描述 + 参数描述 + + + + 字段外键属性 + 在外键ID字段上使用 + + + + + 导航字段名称 + + + + + 主表导航字段名称 + + + + + + + 导航字段名称 + 主表导航字段名称 + + + + + + 导航字段名称 + + + + 基础过滤器 + + + + + 菜单参数 + + + + + 组织类型 + + + + + 是否加载全部数据 + + + + + 公司编号 + + + + + 数据层级 + + + + + 树结构是否加载上级数据 + + + + + 是否不跟踪 + + + + + 是否查询多个库 + + + + + 知否指定数据库 + + + + + 指定数据库连接 + + + + + 指定租户 + + + + + 授权组织编号,多个可以逗号隔开 + 本组织可以查询授权组织数据 + + + + 窗体模板ID + + + + 排序字段 + + + + + 排序方式 + + + + + 过滤条件 + + + + + 关联表 + + + + + 查询/更新字段 + + + + + 多字段排序 + + + + + 数据权限 + + + + + 组织权限 + + + + + 是否忽略数据权限 + + + + + 是否忽略组织权限 + + + + + 树选择的ID + + + + + 分页条件 + + + + + 获取第Start+1页的数据 + + + + + 每一个分页获取的条数 + + + + + 第几页 + + + + + 是否查询所有数据 + + + + + 排序条件 + + + + + 获取或设置 字段名称 + + + + + 获取或设置 过滤值 + + + + + 领域异常,主要用在业务逻辑出错,需要终止当前业务时 + + + + + 领域异常,主要用在业务逻辑出错,需要终止当前业务时 + + + + + 领域异常,主要用在业务逻辑出错,需要终止当前业务时 + + 错误信息 + + + + 领域异常,主要用在业务逻辑出错,需要终止当前业务时 + + 错误信息 + 内部异常 + + + + / + + + + + + + + + + 领域异常,主要用在业务逻辑出错,需要终止当前业务时 + + 错误信息 + + + + 领域异常,主要用在业务逻辑出错,需要终止当前业务时 + + 错误信息 + 内部异常 + + + + 更新类型 + + + + + 插入 + + + + + 更新 + + + + + 删除 + + + + + 批量新增 + + + + + 批量更新 + + + + + 数据库类型 + + + + + 在执行数据库命令或查询期间控制事务创建行为。 + + + + + 如果存在现有事务,则使用它,否则在没有事务的情况下执行命令或查询。 + + + + + 如果不存在任何事务,则使用新事务进行操作。 + + + + + 排序方式 + + + + + 过滤方式 + + + + + 等于 + + + + + 不等于 + + + + + 小于 + + + + + 小于或等于 + + + + + 大于 + + + + + 大于或等于 + + + + + 以……开始,只适用于String + + + + + 以……结束,只适用于String + + + + + 包含(相似),只适用于String + + + + + 数据方向 + + + + + 不进行数据数据交换 + + + + + 推送 + + + + + 上传 + + + + 每天每隔固定时间执行一次 + + + 每天每隔固定时间执行一次 + + + 固定时间执行一次 + + + 只执行一次 + + + + 不间断执行 + + + + 间隔秒 + + + 间隔分钟 + + + 间隔小时 + + + 间隔天 + + + 间隔月 + + + 间隔年 + + + + 过滤条件组 + + + + + 初始化一个的新实例 + + + + + 获取或设置 是否是And关系 + + + + + 获取或设置 条件集合 + + + + + 获取或设置 条件组集合 + + + + + 过滤条件 + + + + + 初始化一个的新实例 + + + + + 使用指定数据名称,数据值初始化一个的新实例 + + 数据名称 + 数据值 + + + + 使用指定数据名称,数据值及操作方式初始化一个的新实例 + + 数据名称 + 数据值 + 操作方式 + + + + 获取或设置 字段名称 + + + + + 获取或设置 过滤值 + + + + + 获取或设置 操作类型 + + + + + 是否是系统参数条件 + + + + + 会话信息 + + + + + 用户ID + + + + + 用户ID + + + + + 用户编号 + + + + + 用户名称 + + + + + 部门ID + + + + + 部门ID + + + + + 组织ID + + + + + 适用于WebApi的统一格式的ActionResult + + 返回结果数据类型 + + + + 是否执行成功 + + + + + 返回结果,如果值为时有值 + + + + + 错误信息,如果值为时有值 + + + + + 消息类型 + + + + + 消息代码 + + + + + 适用于WebApi的统一格式的ActionResult + + 返回结果数据类型 + + + + 是否执行成功 + + + + + 返回结果,如果值为时有值 + + + + + 错误信息,如果值为时有值 + + + + + 消息类型 + + + + + 消息代码 + + + + + 基础区域过滤条件 + + + + + 公共参数 + + + + + 构造函数1 + + + + + 构造函数2 + + keyword + orgid + + + + 参数1 + + + + + 参数2 + + + + + 参数3 + + + + + 参数4 + + + + + 参数5 + + + + + 参数5 + + + + + 参数 + + + + + 参数5 + + + + + 参数5 + + + + + 参数5 + + + + + 参数11 + + + + + 参数5 + + + + + 参数 + + + + + 参数5 + + + + + 参数5 + + + + + 参数5 + + + + + 参数5 + + + + + 参数 + + + + + 参数5 + + + + + 参数5 + + + + + 参数5 + + + + + 参数5 + + + + + 参数5 + + + + + 参数5 + + + + + 参数5 + + + + + 参数5 + + + + + 参数5 + + + + + 参数5 + + + + + 参数5 + + + + + 参数5 + + + + + 餐台区域过滤条件 + + + + + 公共参数 + + + + + 参数1 + + + + + 参数2 + + + + + 参数3 + + + + + 参数4 + + + + + 参数5 + + + + + 参数6 + + + + + 适用于WebApi的统一格式的分页数据结构 + + + + + + 是否执行成功 + + + + + 返回结果,如果值为时有值 + + + + + 其他数据 + + + + + 总记录数 + + + + + 错误信息,如果值为时有值 + + + + + 消息类型 + + + + + 消息代码 + + + + + 構造函數 + + + + + + + + + 構造函數 + + + + + 统一格式的分页结果集 + + + + + + 统一格式的分页结果集 + + + + + 统一格式的分页结果集 + + 总数 + 结果集 + + + + 总数 + + + + + 数据集合 + + + + + 编码规则参数 + + + + + 数量 + + + + + 公共参数 + + + + + 树结构 + + + + + + 节点 + + + + + 是否叶子节点 + + + + + 层级 + + + + + 数据集合 + + + + + 数据记录 + + + + + 实体名称 + + + + + 实体强类型名称 + + + + + 实体ID + + + + + 更新类型 + + + + + 更新字段 + + + + + 目标门店ID + + + + + 实体基类 + + 主键类型 + + + + 实体基类 + + + + + EntityOrgTypeEnum + + + + + 参数 + + + + + 主键类型为Guid的实体基类 + + + + + int型主键基类 + + + + + int型主键的树形表基类 + + + + + 父级ID + + + + + 显示名称 + + + + + GUID主键的树形表基类 + + + + + 父级ID + + + + + 显示名称 + + + + + 是否叶子节点 + + + + + 审核 + + + + + 审核状态 + + + + + 当前审批子节点ID + + + + + 当前审批节点ID + + + + + 审批流ID + + + + + 构造函数 + + + + + 包含部门ID的实体接口 + + + + + 部门ID + + + + + 初始化错误消息 + + + + diff --git a/APT.Infrastructure.Core/EF/IOrderable.cs b/APT.Infrastructure.Core/EF/IOrderable.cs new file mode 100644 index 0000000..c53dff6 --- /dev/null +++ b/APT.Infrastructure.Core/EF/IOrderable.cs @@ -0,0 +1,45 @@ +using System; +using System.Linq.Expressions; + +namespace APT.Infrastructure.Core +{ + /// + /// 排序规范 + /// + /// + public interface IOrderable + { + /// + /// 递增 + /// + /// + /// + /// + IOrderable Asc(global::System.Linq.Expressions.Expression> keySelector); + /// + /// 然后递增 + /// + /// + /// + /// + IOrderable ThenAsc(Expression> keySelector); + /// + /// 递减 + /// + /// + /// + /// + IOrderable Desc(global::System.Linq.Expressions.Expression> keySelector); + /// + /// 然后递减 + /// + /// + /// + /// + IOrderable ThenDesc(Expression> keySelector); + /// + /// 排序后的结果集 + /// + global::System.Linq.IQueryable Queryable { get; } + } +} diff --git a/APT.Infrastructure.Core/EF/IRepository.cs b/APT.Infrastructure.Core/EF/IRepository.cs new file mode 100644 index 0000000..7b960c8 --- /dev/null +++ b/APT.Infrastructure.Core/EF/IRepository.cs @@ -0,0 +1,222 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Threading.Tasks; + +namespace APT.Infrastructure.Core +{ + public interface IRepository : IDependInject + { + #region properties + + /// + /// 获取 当前单元操作对象 + /// + IUnitOfWork UnitOfWork { get; } + + + #endregion + + #region methods + + + void AddEntity(T entity, bool isSave = true) where T : MesEntityBase, new(); + + T AddAndGetEntity(T entity, bool isSave = true) where T : MesEntityBase, new(); + + void AddEntities(IEnumerable entities, bool isSave = true) where T : MesEntityBase, new(); + + void DeleteEntity(T entity, bool isSave = true) where T : MesEntityBase, new(); + + void DeleteEntity(Guid key, bool isSave = true) where T : MesEntityBase, new(); + + void DeleteEntity(Expression> predicate, bool isSave = true) where T : MesEntityBase, new(); + + + void DeleteEntities(IEnumerable entities, bool isSave = true) where T : MesEntityBase, new(); + + + bool UpdateEntity(T entity, bool isSave = true, params string[] updateField) where T : MesEntityBase, new(); + + void UpdateEntities(IEnumerable entities, bool isSave = true, params string[] updateField) where T : MesEntityBase, new(); + + void SaveEntities(IEnumerable entities, bool isSave = true) where T : MesEntityBase, new(); + + T GetEntity(Guid id, params string[] paths) + where T : MesEntityBase, new(); + T GetEntity(Expression> expression, BaseFilter filter, params string[] paths) + where T : MesEntityBase, new(); + T GetEntity(Expression> expression, BaseFilter filter, bool isTracking = true, params string[] paths) + where T : MesEntityBase, new(); + + T GetEntityByRedis(string key, Guid orgid) where T : MesEntityBase, new(); + + Task> GetEntitiesByRedis(BaseFilter filter) where T : MesEntityBase, new(); + + List GetEntitiesByRedis(Expression> expression, BaseFilter filter) where T : MesEntityBase, new(); + + Task> GetEntitiesTableByRedis(Expression> expression, BaseFilter filter, + params string[] paths) where T : MesEntityBase, new(); + + Task> GetEntitiesByRedis(Expression> expression, BaseFilter filter, string groupValue, + params string[] paths) where T : MesEntityBase, new(); + + PagedResultDto GetOrderPageByRedis(Expression> expression, BasePageFilter pageFilter, + params string[] paths) where T : MesEntityBase, new(); + + T GetEntityByRedis(Guid key, Guid orgid) where T : MesEntityBase, new(); + + Task> GetEntitiesByGroupRedis(BaseFilter filter, string groupValue) where T : MesEntityBase, new(); + + IEnumerable GetEntities(Expression> expression, BaseFilter filter, + params string[] paths) where T : MesEntityBase, new(); + IEnumerable GetEntities(Expression> expression, BaseFilter filter, + bool isTracking = true, params string[] paths) where T : MesEntityBase, new(); + IEnumerable GetOrderEntities(Expression> expression, BaseFilter filter, + params string[] paths) where T : MesEntityBase, new(); + IEnumerable GetOrderEntities(Expression> expression, BaseFilter filter, + bool isTracking = true, params string[] paths) where T : MesEntityBase, new(); + IEnumerable GetOrderEntities(Expression> expression, BaseFilter filter, Dictionary orders, + bool isTracking = true, params string[] paths) where T : MesEntityBase, new(); + IEnumerable GetOrderEntities(Expression> expression, BaseFilter filter, Dictionary orders, + Action> orderBy, + bool isTracking = true, params string[] paths) where T : MesEntityBase, new(); + + PagedResultDto GetPageEntities(Expression> expression, BasePageFilter pageFilter, + params string[] paths) where T : MesEntityBase, new(); + + PagedResultDto GetOrderPageEntities(Expression> expression, BasePageFilter pageFilter, + params string[] paths) where T : MesEntityBase, new(); + PagedResultDto GetOrderPageEntities(Expression> expression, BasePageFilter pageFilter, + int pageSize, int startIndex, + params string[] paths) where T : MesEntityBase, new(); + PagedResultDto GetOrderPageEntities(Expression> expression, BasePageFilter pageFilter, + int pageSize, int startIndex, bool isTracking = true, + params string[] paths) where T : MesEntityBase, new(); + PagedResultDto GetOrderPageEntities(Expression> expression, BasePageFilter pageFilter, + Dictionary orders, + int pageSize, int startIndex, bool isTracking = true, + params string[] paths) where T : MesEntityBase, new(); + IEnumerable> GetTreeOrderEntities(Expression> expression, BaseFilter filter, bool isTracking = true, + params string[] paths) where T : TreeEntityBase, new(); + + IEnumerable GetTree(string id, bool containCurrent = true, BaseFilter filter = null, + params string[] paths) where T : TreeEntityBase, new(); + + + PagedResultDto GetOrderPageEntities(Expression> expression, BasePageFilter pageFilter, + Dictionary orders, + int pageSize, int startIndex, Action> orderBy, bool isTracking = true, + params string[] paths) where T : MesEntityBase, new(); + // + PagedResultDto GetOrderPageEntities(Expression> expression, BasePageFilter pageFilter, + string[] selectField, params string[] paths) where T : MesEntityBase, new(); + + Task> GetOrderPageEntitiesSync(Expression> expression, BasePageFilter pageFilter, + params string[] paths) where T : MesEntityBase, new(); + Task> GetOrderPageEntitiesSync(Expression> expression, BasePageFilter pageFilter, + int pageSize, int startIndex, + params string[] paths) where T : MesEntityBase, new(); + Task> GetOrderPageEntitiesSync(Expression> expression, BasePageFilter pageFilter, + int pageSize, int startIndex, bool isTracking = true, + params string[] paths) where T : MesEntityBase, new(); + Task> GetOrderPageEntitiesSync(Expression> expression, BasePageFilter pageFilter, + Dictionary orders, + int pageSize, int startIndex, bool isTracking = true, + params string[] paths) where T : MesEntityBase, new(); + + Task> GetOrderPageEntitiesSync(Expression> expression, BasePageFilter pageFilter, + Dictionary orders, + int pageSize, int startIndex, Action> orderBy, bool isTracking = true, + params string[] paths) where T : MesEntityBase, new(); + + int GetCount(Expression> expression, BaseFilter filter) where T : MesEntityBase, new(); + bool IsAny(Expression> expression, BaseFilter filter) where T : MesEntityBase, new(); + #endregion + + /// + /// 填充系统参数 + /// + /// + /// + /// + void FillGetEntitySysParam(IEnumerable entities, BaseFilter filter, string[] includes); + + + T AddAndGetEntity_noneBase(T entity) where T : class; + + void AddEntities_noneBase(IEnumerable entities) where T : class; + + T GetEntity_noneBase(Expression> expressions) where T : class; + + List GetEntities_noneBase(Expression> expressions) where T : class; + + void UpdateEntities_noneBase(IEnumerable entities) where T : class; + + void DeleteEntity_noneBase(Expression> expression) where T : class; + + #region nocomit + void AddEntityNoCommit(T entity) where T : MesEntityBase, new(); + + + void AddEntitiesNoCommit(IEnumerable entities) where T : MesEntityBase, new(); + + + void UpdateEntitiesNoCommit(IEnumerable entities) where T : MesEntityBase, new(); + + bool UpdateEntityNoCommit(T entity, params string[] updateField) where T : MesEntityBase, new(); + + + void UpdateEntitiesNoCommit(IEnumerable entities, params string[] updateField) where T : MesEntityBase, new(); + + void DeleteEntityNoCommit(Expression> expression) where T : MesEntityBase, new(); + + + void DeleteEntityNoCommit(T entity) where T : MesEntityBase, new(); + + void DeleteEntityNoCommit(Guid id) where T : MesEntityBase, new(); + + void DeleteEntitiesNoCommit(IEnumerable entities) where T : MesEntityBase, new(); + + void SaveEntitiesNoCommit(IEnumerable entities) where T : MesEntityBase, new(); + + T AddAndGetEntityNoCommit(T entity) where T : MesEntityBase, new(); + + + void AddEntityByConn(T entity, string conn) where T : MesEntityBase, new(); + + void UpdateEntitiesByConn(IEnumerable entities, string conn) where T : MesEntityBase, new(); + + void UpdateEntityByConn(T entity, string conn, params string[] updateField) where T : MesEntityBase, new(); + + void DeleteEntityByConn(Expression> expression, string conn) where T : MesEntityBase, new(); + + void DeleteEntityByConn(T entity, string conn) where T : MesEntityBase, new(); + void DeleteEntityByConn(Guid id, string conn) where T : MesEntityBase, new(); + void DeleteEntitiesByConn(IEnumerable entities, string conn) where T : MesEntityBase, new(); + void AddEntitiesByConn(IEnumerable entities, string conn) where T : MesEntityBase, new(); + void UpdateEntitiesByConn(IEnumerable entities, string conn, params string[] updateField) where T : MesEntityBase, new(); + + //Tenant + void AddEntityByTenant(T entity, string Tenant) where T : MesEntityBase, new(); + + void UpdateEntitiesByTenant(IEnumerable entities, string Tenant) where T : MesEntityBase, new(); + + void UpdateEntityByTenant(T entity, string Tenant, params string[] updateField) where T : MesEntityBase, new(); + + void DeleteEntityByTenant(Expression> expression, string Tenant) where T : MesEntityBase, new(); + + void DeleteEntityByTenant(T entity, string Tenant) where T : MesEntityBase, new(); + void DeleteEntityByTenant(Guid id, string Tenant) where T : MesEntityBase, new(); + void DeleteEntitiesByTenant(IEnumerable entities, string Tenant) where T : MesEntityBase, new(); + void AddEntitiesByTenant(IEnumerable entities, string Tenant) where T : MesEntityBase, new(); + void UpdateEntitiesByTenant(IEnumerable entities, string Tenant, params string[] updateField) where T : MesEntityBase, new(); + + #endregion + } + + + +} diff --git a/APT.Infrastructure.Core/EF/IRepositoryAsync.cs b/APT.Infrastructure.Core/EF/IRepositoryAsync.cs new file mode 100644 index 0000000..bcf5ce5 --- /dev/null +++ b/APT.Infrastructure.Core/EF/IRepositoryAsync.cs @@ -0,0 +1,120 @@ +using System; +using System.Collections.Generic; +using System.Linq.Expressions; +using System.Threading.Tasks; + +namespace APT.Infrastructure.Core +{ + /// + /// 异步泛型主键实体仓储接口 + /// + /// 实体类型 + /// 实体主键类型 + public interface IRepositoryAsync where TEntity : EntityBase + { + /// + /// 异步插入实体 + /// + /// 实体对象 + /// 操作影响的行数 + Task AddAsync(TEntity entity); + + /// + /// 异步批量插入实体 + /// + /// 实体对象集合 + /// 操作影响的行数 + Task AddAsync(IEnumerable entities); + + /// + /// 异步删除实体 + /// + /// 实体对象 + /// 操作影响的行数 + Task DeleteAsync(TEntity entity); + + /// + /// 异步删除指定编号的实体 + /// + /// 实体编号 + /// 操作影响的行数 + Task DeleteAsync(TKey key); + + /// + /// 异步删除所有符合特定条件的实体 + /// + /// 查询条件谓语表达式 + /// 操作影响的行数 + Task DeleteAsync(Expression> predicate); + + /// + /// 异步批量删除删除实体 + /// + /// 实体对象集合 + /// 操作影响的行数 + Task DeleteAsync(IEnumerable entities); + + /// + /// 异步更新实体对象 + /// + /// 实体对象 + /// 操作影响的行数 + Task UpdateAsync(TEntity entity); + + /// + /// 异步批量更新实体对象 + /// + /// 实体对象集合 + /// 操作影响的行数 + Task UpdateAsync(IEnumerable entities); + + /// + /// 批量更新 + /// + /// 查询条件谓语表达式 + /// 更新表达式 + /// 操作影响的行数 + Task UpdateAsync(Expression> predicate, Expression> updateExpression); + + /// + /// 异步获取指定主键的实体 + /// + /// 实体主键 + /// 符合主键的实体,不存在时返回null + Task GetByKeyAsync(TKey key); + + /// + /// 异步获取符合条件的实体 + /// + /// 查询条件谓语表达式 + /// 符合条件的实体,不存在时返回null + Task GetAsync(Expression> predicate); + + /// + /// 异步获取记录数 + /// + /// + Task CountAsync(); + + /// + /// 异步获取符合条件的记录数 + /// + /// 查询条件谓语表达式 + /// + Task CountAsync(Expression> predicate = null); + + /// + /// 异步是否存在符合条件的记录 + /// + /// 查询条件谓语表达式 + /// + Task ExistsAsync(Expression> predicate); + } + + public interface IRepositoryAsync : IRepositoryAsync where TEntity : EntityBase + { + } + public interface IIntRepositoryAsync : IRepositoryAsync where TEntity : EntityBase + { + } +} diff --git a/APT.Infrastructure.Core/EF/IRowVersion.cs b/APT.Infrastructure.Core/EF/IRowVersion.cs new file mode 100644 index 0000000..b0b1fd9 --- /dev/null +++ b/APT.Infrastructure.Core/EF/IRowVersion.cs @@ -0,0 +1,10 @@ +namespace APT.Infrastructure.Core +{ + /// + /// 泛型时间戳接口 + /// + public interface IRowVersion + { + int ROW_VERSION { get; set; } + } +} diff --git a/APT.Infrastructure.Core/EF/IUnitOfWork.cs b/APT.Infrastructure.Core/EF/IUnitOfWork.cs new file mode 100644 index 0000000..f0e8ecb --- /dev/null +++ b/APT.Infrastructure.Core/EF/IUnitOfWork.cs @@ -0,0 +1,221 @@ + +using Microsoft.EntityFrameworkCore.Storage; +using System; +using System.Collections; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Data; +using System.Data.Common; +using System.Linq.Expressions; +using System.Threading; +using System.Threading.Tasks; + +namespace APT.Infrastructure.Core +{ + + public interface IUnitOfWork : IDependInject + { + #region methods + + string ConnectionString { get; } + + /// + /// 对数据库执行给定的 DDL/DML 命令。 + /// + /// 命令字符串 + /// 参数 + /// 受影响的行数 + int ExecuteSqlCommand(string sql, params object[] parameters); + /// + /// 对数据库执行给定的 DDL/DML 命令。 + /// + /// 事务行为 + /// 命令字符串 + /// 参数 + /// 受影响的行数 + int ExecuteSqlCommand(TransactionalBehavior transactionalBehavior, string sql, params object[] parameters); + + /// + /// 对数据库执行给定的 DDL/DML 命令返回reader。 + /// + /// 命令字符串 + /// reader委托 + void ExecuteReader(string sql, ReaderColumn[] readerColumns, Action readerAction); + + /// + /// 对数据库执行给定的 DDL/DML 命令返回reader。 + /// + /// 命令字符串 + /// 参数 + /// reader委托 + void ExecuteReader(string sql, ReaderColumn[] readerColumns, DbParameter[] parameters, Action readerAction); + + /// + /// 对数据库执行给定的 DDL/DML 命令返回reader。 + /// + /// 命令类型 + /// 命令字符串 + /// 参数 + /// reader委托 + void ExecuteReader(CommandType commandType, string sql, ReaderColumn[] readerColumns, DbParameter[] parameters, Action readerAction); + + /// + /// 对数据库执行给定的 DDL/DML 命令。 + /// + /// 命令类型 + /// 命令字符串 + /// 参数 + /// + int ExecuteNonQuery(CommandType commandType, string sql, ReaderColumn[] readerColumns, DbParameter[] parameters); + + + /// + /// 创建一个原始 SQL 查询,该查询将返回给定类型的元素。 + /// + /// 查询所返回对象的类型 + /// SQL 查询字符串 + /// 要应用于 SQL 查询字符串的参数 + /// + IEnumerable SqlQuery(Type elementType, string sql, ReaderColumn[] readerColumns, params Object[] parameters); + + /// + /// 提交当前单元操作的更改。 + /// + /// 操作影响的行数 + int SaveChanges(); + /// + /// 执行数据sql语句 + /// + /// 执行数据sql语句 + Task ExecuteSqlCommandAsync(TransactionalBehavior transactionalBehavior, string sql, params object[] parameters); + + /// + /// 异步提交当前单元操作的更改。 + /// + /// 操作影响的行数 + Task SaveChangesAsync(CancellationToken cancellationToken = default(CancellationToken)); + + /// + /// 开启事务 + /// + void BeginTransaction(); + + + /// + /// 提交事务 + /// + void CommitTransaction(); + + /// + /// 回滚事务 + /// + void RollbackTransaction(); + + T AddEntity(T entity) where T : class; + + void AddEntities(IEnumerable entities) where T : class; + + public void UpdateEntity(T entity) where T : class; + + void UpdateEntities(IEnumerable entities) where T : class; + + void UpdateEntities(IEnumerable entities, params string[] updateField) where T : class; + + + void DeleteEntities(IEnumerable entities) where T : class; + + DataBaseType GetDataBaseType(); + T GetEntity(Expression> expression, string[] selectField = null, params string[] paths) where T : class; + + T GetEntity(Expression> expression, string[] selectField = null, bool isTracking = true, params string[] paths) where T : class; + T GetEntity(Expression> expression, Dictionary orders, string[] selectField, + bool isTracking = true, params string[] paths) where T : class; + + int GetCount(Expression> expression) where T : class; + IEnumerable GetEntities(Expression> expression, string[] selectField = null, params string[] paths) where T : class; + + IEnumerable GetEntities(Expression> expression, string[] selectField = null, bool isTracking = true, params string[] paths) where T : class; + IEnumerable GetOrderEntities(Expression> expression, + Dictionary orders, string[] selectField = null, + params string[] paths) where T : class; + IEnumerable GetOrderEntities(Expression> expression, Dictionary orders, string[] selectField = null, + bool isTracking = true, params string[] paths) where T : class; + IEnumerable GetOrderEntities(Expression> expression, Dictionary orders, + Action> orderBy, string[] selectField, + bool isTracking = true, params string[] paths) where T : class; + + PagedResultDto GetOrderPageEntities(Expression> expression, Dictionary orders, string[] selectField, + int pageSize, int startIndex, + params string[] paths) where T : class; + + PagedResultDto GetOrderPageEntities(Expression> expression, Dictionary orders, string[] selectField, + int pageSieze, int startIndex, bool isTracking = true, + params string[] paths) where T : class; + PagedResultDto GetOrderPageEntities(Expression> expression, Dictionary orders, + int pageSieze, int startIndex, Action> orderBy, bool isTracking = true, + params string[] paths) where T : class; + + + PagedResultDto GetOrderPageEntities(Expression> expression, Dictionary orders, string[] selectField, + int pageSize, int startIndex, Action> orderBy, bool isTracking = true, + params string[] paths) where T : class; + + // + Task> GetOrderPageEntitiesSync(Expression> expression, Dictionary orders, + int pageSize, int startIndex, + params string[] paths) where T : class; + + Task> GetOrderPageEntitiesSync(Expression> expression, Dictionary orders, + int pageSieze, int startIndex, bool isTracking = true, + params string[] paths) where T : class; + Task> GetOrderPageEntitiesSync(Expression> expression, Dictionary orders, + int pageSieze, int startIndex, Action> orderBy, bool isTracking = true, + params string[] paths) where T : class; + + PagedResultDto GetPageEntities(Expression> expression, Dictionary orders, string[] selectField, + int pageSieze, int startIndex, Action> orderBy, bool isTracking = true, + params string[] paths) where T : class; + + /// + /// 根据表名获取表数据结构 + /// + /// + /// + EFModelTable GetModelTable(string tableName); + + /// + /// 根据表名、字段名称获取字段结构 + /// + /// + /// + /// + EFModelField GetModelField(string tableName, string fieldName); + + /// + /// 根据表名,导航名称获取外键信息 + /// + /// + /// + /// + EFModelForeignKey GetModelForeignKey(string tableName, string navName); + /// + /// 获取所有外键信息 + /// + /// + /// + List GetModelForeignKey(string tableName); + + /// + /// 根据表名,ID字段名称获取外键信息 + /// + /// + /// + /// + EFModelForeignKey GetModelForeignKeyById(string tableName, string idFieldName); + + public IEnumerable> GetTreeOrderEntities(Expression> expression, BaseFilter filter, + Expression> orgExpression, out List resultList, bool isTracking = true, + params string[] paths) where T : TreeEntityBase, new(); + #endregion + } +} diff --git a/APT.Infrastructure.Core/EF/Orderable.cs b/APT.Infrastructure.Core/EF/Orderable.cs new file mode 100644 index 0000000..080b1cd --- /dev/null +++ b/APT.Infrastructure.Core/EF/Orderable.cs @@ -0,0 +1,83 @@ +using System; +using System.Linq; +using System.Linq.Expressions; + + +namespace APT.Infrastructure.Core +{ + + /// + /// Linq架构里对集合排序实现 + /// + /// + public class Orderable : IOrderable + { + private IQueryable _queryable; + + /// + /// 排序后的结果集 + /// + /// + public Orderable(IQueryable enumerable) + { + _queryable = enumerable; + } + + /// + /// 排序之后的结果集 + /// + public IQueryable Queryable + { + get { return _queryable; } + } + /// + /// 递增 + /// + /// + /// + /// + public IOrderable Asc(Expression> keySelector) + { + _queryable = (_queryable as IOrderedQueryable) + .OrderBy(keySelector); + return this; + } + /// + /// 然后递增 + /// + /// + /// + /// + public IOrderable ThenAsc(Expression> keySelector) + { + _queryable = (_queryable as IOrderedQueryable) + .ThenBy(keySelector); + return this; + } + /// + /// 递减 + /// + /// + /// + /// + public IOrderable Desc(Expression> keySelector) + { + _queryable = _queryable + .OrderByDescending(keySelector); + return this; + } + /// + /// 然后递减 + /// + /// + /// + /// + public IOrderable ThenDesc(Expression> keySelector) + { + _queryable = (_queryable as IOrderedQueryable) + .ThenByDescending(keySelector); + return this; + } + } + +} \ No newline at end of file diff --git a/APT.Infrastructure.Core/Extensions/DateTimeExtension.cs b/APT.Infrastructure.Core/Extensions/DateTimeExtension.cs new file mode 100644 index 0000000..da42580 --- /dev/null +++ b/APT.Infrastructure.Core/Extensions/DateTimeExtension.cs @@ -0,0 +1,30 @@ +using System; + +namespace APT.Infrastructure.Core +{ + /// + /// DateTime 扩展类 + /// + public static class DateTimeExtensions + { + /// + /// 将当前DateTime值转换成yyyy-MM-dd字符串。 + /// + /// + /// + public static string ToDateString(this DateTime datetime) + { + return datetime.ToString("yyyy-MM-dd"); + } + + /// + /// 将当前DateTime值星期几中文字符串。 + /// + /// + /// + public static string ToDayOfWeekString(this DateTime datetime) + { + return datetime.ToString("dddd", new System.Globalization.CultureInfo("zh-CN")); + } + } +} diff --git a/APT.Infrastructure.Core/Extensions/EnumExtensions.cs b/APT.Infrastructure.Core/Extensions/EnumExtensions.cs new file mode 100644 index 0000000..7485274 --- /dev/null +++ b/APT.Infrastructure.Core/Extensions/EnumExtensions.cs @@ -0,0 +1,75 @@ +using System; +using System.ComponentModel; +using System.Collections.Generic; +using System.Linq; + + +namespace APT.Infrastructure.Core +{ + /// + /// 类型扩展方法类 + /// + public static class EnumExtensions + { + /// + /// 获取枚举值值 + /// + /// 枚举值 + /// + public static String GetDescription(this Enum enumeration) + { + if (enumeration == null) + return String.Empty; + + var enumType = enumeration.GetType(); + var fi = enumType.GetField(Enum.GetName(enumType, enumeration)); + var descAttr = (DescriptionAttribute)Attribute.GetCustomAttribute(fi, typeof(DescriptionAttribute)); + return descAttr == null || String.IsNullOrEmpty(descAttr.Description) ? enumeration.ToString() : descAttr.Description; + } + + /// + /// 将一个或多个枚举常数的名称或数字值的字符串表示转换成等效的枚举对象。 用于指示转换是否成功的返回值。 + /// + /// 要将 value 转换为的枚举类型。 + /// 要转换的枚举名称或基础值的字符串表示形式。 + /// 默认值 + /// 如果 value 参数成功转换,则返回类型为 TEnum 的一个对象,其值由 value 表示;否则为 defaultValue。 + public static TEnum ToEnum(this String value, TEnum defaultValue) where TEnum : struct + { + if (String.IsNullOrEmpty(value)) + return defaultValue; + TEnum result; + bool parseResult = Enum.TryParse(value, out result); + return parseResult ? result : defaultValue; + } + + + } + public class CommonEqualityComparer : IEqualityComparer + { + private Func keySelector; + + public CommonEqualityComparer(Func keySelector) + { + this.keySelector = keySelector; + } + + public bool Equals(T x, T y) + { + return EqualityComparer.Default.Equals(keySelector(x), keySelector(y)); + } + + public int GetHashCode(T obj) + { + return EqualityComparer.Default.GetHashCode(keySelector(obj)); + } + } + + public static class DistinctExtensions + { + public static IEnumerable Distinct(this IEnumerable source, Func keySelector) + { + return source.Distinct(new CommonEqualityComparer(keySelector)); + } + } +} diff --git a/APT.Infrastructure.Core/Extensions/EnumerableExtension.cs b/APT.Infrastructure.Core/Extensions/EnumerableExtension.cs new file mode 100644 index 0000000..778a512 --- /dev/null +++ b/APT.Infrastructure.Core/Extensions/EnumerableExtension.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Text; + +namespace APT.Infrastructure.Core.Extensions +{ + public static class QueryableExtensions + { + public static IQueryable OrderByName(this IQueryable queryable, string propertyName, bool desc = false) + { + return QueryableHelper.OrderBy(queryable, propertyName, desc); + } + static class QueryableHelper + { + private static Dictionary cache = new Dictionary(); + public static IQueryable OrderBy(IQueryable queryable, string propertyName, bool desc) + { + dynamic keySelector = GetLambdaExpression(propertyName); + return desc ? Queryable.OrderByDescending(queryable, keySelector) : Queryable.OrderBy(queryable, keySelector); + } + private static LambdaExpression GetLambdaExpression(string propertyName) + { + if (cache.ContainsKey(propertyName)) return cache[propertyName]; + var param = Expression.Parameter(typeof(T)); + var body = Expression.Property(param, propertyName); + var keySelector = Expression.Lambda(body, param); + cache[propertyName] = keySelector; + return keySelector; + } + } + } +} diff --git a/APT.Infrastructure.Core/Extensions/ExpressionExtensions.cs b/APT.Infrastructure.Core/Extensions/ExpressionExtensions.cs new file mode 100644 index 0000000..71e4178 --- /dev/null +++ b/APT.Infrastructure.Core/Extensions/ExpressionExtensions.cs @@ -0,0 +1,80 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; + + +namespace APT.Infrastructure.Core +{ + /// + /// Expression表达式扩展操作类 + /// + public static class ExpressionExtensions + { + /// + /// 以特定的条件运行组合两个Expression表达式 + /// + /// 表达式的主实体类型 + /// 第一个Expression表达式 + /// 要组合的Expression表达式 + /// 组合条件运算方式 + /// 组合后的表达式 + public static Expression Compose(this Expression first, Expression second, Func merge) + { + Dictionary map = + first.Parameters.Select((f, i) => new { f, s = second.Parameters[i] }).ToDictionary(p => p.s, p => p.f); + Expression secondBody = ParameterRebinder.ReplaceParameters(map, second.Body); + return Expression.Lambda(merge(first.Body, secondBody), first.Parameters); + } + + /// + /// 以 Expression.AndAlso 组合两个Expression表达式 + /// + /// 表达式的主实体类型 + /// 第一个Expression表达式 + /// 要组合的Expression表达式 + /// 组合后的表达式 + public static Expression> And(this Expression> first, Expression> second) + { + return first.Compose(second, Expression.AndAlso); + } + + /// + /// 以 Expression.OrElse 组合两个Expression表达式 + /// + /// 表达式的主实体类型 + /// 第一个Expression表达式 + /// 要组合的Expression表达式 + /// 组合后的表达式 + public static Expression> Or(this Expression> first, Expression> second) + { + return first.Compose(second, Expression.OrElse); + } + + + private class ParameterRebinder : ExpressionVisitor + { + private readonly Dictionary _map; + + private ParameterRebinder(Dictionary map) + { + _map = map ?? new Dictionary(); + } + + public static Expression ReplaceParameters(Dictionary map, Expression exp) + { + return new ParameterRebinder(map).Visit(exp); + } + + protected override Expression VisitParameter(ParameterExpression node) + { + ParameterExpression replacement; + if (_map.TryGetValue(node, out replacement)) + { + node = replacement; + } + return base.VisitParameter(node); + } + } + } +} \ No newline at end of file diff --git a/APT.Infrastructure.Core/Extensions/FilterGroupExtensions.cs b/APT.Infrastructure.Core/Extensions/FilterGroupExtensions.cs new file mode 100644 index 0000000..71ceadd --- /dev/null +++ b/APT.Infrastructure.Core/Extensions/FilterGroupExtensions.cs @@ -0,0 +1,45 @@ +using System; +using System.Linq.Expressions; + +namespace APT.Infrastructure.Core +{ + /// + /// 类型扩展方法类 + /// + public static class FilterGroupExtensions + { + /// + /// 生成条件表达式 + /// + /// 类型 + /// 条件组 + /// + public static Expression> BuildExpression(this FilterGroup group, IUnitOfWork unitOfWork) + { + return FilterHelper.GetExpression(group, unitOfWork); + } + /// + /// 生成条件表达式 + /// + /// + /// + /// + public static Expression> BuildExpression(this FilterRule rule) + { + return FilterHelper.GetExpression(rule); + } + + /// + /// 生成条件表达式 + /// + /// 类型 + /// 条件组 + /// + public static Expression> BuildExpression(this BaseFilter filter, IUnitOfWork unitOfWork) + { + //var expression = FilterHelper.GetExpression(filter.FilterRule); + return FilterHelper.GetExpression(filter.FilterGroup, unitOfWork); + } + + } +} diff --git a/APT.Infrastructure.Core/Extensions/Int32Extensions.cs b/APT.Infrastructure.Core/Extensions/Int32Extensions.cs new file mode 100644 index 0000000..7cdc959 --- /dev/null +++ b/APT.Infrastructure.Core/Extensions/Int32Extensions.cs @@ -0,0 +1,34 @@ +using System; + +namespace APT.Infrastructure.Core +{ + /// + /// 类型扩展方法类 + /// + public static class Int32Extensions + { + /// + /// 返回一个新字符串,该字符串通过在此实例中的字符左侧填充指定的 Unicode 字符来达到指定的总长度,从而使这些字符右对齐。 + /// + /// + /// + /// + /// + public static String PadLeft(this Int32 source, int totalWidth, char paddingChar) + { + return source.ToString().PadLeft(totalWidth, paddingChar); + } + + /// + /// 返回一个新字符串,该字符串通过在此字符串中的字符右侧填充指定的 Unicode 字符来达到指定的总长度,从而使这些字符左对齐。 + /// + /// + /// + /// + /// + public static String PadRight(this Int32 source, int totalWidth, char paddingChar) + { + return source.ToString().PadRight(totalWidth, paddingChar); + } + } +} diff --git a/APT.Infrastructure.Core/Extensions/JsonExtensions.cs b/APT.Infrastructure.Core/Extensions/JsonExtensions.cs new file mode 100644 index 0000000..9d31716 --- /dev/null +++ b/APT.Infrastructure.Core/Extensions/JsonExtensions.cs @@ -0,0 +1,37 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using System; +using System.Collections.Generic; +using System.Text; + +namespace APT.Infrastructure.Core +{ + public static class JsonExtensions + { + /// + /// 把对象序列化成Json字符串格式 + /// + /// + /// + public static string ToJson(this object obj) + { + JsonSerializerSettings settings = new JsonSerializerSettings(); + settings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore; + settings.NullValueHandling = NullValueHandling.Ignore; + settings.DateFormatString = "yyyy-MM-dd HH:mm:ss"; + return JsonConvert.SerializeObject(obj, settings); + } + /// + /// 把Json字符串转换为强类型对象 + /// + public static T DeserializeObject(this string json) + { + return JsonConvert.DeserializeObject(json); + } + + public static JObject ToJObject(this string Json) + { + return Json == null ? JObject.Parse("{}") : JObject.Parse(Json.Replace(" ", "")); + } + } +} diff --git a/APT.Infrastructure.Core/Extensions/LinqExtensions.cs b/APT.Infrastructure.Core/Extensions/LinqExtensions.cs new file mode 100644 index 0000000..f843963 --- /dev/null +++ b/APT.Infrastructure.Core/Extensions/LinqExtensions.cs @@ -0,0 +1,67 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics.Contracts; +using System.Linq; + +namespace APT.Infrastructure.Core +{ + /// + /// Linq 拓展方法类 + /// + public static class LinqExtensions + { + public static void ForEach(this IEnumerable source, Action action) + { + Contract.Requires(action != null); + foreach (var element in source) + action(element); + } + public class DGroupBy : IGrouping + { + private List _innerlist = new List(); + + private object[] _key; + + public DGroupBy(object[] key) { _key = key; } + + public object[] Key + { + get { return _key; } + } + + public void Add(T value) + { + _innerlist.Add(value); + } + + public IEnumerator GetEnumerator() + { + return this._innerlist.GetEnumerator(); + } + + System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() + { + return this._innerlist.GetEnumerator(); + } + } + + public static IEnumerable> DynamicGroupBy(this IEnumerable data, string[] keys) + { + List> list = new List>(); + foreach (var item in data.Select(x => new { + k = keys.Select(y => x.GetType().GetProperty(y).GetValue(x, null)).ToArray(), + v = x + })) + { + DGroupBy existing = list.SingleOrDefault(x => x.Key.Zip(item.k, (a, b) => a.Equals(b)).All(y => y)); + if (existing == null) + { + existing = new DGroupBy(item.k); + list.Add(existing); + } + existing.Add(item.v); + } + return list; + } + } +} diff --git a/APT.Infrastructure.Core/Extensions/QueryableOrderExtension.cs b/APT.Infrastructure.Core/Extensions/QueryableOrderExtension.cs new file mode 100644 index 0000000..dba3051 --- /dev/null +++ b/APT.Infrastructure.Core/Extensions/QueryableOrderExtension.cs @@ -0,0 +1,57 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using System.Diagnostics.Contracts; +namespace APT.Infrastructure.Core +{ + public static class QueryableOrderExtension + { + public static IQueryable SetQueryableOrder(this IQueryable query, string sort, string order, bool isThen = false) + { + if (string.IsNullOrEmpty(sort)) + throw new Exception("必须指定排序字段!"); + + //PropertyInfo sortProperty = typeof(T).GetProperty(sort, BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase); + //if (sortProperty == null) + // throw new Exception("查询对象中不存在排序字段" + sort + "!"); + + ParameterExpression param = Expression.Parameter(typeof(T), "t"); + Expression body = param; + if (Nullable.GetUnderlyingType(body.Type) != null) + body = Expression.Property(body, "Value"); + body = GetPropertyLambdaExpression(body, sort); + LambdaExpression keySelectorLambda = Expression.Lambda(body, param); + + if (string.IsNullOrEmpty(order)) + order = "ASC"; + string queryMethod = isThen ? order.ToUpper() == "DESC" ? "ThenByDescending" : "ThenBy" : order.ToUpper() == "DESC" ? "OrderByDescending" : "OrderBy"; + query = query.Provider.CreateQuery(Expression.Call(typeof(Queryable), queryMethod, + new Type[] { typeof(T), body.Type }, + query.Expression, + Expression.Quote(keySelectorLambda))); + return query; + } + + private static Expression GetPropertyLambdaExpression(Expression body, string fileName) + { + string[] propertyNames = fileName.Split('.'); + Type type = body.Type; + foreach (string propertyName in propertyNames) + { + PropertyInfo property = type.GetProperty(propertyName); + //Contract.Assume(property != null); + if (property == null) + { + throw new Exception($"类型{type.Name}不存在属性{propertyName}"); + } + type = property.PropertyType; + body = Expression.MakeMemberAccess(body, property); + } + return body; + } + } +} diff --git a/APT.Infrastructure.Core/Extensions/RandomExtensions.cs b/APT.Infrastructure.Core/Extensions/RandomExtensions.cs new file mode 100644 index 0000000..60003bb --- /dev/null +++ b/APT.Infrastructure.Core/Extensions/RandomExtensions.cs @@ -0,0 +1,78 @@ +using System; +using System.Text; + +namespace APT.Infrastructure.Core +{ + /// + /// 类型扩展方法类 + /// + public static class RandomExtensions + { + static char[] _numberPattern = new char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' }; + static char[] _letterPattern = new char[] { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L','M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' }; + static char[] _letterAndNumberPattern = new char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P','Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' }; + + /// + /// 获取指定的长度的随机数字字符串 + /// + /// + /// 要获取随机数长度 + /// 指定长度的随机数字符串 + public static string NextNumberString(this Random random, int length) + { + if (length < 0) + throw new ArgumentOutOfRangeException("length"); + int n = _numberPattern.Length; + StringBuilder randomBuilder = new StringBuilder(); + for (int i = 0; i < length; i++) + { + int rnd = random.Next(0, n); + randomBuilder.Append(_numberPattern[rnd]); + } + return randomBuilder.ToString(); + } + + /// + /// 获取指定的长度的随机字母字符串 + /// + /// + /// 要获取随机数长度 + /// 指定长度的随机字母组成字符串 + public static string NextLetterString(this Random random, int length) + { + if (length < 0) + { + throw new ArgumentOutOfRangeException("length"); + } + int n = _letterPattern.Length; + StringBuilder randomBuilder = new StringBuilder(); + for (int i = 0; i < length; i++) + { + int rnd = random.Next(0, n); + randomBuilder.Append(_letterPattern[rnd]); + } + return randomBuilder.ToString(); + } + + /// + /// 获取指定的长度的随机字母和数字字符串 + /// + /// + /// 要获取随机数长度 + /// 指定长度的随机字母和数字组成字符串 + public static string NextLetterAndNumberString(this Random random, int length) + { + if (length < 0) + throw new ArgumentOutOfRangeException("length"); + int n = _letterAndNumberPattern.Length; + StringBuilder randomBuilder = new StringBuilder(); + for (int i = 0; i < length; i++) + { + int rnd = random.Next(0, n); + randomBuilder.Append(_letterAndNumberPattern[rnd]); + } + return randomBuilder.ToString(); + } + } +} diff --git a/APT.Infrastructure.Core/Extensions/TypeExtensions.cs b/APT.Infrastructure.Core/Extensions/TypeExtensions.cs new file mode 100644 index 0000000..59c2380 --- /dev/null +++ b/APT.Infrastructure.Core/Extensions/TypeExtensions.cs @@ -0,0 +1,167 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Reflection; + +namespace APT.Infrastructure.Core +{ + /// + /// 类型扩展方法类 + /// + public static class TypeExtensions + { + public static object GetListObject(this Type p_Type) + { + Assembly _Assembly = Assembly.Load("mscorlib"); + Type _TypeList = _Assembly.GetType("System.Collections.Generic.List`1[[" + p_Type.FullName + "," + p_Type.Assembly.FullName + "]]"); + object _List = System.Activator.CreateInstance(_TypeList); + return _List; + } + /// + /// 判断类型是否为Nullable类型 + /// + /// 要处理的类型 + /// 是返回True,不是返回False + public static bool IsNullableType(this Type type) + { + return ((type != null) && type.IsGenericType) && (type.GetGenericTypeDefinition().Equals(typeof(Nullable<>))); + } + + /// + /// 由类型的Nullable类型返回实际类型 + /// + /// 要处理的类型对象 + /// + public static Type GetNonNummableType(this Type type) + { + if (IsNullableType(type)) + { + return type.GetGenericArguments()[0]; + } + return type; + } + + /// + /// 通过类型转换器获取Nullable类型的基础类型 + /// + /// 要处理的类型对象 + /// + public static Type GetUnNullableType(this Type type) + { + if (IsNullableType(type)) + { + NullableConverter nullableConverter = new NullableConverter(type); + return nullableConverter.UnderlyingType; + } + return type; + } + + /// + /// 获取成员元数据的Description特性描述信息 + /// + /// 成员元数据对象 + /// 是否搜索成员的继承链以查找描述特性 + /// 返回Description特性描述信息,如不存在则返回成员的名称 + public static string ToDescription(this MemberInfo member, bool inherit = false) + { + DescriptionAttribute desc = member.GetAttribute(inherit); + return desc == null ? member.Name : desc.Description; + } + + /// + /// 检查指定指定类型成员中是否存在指定的Attribute特性 + /// + /// 要检查的Attribute特性类型 + /// 要检查的类型成员 + /// 是否从继承中查找 + /// 是否存在 + public static bool ExistsAttribute(this MemberInfo memberInfo, bool inherit = false) where T : Attribute + { + return memberInfo.GetCustomAttributes(typeof(T), inherit).Any(m => (m as T) != null); + } + + /// + /// 从类型成员获取指定Attribute特性 + /// + /// Attribute特性类型 + /// 类型类型成员 + /// 是否从继承中查找 + /// 存在返回第一个,不存在返回null + public static T GetAttribute(this MemberInfo memberInfo, bool inherit = false) where T : Attribute + { + var descripts = memberInfo.GetCustomAttributes(typeof(T), inherit); + return descripts.FirstOrDefault() as T; + } + + /// + /// 从类型成员获取指定Attribute特性 + /// + /// Attribute特性类型 + /// 类型类型成员 + /// 是否从继承中查找 + /// 返回所有指定Attribute特性的数组 + public static T[] GetAttributes(this MemberInfo memberInfo, bool inherit = false) where T : Attribute + { + return memberInfo.GetCustomAttributes(typeof(T), inherit).Cast().ToArray(); + } + + /// + /// 判断类型是否为集合类型 + /// + /// 要处理的类型 + /// 是返回True,不是返回False + public static bool IsEnumerable(this Type type) + { + if (type == typeof(string)) + { + return false; + } + return typeof(IEnumerable).IsAssignableFrom(type); + } + + /// + /// 判断当前泛型类型是否可由指定类型的实例填充 + /// + /// 泛型类型 + /// 指定类型 + /// + public static bool IsGenericAssignableFrom(this Type genericType, Type type) + { + if (genericType == null || type == null) + { + return false; + } + if (!genericType.IsGenericType) + { + throw new ArgumentException("该功能只支持泛型类型的调用,非泛型类型可使用 IsAssignableFrom 方法。"); + } + + List allOthers = new List { type }; + if (genericType.IsInterface) + { + allOthers.AddRange(type.GetInterfaces()); + } + + foreach (var other in allOthers) + { + Type cur = other; + while (cur != null) + { + if (cur.IsGenericType) + { + cur = cur.GetGenericTypeDefinition(); + } + if (cur.IsSubclassOf(genericType) || cur == genericType) + { + return true; + } + cur = cur.BaseType; + } + } + return false; + } + + } +} diff --git a/APT.Infrastructure.Core/Helper/ApiHelper.cs b/APT.Infrastructure.Core/Helper/ApiHelper.cs new file mode 100644 index 0000000..102bed0 --- /dev/null +++ b/APT.Infrastructure.Core/Helper/ApiHelper.cs @@ -0,0 +1,683 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net; +using System.Net.Http; +using System.Net.Security; +using System.Reflection; +using System.Security.Cryptography.X509Certificates; +using System.Text; +using System.Threading.Tasks; + +namespace APT.Infrastructure.Core +{ + public class ApiHelper + { + public static int URL_TIMEOUT = 60000 * 120;//2个小时 + private static string ApiByGet(string url, IDictionary parameters, string token, IDictionary headParams) + { + HttpWebResponse response = HttpWebResponseUtility.CreateGetHttpResponseByParams(url, parameters, URL_TIMEOUT, "", null, token, headParams); + var sr = new System.IO.StreamReader(response.GetResponseStream()); + string content = sr.ReadToEnd(); //这里的content就是网页内容了 + sr.Close(); + return content; + } + private static string ApiByPost(string url, IDictionary parameters, string token, IDictionary headParams = null) + { + HttpWebResponse response = HttpWebResponseUtility.CreateApiPostHttpResponse(url, parameters, URL_TIMEOUT, "", Encoding.UTF8, null, token, headParams); + var sr = new System.IO.StreamReader(response.GetResponseStream()); + string content = sr.ReadToEnd(); //这里的content就是网页内容了 + sr.Close(); + return content; + } + private static string ApiSend(ApiBody body) + { + var response = HttpWebResponseUtility.CreatePostHttpResponseByJson(body.ApiUrl, body.SendObj != null ? JsonConvert.SerializeObject(body.SendObj) : string.Empty, + URL_TIMEOUT, "", null, body.Token, body.HeadParams); + if (response != null) + { + var sr = new System.IO.StreamReader(response.GetResponseStream()); + string content = sr.ReadToEnd(); //这里的content就是网页内容了 + sr.Close(); + System.Diagnostics.Debug.WriteLine(content); + return content; + } + else + { + return ""; + } + } + + public static byte[] ApiPicture(ApiBody body) + { + var response = HttpWebResponseUtility.CreatePostHttpResponseByJson(body.ApiUrl, body.SendObj != null ? JsonConvert.SerializeObject(body.SendObj) : string.Empty, + URL_TIMEOUT, "", null, body.Token, body.HeadParams); + if (response != null) + { + //获取HTTP返回数据 + using (Stream sr = response.GetResponseStream()) + { + byte[] img = new byte[response.ContentLength]; + sr.Read(img, 0, (int)response.ContentLength);//这里获取之后 + sr.Close(); + sr.Dispose(); + return img; + } + response.Close(); + } + else + { + return null; + } + } + + public static T GetApiData(ApiBody body) + { + int totalCount = 0; + var ret = GetApiData(body, ref totalCount); + return ret; + } + public static T GetApiData(ApiBody body, ref int totalCount) + { + string msg = string.Empty; + var ret = GetApiData(body, ref totalCount, ref msg); + + return ret; + } + public static string GetApiData(ApiBody body, ref string msg) + { + string returns = string.Empty; + //参数 + if (body.SendType == SendType.Get) + { + if (body.SendObj != null) + body.Params = GetParameters(body.SendObj); + returns = ApiByGet(body.ApiUrl, body.Params, body.Token, body.HeadParams); + } + else if (body.SendType == SendType.Post) + { + if (body.Params != null && body.Params.Any()) + returns = ApiByPost(body.ApiUrl, body.Params, body.Token, body.HeadParams); + else + returns = ApiSend(body); + } + LoggerManager.GetLogger().Info($"请求接口:{body.ApiUrl},返回:{returns}"); + if (!string.IsNullOrEmpty(returns)) + { + if (body.ResolvingResult) + { + return returns; + } + else + { + var s = Newtonsoft.Json.JsonConvert.DeserializeObject(returns); + var obj = JObject.Parse(s.ToString()); + var result = Convert.ToBoolean(obj["IsSuccessful"]); + if (result) + { + return obj["Data"] == null ? "" : obj["Data"].ToString(); + } + else + { + if (obj["ErrorMessage"] != null) + msg = obj["ErrorMessage"].ToString(); + } + } + } + return ""; + } + + public static T GetApiData(ApiBody body, ref int totalCount, ref string msg) + { + string returns = string.Empty; + //参数 + if (body.SendType == SendType.Get) + { + if (body.SendObj != null) + body.Params = GetParameters(body.SendObj); + returns = ApiByGet(body.ApiUrl, body.Params, body.Token, body.HeadParams); + } + else if (body.SendType == SendType.Post) + { + if (body.Params != null && body.Params.Any()) + returns = ApiByPost(body.ApiUrl, body.Params, body.Token, body.HeadParams); + else + returns = ApiSend(body); + } + LoggerManager.GetLogger().Info($"请求接口:{body.ApiUrl},返回:{returns}"); + if (!string.IsNullOrEmpty(returns)) + { + if (body.ResolvingResult) + { + try + { + var t = JsonConvert.DeserializeObject(returns); + return t; + } + catch (Exception ex) + { + return default(T); + } + } + else + { + var s = Newtonsoft.Json.JsonConvert.DeserializeObject(returns); + var obj = JObject.Parse(s.ToString()); + var result = Convert.ToBoolean(obj["IsSuccessful"]); + if (result) + { + if (obj["Data"].ToString() != "[]") + { + totalCount = obj["TotalCount"] == null ? 0 : Convert.ToInt32(obj["TotalCount"]); + try + { + var t = JsonConvert.DeserializeObject(obj["Data"].ToString()); + return t; + } + catch (Exception ex) + { + return default(T); + } + } + } + else + { + if (obj["ErrorMessage"] != null) + msg = obj["ErrorMessage"].ToString(); + } + } + } + return default(T); + } + + public static bool GetApiData(ApiBody body, ref int totalCount, ref string msg) + { + string returns = string.Empty; + if (body.SendType == SendType.Get) + { + //参数 + if (body.SendObj != null) + body.Params = GetParameters(body.SendObj); + returns = ApiByGet(body.ApiUrl, body.Params, body.Token, body.HeadParams); + } + else if (body.SendType == SendType.Post) + { + if (body.Params != null && body.Params.Any()) + returns = ApiByPost(body.ApiUrl, body.Params, body.Token); + else + returns = ApiSend(body); + } + var result = false; + if (!string.IsNullOrEmpty(returns)) + { + var s = Newtonsoft.Json.JsonConvert.DeserializeObject(returns); + var obj = JObject.Parse(s.ToString()); + result = Convert.ToBoolean(obj["IsSuccessful"]); + if (result && obj["Data"].ToString() != "[]") + { + totalCount = obj["TotalCount"] == null ? 0 : Convert.ToInt32(obj["TotalCount"]); + } + if (obj["ErrorMessage"] != null) + msg = obj["ErrorMessage"].ToString(); + } + return result; + } + public static bool GetApiData(ApiBody body, ref int totalCount) + { + string msg = string.Empty; + return GetApiData(body, ref totalCount, ref msg); + } + + + + + public static IDictionary GetParameters(object obj) + { + IDictionary Params = new Dictionary(); + if (obj != null) + { + var type = obj.GetType(); + PropertyInfo[] properties = type.GetProperties().Where(p => !p.GetMethod.IsVirtual).ToArray(); + + foreach (PropertyInfo info in properties) + { + try + { + + var value = GetObjectPropertyValue(obj, info.Name).ToString(); + if (value == "APT.Infrastructure.Core.FilterGroup" || value.StartsWith("System.Collections.Generic.List")) + { + continue; + } + Params.Add(info.Name, value); + } + catch (Exception ex) + { + throw new Exception(ex.Message); + } + + } + } + return Params; + } + public static IDictionary NewGetPrarams(object obj) + { + IDictionary Params = new Dictionary(); + if (obj != null) + { + var type = obj.GetType(); + PropertyInfo[] properties = type.GetProperties(); + + foreach (PropertyInfo info in properties) + { + try + { + Params.Add(info.Name, GetObjectPropertyValue(obj, info.Name)); + } + catch (Exception ex) + { + System.Diagnostics.Debug.WriteLine(ex.Message); + } + + } + } + return Params; + } + public static object GetObjectPropertyValue(object obj, string propertyname) + { + var t = obj.GetType(); + PropertyInfo property = t.GetProperty(propertyname); + + if (property == null) return string.Empty; + + object o = property.GetValue(obj, null); + + + if (o == null) return string.Empty; + + return o; + } + } + + + public class ApiBody + { + public ApiBody() + { + this.HeadParams = new Dictionary(); + } + public string ApiUrl { get; set; } + public IDictionary Params { get; set; } + public SendType SendType { get; set; } + public Object SendObj { get; set; } + public bool ResolvingResult { get; set; } + + public string Token { get; set; } + public IDictionary HeadParams { get; set; } + } + + public class PagedList : List, IEnumerable + { + public PagedList(IEnumerable currentPageItems, int pageIndex, int pageSize, int totalItemCount) + { + this.AddRange(currentPageItems); + this.CurrentPageIndex = pageIndex; + this.PageSize = pageSize; + this.TotalPageCount = totalItemCount; + } + + public int CurrentPageIndex { get; set; } + public int PageSize { get; set; } + public int TotalPageCount { get; } + } + public enum SendType + { + Get, + Post, + Put, + Delete + } + public class HttpWebResponseUtility + { + private static readonly string DefaultUserAgent = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)"; + /// + /// 创建GET方式的HTTP请求 + /// + /// 请求的URL + /// 请求的超时时间 + /// 请求的客户端浏览器信息,可以为空 + /// 随同HTTP请求发送的Cookie信息,如果不需要身份验证可以为空 + /// + public static HttpWebResponse CreateGetHttpResponse(string url, int? timeout, string userAgent, CookieCollection cookies) + { + if (string.IsNullOrEmpty(url)) + { + throw new ArgumentNullException("url"); + } + HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest; + request.Method = "GET"; + request.UserAgent = DefaultUserAgent; + if (!string.IsNullOrEmpty(userAgent)) + { + request.UserAgent = userAgent; + } + if (timeout.HasValue) + { + request.Timeout = timeout.Value; + } + if (cookies != null) + { + request.CookieContainer = new CookieContainer(); + request.CookieContainer.Add(cookies); + } + return request.GetResponse() as HttpWebResponse; + } + /// + /// 创建GET方式的HTTP请求 + /// + /// 请求的URL + /// 请求的超时时间 + /// 请求的客户端浏览器信息,可以为空 + /// 随同HTTP请求发送的Cookie信息,如果不需要身份验证可以为空 + /// + public static HttpWebResponse CreateGetHttpResponseByParams(string url, IDictionary parameters, int? timeout, string userAgent, CookieCollection cookies, string token, IDictionary headParams) + { + if (string.IsNullOrEmpty(url)) + { + throw new ArgumentNullException("url"); + } + if (!(parameters == null || parameters.Count == 0)) + { + int i = 0; + foreach (string key in parameters.Keys) + { + if (i > 0) + { + url += string.Format("&{0}={1}", key, parameters[key]); + } + else + { + url += string.Format("?{0}={1}", key, parameters[key]); + } + i++; + } + } + HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest; + request.Method = "GET"; + request.UserAgent = DefaultUserAgent; + if (!string.IsNullOrEmpty(token)) + request.Headers.Add("Authorization", "Bearer " + token); + if (headParams != null && headParams.Any()) + headParams.ForEach(t => + { + request.Headers.Add(t.Key, t.Value); + }); + if (!string.IsNullOrEmpty(userAgent)) + { + request.UserAgent = userAgent; + } + if (timeout.HasValue) + { + request.Timeout = timeout.Value; + } + if (cookies != null) + { + request.CookieContainer = new CookieContainer(); + request.CookieContainer.Add(cookies); + } + return request.GetResponse() as HttpWebResponse; + } + + public static HttpWebResponse CreatePostHttpResponseByJson(string url, string json, int? timeout, string userAgent, CookieCollection cookies, string token, IDictionary headParams) + { + if (string.IsNullOrEmpty(url)) + { + throw new ArgumentNullException("url"); + } + byte[] bytes = null; + if (!string.IsNullOrEmpty(json)) + bytes = Encoding.UTF8.GetBytes(json); + HttpWebRequest request = null; + //如果是发送HTTPS请求 + if (url.StartsWith("https", StringComparison.OrdinalIgnoreCase)) + { + ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(CheckValidationResult); + request = WebRequest.Create(url) as HttpWebRequest; + request.ProtocolVersion = HttpVersion.Version10; + } + else + { + request = WebRequest.Create(url) as HttpWebRequest; + } + request.Method = "POST"; + request.ContentType = "application/json"; + if (!string.IsNullOrEmpty(token)) + request.Headers.Add("Authorization", "Bearer " + token); + if (headParams != null && headParams.Any()) + headParams.ForEach(t => + { + request.Headers.Add(t.Key, t.Value); + }); + + if (!string.IsNullOrEmpty(userAgent)) + { + request.UserAgent = userAgent; + } + else + { + request.UserAgent = DefaultUserAgent; + } + + if (timeout.HasValue) + { + request.Timeout = timeout.Value; + } + if (cookies != null) + { + request.CookieContainer = new CookieContainer(); + request.CookieContainer.Add(cookies); + } + if (bytes != null) + { + using (Stream stream = request.GetRequestStream()) + { + stream.Write(bytes, 0, bytes.Length); + } + } + return request.GetResponse() as HttpWebResponse; + + } + + /// + /// 创建POST方式的HTTP请求 + /// + /// 请求的URL + /// 随同请求POST的参数名称及参数值字典 + /// 请求的超时时间 + /// 请求的客户端浏览器信息,可以为空 + /// 发送HTTP请求时所用的编码 + /// 随同HTTP请求发送的Cookie信息,如果不需要身份验证可以为空 + /// + public static HttpWebResponse CreatePostHttpResponse(string url, IDictionary parameters, int? timeout, string userAgent, Encoding requestEncoding, CookieCollection cookies) + { + if (string.IsNullOrEmpty(url)) + { + throw new ArgumentNullException("url"); + } + if (requestEncoding == null) + { + throw new ArgumentNullException("requestEncoding"); + } + HttpWebRequest request = null; + //如果是发送HTTPS请求 + if (url.StartsWith("https", StringComparison.OrdinalIgnoreCase)) + { + ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(CheckValidationResult); + request = WebRequest.Create(url) as HttpWebRequest; + request.ProtocolVersion = HttpVersion.Version10; + } + else + { + request = WebRequest.Create(url) as HttpWebRequest; + } + //request.Method = "POST"; + //request.ContentType = "application/x-www-form-urlencoded"; + + request.Method = "GET"; + //request.ContentType = "application/x-www-form-urlencoded"; + + if (!string.IsNullOrEmpty(userAgent)) + { + request.UserAgent = userAgent; + } + else + { + request.UserAgent = DefaultUserAgent; + } + + if (timeout.HasValue) + { + request.Timeout = timeout.Value; + } + if (cookies != null) + { + request.CookieContainer = new CookieContainer(); + request.CookieContainer.Add(cookies); + } + //如果需要POST数据 + if (!(parameters == null || parameters.Count == 0)) + { + StringBuilder buffer = new StringBuilder(); + int i = 0; + foreach (string key in parameters.Keys) + { + if (i > 0) + { + buffer.AppendFormat("&{0}={1}", key, parameters[key]); + } + else + { + buffer.AppendFormat("{0}={1}", key, parameters[key]); + } + i++; + } + byte[] data = requestEncoding.GetBytes(buffer.ToString()); + using (Stream stream = request.GetRequestStream()) + { + stream.Write(data, 0, data.Length); + } + } + return request.GetResponse() as HttpWebResponse; + } + /// + /// 创建POST方式的HTTP请求 + /// + /// 请求的URL + /// 随同请求POST的参数名称及参数值字典 + /// 请求的超时时间 + /// 请求的客户端浏览器信息,可以为空 + /// 发送HTTP请求时所用的编码 + /// 随同HTTP请求发送的Cookie信息,如果不需要身份验证可以为空 + /// + public static HttpWebResponse CreateApiPostHttpResponse(string url, IDictionary parameters, int? timeout, string userAgent, Encoding requestEncoding, CookieCollection cookies, string token, IDictionary headParams = null) + { + if (string.IsNullOrEmpty(url)) + { + throw new ArgumentNullException("url"); + } + if (requestEncoding == null) + { + throw new ArgumentNullException("requestEncoding"); + } + HttpWebRequest request = null; + //如果是发送HTTPS请求 + if (url.StartsWith("https", StringComparison.OrdinalIgnoreCase)) + { + ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(CheckValidationResult); + request = WebRequest.Create(url) as HttpWebRequest; + request.ProtocolVersion = HttpVersion.Version10; + } + else + { + request = WebRequest.Create(url) as HttpWebRequest; + } + request.Method = "POST"; + request.ContentType = "application/x-www-form-urlencoded"; + if (!string.IsNullOrEmpty(token)) + request.Headers.Add("Authorization", "Bearer " + token); + + if (headParams != null) + { + foreach (var header in headParams) + { + request.Headers.Add(header.Key, header.Value); + } + } + + + if (!string.IsNullOrEmpty(userAgent)) + { + request.UserAgent = userAgent; + } + else + { + request.UserAgent = DefaultUserAgent; + } + + if (timeout.HasValue) + { + request.Timeout = timeout.Value; + } + if (cookies != null) + { + request.CookieContainer = new CookieContainer(); + request.CookieContainer.Add(cookies); + } + //如果需要POST数据 + if (!(parameters == null || parameters.Count == 0)) + { + StringBuilder buffer = new StringBuilder(); + int i = 0; + foreach (string key in parameters.Keys) + { + if (i > 0) + { + buffer.AppendFormat("&{0}={1}", key, parameters[key]); + } + else + { + buffer.AppendFormat("{0}={1}", key, parameters[key]); + } + i++; + } + byte[] data = requestEncoding.GetBytes(buffer.ToString()); + using (Stream stream = request.GetRequestStream()) + { + stream.Write(data, 0, data.Length); + } + } + return request.GetResponse() as HttpWebResponse; + } + + public static async Task DoPostTask(string url, IDictionary paramsa) + { + var handler = new HttpClientHandler() { AutomaticDecompression = DecompressionMethods.GZip }; + using (var http = new HttpClient(handler)) + { + var content = new FormUrlEncodedContent(paramsa); + var response = await http.PostAsync(url, content); + response.EnsureSuccessStatusCode(); + return await response.Content.ReadAsStringAsync(); + } + + } + + private static bool CheckValidationResult(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors) + { + return true; //总是接受 + } + } +} diff --git a/APT.Infrastructure.Core/Helper/DataHelper.cs b/APT.Infrastructure.Core/Helper/DataHelper.cs new file mode 100644 index 0000000..8508ac5 --- /dev/null +++ b/APT.Infrastructure.Core/Helper/DataHelper.cs @@ -0,0 +1,78 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.IO; +using System.Linq.Expressions; +using System.Reflection; +using System.Runtime.Serialization.Formatters.Binary; +using System.Security.Cryptography; +using System.Text; + +namespace APT.Infrastructure.Core +{ + public static class CloneExtends + { + + public static T DeepCloneObject(this T t) where T : class + { + JsonSerializerSettings js = new JsonSerializerSettings(); + js.ReferenceLoopHandling = ReferenceLoopHandling.Ignore; + var obj = JsonConvert.SerializeObject(t,js); + return JsonConvert.DeserializeObject(obj); + } + + } + + public static class EncryptHelper + { + /// + /// AES 加密 + /// + /// 明文(待加密) + /// 密文 + /// + public static string AesEncrypt(string str, string key) + { + if (string.IsNullOrEmpty(str)) return null; + Byte[] toEncryptArray = Encoding.UTF8.GetBytes(str); + + RijndaelManaged rm = new RijndaelManaged + { + Key = Encoding.UTF8.GetBytes(key), + Mode = CipherMode.ECB, + Padding = PaddingMode.PKCS7 + }; + + ICryptoTransform cTransform = rm.CreateEncryptor(); + Byte[] resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length); + return Convert.ToBase64String(resultArray); + } + + /// + /// AES 解密 + /// + /// 明文(待解密) + /// 密文 + /// + public static string AesDecrypt(string str, string key) + { + if (string.IsNullOrEmpty(str)) return null; + Byte[] toEncryptArray = Convert.FromBase64String(str); + + RijndaelManaged rm = new RijndaelManaged + { + Key = Encoding.UTF8.GetBytes(key), + Mode = CipherMode.ECB, + Padding = PaddingMode.PKCS7 + }; + + ICryptoTransform cTransform = rm.CreateDecryptor(); + Byte[] resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length); + + return Encoding.UTF8.GetString(resultArray); + } + } + + +} diff --git a/APT.Infrastructure.Core/Helper/FilterHelper.cs b/APT.Infrastructure.Core/Helper/FilterHelper.cs new file mode 100644 index 0000000..56aef07 --- /dev/null +++ b/APT.Infrastructure.Core/Helper/FilterHelper.cs @@ -0,0 +1,369 @@ + +using System; +using System.Collections.Generic; +using System.Diagnostics.Contracts; +using System.Linq; +using System.Linq.Expressions; +using System.Reflection; +using System.Threading; +namespace APT.Infrastructure.Core +{ + /// + /// 查询表达式辅助操作类 + /// + public static class FilterHelper + { + #region fields + + private static readonly Dictionary> ExpressionDict; + #endregion + + #region ctor. + private static MethodInfo _methodInfo; + private static MethodInfo MethodInfo + { + get + { + if (_methodInfo == null) + _methodInfo = typeof(String).GetMethod("CompareTo", new Type[] { typeof(String) }); + return _methodInfo; + } + } + + static FilterHelper() + { + ExpressionDict = new Dictionary> + { + {FilterOperate.Equal, Expression.Equal}, + {FilterOperate.NotEqual, Expression.NotEqual}, + {FilterOperate.LessThan,(left,right)=>{ + if (left.Type == typeof(string)) + { + return Expression.LessThan( + Expression.Call( + left, + MethodInfo, + right), + Expression.Constant(0, typeof(Int32)) //比较String.CompareTo的返回结果和0,来实现>=的效果 + ); + } + else + return Expression.LessThan(left,right); } + }, + {FilterOperate.LessThanOrEqual,(left,right)=>{ + if (left.Type == typeof(string)) + { + return Expression.LessThanOrEqual( + Expression.Call( + left, + MethodInfo, + right), + Expression.Constant(0, typeof(Int32)) //比较String.CompareTo的返回结果和0,来实现>=的效果 + ); + } + else + return Expression.LessThanOrEqual(left,right); } + }, + {FilterOperate.GreaterThan,(left,right)=>{ + if (left.Type == typeof(string)) + { + return Expression.GreaterThan( + Expression.Call( + left, + MethodInfo, + right), + Expression.Constant(0, typeof(Int32)) //比较String.CompareTo的返回结果和0,来实现>=的效果 + ); + } + else + return Expression.GreaterThan(left,right); } + }, + {FilterOperate.GreaterThanOrEqual, (left,right)=>{ + if (left.Type == typeof(string)) + { + return Expression.GreaterThanOrEqual( + Expression.Call( + left, + MethodInfo, + right), + Expression.Constant(0, typeof(Int32)) //比较String.CompareTo的返回结果和0,来实现>=的效果 + ); + } + else + return Expression.GreaterThanOrEqual(left,right); + + } }, + {FilterOperate.StartsWith, (left, right) => + { + if (left.Type != typeof(string)) + { + throw new NotSupportedException("“StartsWith”比较方式只支持字符串类型的数据"); + } + return Expression.Call(left, typeof(string).GetMethod("StartsWith", new[] { typeof(string) }), right); + } + }, + {FilterOperate.EndsWith, (left, right) => + { + if (left.Type != typeof(string)) + { + throw new NotSupportedException("“EndsWith”比较方式只支持字符串类型的数据"); + } + return Expression.Call(left, typeof(string).GetMethod("EndsWith", new[] { typeof(string) }), right); + } + }, + {FilterOperate.Contains, (left, right) => + { + if (left.Type != typeof(string)) + { + throw new NotSupportedException("“Contains”比较方式只支持字符串类型的数据"); + } + return Expression.Call(left, typeof(string).GetMethod("Contains", new[] { typeof(string) }), right); + } + }, + }; + } + #endregion + + #region methods + /// + /// 获取指定查询条件组的查询表达式 + /// + /// 表达式实体类型 + /// 查询条件组,如果为null,则直接返回 true 表达式 + public static Expression> GetExpression(FilterGroup group, IUnitOfWork unitOfWork) + { + ParameterExpression param = Expression.Parameter(typeof(T), "m"); + ResetGroupByAcronym(group); + Expression body = GetExpressionBody(param, group, unitOfWork); + Expression> expression = Expression.Lambda>(body, param); + return expression; + } + + + private static void GetAcronymFeild(Type type, string[] array, int index, ref string acronymFeild) + { + var p = type.GetProperty(array[index]); + if (p != null && index == array.Length - 1) + { + AcronymFieldAttribute acronymAttr = null; + object[] attrs = p.GetCustomAttributes(typeof(AcronymFieldAttribute), true); + if (attrs.Length == 1) + acronymAttr = (AcronymFieldAttribute)attrs[0]; + if (acronymAttr == null || string.IsNullOrEmpty(acronymAttr.AcronymFieldName)) return; + var acronymP = type.GetProperty(acronymAttr.AcronymFieldName); + if (acronymP == null) return; + array[array.Length - 1] = acronymP.Name; + acronymFeild = string.Join(".", array); + } + else if (p != null) + GetAcronymFeild(p.PropertyType, array, index + 1, ref acronymFeild); + } + + private static void ResetGroupByAcronym(FilterGroup group) + { + if (!group.IsAnd || group.Rules.Count == 1 && group.Groups.Count == 0) + { + List filterRules = new List(); + foreach (var r in group.Rules) + { + var fs = r.Field.Split('.'); + string acronymFeild = string.Empty; + GetAcronymFeild(typeof(T), fs, 0, ref acronymFeild); + if (!string.IsNullOrEmpty(acronymFeild)) + filterRules.Add(new FilterRule() + { + Field = acronymFeild, + Operate = r.Operate, + Value = r.Value, + IsSysParamRule = r.IsSysParamRule, + }); + } + if (filterRules.Any()) + { + filterRules.ForEach(t => group.Rules.Add(t)); + group.IsAnd = false; + } + } + if (group.Groups.Any()) + foreach (var g in group.Groups) + ResetGroupByAcronym(g); + } + + + /// + /// 获取指定查询条件的查询表达式 + /// + /// 表达式实体类型 + /// 查询条件,如果为null,则直接返回 true 表达式 + /// + public static Expression> GetExpression(FilterRule rule = null) + { + ParameterExpression param = Expression.Parameter(typeof(T), "m"); + Expression body = GetExpressionBody(param, rule); + Expression> expression = Expression.Lambda>(body, param); + return expression; + } + + private static Expression GetExpressionBody(ParameterExpression param, FilterGroup group, IUnitOfWork unitOfWork) + { + Contract.Requires(param != null); + + //如果无条件或条件为空,直接返回 true表达式 + if (group == null || (group.Rules.Count == 0 && group.Groups.Count == 0)) + { + return Expression.Constant(true); + } + var rules = group.Rules.Where(t => !t.IsSysParamRule).ToList(); + + + var sysRules = group.Rules.Where(t => t.IsSysParamRule).ToList(); + + List bodys = new List(); + if (rules.Any()) + bodys.AddRange(rules.Select(rule => GetExpressionBody(param, rule))); + if (sysRules.Any()) + { + if (unitOfWork == null) throw new Exception("参数异常"); + Expression> predicate = null; + if (group.IsAnd) + predicate = t => true; + else + predicate = t => false; + foreach (var item in sysRules) + { + Expression> expression = null; + if (item.Operate == FilterOperate.Equal) + expression = t => t.CODE == item.Field && t.VALUE == item.Value.ToString(); + else if (item.Operate == FilterOperate.Contains) + expression = t => t.CODE == item.Field && t.VALUE.Contains(item.Value.ToString()); + else if (item.Operate == FilterOperate.GreaterThan) + expression = t => t.CODE == item.Field && string.Compare(t.VALUE, item.Value.ToString()) > 0; + else if (item.Operate == FilterOperate.GreaterThanOrEqual) + expression = t => t.CODE == item.Field && string.Compare(t.VALUE, item.Value.ToString()) >= 0; + else if (item.Operate == FilterOperate.LessThan) + expression = t => t.CODE == item.Field && string.Compare(t.VALUE, item.Value.ToString()) < 0; + else if (item.Operate == FilterOperate.LessThanOrEqual) + expression = t => t.CODE == item.Field && string.Compare(t.VALUE, item.Value.ToString()) <= 0; + else + throw new Exception("系统参数不支持该种类型的条件"); + if (group.IsAnd) + predicate = predicate.And(expression); + else + predicate = predicate.Or(expression); + } + var ids = unitOfWork.GetEntities(predicate, null, false).Select(t => t.ENTITY_ID.Value).ToList(); + FilterGroup sysParamGroup = new FilterGroup(false); + if (ids.Any()) + { + if (ids.Count >= 1210)//通过实测,如果参数大于1210时,会发生EF框架栈溢出,暂时无解决方案。 + throw new Exception("系统参数获取到的参数超过最大限制,不允许使用该功能"); + foreach (var item in ids) + sysParamGroup.Rules.Add(new FilterRule("ID", item, FilterOperate.Equal)); + } + else + { + sysParamGroup.Rules.Add(new FilterRule("ID", Guid.Empty, FilterOperate.Equal)); + } + group.Groups.Add(sysParamGroup); + } + bodys.AddRange(group.Groups.Select(subGroup => GetExpressionBody(param, subGroup, unitOfWork))); + + + return group.IsAnd ? bodys.Aggregate(Expression.AndAlso) : bodys.Aggregate(Expression.OrElse); + } + + private static Expression GetExpressionBody(ParameterExpression param, FilterRule rule) + { + //if (rule == null || rule.Value == null || string.IsNullOrEmpty(rule.Value.ToString())) + //{ + // return Expression.Constant(true); + //} + LambdaExpression expression = GetPropertyLambdaExpression(param, rule); + Expression constant = ChangeTypeToExpression(rule, expression.Body.Type); + var expressionChange = ExpressionDict[rule.Operate]; + return expressionChange(expression.Body, constant); + } + + private static LambdaExpression GetPropertyLambdaExpression(ParameterExpression param, FilterRule rule) + { + string[] propertyNames = rule.Field.Split('.'); + Expression propertyAccess = param; + Type type = param.Type; + foreach (string propertyName in propertyNames) + { + PropertyInfo property = type.GetProperty(propertyName); + if (property != null) + { + //Contract.Assume(property != null); + type = property.PropertyType; + propertyAccess = Expression.MakeMemberAccess(propertyAccess, property); + } + } + return Expression.Lambda(propertyAccess, param); + } + + private static Expression ChangeTypeToExpression(FilterRule rule, Type conversionType) + { + Type elementType = conversionType.GetUnNullableType(); + object value = null; + switch (elementType.Name.ToUpper()) + { + case "GUID": + { + if (rule.Value != null && !string.IsNullOrEmpty(rule.Value.ToString()) && rule.Value.ToString().ToLower() != "null") + { + value = Guid.Parse(rule.Value.ToString()); + } + //else + //{ + // return Expression.Constant(null, typeof(Guid?)); + //} + + break; + } + default: + { + //if (rule.Value.ToString() == "null") + //{ + // rule.Value = null; + //} + value = ConvertHelper.ChangeType(rule.Value, elementType); + break; + } + } + return Expression.Constant(value, conversionType); + } + + #endregion + + public static class ConvertHelper + { + #region = ChangeType = + public static object ChangeType(object obj, Type conversionType) + { + return ChangeType(obj, conversionType, Thread.CurrentThread.CurrentCulture); + } + public static object ChangeType(object obj, Type conversionType, IFormatProvider provider) + { + #region Nullable + if (obj != null && obj.ToString().ToLower() == "null") return null; + Type nullableType = Nullable.GetUnderlyingType(conversionType); + if (nullableType != null) + { + if (obj == null) + { + return null; + } + return Convert.ChangeType(obj, nullableType, provider); + } + #endregion + if (typeof(System.Enum).IsAssignableFrom(conversionType)) + { + return Enum.Parse(conversionType, obj.ToString()); + } + return Convert.ChangeType(obj, conversionType, provider); + } + #endregion + } + } +} diff --git a/APT.Infrastructure.Core/Helper/HashUtil.cs b/APT.Infrastructure.Core/Helper/HashUtil.cs new file mode 100644 index 0000000..47981f8 --- /dev/null +++ b/APT.Infrastructure.Core/Helper/HashUtil.cs @@ -0,0 +1,109 @@ +using System; +using System.ComponentModel; +using System.Security.Cryptography; +using System.Text; + +namespace APT.Infrastructure.Core +{ + /// + /// Hash工具类 + /// + public static class HashUtil + { + /// + /// 计算字符串MD5值 + /// + /// 要计算的值 + /// + public static string GetMD5(string source) + { + byte[] bytes = Encoding.UTF8.GetBytes(source); + return GetMD5(bytes); + } + + /// + /// 计算byte数组MD5值 + /// + /// 要计算的byte数组 + /// + public static string GetMD5(byte[] bytes) + { + StringBuilder builder = new StringBuilder(); + MD5 hash = new MD5CryptoServiceProvider(); + bytes = hash.ComputeHash(bytes); + foreach (byte b in bytes) + { + builder.AppendFormat("{0:X2}", b); + } + return builder.ToString(); + } + + /// + /// 产生随机字串,可用来自动生成密码,默认长度8位16进制 + /// + /// 长度 + /// 字串类型 0 字母 1 数字 2 大写字母 3 小写字母 4 十六进制字母 5 混合 + /// 额外字符 + /// + public static string rand_string(int len = 8, RandomTypeEnum type = RandomTypeEnum.Hex, string addChars = "") + { + string chars = ""; + switch (type) { + case RandomTypeEnum.Alphabet: + chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"+addChars; + break; + case RandomTypeEnum.Number: + chars = "0123456789"; + break; + case RandomTypeEnum.Uppercase: + chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"+addChars; + break; + case RandomTypeEnum.Lowercase: + chars = "abcdefghijklmnopqrstuvwxyz"+ addChars; + break; + case RandomTypeEnum.Hex: + chars = "0123456789ABCDEF"+addChars; + break; + default : + // 默认去掉了容易混淆的字符oOLl和数字01,要添加请使用addChars参数 + chars = "ABCDEFGHIJKMNPQRSTUVWXYZabcdefghijkmnpqrstuvwxyz23456789"+ addChars; + break; + } + + char[] constant = chars.ToCharArray(); + System.Text.StringBuilder newRandom = new System.Text.StringBuilder(constant.Length); + Random rd = new Random(); + for (int i = 0; i < len; i++) + { + newRandom.Append(constant[rd.Next(constant.Length)]); + } + return newRandom.ToString(); + } + + + } + /// + /// 随机数类型 + /// + public enum RandomTypeEnum + { + [Description("字母")] + Alphabet = 0, + + [Description("数字")] + Number = 1, + + [Description("大写字母")] + Uppercase = 2, + + [Description("小写字母")] + Lowercase = 3, + + [Description("十六进制字母")] + Hex = 4, + + [Description("混合")] + Mix = 5 + + } +} diff --git a/APT.Infrastructure.Core/Helper/LibUtils.cs b/APT.Infrastructure.Core/Helper/LibUtils.cs new file mode 100644 index 0000000..acb59b5 --- /dev/null +++ b/APT.Infrastructure.Core/Helper/LibUtils.cs @@ -0,0 +1,181 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace APT.Infrastructure.Core +{ + public static class LibUtils + { + + /// + /// 转为字符串 + /// + /// + /// + public static string ToString(object obj) + { + if (obj == null||obj==DBNull.Value) return string.Empty; + return obj.ToString(); + } + + + /// + /// 转为整数 + /// + /// + /// + public static int ToInt(object obj) + { + if (obj == null || obj == DBNull.Value) return 0; + try + { + return Convert.ToInt32(obj.ToString()); + } + catch + { + } + return 0; + } + + /// + /// 转为Decimal + /// + /// + /// + public static decimal ToDecimal(object obj) + { + if (obj == null || obj == DBNull.Value) return 0; + try + { + return Convert.ToDecimal(obj.ToString()); + } + catch + { + } + return 0; + } + + + /// + /// 转为日期 + /// + /// + /// + public static DateTime? ToDateTime(object obj) + { + if (obj == null || obj == DBNull.Value) return null; + try + { + return Convert.ToDateTime(obj.ToString()); + } + catch + { + } + return null; + } + + + /// + /// 转为Guid + /// + /// + /// + public static Guid? ToGuid(object obj) + { + if (obj == null || obj == DBNull.Value) return null; + try + { + return new Guid(obj.ToString()); + } + catch + { + } + return null; + } + + + /// + /// 转为布尔类型 + /// + /// + /// + public static bool ToBoolean(object obj) + { + if (obj == null || obj == DBNull.Value) return false; + try + { + return Convert.ToBoolean(obj); + } + catch + { + string str = LibUtils.ToString(obj); + if (string.Compare(str, "是", true) == 0) + return true; + } + return false; + } + + + /// + /// 比较两个指定的 System.String 对象(其中忽略或考虑其大小写),并返回一个整数 + /// + /// + /// + /// 是否忽略大小写 + /// + public static int Compare(object objA, object objB, bool ignoreCase = true) + { + if (objA == null || objB == null) return 0; + return string.Compare(ToString(objA), ToString(objB), ignoreCase); + } + + + /// + /// 保留指定小数点位数 + /// + /// + /// + /// + /// + public static decimal Round(decimal qty,int len, LibRoundTypeEnum type) + { + if (type == LibRoundTypeEnum.向上进位) + { + if (len != 0) + { + var s = qty.ToString().Split('.'); + if (s.Length >= 2) + { + var x = s[1].PadRight(6, '0'); + qty = Convert.ToDecimal(s[0] + "." + x.Substring(0, len)); + } + } + else + qty = Math.Ceiling(qty); + return qty; + } + else if (type == LibRoundTypeEnum.向下舍弃) + { + if (len != 0) + { + var s = qty.ToString().Split('.'); + if (s.Length >= 2) + { + var x = s[1].PadRight(6, '0'); + qty = Convert.ToDecimal(s[0] + "." + x.Substring(0, len)); + if (x[len] != '0') + qty += 1 / (decimal)Math.Pow(10, len); + } + } + else + { + qty = Math.Floor(qty); + } + return qty; + } + return Math.Round(qty, len, MidpointRounding.AwayFromZero); + } + + + } +} diff --git a/APT.Infrastructure.Core/Helper/ReflectHelper.cs b/APT.Infrastructure.Core/Helper/ReflectHelper.cs new file mode 100644 index 0000000..4565303 --- /dev/null +++ b/APT.Infrastructure.Core/Helper/ReflectHelper.cs @@ -0,0 +1,121 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; + +namespace APT.Infrastructure.Core.Refctor +{ + public class FuctionAttrDesc + { + public Guid ID { get; set; } + public string FuncName { get; set; } + public string AttrName { get; set; } + + public List Parmaters { get; set; } + + } + public class ParmaterModel + { + public Guid ID { get; set; } + public string ParmaterName { get; set; } + + public string ParmaterType { get; set; } + public string ParmaterAttr { get; set; } + } + public static class ReflectHelper + { + public static Type FindTypeInCurrentDomain(string typeName) + { + Type type = null; + + //如果该类型已经装载 + type = Type.GetType(typeName); + if (type != null) + { + return type; + } + + //在EntryAssembly中查找 + if (Assembly.GetEntryAssembly() != null) + { + type = Assembly.GetEntryAssembly().GetType(typeName); + if (type != null) + { + return type; + } + } + + //在CurrentDomain的所有Assembly中查找 + Assembly[] assemblyArray = AppDomain.CurrentDomain.GetAssemblies(); + int assemblyArrayLength = assemblyArray.Length; + for (int i = 0; i < assemblyArrayLength; ++i) + { + type = assemblyArray[i].GetType(typeName); + if (type != null) + { + return type; + } + } + + for (int i = 0; (i < assemblyArrayLength); ++i) + { + Type[] typeArray = assemblyArray[i].GetTypes(); + int typeArrayLength = typeArray.Length; + for (int j = 0; j < typeArrayLength; ++j) + { + if (typeArray[j].Name.Equals(typeName)) + { + return typeArray[j]; + } + } + } + + return type; + } + public static List GetClassMethodAttr(Type type) + { + List fads = new List(); + MethodInfo[] properties = type.GetMethods(); + if (properties.Any()) + { + + foreach (var p in properties) + { + object[] attrs = p.GetCustomAttributes(typeof(FuctionDescAttribute), true); + if (attrs.Length == 1) + { + var param = p.GetParameters(); + var s = (FuctionDescAttribute)attrs[0]; + FuctionAttrDesc fad = new FuctionAttrDesc(); + fad.AttrName = s.FucName; + fad.FuncName = p.Name; + fad.Parmaters = new List(); + if (param.Length != s.ParamterDesc.Length) + { + //throw new Exception("参数个数不匹配"); + + } + for (var n = 0; n < param.Length; n++) + { + ParmaterModel mode = new ParmaterModel(); + mode.ParmaterName = param[n].Name; + mode.ParmaterType = param[n].ParameterType.Name; + if (s.ParamterDesc.Length >= n + 1) + { + mode.ParmaterAttr = s.ParamterDesc[n]; + } + fad.Parmaters.Add(mode); + + } + fads.Add(fad); + } + + } + } + return fads; + } + + + } +} diff --git a/APT.Infrastructure.Core/Helper/Util.cs b/APT.Infrastructure.Core/Helper/Util.cs new file mode 100644 index 0000000..880e8a2 --- /dev/null +++ b/APT.Infrastructure.Core/Helper/Util.cs @@ -0,0 +1,100 @@ +using System; +using System.Globalization; +using System.Text; + +namespace APT.Infrastructure.Core +{ + /// + /// 工具类 + /// + public static class Util + { + /// + /// 新建一个 混合构成的适用于DB的可排序的 + /// + /// Comb Guid数据 + public static Guid NewID() + { + byte[] guidArray = Guid.NewGuid().ToByteArray(); + DateTime dtBase = new DateTime(1900, 1, 1); + DateTime dtNow = DateTime.Now; + //获取用于生成byte字符串的天数与毫秒数 + TimeSpan days = new TimeSpan(dtNow.Ticks - dtBase.Ticks); + TimeSpan msecs = new TimeSpan(dtNow.Ticks - (new DateTime(dtNow.Year, dtNow.Month, dtNow.Day).Ticks)); + //转换成byte数组 + //注意SqlServer的时间计数只能精确到1/300秒 + byte[] daysArray = BitConverter.GetBytes(days.Days); + byte[] msecsArray = BitConverter.GetBytes((long)(msecs.TotalMilliseconds / 3.333333)); + + //反转字节以符合SqlServer的排序 + Array.Reverse(daysArray); + Array.Reverse(msecsArray); + + //把字节复制到Guid中 + Array.Copy(daysArray, daysArray.Length - 2, guidArray, guidArray.Length - 6, 2); + Array.Copy(msecsArray, msecsArray.Length - 4, guidArray, guidArray.Length - 4, 4); + return new Guid(guidArray); + } + + /// + /// 加密密码 + /// + /// + public static string EncryptPassword(string userCode, string password) + { + var fixedMark = "-_-APT-_-"; + String sourceString = string.Concat(fixedMark, userCode.ToUpper(), password); + return HashUtil.GetMD5(sourceString); + } + + /// + /// 获取指定日期,在为一年中为第几周 + /// + /// 指定时间 + /// 返回第几周 + public static int GetWeekOfYear(DateTime dt) + { + GregorianCalendar gc = new GregorianCalendar(); + int weekOfYear = gc.GetWeekOfYear(dt, CalendarWeekRule.FirstDay, DayOfWeek.Monday); + return weekOfYear; + } + /// + /// + /// + /// + /// + public static string UrlEncode(string str) + { + StringBuilder sb = new StringBuilder(); + byte[] byStr = System.Text.Encoding.UTF8.GetBytes(str); //默认是System.Text.Encoding.Default.GetBytes(str) + for (int i = 0; i < byStr.Length; i++) + { + sb.Append(@"%" + Convert.ToString(byStr[i], 16)); + } + + return (sb.ToString()); + } + + /// + /// 判断byte数组是否相等 + /// + /// + /// + /// + public static bool CompareArray(byte[] bt1, byte[] bt2) + { + var len1 = bt1.Length; + var len2 = bt2.Length; + if (len1 != len2) + { + return false; + } + for (var i = 0; i < len1; i++) + { + if (bt1[i] != bt2[i]) + return false; + } + return true; + } + } +} diff --git a/APT.Infrastructure.Core/Helper/WebUtils.cs b/APT.Infrastructure.Core/Helper/WebUtils.cs new file mode 100644 index 0000000..cd36597 --- /dev/null +++ b/APT.Infrastructure.Core/Helper/WebUtils.cs @@ -0,0 +1,318 @@ +using System.Collections.Generic; + +namespace APT.Infrastructure.Core +{ + public class WebUtils + { + /// + /// 通过唯一编号获得数据表 + /// + /// + /// + /// + /// + public static T Get(string url, string id, string token, string tenant = "") + { + BaseFilter baseFilter = new BaseFilter(); + baseFilter.FilterGroup.Rules.Add(new FilterRule("ID", id)); + return Get(url, baseFilter, token, SendType.Post, tenant); + } + public static T Get(string url, string key, string value, string token = "", string tenant = "") + { + return Get(url + $"?{key}={value}", token, tenant); + } + public static string Get(string url, string key, string value, string token = "", string tenant = "") + { + return Get(url + $"?{key}={value}", token, tenant); + } + public static string Get(string url, string token, string tenant = "") + { + var body = new ApiBody(); + body.SendType = SendType.Get; + body.ApiUrl = url; + body.SendObj = null; + body.Token = token; + body.ResolvingResult = false; + if (!string.IsNullOrEmpty(tenant)) + body.HeadParams.Add("Tenant", tenant); + var msg = ""; + var result = ApiHelper.GetApiData(body, ref msg); + return result; + } + public static T Get(string url, string token, string tenant = "") + { + var body = new ApiBody(); + body.SendType = SendType.Get; + body.ApiUrl = url; + body.SendObj = null; + body.Token = token; + body.ResolvingResult = false; + if (!string.IsNullOrEmpty(tenant)) + body.HeadParams.Add("Tenant", tenant); + int totalCount = 0; + var result = ApiHelper.GetApiData(body, ref totalCount); + return result; + } + + /// + /// 通过过滤条件获取一条数据 + /// + /// + /// + /// + /// 是否直接转换对象 + /// + public static T Get(string url, BaseFilter filter, string token, SendType type = SendType.Post, + string tenant = "", bool isResolvingResult = false) + { + var body = new ApiBody(); + body.SendType = type; + body.ApiUrl = url; + body.SendObj = filter; + body.Token = token; + body.ResolvingResult = isResolvingResult; + if (!string.IsNullOrEmpty(tenant)) + body.HeadParams.Add("Tenant", tenant); + int totalCount = 0; + var result = ApiHelper.GetApiData(body, ref totalCount); + return result; + } + + + public static bool Save(string url, T t, string token, string tenant = "") + { + string msg = string.Empty; + return Save(url, t, token, ref msg, tenant); + } + public static bool Save(string url, T t, string token, ref string msg, string tenant = "") + { + var body = new ApiBody(); + body.SendType = SendType.Post; + body.ApiUrl = url; + body.SendObj = t; + body.Token = token; + if (!string.IsNullOrEmpty(tenant)) + body.HeadParams.Add("Tenant", tenant); + int totalCount = 0; + var result = ApiHelper.GetApiData(body, ref totalCount, ref msg); + return result; + } + /// + /// 执行某个接口 + /// + /// + /// + /// + public static bool Do(string url, BaseFilter filter, string token, SendType type = SendType.Post, string tenant = "") + { + string ms = string.Empty; + return Do(url, filter, token, ref ms, type, tenant); + } + public static bool Do(string url, BaseFilter filter, string token, ref string msg, SendType type = SendType.Post, string tenant = "") + { + var body = new ApiBody(); + body.SendType = type; + body.ApiUrl = url; + body.SendObj = filter; + body.Token = token; + if (!string.IsNullOrEmpty(tenant)) + body.HeadParams.Add("Tenant", tenant); + int totalCount = 0; + var result = ApiHelper.GetApiData(body, ref totalCount, ref msg); + return result; + } + /// + /// + /// + /// + /// + /// + /// + public static bool Delete(string url, string id, string token, string tenant = "") + { + var body = new ApiBody(); + body.SendType = SendType.Get; + body.ApiUrl = url; + body.Token = token; + if (!string.IsNullOrEmpty(tenant)) + body.HeadParams.Add("Tenant", tenant); + IDictionary parameters = new Dictionary(); + body.Params = parameters; + parameters.Add("id", id); + int totalCount = 0; + var result = ApiHelper.GetApiData(body, ref totalCount); + return result; + } + + public static bool BatchDelete(string url, string[] id, string token, string tenant = "") + { + var body = new ApiBody(); + var sendStr = string.Join(",", id); + body.SendType = SendType.Get; + body.ApiUrl = url; + body.Token = token; + if (!string.IsNullOrEmpty(tenant)) + body.HeadParams.Add("Tenant", tenant); + IDictionary parameters = new Dictionary(); + parameters.Add("ids", sendStr); + body.Params = parameters; + int totalCount = 0; + var result = ApiHelper.GetApiData(body, ref totalCount); + return result; + } + + public static List List(string url, BaseFilter filter, string token, + SendType type = SendType.Post, string tenant = "") + { + int totalCount = 0; + return List(url, filter, ref totalCount, token, type, tenant); + } + public static List List(string url, BaseFilter filter, ref int totalCount, + string token, SendType type = SendType.Post, string tenant = "") + { + var body = new ApiBody(); + body.SendType = type; + body.ApiUrl = url; + body.SendObj = filter; + body.Token = token; + if (!string.IsNullOrEmpty(tenant)) + body.HeadParams.Add("Tenant", tenant); + var result = ApiHelper.GetApiData>(body, ref totalCount); + return result; + } + + public static PagedList PageList(string url, BasePageFilter filter, + string token, SendType type = SendType.Post, string tenant = "") + { + var startIndex = filter.PageIndex > 0 ? filter.PageIndex : filter.Start / filter.Limit + 1; + var body = new ApiBody(); + body.SendType = type; + body.ApiUrl = url; + body.SendObj = filter; + body.Token = token; + if (!string.IsNullOrEmpty(tenant)) + body.HeadParams.Add("Tenant", tenant); + int totalCount = 0; + var result = ApiHelper.GetApiData>(body, ref totalCount); + PagedList pageList = null; + if (result != null) + pageList = new PagedList(result, startIndex, filter.Limit, totalCount); + return pageList; + } + + + + + /// + /// 通过过滤条件获取一条数据 + /// + /// + /// + /// + /// + public static T Execute(string url, object sendObj, string token, + SendType type = SendType.Post, IDictionary headParams = null, + bool isResolvingResult = false, string tenant = "") + { + var body = new ApiBody(); + body.SendType = type; + body.ApiUrl = url; + body.SendObj = sendObj; + body.Token = token; + body.HeadParams = headParams; + body.ResolvingResult = isResolvingResult; + if (!string.IsNullOrEmpty(tenant)) + body.HeadParams.Add("Tenant", tenant); + int totalCount = 0; + var result = ApiHelper.GetApiData(body, ref totalCount); + return result; + } + + /// + /// 获取二进制图片 + /// + /// + /// + /// + /// + /// + /// + /// + /// + public static byte[] GetPicture(string url, object sendObj, string token, + SendType type = SendType.Post, IDictionary headParams = null, + bool isResolvingResult = false, string tenant = "") + { + var body = new ApiBody(); + body.SendType = type; + body.ApiUrl = url; + body.SendObj = sendObj; + body.Token = token; + body.HeadParams = headParams; + body.ResolvingResult = isResolvingResult; + if (!string.IsNullOrEmpty(tenant)) + body.HeadParams.Add("Tenant", tenant); + var result = ApiHelper.ApiPicture(body); + return result; + } + + /// + /// isResolvingResult=true + /// + /// + /// + /// + /// + /// + /// + /// + public static T ExecuteByResolving(string url, object sendObj, string token, SendType type = SendType.Post, + IDictionary headParams = null, string tenant = "") + { + return Execute(url, sendObj, token, type, headParams, true, tenant); + } + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + public static T Execute(string url, IDictionary bodyParams, + string token, SendType type = SendType.Post, IDictionary headParams = null, + bool isResolvingResult = false, string tenant = "") + { + var body = new ApiBody(); + body.SendType = type; + body.ApiUrl = url; + body.Params = bodyParams; + body.HeadParams = headParams; + body.ResolvingResult = isResolvingResult; + body.Token = token; + if (!string.IsNullOrEmpty(tenant)) + body.HeadParams.Add("Tenant", tenant); + int totalCount = 0; + var result = ApiHelper.GetApiData(body, ref totalCount); + return result; + } + /// + /// isResolvingResult=true + /// + /// + /// + /// + /// + /// + /// + /// + public static T ExecuteByResolving(string url, IDictionary bodyParams, + string token, SendType type = SendType.Post, IDictionary headParams = null, string tenant = "") + { + return Execute(url, bodyParams, token, type, headParams, true, tenant); + } + } +} diff --git a/APT.Infrastructure.Core/Interface/ILibMessageManager.cs b/APT.Infrastructure.Core/Interface/ILibMessageManager.cs new file mode 100644 index 0000000..4254825 --- /dev/null +++ b/APT.Infrastructure.Core/Interface/ILibMessageManager.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace APT.Infrastructure.Core +{ + public interface ILibMessageManager + { + void AddMessage(EFMessageType type, string message); + void AddMessage(EFMessageType type, string code, string message); + + void AddMessage(EFApiActionMessage message); + void StoreMessage(EFApiActionResult ret); + + } +} diff --git a/APT.Infrastructure.Core/LDX.Infrastructure.Core.xml b/APT.Infrastructure.Core/LDX.Infrastructure.Core.xml new file mode 100644 index 0000000..8b71259 --- /dev/null +++ b/APT.Infrastructure.Core/LDX.Infrastructure.Core.xml @@ -0,0 +1,2249 @@ + + + + APT.Infrastructure.Core + + + + + 排序规范 + + + + + + 递增 + + + + + + + + 然后递增 + + + + + + + + 递减 + + + + + + + + 然后递减 + + + + + + + + 排序后的结果集 + + + + + 获取 当前单元操作对象 + + + + + 填充系统参数 + + + + + + + + 异步泛型主键实体仓储接口 + + 实体类型 + 实体主键类型 + + + + 异步插入实体 + + 实体对象 + 操作影响的行数 + + + + 异步批量插入实体 + + 实体对象集合 + 操作影响的行数 + + + + 异步删除实体 + + 实体对象 + 操作影响的行数 + + + + 异步删除指定编号的实体 + + 实体编号 + 操作影响的行数 + + + + 异步删除所有符合特定条件的实体 + + 查询条件谓语表达式 + 操作影响的行数 + + + + 异步批量删除删除实体 + + 实体对象集合 + 操作影响的行数 + + + + 异步更新实体对象 + + 实体对象 + 操作影响的行数 + + + + 异步批量更新实体对象 + + 实体对象集合 + 操作影响的行数 + + + + 批量更新 + + 查询条件谓语表达式 + 更新表达式 + 操作影响的行数 + + + + 异步获取指定主键的实体 + + 实体主键 + 符合主键的实体,不存在时返回null + + + + 异步获取符合条件的实体 + + 查询条件谓语表达式 + 符合条件的实体,不存在时返回null + + + + 异步获取记录数 + + + + + + 异步获取符合条件的记录数 + + 查询条件谓语表达式 + + + + + 异步是否存在符合条件的记录 + + 查询条件谓语表达式 + + + + + 泛型时间戳接口 + + + + + 对数据库执行给定的 DDL/DML 命令。 + + 命令字符串 + 参数 + 受影响的行数 + + + + 对数据库执行给定的 DDL/DML 命令。 + + 事务行为 + 命令字符串 + 参数 + 受影响的行数 + + + + 对数据库执行给定的 DDL/DML 命令返回reader。 + + 命令字符串 + reader委托 + + + + 对数据库执行给定的 DDL/DML 命令返回reader。 + + 命令字符串 + 参数 + reader委托 + + + + 对数据库执行给定的 DDL/DML 命令返回reader。 + + 命令类型 + 命令字符串 + 参数 + reader委托 + + + + 对数据库执行给定的 DDL/DML 命令。 + + 命令类型 + 命令字符串 + 参数 + + + + + 创建一个原始 SQL 查询,该查询将返回给定类型的元素。 + + 查询所返回对象的类型 + SQL 查询字符串 + 要应用于 SQL 查询字符串的参数 + + + + + 提交当前单元操作的更改。 + + 操作影响的行数 + + + + 执行数据sql语句 + + 执行数据sql语句 + + + + 异步提交当前单元操作的更改。 + + 操作影响的行数 + + + + 开启事务 + + + + + 提交事务 + + + + + 回滚事务 + + + + + 根据表名获取表数据结构 + + + + + + + 根据表名、字段名称获取字段结构 + + + + + + + + 根据表名,导航名称获取外键信息 + + + + + + + + 根据表名,ID字段名称获取外键信息 + + + + + + + + Linq架构里对集合排序实现 + + + + + + 排序后的结果集 + + + + + + 排序之后的结果集 + + + + + 递增 + + + + + + + + 然后递增 + + + + + + + + 递减 + + + + + + + + 然后递减 + + + + + + + + DateTime 扩展类 + + + + + 将当前DateTime值转换成yyyy-MM-dd字符串。 + + + + + + + 将当前DateTime值星期几中文字符串。 + + + + + + + 类型扩展方法类 + + + + + 获取枚举值值 + + 枚举值 + + + + + 将一个或多个枚举常数的名称或数字值的字符串表示转换成等效的枚举对象。 用于指示转换是否成功的返回值。 + + 要将 value 转换为的枚举类型。 + 要转换的枚举名称或基础值的字符串表示形式。 + 默认值 + 如果 value 参数成功转换,则返回类型为 TEnum 的一个对象,其值由 value 表示;否则为 defaultValue。 + + + + Expression表达式扩展操作类 + + + + + 以特定的条件运行组合两个Expression表达式 + + 表达式的主实体类型 + 第一个Expression表达式 + 要组合的Expression表达式 + 组合条件运算方式 + 组合后的表达式 + + + + 以 Expression.AndAlso 组合两个Expression表达式 + + 表达式的主实体类型 + 第一个Expression表达式 + 要组合的Expression表达式 + 组合后的表达式 + + + + 以 Expression.OrElse 组合两个Expression表达式 + + 表达式的主实体类型 + 第一个Expression表达式 + 要组合的Expression表达式 + 组合后的表达式 + + + + 类型扩展方法类 + + + + + 生成条件表达式 + + 类型 + 条件组 + + + + + 生成条件表达式 + + + + + + + + 生成条件表达式 + + 类型 + 条件组 + + + + + 类型扩展方法类 + + + + + 返回一个新字符串,该字符串通过在此实例中的字符左侧填充指定的 Unicode 字符来达到指定的总长度,从而使这些字符右对齐。 + + + + + + + + + 返回一个新字符串,该字符串通过在此字符串中的字符右侧填充指定的 Unicode 字符来达到指定的总长度,从而使这些字符左对齐。 + + + + + + + + + 把对象序列化成Json字符串格式 + + + + + + + 把Json字符串转换为强类型对象 + + + + + Linq 拓展方法类 + + + + + 类型扩展方法类 + + + + + 获取指定的长度的随机数字字符串 + + + 要获取随机数长度 + 指定长度的随机数字符串 + + + + 获取指定的长度的随机字母字符串 + + + 要获取随机数长度 + 指定长度的随机字母组成字符串 + + + + 获取指定的长度的随机字母和数字字符串 + + + 要获取随机数长度 + 指定长度的随机字母和数字组成字符串 + + + + 类型扩展方法类 + + + + + 判断类型是否为Nullable类型 + + 要处理的类型 + 是返回True,不是返回False + + + + 由类型的Nullable类型返回实际类型 + + 要处理的类型对象 + + + + + 通过类型转换器获取Nullable类型的基础类型 + + 要处理的类型对象 + + + + + 获取成员元数据的Description特性描述信息 + + 成员元数据对象 + 是否搜索成员的继承链以查找描述特性 + 返回Description特性描述信息,如不存在则返回成员的名称 + + + + 检查指定指定类型成员中是否存在指定的Attribute特性 + + 要检查的Attribute特性类型 + 要检查的类型成员 + 是否从继承中查找 + 是否存在 + + + + 从类型成员获取指定Attribute特性 + + Attribute特性类型 + 类型类型成员 + 是否从继承中查找 + 存在返回第一个,不存在返回null + + + + 从类型成员获取指定Attribute特性 + + Attribute特性类型 + 类型类型成员 + 是否从继承中查找 + 返回所有指定Attribute特性的数组 + + + + 判断类型是否为集合类型 + + 要处理的类型 + 是返回True,不是返回False + + + + 判断当前泛型类型是否可由指定类型的实例填充 + + 泛型类型 + 指定类型 + + + + + 创建GET方式的HTTP请求 + + 请求的URL + 请求的超时时间 + 请求的客户端浏览器信息,可以为空 + 随同HTTP请求发送的Cookie信息,如果不需要身份验证可以为空 + + + + + 创建GET方式的HTTP请求 + + 请求的URL + 请求的超时时间 + 请求的客户端浏览器信息,可以为空 + 随同HTTP请求发送的Cookie信息,如果不需要身份验证可以为空 + + + + + 创建POST方式的HTTP请求 + + 请求的URL + 随同请求POST的参数名称及参数值字典 + 请求的超时时间 + 请求的客户端浏览器信息,可以为空 + 发送HTTP请求时所用的编码 + 随同HTTP请求发送的Cookie信息,如果不需要身份验证可以为空 + + + + + 创建POST方式的HTTP请求 + + 请求的URL + 随同请求POST的参数名称及参数值字典 + 请求的超时时间 + 请求的客户端浏览器信息,可以为空 + 发送HTTP请求时所用的编码 + 随同HTTP请求发送的Cookie信息,如果不需要身份验证可以为空 + + + + + 查询表达式辅助操作类 + + + + + 获取指定查询条件组的查询表达式 + + 表达式实体类型 + 查询条件组,如果为null,则直接返回 true 表达式 + + + + 获取指定查询条件的查询表达式 + + 表达式实体类型 + 查询条件,如果为null,则直接返回 true 表达式 + + + + + Hash工具类 + + + + + 计算字符串MD5值 + + 要计算的值 + + + + + 计算byte数组MD5值 + + 要计算的byte数组 + + + + + 产生随机字串,可用来自动生成密码,默认长度8位16进制 + + 长度 + 字串类型 0 字母 1 数字 2 大写字母 3 小写字母 4 十六进制字母 5 混合 + 额外字符 + + + + + 随机数类型 + + + + + 转为字符串 + + + + + + + 转为整数 + + + + + + + 转为Decimal + + + + + + + 转为日期 + + + + + + + 转为Guid + + + + + + + 转为布尔类型 + + + + + + + 比较两个指定的 System.String 对象(其中忽略或考虑其大小写),并返回一个整数 + + + + 是否忽略大小写 + + + + + 保留指定小数点位数 + + + + + + + + + 工具类 + + + + + 新建一个 混合构成的适用于DB的可排序的 + + Comb Guid数据 + + + + 加密密码 + + + + + + 获取指定日期,在为一年中为第几周 + + 指定时间 + 返回第几周 + + + + + + + + + + + 判断byte数组是否相等 + + + + + + + + 通过唯一编号获得数据表 + + + + + + + + + 通过过滤条件获取一条数据 + + + + + + + + + 执行某个接口 + + + + + + + + + + + + + + + + + 通过过滤条件获取一条数据 + + + + + + + + + isResolvingResult=true + + + + + + + + + + + + + + + + + + + + + + + + + isResolvingResult=true + + + + + + + + + + + + 日志记录器 + + + + + 写入日志消息 + + 日志消息 + + + + 写入格式化日志消息 + + 日志消息格式 + 格式化参数 + + + + 写入日志消息 + + 日志消息 + + + + 写入格式化日志消息 + + 日志消息格式 + 格式化参数 + + + + 写入日志消息 + + 日志消息 + + + + 写入格式化日志消息 + + 日志消息格式 + 格式化参数 + + + + 写入日志消息 + + 日志消息 + + + + 写入格式化日志消息 + + 日志消息格式 + 格式化参数 + + + + 写入日志消息,并记录异常 + + 日志消息 + 异常 + + + + 写入格式化日志消息,并记录异常 + + 日志消息格式 + 异常 + 格式化参数 + + + + 写入日志消息 + + 日志消息 + + + + 写入格式化日志消息 + + 日志消息格式 + 格式化参数 + + + + 写入日志消息,并记录异常 + + 日志消息 + 异常 + + + + 写入格式化日志消息,并记录异常 + + 日志消息格式 + 异常 + 格式化参数 + + + + log4net日志记录器 + + + + + Logger管理器 + + + + + 枚举属性 + + + + + 枚举项排序索引小标 属性 + + + + + 枚举属性 + + + + + 数据记录 + + + + + 数据记录 + + 数据方向 + + + + 数据方向 + + + + + 初始化一个类型的新实例 + + + + + 获取 操作符 + + + + + 首字母简称属性 + + + + + 编辑表单显示字段属性 + 用于定义字段是否显示在编辑表单中 + + + + + 字段显示文本 + + + + + 顺序索引 + + + + + + + 字段显示文本 + 顺序索引 + + + + + + 字段显示文本 + + + + 列表表单显示字段属性 + 用于定义字段是否显示在列表表单中 + + + + + 字段显示文本 + + + + + 顺序索引 + + + + + + + 字段显示文本 + 顺序索引 + + + + + + 字段显示文本 + + + + 树表单显示字段属性 + 用于定义字段是否显示在树表单中 + + + + + 字段显示文本 + + + + + 顺序索引 + + + + + + + 字段显示文本 + 顺序索引 + + + + + + 字段显示文本 + + + + 列表单显示查询字段属性 + 用于定义字段是否显示在列表表单查询中 + + + + + 字段显示文本 + + + + + 顺序索引 + + + + + + + 字段显示文本 + + + + + + 字段显示文本 + + + + 编辑表单显示字段属性 + 用于定义字段是否显示在编辑表单中 + + + + + 字段显示文本 + + + + + + + 字段显示文本 + + + + 列表表单显示字段属性 + 用于定义字段是否显示在列表表单中 + + + + + 字段显示文本 + + + + + + + 字段显示文本 + + + + 树表单显示字段属性 + 用于定义字段是否显示在树表单中 + + + + + 字段显示文本 + + + + + + + 字段显示文本 + + + + 字段长度属性 + + + + + 字段长度 + + + + + + + 字段长度 + + + + 字段忽略属性 + + + + + 类索引属性 + 用于联合索引 + + + + + 索引字段列表 + + + + + 是否唯一索引 + + + + + + + 索引字段列表 + 是否唯一索引 + + + + + + 索引字段列表 + + + + 字段索引属性 + + + + + 是否唯一索引 + + + + + + + 是否唯一索引 + + + + 字段必填属性 + + + + + 是否必填 + + + + + + + 是否必填 + + + + 字段外键属性 + 在外键ID字段上使用 + + + + + 导航字段名称 + + + + + 主表导航字段名称 + + + + + + + 导航字段名称 + 主表导航字段名称 + + + + + + 导航字段名称 + + + + 字段外键属性 + 在主表的外键导航属性上使用 + + + + + 导航字段名称 + + + + + ID字段名称 + + + + + + + ID字段名称 + 导航字段名称 + + + + + + ID字段名称 + 导航字段名称 + + + + 字段外键属性 + 在外键ID字段上使用 + + + + + 导航字段名称 + + + + + 主表导航字段名称 + + + + + + + 导航字段名称 + 主表导航字段名称 + + + + + + 导航字段名称 + + + + 基础过滤器 + + + + + 组织类型 + + + + + 是否加载全部数据 + + + + + 公司编号 + + + + + 授权组织编号,多个可以逗号隔开 + 本组织可以查询授权组织数据 + + + + 窗体模板ID + + + + 排序字段 + + + + + 排序方式 + + + + + 过滤条件 + + + + + 关联表 + + + + + 分页条件 + + + + + 获取第Start+1页的数据 + + + + + 每一个分页获取的条数 + + + + + 第几页 + + + + + 排序条件 + + + + + 获取或设置 字段名称 + + + + + 获取或设置 过滤值 + + + + + 领域异常,主要用在业务逻辑出错,需要终止当前业务时 + + + + + 领域异常,主要用在业务逻辑出错,需要终止当前业务时 + + + + + 领域异常,主要用在业务逻辑出错,需要终止当前业务时 + + 错误信息 + + + + 领域异常,主要用在业务逻辑出错,需要终止当前业务时 + + 错误信息 + 内部异常 + + + + / + + + + + + + + + + 领域异常,主要用在业务逻辑出错,需要终止当前业务时 + + 错误信息 + + + + 领域异常,主要用在业务逻辑出错,需要终止当前业务时 + + 错误信息 + 内部异常 + + + + 更新类型 + + + + + 插入 + + + + + 更新 + + + + + 删除 + + + + + 批量新增 + + + + + 批量更新 + + + + + 数据库类型 + + + + + 在执行数据库命令或查询期间控制事务创建行为。 + + + + + 如果存在现有事务,则使用它,否则在没有事务的情况下执行命令或查询。 + + + + + 如果不存在任何事务,则使用新事务进行操作。 + + + + + 排序方式 + + + + + 过滤方式 + + + + + 等于 + + + + + 不等于 + + + + + 小于 + + + + + 小于或等于 + + + + + 大于 + + + + + 大于或等于 + + + + + 以……开始,只适用于String + + + + + 以……结束,只适用于String + + + + + 包含(相似),只适用于String + + + + + 数据方向 + + + + + 不进行数据数据交换 + + + + + 推送 + + + + + 上传 + + + + 每天每隔固定时间执行一次 + + + 每天每隔固定时间执行一次 + + + 固定时间执行一次 + + + 只执行一次 + + + + 不间断执行 + + + + 间隔秒 + + + 间隔分钟 + + + 间隔小时 + + + 间隔天 + + + 间隔月 + + + 间隔年 + + + + 过滤条件组 + + + + + 初始化一个的新实例 + + + + + 获取或设置 是否是And关系 + + + + + 获取或设置 条件集合 + + + + + 获取或设置 条件组集合 + + + + + 过滤条件 + + + + + 初始化一个的新实例 + + + + + 使用指定数据名称,数据值初始化一个的新实例 + + 数据名称 + 数据值 + + + + 使用指定数据名称,数据值及操作方式初始化一个的新实例 + + 数据名称 + 数据值 + 操作方式 + + + + 获取或设置 字段名称 + + + + + 获取或设置 过滤值 + + + + + 获取或设置 操作类型 + + + + + 是否是系统参数条件 + + + + + 会话信息 + + + + + 用户ID + + + + + 用户ID + + + + + 用户编号 + + + + + 用户名称 + + + + + 部门ID + + + + + 部门ID + + + + + 组织ID + + + + + 适用于WebApi的统一格式的ActionResult + + 返回结果数据类型 + + + + 是否执行成功 + + + + + 返回结果,如果值为时有值 + + + + + 错误信息,如果值为时有值 + + + + + 消息类型 + + + + + 消息代码 + + + + + 基础区域过滤条件 + + + + + 公共参数 + + + + + 构造函数1 + + + + + 构造函数2 + + keyword + orgid + + + + 参数1 + + + + + 参数2 + + + + + 参数3 + + + + + 参数4 + + + + + 参数5 + + + + + 参数5 + + + + + 参数 + + + + + 参数5 + + + + + 参数5 + + + + + 参数5 + + + + + 参数11 + + + + + 参数5 + + + + + 参数 + + + + + 参数5 + + + + + 参数5 + + + + + 参数5 + + + + + 参数5 + + + + + 参数 + + + + + 参数5 + + + + + 参数5 + + + + + 参数5 + + + + + 参数5 + + + + + 参数5 + + + + + 参数5 + + + + + 参数5 + + + + + 参数5 + + + + + 参数5 + + + + + 参数5 + + + + + 参数5 + + + + + 参数5 + + + + + 餐台区域过滤条件 + + + + + 公共参数 + + + + + 参数1 + + + + + 参数2 + + + + + 参数3 + + + + + 参数4 + + + + + 参数5 + + + + + 参数6 + + + + + 适用于WebApi的统一格式的分页数据结构 + + + + + + 是否执行成功 + + + + + 返回结果,如果值为时有值 + + + + + 总记录数 + + + + + 错误信息,如果值为时有值 + + + + + 消息类型 + + + + + 消息代码 + + + + + 構造函數 + + + + + + + + + 構造函數 + + + + + 统一格式的分页结果集 + + + + + + 统一格式的分页结果集 + + + + + 统一格式的分页结果集 + + 总数 + 结果集 + + + + 总数 + + + + + 数据集合 + + + + + 编码规则参数 + + + + + 数量 + + + + + 公共参数 + + + + + 数据记录 + + + + + 实体名称 + + + + + 实体强类型名称 + + + + + 实体ID + + + + + 更新类型 + + + + + 更新字段 + + + + + 目标门店ID + + + + + 实体基类 + + 主键类型 + + + + 实体基类 + + + + + EntityOrgTypeEnum + + + + + 参数 + + + + + 主键类型为Guid的实体基类 + + + + + int型主键基类 + + + + + int型主键的树形表基类 + + + + + 父级ID + + + + + 显示名称 + + + + + GUID主键的树形表基类 + + + + + 父级ID + + + + + 显示名称 + + + + + 是否叶子节点 + + + + + 审核 + + + + + 审核状态 + + + + + 当前审批子节点ID + + + + + 当前审批节点ID + + + + + 审批流ID + + + + + 构造函数 + + + + + 包含部门ID的实体接口 + + + + + 部门ID + + + + + + + + + + 初始化错误消息 + + + + diff --git a/APT.Infrastructure.Core/Logging/ILogger.cs b/APT.Infrastructure.Core/Logging/ILogger.cs new file mode 100644 index 0000000..fd67e70 --- /dev/null +++ b/APT.Infrastructure.Core/Logging/ILogger.cs @@ -0,0 +1,105 @@ +using System; + +namespace APT.Infrastructure.Core +{ + /// + /// 日志记录器 + /// + public interface ILog4netLogger : IDependInject + { + /// + /// 写入日志消息 + /// + /// 日志消息 + void Debug(object message); + + /// + /// 写入格式化日志消息 + /// + /// 日志消息格式 + /// 格式化参数 + void Debug(string format, params object[] args); + + /// + /// 写入日志消息 + /// + /// 日志消息 + void Info(object message); + + /// + /// 写入格式化日志消息 + /// + /// 日志消息格式 + /// 格式化参数 + void Info(string format, params object[] args); + + /// + /// 写入日志消息 + /// + /// 日志消息 + void Warn(object message); + + /// + /// 写入格式化日志消息 + /// + /// 日志消息格式 + /// 格式化参数 + void Warn(string format, params object[] args); + + /// + /// 写入日志消息 + /// + /// 日志消息 + void Error(object message); + + /// + /// 写入格式化日志消息 + /// + /// 日志消息格式 + /// 格式化参数 + void Error(string format, params object[] args); + + /// + /// 写入日志消息,并记录异常 + /// + /// 日志消息 + /// 异常 + void Error(object message, Exception exception); + + /// + /// 写入格式化日志消息,并记录异常 + /// + /// 日志消息格式 + /// 异常 + /// 格式化参数 + void Error(string format, Exception exception, params object[] args); + + /// + /// 写入日志消息 + /// + /// 日志消息 + void Fatal(object message); + + /// + /// 写入格式化日志消息 + /// + /// 日志消息格式 + /// 格式化参数 + void Fatal(string format, params object[] args); + + /// + /// 写入日志消息,并记录异常 + /// + /// 日志消息 + /// 异常 + void Fatal(object message, Exception exception); + + /// + /// 写入格式化日志消息,并记录异常 + /// + /// 日志消息格式 + /// 异常 + /// 格式化参数 + void Fatal(string format, Exception exception, params object[] args); + } +} diff --git a/APT.Infrastructure.Core/Logging/Log4netLogger.cs b/APT.Infrastructure.Core/Logging/Log4netLogger.cs new file mode 100644 index 0000000..c1a5464 --- /dev/null +++ b/APT.Infrastructure.Core/Logging/Log4netLogger.cs @@ -0,0 +1,96 @@ +using log4net; +using System; +using System.Reflection; + +namespace APT.Infrastructure.Core +{ + /// + /// log4net日志记录器 + /// + public class Log4netLogger : ILog4netLogger + { + private readonly log4net.ILog _logger; + + #region ctor. + + public Log4netLogger(string name) + { + _logger = LogManager.GetLogger(Assembly.GetEntryAssembly(), name); + } + #endregion + + #region ILog 成员 + + public void Debug(object message) + { + _logger.Debug(message); + } + + public void Debug(string format, params object[] args) + { + _logger.DebugFormat(format, args); + } + + public void Info(object message) + { + _logger.Info(message); + } + + public void Info(string format, params object[] args) + { + _logger.InfoFormat(format, args); + } + + public void Warn(object message) + { + _logger.Warn(message); + } + + public void Warn(string format, params object[] args) + { + _logger.WarnFormat(format, args); + } + + public void Error(object message) + { + _logger.Error(message); + } + + public void Error(string format, params object[] args) + { + _logger.ErrorFormat(format, args); + } + + public void Error(object message, Exception exception) + { + _logger.Error(message, exception); + } + + public void Error(string format, Exception exception, params object[] args) + { + _logger.ErrorFormat(format, exception, args); + } + + public void Fatal(object message) + { + _logger.Fatal(message); + } + + public void Fatal(string format, params object[] args) + { + _logger.FatalFormat(format, args); + } + + public void Fatal(object message, Exception exception) + { + _logger.Fatal(message, exception); + } + + public void Fatal(string format, Exception exception, params object[] args) + { + _logger.FatalFormat(format, exception, args); + } + + #endregion + } +} diff --git a/APT.Infrastructure.Core/Logging/LogAttribute.cs b/APT.Infrastructure.Core/Logging/LogAttribute.cs new file mode 100644 index 0000000..50fd2e5 --- /dev/null +++ b/APT.Infrastructure.Core/Logging/LogAttribute.cs @@ -0,0 +1,85 @@ +using APT.Infrastructure.Core; +using log4net; +using Microsoft.AspNetCore.Mvc.Filters; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace APT.Infrastructure.Core +{ + public class LogAttribute : Attribute, IAsyncActionFilter + { + /// + /// 添加操作日志 liyouming + /// + /// + /// + /// + public async Task OnActionExecutionAsync(Microsoft.AspNetCore.Mvc.Filters.ActionExecutingContext context, ActionExecutionDelegate next) + { + + try + { + + string actionArguments = context.ActionArguments.ToJson(); + var resultContext = await next(); + + string url = resultContext.HttpContext.Request.Host + resultContext.HttpContext.Request.Path + resultContext.HttpContext.Request.QueryString; + + string method = resultContext.HttpContext.Request.Method; + + dynamic result = resultContext.Result.GetType().Name == "EmptyResult" ? new { Value = "EmptyResult" } : resultContext.Result as dynamic; + + var userHeads = resultContext.HttpContext.Request.Headers; + var userid = string.Empty; + var username = string.Empty; + if (userHeads.ContainsKey("userid")) + { + userid = userHeads["userid"].ToString(); + } + if (userHeads.ContainsKey("username")) + { + username = userHeads["username"].ToString(); + } + string response = JsonConvert.SerializeObject(result.Value); + //var str = $"用户ID:[{userid}],姓名:[{username}],api地址:[{url}],方法:[{method}],接口参数:[{actionArguments}],应答:[{response}]"; + //var points = new Point + //{ + // Name = "ApiLog", + // Timestamp = DateTime.Now, + // Tags = new Dictionary() + //{ + // { "Id", Guid.NewGuid()} + //}, + // Fields = new Dictionary() + //{ + // { "UserId", userid }, + // { "UserName", username }, + // { "ApiUrl", url }, + // { "Method", method }, + // { "ActionArguments", actionArguments }, + // { "Response", response } + //}, + //}; + + + LoggerManager.GetLogger().Info("时序数据库开始写入数据"); + //var ret = await InfluxDbHelper.InfluxDbClient.Client.WriteAsync(points, InfluxDbHelper.InfluxLogDbName); + //LoggerManager.GetLogger().Info("时序数据库插入结果:" + ret.Success); + } + catch (Exception ex) + { + LoggerManager.GetLogger().Error(Infrastructure.Core.LogHelper.GetCurSourceFileName() + " - " + LogHelper.GetLineNum() + ":" + ex.Message); + //throw; + } + finally + { + await next.Invoke(); + } + + } + + } +} diff --git a/APT.Infrastructure.Core/Logging/LogHelper.cs b/APT.Infrastructure.Core/Logging/LogHelper.cs new file mode 100644 index 0000000..b4a016c --- /dev/null +++ b/APT.Infrastructure.Core/Logging/LogHelper.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace APT.Infrastructure.Core +{ + public static class LogHelper + { + /// /// 取得当前源码的哪一行 /// /// + + public static int GetLineNum() + + { System.Diagnostics.StackTrace st = new System.Diagnostics.StackTrace(1, true); return st.GetFrame(0).GetFileLineNumber(); } + + /// /// 取当前源码的源文件名 /// /// + + public static string GetCurSourceFileName() + + { System.Diagnostics.StackTrace st = new System.Diagnostics.StackTrace(1, true); return st.GetFrame(0).GetFileName(); } + } +} diff --git a/APT.Infrastructure.Core/Logging/LoggerManager.cs b/APT.Infrastructure.Core/Logging/LoggerManager.cs new file mode 100644 index 0000000..21cc486 --- /dev/null +++ b/APT.Infrastructure.Core/Logging/LoggerManager.cs @@ -0,0 +1,35 @@ +using System.Collections.Concurrent; + +namespace APT.Infrastructure.Core +{ + /// + /// Logger管理器 + /// + public static class LoggerManager + { + private static readonly ConcurrentDictionary Loggers; + private static readonly object LockObj = new object(); + + static LoggerManager() + { + Loggers = new ConcurrentDictionary(); + } + + public static ILog4netLogger GetLogger() + { + return GetLogger("Application"); + } + + public static ILog4netLogger GetLogger(string name) + { + ILog4netLogger logger; + if (Loggers.TryGetValue(name, out logger)) + { + return logger; + } + logger = new Log4netLogger(name); + Loggers[name] = logger; + return logger; + } + } +} diff --git a/APT.Infrastructure.Core/Structs/Attributes.cs b/APT.Infrastructure.Core/Structs/Attributes.cs new file mode 100644 index 0000000..d8ec7a8 --- /dev/null +++ b/APT.Infrastructure.Core/Structs/Attributes.cs @@ -0,0 +1,891 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Text; + +namespace APT.Infrastructure.Core +{ + + [AttributeUsage(AttributeTargets.Class, Inherited = true)] + public class UnionKeyAttribute : Attribute + { + private string _unionKey = string.Empty; + + public string UnionKey + { + get { return _unionKey; } + } + public UnionKeyAttribute(string unionKey) + { + _unionKey = unionKey; + } + + } + + [AttributeUsage(AttributeTargets.Property, Inherited = true)] + public class CUniqueAttribute : Attribute + { + private string _displayName = string.Empty; + private bool _isCheckOrg = false; + private bool _isCheckEmpty = true; + public string DisplayName + { + get { return _displayName; } + } + public bool IsCheckOrg + { + get { return _isCheckOrg; } + } + public bool IsCheckEmpty + { + get { return _isCheckEmpty; } + } + + public CUniqueAttribute() + : this(string.Empty) + { + + } + public CUniqueAttribute(bool isCheckOrg) + : this(string.Empty, isCheckOrg) + { + + } + + public CUniqueAttribute(string displayName) + : this(displayName, false) + { + } + public CUniqueAttribute(string displayName, bool isCheckOrg) + : this(displayName, isCheckOrg, true) + { + + } + + public CUniqueAttribute(string displayName, bool isCheckOrg, bool isCheckEmpty) + : base() + { + _displayName = displayName; + _isCheckOrg = isCheckOrg; + _isCheckEmpty = isCheckEmpty; + + } + } + + /// + /// 枚举属性 + /// + [AttributeUsage(AttributeTargets.Property, Inherited = true)] + public class EnumNameAttribute : Attribute + { + private string _enumName = string.Empty; + public string EnumName + { + get { return _enumName; } + } + public EnumNameAttribute(string enumName) + : base() + { + _enumName = enumName; + } + } + /// + /// 枚举项排序索引小标 属性 + /// + [AttributeUsage(AttributeTargets.All, Inherited = true)] + public class EnumSortIndexAttribute : Attribute + { + private int _sortIndex = 0; + public int SortIndex + { + get { return _sortIndex; } + } + public EnumSortIndexAttribute() + : base() + { + } + public EnumSortIndexAttribute(int sortIndex) + : base() + { + _sortIndex = sortIndex; + } + } + /// + /// 枚举项排序索引小标 属性 + /// + [AttributeUsage(AttributeTargets.All, Inherited = true)] + public class IgnoreT4Attribute : Attribute + { + public IgnoreT4Attribute() + : base() + { + } + } + + [AttributeUsage(AttributeTargets.All, Inherited = true)] + public class DataRuleFieldAttribute : Attribute + { + private string _fileName = ""; + public DataRuleFieldAttribute(string fileName) + : base() + { + _fileName = fileName; + } + public string FileName { get { return _fileName; } } + } + + + + /// + /// 枚举属性 + /// + [AttributeUsage(AttributeTargets.Property, Inherited = true)] + public class CodeRuleAttribute : Attribute + { + private int[] _codeRuleTypes = null; + private bool _isCheckState = true; + + public bool IsCheckState { get { return _isCheckState; } } + + public int[] CodeRuleTypes + { + get { return _codeRuleTypes; } + } + public CodeRuleAttribute(params int[] codeRuleTypes) + : this(true, codeRuleTypes) + { + } + public CodeRuleAttribute(bool isCheckState, params int[] codeRuleTypes) + : base() + { + _isCheckState = isCheckState; + _codeRuleTypes = codeRuleTypes; + } + } + + + /// + /// 数据记录 + /// + [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = true)] + public sealed class DataRecordAttribute : Attribute + { + /// + /// 数据记录 + /// + /// 数据方向 + public DataRecordAttribute(DataDirection direction) + { + Direction = direction; + } + + /// + /// 数据方向 + /// + public DataDirection Direction { get; set; } + } + + + + public class OperateCodeAttribute : Attribute + { + /// + /// 初始化一个类型的新实例 + /// + public OperateCodeAttribute(String code) + { + Code = code; + } + + /// + /// 获取 操作符 + /// + public String Code { get; private set; } + } + + + + /// + /// 首字母简称属性 + /// + [AttributeUsage(AttributeTargets.Property, Inherited = true)] + public class AcronymFieldAttribute : Attribute + { + private string _acronymFieldName = null; + public string AcronymFieldName + { + get { return _acronymFieldName; } + } + public AcronymFieldAttribute(string acronymFieldName) + : base() + { + _acronymFieldName = acronymFieldName; + } + } + + + + /// + /// 编辑表单显示字段属性 + /// 用于定义字段是否显示在编辑表单中 + /// + [AttributeUsage(AttributeTargets.Property, Inherited = true)] + public class FormFieldEditAttribute : Attribute + { + private string _displayName; + private int _num; + + /// + /// 字段显示文本 + /// + [Description("字段显示文本")] + public string DisplayName { get { return _displayName; } } + + + /// + /// 顺序索引 + /// + [Description("顺序索引")] + public int Num { get { return _num; } } + + /// + /// + /// + /// 字段显示文本 + /// 顺序索引 + public FormFieldEditAttribute(string diplayName, int num) + : base() + { + _displayName = diplayName; + _num = num; + } + + /// + /// + /// + /// 字段显示文本 + public FormFieldEditAttribute(string diplayName) + : this(diplayName, 0) + { + } + public FormFieldEditAttribute() + : this(string.Empty) + { + } + } + + /// + /// 列表表单显示字段属性 + /// 用于定义字段是否显示在列表表单中 + /// + [AttributeUsage(AttributeTargets.Property, Inherited = true)] + public class FormFieldTableAttribute : Attribute + { + private string _displayName; + private int _num; + /// + /// 字段显示文本 + /// + [Description("字段显示文本")] + public string DisplayName { get { return _displayName; } } + /// + /// 顺序索引 + /// + [Description("顺序索引")] + public int Num { get { return _num; } } + + /// + /// + /// + /// 字段显示文本 + /// 顺序索引 + public FormFieldTableAttribute(string displayName, int num) + : base() + { + _displayName = displayName; + _num = num; + } + /// + /// + /// + /// 字段显示文本 + public FormFieldTableAttribute(string displayName) + : this(displayName, 0) + { + } + public FormFieldTableAttribute(int num) + : this(string.Empty, num) + { + } + public FormFieldTableAttribute() + : this(string.Empty) + { + } + } + + + + /// + /// 树表单显示字段属性 + /// 用于定义字段是否显示在树表单中 + /// + [AttributeUsage(AttributeTargets.Property, Inherited = true)] + public class FormFieldTreeAttribute : Attribute + { + private string _displayName; + private int _num; + + /// + /// 字段显示文本 + /// + [Description("字段显示文本")] + public string DisplayName { get { return _displayName; } } + /// + /// 顺序索引 + /// + [Description("顺序索引")] + public int Num { get { return _num; } } + /// + /// + /// + /// 字段显示文本 + /// 顺序索引 + public FormFieldTreeAttribute(string displayName, int num) + : base() + { + _displayName = displayName; + _num = num; + } + + /// + /// + /// + /// 字段显示文本 + public FormFieldTreeAttribute(string displayName) + : this(displayName, 0) + { + } + public FormFieldTreeAttribute(int num) + : this(string.Empty, num) + { + } + + public FormFieldTreeAttribute() + : this(string.Empty) + { + } + } + + + + /// + /// 列表单显示查询字段属性 + /// 用于定义字段是否显示在列表表单查询中 + /// + [AttributeUsage(AttributeTargets.Property, Inherited = true)] + public class FormFieldQueryAttribute : Attribute + { + private string _displayName; + private int _num; + /// + /// 字段显示文本 + /// + [Description("字段显示文本")] + public string DisplayName { get { return _displayName; } } + + /// + /// 顺序索引 + /// + [Description("顺序索引")] + public int Num { get { return _num; } } + + /// + /// + /// + /// 字段显示文本 + public FormFieldQueryAttribute(string displayName, int num) + : base() + { + _displayName = displayName; + _num = num; + } + + /// + /// + /// + /// 字段显示文本 + public FormFieldQueryAttribute(string displayName) + : this(displayName, 0) + { + } + public FormFieldQueryAttribute(int num) + : this(string.Empty, num) + { + } + + public FormFieldQueryAttribute() + : this(string.Empty) + { + } + } + + + /// + /// 编辑表单显示字段属性 + /// 用于定义字段是否显示在编辑表单中 + /// + [AttributeUsage(AttributeTargets.Class, Inherited = true)] + public class FormClassEditAttribute : Attribute + { + private string _displayName; + + /// + /// 字段显示文本 + /// + [Description("字段显示文本")] + public string DisplayName { get { return _displayName; } } + /// + /// + /// + /// 字段显示文本 + public FormClassEditAttribute(string diplayName) + : base() + { + _displayName = diplayName; + } + public FormClassEditAttribute() + : this(string.Empty) + { + } + } + + /// + /// 列表表单显示字段属性 + /// 用于定义字段是否显示在列表表单中 + /// + [AttributeUsage(AttributeTargets.Class, Inherited = true)] + public class FormClassTableAttribute : Attribute + { + private string _displayName; + + /// + /// 字段显示文本 + /// + [Description("字段显示文本")] + public string DisplayName { get { return _displayName; } } + + /// + /// + /// + /// 字段显示文本 + public FormClassTableAttribute(string displayName) + : base() + { + _displayName = displayName; + } + public FormClassTableAttribute() + : this(string.Empty) + { + } + } + + + + /// + /// 树表单显示字段属性 + /// 用于定义字段是否显示在树表单中 + /// + [AttributeUsage(AttributeTargets.Class, Inherited = true)] + public class FormClassTreeAttribute : Attribute + { + private string _displayName; + /// + /// 字段显示文本 + /// + [Description("字段显示文本")] + public string DisplayName { get { return _displayName; } } + + /// + /// + /// + /// 字段显示文本 + public FormClassTreeAttribute(string displayName) + : base() + { + _displayName = displayName; + } + + public FormClassTreeAttribute() + : this(string.Empty) + { + } + } + + /// + /// 字段长度属性 + /// + [AttributeUsage(AttributeTargets.Property, Inherited = true)] + public class DataFieldLengthAttribute : Attribute + { + private int _length = 0; + /// + /// 字段长度 + /// + [Description("字段长度")] + public int Length + { + get { return _length; } + } + /// + /// + /// + /// 字段长度 + public DataFieldLengthAttribute(int length) + : base() + { + _length = length; + } + } + + /// + /// 字段忽略属性 + /// + [AttributeUsage(AttributeTargets.Property, Inherited = true)] + public class DataFieldIngoreAttribute : Attribute + { + + public DataFieldIngoreAttribute() + : base() + { + + } + + } + + + /// + /// 类索引属性 + /// 用于联合索引 + /// + [AttributeUsage(AttributeTargets.Class, Inherited = true, AllowMultiple = true)] + public class DataClassIndexAttribute : Attribute + { + private string[] _fields = null; + bool _isUnique = false; + /// + /// 索引字段列表 + /// + [Description("索引字段列表")] + public string[] Fields + { + get { return _fields; } + } + /// + /// 是否唯一索引 + /// + [Description("是否唯一索引")] + public bool IsUnique { get { return _isUnique; } } + /// + /// + /// + /// 索引字段列表 + /// 是否唯一索引 + public DataClassIndexAttribute(string[] fields, bool isUnique) + : base() + { + if (fields == null || fields.Length == 0) throw new Exception("参数异常"); + _fields = fields; + _isUnique = isUnique; + } + /// + /// + /// + /// 索引字段列表 + public DataClassIndexAttribute(string[] fields) + : this(fields, false) + { + + } + } + + /// + /// 字段索引属性 + /// + [AttributeUsage(AttributeTargets.Property, Inherited = true)] + public class DataFieldIndexAttribute : Attribute + { + bool _isUnique = false; + + string[] _fields = null; + + /// + /// 是否唯一索引 + /// + [Description("是否唯一索引")] + public bool IsUnique { get { return _isUnique; } } + + [Description("是否唯一索引")] + public string[] Fields { get { return _fields; } } + + /// + /// + /// + /// 是否唯一索引 + public DataFieldIndexAttribute(bool isUnique,params string[] fields) + : base() + { + _isUnique = isUnique; + _fields = fields; + } + public DataFieldIndexAttribute() + : this(false) + { + } + } + + + /// + /// 字段必填属性 + /// + [AttributeUsage(AttributeTargets.Property, Inherited = true)] + public class DataFieldRequireAttribute : Attribute + { + private bool _isRequire = true; + + /// + /// 是否必填 + /// + public bool IsRequire + { + get { return _isRequire; } + } + /// + /// + /// + /// 是否必填 + public DataFieldRequireAttribute(bool isRequire) + : base() + { + _isRequire = isRequire; + } + + public DataFieldRequireAttribute() + : this(true) + { + } + } + + /// + /// 字段外键属性 + /// 在外键ID字段上使用 + /// + [AttributeUsage(AttributeTargets.Property, Inherited = true)] + public class DataFieldForeignKeyAttribute : Attribute + { + private string _navFieldName = null; + private string _masterFieldName = string.Empty; + private bool _isOneOnOne = false; + /// + /// 导航字段名称 + /// + [Description("导航字段名称")] + public string NavFieldName + { + get { return _navFieldName; } + } + /// + /// 主表导航字段名称 + /// + [Description("主表导航字段名称")] + public string MasterFieldName + { + get { return _masterFieldName; } + } + + /// + /// 主表导航字段名称 + /// + [Description("是否一对一")] + public bool IsOneOnOne + { + get { return _isOneOnOne; } + } + + /// + /// + /// + /// 导航字段名称 + /// 主表导航字段名称 + /// 是否1对1 + public DataFieldForeignKeyAttribute(string navFieldName, string masterFieldName, bool isOneOnOne = false) + : base() + { + if (string.IsNullOrEmpty(navFieldName)) throw new Exception("参数异常"); + + _navFieldName = navFieldName; + _masterFieldName = masterFieldName; + _isOneOnOne = isOneOnOne; + } + + /// + /// + /// + /// 导航字段名称 + /// 是否1对1 + public DataFieldForeignKeyAttribute(string navFieldName, bool isOneOnOne = false) + : this(navFieldName, string.Empty, isOneOnOne) + { + } + + } + /// + /// 字段外键属性 + /// 在主表的外键导航属性上使用 + /// + [AttributeUsage(AttributeTargets.Property, Inherited = true)] + public class DataFieldForeignKeyForMasterAttribute : Attribute + { + private string _navFieldName = null; + private string _idFieldName = null; + private bool _isOneOnOne = false; + /// + /// 导航字段名称 + /// + [Description("导航字段名称")] + public string NavFieldName + { + get { return _navFieldName; } + } + /// + /// ID字段名称 + /// + [Description("ID字段名称")] + public string IdFieldName + { + get { return _idFieldName; } + } + /// + /// 主表导航字段名称 + /// + [Description("是否一对一")] + public bool IsOneOnOne + { + get { return _isOneOnOne; } + } + /// + /// + /// + /// ID字段名称 + /// 导航字段名称 + /// 是否一对一 + public DataFieldForeignKeyForMasterAttribute(string idFieldName, string navFieldName, bool isOneOnOne = false) + : base() + { + if (string.IsNullOrEmpty(idFieldName)) throw new Exception("参数异常"); + _navFieldName = navFieldName; + _idFieldName = idFieldName; + _isOneOnOne = isOneOnOne; + } + + /// + /// + /// + /// ID字段名称 + /// 是否一对一 + public DataFieldForeignKeyForMasterAttribute(string idFieldName, bool isOneOnOne = false) + : this(idFieldName, string.Empty, isOneOnOne) + { + } + } + + /// + ///获取方法的描述 + /// + [AttributeUsage(AttributeTargets.Method, Inherited = true)] + public class FuctionDescAttribute : Attribute + { + private string _fucName = null; + private string[] _paramterDesc ; + /// + /// 导航字段名称 + /// + [Description("函数名")] + public string FucName + { + get { return _fucName; } + } + /// + /// 参数说明 + /// + [Description("参数说明")] + public string[] ParamterDesc + { + get { return _paramterDesc; } + } + + /// + /// 构造函数 + /// + /// 方法描述 + /// 参数描述 + public FuctionDescAttribute(string fucName, params string[] paramterDesc) + : base() + { + + _fucName = fucName; + _paramterDesc = paramterDesc; + } + + } + + /// + /// 字段外键属性 + /// 在外键ID字段上使用 + /// + [AttributeUsage(AttributeTargets.Property, Inherited = true)] + public class UnionForeignKeyAttribute : Attribute + { + private string _unionKeyName = null; + private string _masterFieldName = string.Empty; + /// + /// 导航字段名称 + /// + [Description("导航字段名称")] + public string UnionKeyName + { + get { return _unionKeyName; } + } + /// + /// 主表导航字段名称 + /// + [Description("主表导航字段名称")] + public string MasterFieldName + { + get { return _masterFieldName; } + } + + /// + /// + /// + /// 导航字段名称 + /// 主表导航字段名称 + public UnionForeignKeyAttribute(string unionKeyName, string masterFieldName) + : base() + { + if (string.IsNullOrEmpty(unionKeyName)) throw new Exception("参数异常"); + + _unionKeyName = unionKeyName; + _masterFieldName = masterFieldName; + } + + /// + /// + /// + /// 导航字段名称 + public UnionForeignKeyAttribute(string navFieldName) + : this(navFieldName, string.Empty) + { + } + } +} diff --git a/APT.Infrastructure.Core/Structs/BaseFilter.cs b/APT.Infrastructure.Core/Structs/BaseFilter.cs new file mode 100644 index 0000000..81a9e6a --- /dev/null +++ b/APT.Infrastructure.Core/Structs/BaseFilter.cs @@ -0,0 +1,160 @@ +using System; +using System.Collections.Generic; +using System.Linq; +namespace APT.Infrastructure.Core +{ + /// + /// 基础过滤器 + /// + public class BaseFilter + { + public BaseFilter(Guid? orgId, FilterOrgTypeEnum orgType) + { + this.OrgId = orgId; + FilterGroup = new FilterGroup(); + Include = new List(); + Orders = new List(); + SelectField = new List(); + OrgRule = new List(); + this.OrgType = orgType; + Level = -1;//无限 + + } + + public BaseFilter(Guid? orgId) + { + OrgId = orgId; + FilterGroup = new FilterGroup(); + Include = new List(); + SelectField = new List(); + Orders = new List(); + DataRule = new List(); + OrgRule = new List(); + this.OrgType = FilterOrgTypeEnum.默认; + Level = -1;//无限级 + } + public BaseFilter() + { + FilterGroup = new FilterGroup(); + Include = new List(); + Orders = new List(); + SelectField = new List(); + DataRule = new List(); + OrgRule = new List(); + this.OrgType = FilterOrgTypeEnum.默认; + Level = -1;//无限级 + } + public Guid GetOrgId() + { + return OrgId ?? Guid.Empty; + } + /// + /// 菜单参数 + /// + public string MenuParameter { get; set; } + /// + /// 组织类型 + /// + public FilterOrgTypeEnum OrgType { get; set; } + + /// + /// 是否加载全部数据 + /// + public bool All { get; set; } + /// + /// 公司编号 + /// + public Guid? OrgId { get; set; } + /// + /// 数据层级 + /// + public int Level { get; set; } + /// + /// 树结构是否加载上级数据 + /// + public bool IsParentData { get; set; } + /// + /// 是否不跟踪 + /// + public bool IsNoTranking { get; set; } + + /// + /// 是否查询多个库 + /// + public bool IsMultipleDb { get; set; } + + /// + /// 知否指定数据库 + /// + public bool IsSpecifyDb { get; set; } + + /// + /// 指定数据库连接 + /// + public string SpecifyDbConn{ get; set; } + /// + /// 指定租户 + /// + public string SpecifyTenant { get; set; } + + /// + /// 授权组织编号,多个可以逗号隔开 + /// 本组织可以查询授权组织数据 + /// + public string AuthOrgCodes { get; set; } + + /// 窗体模板ID + public Guid? FormId { get; set; } + + /// + /// 排序字段 + /// + public string Sort { get; set; } + + /// + /// 排序方式 + /// + public DbOrder Order { get; set; } + /// + /// 过滤条件 + /// + public FilterGroup FilterGroup { get; set; } + /// + /// 关联表 + /// + public ICollection Include { get; set; } + /// + /// 查询/更新字段 + /// + public ICollection SelectField { get; set; } + /// + /// 多字段排序 + /// + public ICollection Orders { get; set; } + /// + /// 数据权限 + /// + public ICollection DataRule { get; set; } + + /// + /// 组织权限 + /// + public List OrgRule { get; set; } + + /// + /// 是否忽略数据权限 + /// + public bool IgnoreDataRule { get; set; } + + /// + /// 是否忽略组织权限 + /// + public bool IgnoreOrgRule { get; set; } = true; + + /// + /// 树选择的ID + /// + public ICollection TreeSelected { get; set; } + + } +} diff --git a/APT.Infrastructure.Core/Structs/BasePageFilter.cs b/APT.Infrastructure.Core/Structs/BasePageFilter.cs new file mode 100644 index 0000000..cd9c3bc --- /dev/null +++ b/APT.Infrastructure.Core/Structs/BasePageFilter.cs @@ -0,0 +1,46 @@ +namespace APT.Infrastructure.Core +{ + /// + /// 分页条件 + /// + public class BasePageFilter : BaseFilter + { + + /// + /// 获取第Start+1页的数据 + /// + public int Start + { + get + { + return (PageIndex - 1) * Limit; + } + } + + /// + /// 每一个分页获取的条数 + /// + public int Limit { get; set; } + /// + /// 第几页 + /// + public int PageIndex { get; set; } + + /// + /// 是否查询所有数据 + /// + public bool IsAllLoad { get; set; } + + public BasePageFilter() + { + + } + + public BasePageFilter(int PageIndex, int PageSize) + { + this.PageIndex = PageIndex; + this.Limit = PageSize; + } + } + +} diff --git a/APT.Infrastructure.Core/Structs/CodeException.cs b/APT.Infrastructure.Core/Structs/CodeException.cs new file mode 100644 index 0000000..2d6ed05 --- /dev/null +++ b/APT.Infrastructure.Core/Structs/CodeException.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace APT.Infrastructure.Core +{ + public class CodeException: Exception + { + public string _code = null; + public string Code + { + get { return _code; } + set { _code = value; } + } + + public CodeException() + { + + } + public CodeException(string message) : this(string.Empty, message, null) + { + } + + public CodeException(string code, string message):this(code,message,null) + { + } + public CodeException(string message, Exception innerException):this(string.Empty,message,innerException) + { + + } + + public CodeException(string code, string message, Exception innerException) + :base(message,innerException) + { + this._code = code; + } + } +} diff --git a/APT.Infrastructure.Core/Structs/CodeRuleParam.cs b/APT.Infrastructure.Core/Structs/CodeRuleParam.cs new file mode 100644 index 0000000..0228f85 --- /dev/null +++ b/APT.Infrastructure.Core/Structs/CodeRuleParam.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace APT.Infrastructure.Core +{ + public class CodeRuleParam + { + public CodeRuleParam() + { + this.IsUpdate = true; + this.Time = DateTime.Now; + } + public Guid? OrgId { get; set; } + + public int CodeType { get; set; } + + public int Count { get; set; } + + public bool IsUpdate { get; set; } + + public DateTime Time { get; set; } + } +} diff --git a/APT.Infrastructure.Core/Structs/DataOrder.cs b/APT.Infrastructure.Core/Structs/DataOrder.cs new file mode 100644 index 0000000..ae227c0 --- /dev/null +++ b/APT.Infrastructure.Core/Structs/DataOrder.cs @@ -0,0 +1,27 @@ +using System; + +namespace APT.Infrastructure.Core +{ + /// + /// 排序条件 + /// + public class DataOrder + { + + + + /// + /// 获取或设置 字段名称 + /// + public String Field { get; set; } + + /// + /// 获取或设置 过滤值 + /// + public DbOrder Order { get; set; } + + + + + } +} diff --git a/APT.Infrastructure.Core/Structs/DomainException.cs b/APT.Infrastructure.Core/Structs/DomainException.cs new file mode 100644 index 0000000..1ecda47 --- /dev/null +++ b/APT.Infrastructure.Core/Structs/DomainException.cs @@ -0,0 +1,68 @@ +using System; +using System.Runtime.Serialization; + +namespace APT.Infrastructure.Core +{ + /// + /// 领域异常,主要用在业务逻辑出错,需要终止当前业务时 + /// + [Serializable] + public class DomainException: Exception + { + /// + /// 领域异常,主要用在业务逻辑出错,需要终止当前业务时 + /// + public DomainException() + { } + + /// + /// 领域异常,主要用在业务逻辑出错,需要终止当前业务时 + /// + /// 错误信息 + public DomainException(string message) + : base(message) + { } + + /// + /// 领域异常,主要用在业务逻辑出错,需要终止当前业务时 + /// + /// 错误信息 + /// 内部异常 + public DomainException(string message, Exception inner) + : base(message, inner) + { } + + protected DomainException(SerializationInfo info, StreamingContext context) + : base(info, context) + { } + } + + /// + /// / + /// + public class RowVersionException : Exception + { + /// + /// + /// + public RowVersionException() + { } + + /// + /// 领域异常,主要用在业务逻辑出错,需要终止当前业务时 + /// + /// 错误信息 + public RowVersionException(string message) + : base(message) + { } + + /// + /// 领域异常,主要用在业务逻辑出错,需要终止当前业务时 + /// + /// 错误信息 + /// 内部异常 + public RowVersionException(string message, Exception inner) + : base(message, inner) + { } + } +} diff --git a/APT.Infrastructure.Core/Structs/EFApiActionMessage.cs b/APT.Infrastructure.Core/Structs/EFApiActionMessage.cs new file mode 100644 index 0000000..bb9025f --- /dev/null +++ b/APT.Infrastructure.Core/Structs/EFApiActionMessage.cs @@ -0,0 +1,15 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Text; + +namespace APT.Infrastructure.Core +{ + public class EFApiActionMessage + { + public EFMessageType MessageType { get; set; } + + public string Code { get; set; } + public string Message { get; set; } + } +} diff --git a/APT.Infrastructure.Core/Structs/EFApiActionResult.cs b/APT.Infrastructure.Core/Structs/EFApiActionResult.cs new file mode 100644 index 0000000..74489c2 --- /dev/null +++ b/APT.Infrastructure.Core/Structs/EFApiActionResult.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace APT.Infrastructure.Core +{ + public class EFApiActionResult + { + public EFApiActionResult() + { + this.Messages = new List(); + } + public bool IsError { get; set; } + + + public T Data { get; set; } + + public List Messages { get; set; } + } + +} diff --git a/APT.Infrastructure.Core/Structs/EFModel.cs b/APT.Infrastructure.Core/Structs/EFModel.cs new file mode 100644 index 0000000..c5c2b3d --- /dev/null +++ b/APT.Infrastructure.Core/Structs/EFModel.cs @@ -0,0 +1,85 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Text; + +namespace APT.Infrastructure.Core +{ + public class EFModel + { + List _tables = null; + + public EFModel() + { + _tables = new List(); + } + + public List Tables { get { return _tables; } } + } + + + public class EFModelTable + { + List _foreignKeys = null; + List _allForeignKeys = null; + List _fields = null; + + public EFModelTable() + { + _foreignKeys = new List(); + _fields = new List(); + _allForeignKeys = new List(); + } + + + public string Name { get; set; } + + + public List ForeignKeys { get { return _foreignKeys; } } + + public List Fields { get { return _fields; } } + + public List AllForeignKeys { get { return _allForeignKeys; } } + + } + + public class EFModelField + { + public EFModelField() + { + + } + + public bool IsNull { get; set; } + public string Name { get; set; } + public string TypeName { get; set; } + public Type FieldType { get; set; } + public PropertyInfo PropertyInfo { get; set; } + public new string ToString() + { + if (string.IsNullOrEmpty(this.Name)) return "EFModelField"; + return this.Name + ":" + this.TypeName; + } + } + + public class EFModelForeignKey + { + public EFModelForeignKey() + { + + } + + public string Name { get; set; } + + public bool IsNull { get; set; } + public string ForeignFieldName { get; set; } + public string ForeignNavName { get; set; } + public string ForeignTableName { get; set; } + + public dynamic ForeignKey { get; set; } + public string MasterNavName { get; set; } + + } + + +} diff --git a/APT.Infrastructure.Core/Structs/Enums.cs b/APT.Infrastructure.Core/Structs/Enums.cs new file mode 100644 index 0000000..d81c4d3 --- /dev/null +++ b/APT.Infrastructure.Core/Structs/Enums.cs @@ -0,0 +1,225 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace APT.Infrastructure.Core +{ + /// + /// 更新类型 + /// + public enum UpdateType + { + /// + /// 插入 + /// + Insert = 10, + + /// + /// 更新 + /// + Update = 20, + + /// + /// 删除 + /// + Delete = 30, + /// + /// 批量新增 + /// + BantchAdd = 40, + /// + /// 批量更新 + /// + + BantchUpdate = 50 + } + + /// + /// 数据库类型 + /// + public enum DataBaseType + { + SQL = 1, + MySQL = 2, + Oracle = 3, + Postgresql = 4 + } + + + public enum EntityOrgTypeEnum + { + 默认 = 0, + 包含上级组织 = 1, + 忽略组织 = 2, + 仅本组织 = 3, + } + + public enum FilterOrgTypeEnum + { + 默认 = 0, + 仅本组织 = 1, + 忽略组织 = 2, + } + + + /// + /// 在执行数据库命令或查询期间控制事务创建行为。 + /// + public enum TransactionalBehavior + { + /// + /// 如果存在现有事务,则使用它,否则在没有事务的情况下执行命令或查询。 + /// + DoNotEnsureTransaction, + + /// + /// 如果不存在任何事务,则使用新事务进行操作。 + /// + EnsureTransaction + } + + /// + /// 排序方式 + /// + public enum DbOrder + { + ASC = 0, + DESC = 1 + } + + /// + /// 过滤方式 + /// + public enum FilterOperate + { + /// + /// 等于 + /// + [OperateCode("equal")] + Equal = 1, + + /// + /// 不等于 + /// + [OperateCode("notequal")] + NotEqual = 2, + + /// + /// 小于 + /// + [OperateCode("less")] + LessThan = 3, + + /// + /// 小于或等于 + /// + [OperateCode("lessorequal")] + LessThanOrEqual = 4, + + /// + /// 大于 + /// + [OperateCode("greater")] + GreaterThan = 5, + + /// + /// 大于或等于 + /// + [OperateCode("greaterorequal")] + GreaterThanOrEqual = 6, + + /// + /// 以……开始,只适用于String + /// + [OperateCode("startwith")] + StartsWith = 7, + + /// + /// 以……结束,只适用于String + /// + [OperateCode("endwith")] + EndsWith = 8, + + /// + /// 包含(相似),只适用于String + /// + [OperateCode("contains")] + Contains = 9, + + } + /// + /// 数据方向 + /// + public enum DataDirection + { + /// + /// 不进行数据数据交换 + /// + None = 0, + + /// + /// 推送 + /// + Push = 1, + + /// + /// 上传 + /// + Upload = 2, + } + + public enum ThreadState + { + Wait = 0, + Running = 1, + Stop = 2 + } + + public enum ThreadTimeRuleType + { + /// 每天每隔固定时间执行一次 + EveryDayLoopByTime = 0, + /// 每天每隔固定时间执行一次 + EveryDayFiexedTime = 1, + /// 固定时间执行一次 + FiexedTime = 2, + /// 只执行一次 + ExecuteOne = 3, + /// + /// 不间断执行 + /// + Always = 4 + + } + + public enum ThreadTimeRuleLoopType + { + /// 间隔秒 + Second = 0, + /// 间隔分钟 + Minute = 1, + /// 间隔小时 + Hour = 2, + /// 间隔天 + Day = 3, + /// 间隔月 + Month = 4, + /// 间隔年 + Year = 4, + } + + + public enum LibRoundTypeEnum + { + 四舍五入 = 0, + 向上进位 = 1, + 向下舍弃 = 2, + } + + public enum EFMessageType + { + Error = 0, + Warning = 1, + Info = 2, + } +} diff --git a/APT.Infrastructure.Core/Structs/FilterGroup.cs b/APT.Infrastructure.Core/Structs/FilterGroup.cs new file mode 100644 index 0000000..7f83f16 --- /dev/null +++ b/APT.Infrastructure.Core/Structs/FilterGroup.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +namespace APT.Infrastructure.Core +{ + /// + /// 过滤条件组 + /// + public class FilterGroup + { + #region ctor. + + /// + /// 初始化一个的新实例 + /// + public FilterGroup() + : this(true) + { + } + + public FilterGroup(bool isAnd) + { + IsAnd = isAnd; + Rules = new List(); + Groups = new List(); + } + #endregion + + #region properties + + /// + /// 获取或设置 是否是And关系 + /// + public Boolean IsAnd { get; set; } + + /// + /// 获取或设置 条件集合 + /// + public ICollection Rules { get; set; } + + /// + /// 获取或设置 条件组集合 + /// + public ICollection Groups { get; set; } + #endregion + + } +} diff --git a/APT.Infrastructure.Core/Structs/FilterRule.cs b/APT.Infrastructure.Core/Structs/FilterRule.cs new file mode 100644 index 0000000..e211490 --- /dev/null +++ b/APT.Infrastructure.Core/Structs/FilterRule.cs @@ -0,0 +1,71 @@ +using System; + +namespace APT.Infrastructure.Core +{ + /// + /// 过滤条件 + /// + public class FilterRule + { + #region ctor. + + /// + /// 初始化一个的新实例 + /// + public FilterRule() + { + Operate = FilterOperate.Equal; + } + + /// + /// 使用指定数据名称,数据值初始化一个的新实例 + /// + /// 数据名称 + /// 数据值 + public FilterRule(string field, object value) + : this() + { + Field = field; + Value = value; + } + + /// + /// 使用指定数据名称,数据值及操作方式初始化一个的新实例 + /// + /// 数据名称 + /// 数据值 + /// 操作方式 + public FilterRule(string field, object value, FilterOperate operate) + : this(field, value) + { + Operate = operate; + } + + #endregion + + #region properties + + /// + /// 获取或设置 字段名称 + /// + public String Field { get; set; } + + /// + /// 获取或设置 过滤值 + /// + public Object Value { get; set; } + + /// + /// 获取或设置 操作类型 + /// + public FilterOperate Operate { get; set; } + + /// + /// 是否是系统参数条件 + /// + public bool IsSysParamRule { get; set; } + + #endregion + + } +} diff --git a/APT.Infrastructure.Core/Structs/IDependInject.cs b/APT.Infrastructure.Core/Structs/IDependInject.cs new file mode 100644 index 0000000..aec6d81 --- /dev/null +++ b/APT.Infrastructure.Core/Structs/IDependInject.cs @@ -0,0 +1,10 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace APT.Infrastructure.Core +{ + public interface IDependInject + { + } +} diff --git a/APT.Infrastructure.Core/Structs/ISession.cs b/APT.Infrastructure.Core/Structs/ISession.cs new file mode 100644 index 0000000..90c4446 --- /dev/null +++ b/APT.Infrastructure.Core/Structs/ISession.cs @@ -0,0 +1,52 @@ +using System; + +namespace APT.Infrastructure.Core +{ + /// + /// 会话信息 + /// + public interface ISession + { + /// + /// 用户ID + /// + String UserId { get; set; } + + /// + /// 用户ID + /// + Guid? UserID { get; set; } + + /// + /// 用户编号 + /// + String UserCode { get; set; } + + /// + /// 用户名称 + /// + String UserName { get; set; } + + /// + /// 部门ID + /// + String DepartmentId { get; set; } + + /// + /// 部门ID + /// + Guid? DepartmentID { get; set; } + + /// + /// 组织ID + /// + Guid? OrgId { get; set; } + + Guid? RootOrgId { get; set; } + + string MineType { get; set; } + + string[] DataRule { get; set; } + } + +} diff --git a/APT.Infrastructure.Core/Structs/ISessionProvider.cs b/APT.Infrastructure.Core/Structs/ISessionProvider.cs new file mode 100644 index 0000000..134a958 --- /dev/null +++ b/APT.Infrastructure.Core/Structs/ISessionProvider.cs @@ -0,0 +1,7 @@ +namespace APT.Infrastructure.Core +{ + public interface ISessionProvider + { + ISession GetSession(); + } +} diff --git a/APT.Infrastructure.Core/Structs/JsonActionResult.cs b/APT.Infrastructure.Core/Structs/JsonActionResult.cs new file mode 100644 index 0000000..42bb85f --- /dev/null +++ b/APT.Infrastructure.Core/Structs/JsonActionResult.cs @@ -0,0 +1,75 @@ +using System; + +namespace APT.Infrastructure.Core +{ + /// + /// 适用于WebApi的统一格式的ActionResult + /// + /// 返回结果数据类型 + public class JsonActionResult + { + private bool _isSuccessful = true; + /// + /// 是否执行成功 + /// + public bool IsSuccessful + { + get { return this._isSuccessful; } + set { this._isSuccessful = value; } + } + + /// + /// 返回结果,如果值为时有值 + /// + public T Data { get; set; } + public int TotalCount { get; set; } + /// + /// 错误信息,如果值为时有值 + /// + public String ErrorMessage { get; set; } + + /// + /// 消息类型 + /// + public EFMessageType MessageType { get; set; } + /// + /// 消息代码 + /// + public string Code { get; set; } + } + /// + /// 适用于WebApi的统一格式的ActionResult + /// + /// 返回结果数据类型 + public class JsonActionResult + { + private bool _isSuccessful = true; + /// + /// 是否执行成功 + /// + public bool IsSuccessful + { + get { return this._isSuccessful; } + set { this._isSuccessful = value; } + } + + /// + /// 返回结果,如果值为时有值 + /// + public string Data { get; set; } + public int TotalCount { get; set; } + /// + /// 错误信息,如果值为时有值 + /// + public String ErrorMessage { get; set; } + + /// + /// 消息类型 + /// + public EFMessageType MessageType { get; set; } + /// + /// 消息代码 + /// + public string Code { get; set; } + } +} diff --git a/APT.Infrastructure.Core/Structs/JsonContractResolver.cs b/APT.Infrastructure.Core/Structs/JsonContractResolver.cs new file mode 100644 index 0000000..e97cb07 --- /dev/null +++ b/APT.Infrastructure.Core/Structs/JsonContractResolver.cs @@ -0,0 +1,81 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Serialization; +using System; +using System.Linq; +using System.Collections.Generic; +using System.Text; +using System.Reflection; + +namespace APT.Infrastructure.Core +{ + public class JsonContractResolver : DefaultContractResolver + { + protected override IValueProvider CreateMemberValueProvider(MemberInfo member) + { + return new JsonExpressionValueProvider(member); + } + protected override JsonProperty CreatePropertyFromConstructorParameter(JsonProperty matchingMemberProperty, ParameterInfo parameterInfo) + { + var temp = base.CreatePropertyFromConstructorParameter(matchingMemberProperty, parameterInfo); + if (temp.PropertyType.GetUnNullableType() == typeof(Guid) || + temp.PropertyType.GetUnNullableType() == typeof(DateTime)) + temp.NullValueHandling = NullValueHandling.Include; + return temp; + } + protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization) + { + var temp = base.CreateProperty(member, memberSerialization); + if (temp.PropertyType.GetUnNullableType() == typeof(Guid) || + temp.PropertyType.GetUnNullableType() == typeof(DateTime)) + temp.NullValueHandling = NullValueHandling.Include; + return temp; + } + } + + public class JsonExpressionValueProvider : ExpressionValueProvider, IValueProvider + { + private readonly MemberInfo _memberInfo; + + public JsonExpressionValueProvider(MemberInfo memberInfo):base(memberInfo) + { + _memberInfo = memberInfo; + } + + + protected virtual object GetValueByType(Type type) + { + object obj = null; + if (type == typeof(decimal)) + obj = decimal.Zero; + else if (type == typeof(int)) + obj = 0; + else if (type == typeof(byte)) + obj = byte.MinValue; + else if (type == typeof(bool)) + obj = false; + else if (type == typeof(double)) + obj = (double)0; + return obj; + } + + public new object GetValue(object target) + { + object obj = base.GetValue(target); + if (obj == null) + { + Type realType = null; + PropertyInfo propertyInfo = _memberInfo as PropertyInfo; + if (propertyInfo != null) + realType = propertyInfo.PropertyType.GetUnNullableType(); + FieldInfo fieldInfo = _memberInfo as FieldInfo; + if (fieldInfo != null) + realType = fieldInfo.FieldType.GetUnNullableType(); + if (realType != null) + obj = this.GetValueByType(realType); + } + return obj; + } + } + + +} diff --git a/APT.Infrastructure.Core/Structs/KeywordFilter.cs b/APT.Infrastructure.Core/Structs/KeywordFilter.cs new file mode 100644 index 0000000..5784244 --- /dev/null +++ b/APT.Infrastructure.Core/Structs/KeywordFilter.cs @@ -0,0 +1,153 @@ +using System; + +namespace APT.Infrastructure.Core +{ + /// + /// 基础区域过滤条件 + /// + public class KeywordFilter : BaseFilter + { + /// + /// 公共参数 + /// + public string Keyword { get; set; } + /// + /// 构造函数1 + /// + public KeywordFilter() + { + } + /// + /// 构造函数2 + /// + /// keyword + /// orgid + public KeywordFilter(string keyword, Guid? orgId) + { + Keyword = keyword; + OrgId = orgId; + + } + + /// + /// 参数1 + /// + public string Parameter1 { get; set; } + /// + /// 参数2 + /// + public string Parameter2 { get; set; } + /// + /// 参数3 + /// + public string Parameter3 { get; set; } + /// + /// 参数4 + /// + public string Parameter4 { get; set; } + /// + /// 参数5 + /// + public string Parameter5 { get; set; } + /// + /// 参数5 + /// + public string Parameter6 { get; set; } + /// + /// 参数 + /// + public string Parameter7 { get; set; } + /// + /// 参数5 + /// + public string Parameter8 { get; set; } + /// + /// 参数5 + /// + public string Parameter9 { get; set; } + /// + /// 参数5 + /// + public string Parameter10 { get; set; } + /// + /// 参数11 + /// + public string Parameter11 { get; set; } + /// + /// 参数5 + /// + public string Parameter12 { get; set; } + /// + /// 参数 + /// + public string Parameter13 { get; set; } + /// + /// 参数5 + /// + public string Parameter14 { get; set; } + /// + /// 参数5 + /// + public string Parameter15 { get; set; } + /// + /// 参数5 + /// + public string Parameter16 { get; set; } + /// + /// 参数5 + /// + public string Parameter17 { get; set; } + /// + /// 参数 + /// + public string Parameter18 { get; set; } + /// + /// 参数5 + /// + public string Parameter19 { get; set; } + /// + /// 参数5 + /// + public string Parameter20 { get; set; } + /// + /// 参数5 + /// + public string Parameter21 { get; set; } + /// + /// 参数5 + /// + public string Parameter22 { get; set; } + /// + /// 参数5 + /// + public string Parameter23 { get; set; } + /// + /// 参数5 + /// + public string Parameter24 { get; set; } + /// + /// 参数5 + /// + public string Parameter25 { get; set; } + /// + /// 参数5 + /// + public string Parameter26 { get; set; } + /// + /// 参数5 + /// + public string Parameter27 { get; set; } + /// + /// 参数5 + /// + public string Parameter28 { get; set; } + /// + /// 参数5 + /// + public string Parameter29 { get; set; } + /// + /// 参数5 + /// + public string Parameter30 { get; set; } + } +} diff --git a/APT.Infrastructure.Core/Structs/KeywordPageFilter.cs b/APT.Infrastructure.Core/Structs/KeywordPageFilter.cs new file mode 100644 index 0000000..3f5dd3c --- /dev/null +++ b/APT.Infrastructure.Core/Structs/KeywordPageFilter.cs @@ -0,0 +1,55 @@ +using System; + +namespace APT.Infrastructure.Core +{ + /// + /// 餐台区域过滤条件 + /// + public class KeywordPageFilter : BasePageFilter + { + public KeywordPageFilter() + { + base.Limit = 10; + base.PageIndex = 1; + } + public KeywordPageFilter(string keyword, Guid? orgId, int pageIndex, int pageSize) + { + base.Limit = pageSize; + base.PageIndex = pageIndex; + Keyword = keyword; + OrgId = orgId; + } + /// + /// 公共参数 + /// + public string Keyword { get; set; } + /// + /// 参数1 + /// + public string Parameter1 { get; set; } + /// + /// 参数2 + /// + public string Parameter2 { get; set; } + /// + /// 参数3 + /// + public string Parameter3 { get; set; } + /// + /// 参数4 + /// + public string Parameter4 { get; set; } + /// + /// 参数5 + /// + public string Parameter5 { get; set; } + + /// + /// 参数6 + /// + public string Parameter6 { get; set; } + + public string TableName { get; set; } + + } +} diff --git a/APT.Infrastructure.Core/Structs/LibMessageFormatManager.cs b/APT.Infrastructure.Core/Structs/LibMessageFormatManager.cs new file mode 100644 index 0000000..7a8aa16 --- /dev/null +++ b/APT.Infrastructure.Core/Structs/LibMessageFormatManager.cs @@ -0,0 +1,90 @@ +using System; +using System.Linq; +using System.Collections.Generic; +using System.Text; + +namespace APT.Infrastructure.Core +{ + public class LibMessageFormatManager + { + private static LibMessageFormatManager _entityConfigManager = null; + private readonly List _formats = new List(); + + public static LibMessageFormatManager Instance + { + get + { + if (_entityConfigManager == null) + _entityConfigManager = new LibMessageFormatManager(); + return _entityConfigManager; + } + } + + public List Formats { get { return _formats; } } + + public LibMessageFormatManager() + { + + } + + public string GetMessageFormat(string code, string lang) + { + var f = Formats.FirstOrDefault(t => string.Compare(t.Code, code, true) == 0); + if (f == null) throw new Exception(" message code[" + code + "] is not exist"); + var ret = f.GetFormat(lang); + if (string.IsNullOrEmpty(ret)) throw new Exception("error message lang " + lang); + return ret; + } + public void AddMessageFormat(LibMessageFormat format) + { + if (string.IsNullOrEmpty(format.Code)) return; + var old = Formats.FirstOrDefault(t => string.Compare(t.Code, format.Code, true) == 0); + if (old != null) Formats.Remove(old); + Formats.Add(format); + } + + } + + public class LibMessageFormat + { + private readonly List _formatInfos; + public LibMessageFormat() + { + _formatInfos = new List(); + } + + public string Code { get; set; } + + public void AddFormat(string lang,string format) + { + if (string.IsNullOrEmpty(format)) return; + var f = _formatInfos.FirstOrDefault(t => string.Compare(t.Lang, lang, true) == 0); + if (f != null) _formatInfos.Remove(f); + var info = new LibMessageFormatInfo() + { + Lang = lang, + Format = format, + }; + _formatInfos.Add(info); + } + + public string GetFormat(string lang) + { + var f = _formatInfos.FirstOrDefault(t => string.Compare(t.Lang, lang, true) == 0); + if (f != null) return f.Format; + if (_formatInfos.Any()) + { + var r = _formatInfos.FirstOrDefault(t => string.IsNullOrEmpty(t.Lang)); + if (r != null) return r.Format; + } + return null; + } + + } + public class LibMessageFormatInfo + { + public string Lang { get; set; } + + public string Format { get; set; } + } +} diff --git a/APT.Infrastructure.Core/Structs/LibMessageManager.cs b/APT.Infrastructure.Core/Structs/LibMessageManager.cs new file mode 100644 index 0000000..84da3f2 --- /dev/null +++ b/APT.Infrastructure.Core/Structs/LibMessageManager.cs @@ -0,0 +1,44 @@ +using System; +using System.Linq; +using System.Collections.Generic; +using System.Text; + +namespace APT.Infrastructure.Core +{ + public class LibMessageManager: ILibMessageManager + { + private readonly List _messages = new List(); + public void AddMessage(EFMessageType type, string message) + { + AddMessage(type, string.Empty, message); + } + public void AddMessage(EFMessageType type, string code, string message) + { + lock (_messages) + { + _messages.Add(new EFApiActionMessage() + { + Code = code, + MessageType = type, + Message = message, + }); + } + } + public void AddMessage(EFApiActionMessage message) + { + lock (_messages) + { + _messages.Add(message); + } + } + + public void StoreMessage(EFApiActionResult ret) + { + if (ret == null) return; + if (_messages == null || !_messages.Any()) return; + ret.Messages.AddRange(_messages); + if (ret.Messages.Any(t => t.MessageType == EFMessageType.Error)) + ret.IsError = true; + } + } +} diff --git a/APT.Infrastructure.Core/Structs/MultipleDbPageFilter.cs b/APT.Infrastructure.Core/Structs/MultipleDbPageFilter.cs new file mode 100644 index 0000000..08d40ad --- /dev/null +++ b/APT.Infrastructure.Core/Structs/MultipleDbPageFilter.cs @@ -0,0 +1,16 @@ +using System; + +namespace APT.Infrastructure.Core +{ + /// + /// 多库查询分页参数 + /// + //public class MultipleDbPageFilter : KeywordPageFilter + //{ + // /// + // /// 起始终时间(多库查询需要) + // /// + // public DateTime? StartTime { get; set; } + //} + +} diff --git a/APT.Infrastructure.Core/Structs/NoSessionException.cs b/APT.Infrastructure.Core/Structs/NoSessionException.cs new file mode 100644 index 0000000..78819f5 --- /dev/null +++ b/APT.Infrastructure.Core/Structs/NoSessionException.cs @@ -0,0 +1,24 @@ +using System; +using System.Runtime.Serialization; + +namespace APT.Infrastructure.Core +{ + [Serializable] + public class NoSessionException: Exception + { + public NoSessionException() + { } + + public NoSessionException(string message) + : base(message) + { } + + public NoSessionException(string message, Exception inner) + : base(message, inner) + { } + + protected NoSessionException(SerializationInfo info, StreamingContext context) + : base(info, context) + { } + } +} diff --git a/APT.Infrastructure.Core/Structs/PagedActionResult.cs b/APT.Infrastructure.Core/Structs/PagedActionResult.cs new file mode 100644 index 0000000..92a641e --- /dev/null +++ b/APT.Infrastructure.Core/Structs/PagedActionResult.cs @@ -0,0 +1,72 @@ +using System; +using System.Collections.Generic; + +namespace APT.Infrastructure.Core +{ + /// + /// 适用于WebApi的统一格式的分页数据结构 + /// + /// + public class PagedActionResult + { + private bool _isSuccessful = true; + /// + /// 是否执行成功 + /// + public bool IsSuccessful + { + get { return this._isSuccessful; } + set { this._isSuccessful = value; } + } + + /// + /// 返回结果,如果值为时有值 + /// + public IEnumerable Data { get; set; } + /// + /// 其他数据 + /// + public dynamic DynamicData { get; set; } + /// + /// 总记录数 + /// + public int TotalCount { get; set; } + + /// + /// 错误信息,如果值为时有值 + /// + public String ErrorMessage { get; set; } + + /// + /// 消息类型 + /// + public EFMessageType MessageType { get; set; } + /// + /// 消息代码 + /// + public string Code { get; set; } + + + /// + /// 構造函數 + /// + /// + /// + /// + /// + public PagedActionResult(IEnumerable data, int totalCount, bool result = true, string errMsg = "") + { + Data = data; + TotalCount = totalCount; + IsSuccessful = result; + ErrorMessage = errMsg; + } + /// + /// 構造函數 + /// + public PagedActionResult() + { + + } + } +} diff --git a/APT.Infrastructure.Core/Structs/PagedResultDto.cs b/APT.Infrastructure.Core/Structs/PagedResultDto.cs new file mode 100644 index 0000000..b005271 --- /dev/null +++ b/APT.Infrastructure.Core/Structs/PagedResultDto.cs @@ -0,0 +1,46 @@ +using System.Collections.Generic; +using System.Linq; + +namespace APT.Infrastructure.Core +{ + /// + /// 统一格式的分页结果集 + /// + /// + public class PagedResultDto where T : class + { + #region ctor. + + /// + /// 统一格式的分页结果集 + /// + public PagedResultDto() + { + } + + /// + /// 统一格式的分页结果集 + /// + /// 总数 + /// 结果集 + public PagedResultDto(int totalCount, IQueryable items) + { + this.TotalCount = totalCount; + this.Items = items; + } + + #endregion + + #region properties + /// + /// 总数 + /// + public int TotalCount { get; set; } + + /// + /// 数据集合 + /// + public IEnumerable Items { get; set; } + #endregion + } +} diff --git a/APT.Infrastructure.Core/Structs/ParamDynamicDictionary.cs b/APT.Infrastructure.Core/Structs/ParamDynamicDictionary.cs new file mode 100644 index 0000000..177f4a8 --- /dev/null +++ b/APT.Infrastructure.Core/Structs/ParamDynamicDictionary.cs @@ -0,0 +1,91 @@ +using System; +using System.Collections.Generic; +using System.Dynamic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace APT.Infrastructure.Core +{ + public class ParamDynamicDictionary : DynamicObject + { // Fields + private ICollection _dataDictionary = null; + private object _entityBase = null; + // Methods + public ParamDynamicDictionary(ICollection dataDictionary, object entityBase) + { + if (dataDictionary == null||entityBase==null) + throw new Exception("参数异常"); + _dataDictionary = dataDictionary; + _entityBase = entityBase; + } + + + + public string this[string key] + { + get + { + string obj = null; + if (_dataDictionary != null && _dataDictionary.Count > 0) + { + var param = _dataDictionary.FirstOrDefault(t => string.Compare(t.CODE, key, true) == 0); + if (param != null && !string.IsNullOrEmpty(param.VALUE)) + obj = param.VALUE.Trim(); + } + return obj; + } + set + { + if (_dataDictionary != null) + { + var param= _dataDictionary.FirstOrDefault(t => string.Compare(t.CODE, key, true) == 0); + if (param == null) + { + param = new T_PF_PARAM(); + param.CODE = key; + var pro= _entityBase.GetType().GetProperty("ID"); + if (pro != null) + { + var idObj= pro.GetValue(_entityBase, null); + if (idObj != null) + param.ENTITY_ID = new Guid(idObj.ToString()); + } + _dataDictionary.Add(param); + } + if (value == null) + param.VALUE = null; + else + param.VALUE = value.Trim(); + } + } + } + public override IEnumerable GetDynamicMemberNames() + { + Dictionary dic = new Dictionary(); + if (_dataDictionary != null && _dataDictionary.Count > 0) + { + foreach (var item in _dataDictionary) + dic[item.CODE] = item.VALUE; + } + return dic.Keys; + } + public override bool TryGetMember(GetMemberBinder binder, out object result) + { + result = this[binder.Name]; + if (result != null) + result = result.ToString().Trim(); + return true; + } + public override bool TrySetMember(SetMemberBinder binder, object value) + { + if (value == null) + this[binder.Name] = null; + else + { + this[binder.Name] = value.ToString().Trim(); + } + return true; + } + } +} diff --git a/APT.Infrastructure.Core/Structs/Permission.cs b/APT.Infrastructure.Core/Structs/Permission.cs new file mode 100644 index 0000000..2cfca2d --- /dev/null +++ b/APT.Infrastructure.Core/Structs/Permission.cs @@ -0,0 +1,56 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace APT.Infrastructure.Core +{ + public class SysPermission + { + public SysPermission() + { + this.OrgCaches = new SortedDictionary(); + this.UserOrgCaches = new SortedDictionary(); + this.OrgCodeCaches = new SortedDictionary(); + } + public SortedDictionary OrgCaches { get; set; } + + public SortedDictionary OrgCodeCaches { get; set; } + + public SortedDictionary UserOrgCaches { get; set; } + } + + + public class OrgCache + { + public OrgCache() + { + this.AllChildrenIds = new List(); + this.AllParentIds = new List(); + this.Childrens = new List(); + } + + public Guid OrgId { get; set; } + + public string Code { get; set; } + + public List AllChildrenIds { get; set; } + + public List AllParentIds { get; set; } + + public List Childrens { get; set; } + } + + public class UserOrgCache + { + public UserOrgCache() + { + this.Orgs = new List(); + } + public Guid UserId { get; set; } + + public List Orgs { get; set; } + } + + +} diff --git a/APT.Infrastructure.Core/Structs/SimpleSession.cs b/APT.Infrastructure.Core/Structs/SimpleSession.cs new file mode 100644 index 0000000..561a0b9 --- /dev/null +++ b/APT.Infrastructure.Core/Structs/SimpleSession.cs @@ -0,0 +1,40 @@ +using System; + +namespace APT.Infrastructure.Core +{ + public class SimpleSession : ISession, ISessionProvider + { + #region ISession 成员 + + public string UserId { get; set; } + + public Guid? UserID { get; set; } + + public string UserCode { get; set; } + + public string UserName { get; set; } + + public string DepartmentId { get; set; } + + public Guid? DepartmentID { get; set; } + + public Guid? OrgId { get; set; } + + public Guid? RootOrgId { get; set; } + + public string MineType { get; set; } + + public string[] DataRule { get; set; } + + #endregion + + #region ISessionProvider 成员 + + public ISession GetSession() + { + return this; + } + + #endregion + } +} diff --git a/APT.Infrastructure.Core/Structs/SystemCodeFilter.cs b/APT.Infrastructure.Core/Structs/SystemCodeFilter.cs new file mode 100644 index 0000000..a2b838c --- /dev/null +++ b/APT.Infrastructure.Core/Structs/SystemCodeFilter.cs @@ -0,0 +1,31 @@ +namespace APT.Infrastructure.Core +{ + /// + /// 编码规则参数 + /// + public class SystemCodeFilter : BaseFilter + { + /// + /// 数量 + /// + public int Count { get; set; } + /// + /// 公共参数 + /// + public int CodeType { get; set; } + + ///// + ///// 参数1 + ///// + //[Display(Name = "参数")] + //public string Attr1{ get; set; } + + + + /// + /// 编码规则ID + /// + //[Display(Name = "编码规则ID")] + //public string CodeRuleId { get; set; } + } +} diff --git a/APT.Infrastructure.Core/Structs/TreeNode.cs b/APT.Infrastructure.Core/Structs/TreeNode.cs new file mode 100644 index 0000000..0372c5d --- /dev/null +++ b/APT.Infrastructure.Core/Structs/TreeNode.cs @@ -0,0 +1,33 @@ +using System.Collections.Generic; +using System.Linq; + +namespace APT.Infrastructure.Core +{ + /// + /// 树结构 + /// + /// + public class TreeNode where T : class + { + + /// + /// 节点 + /// + public T Node { get; set; } + + /// + /// 是否叶子节点 + /// + public bool IsLeaf { get; set; } + /// + /// 层级 + /// + public int Level { get; set; } + + /// + /// 数据集合 + /// + public List> Children { get; set; } + + } +} diff --git a/APT.Infrastructure.Core/Structs/UpdateCodeSerialInfo.cs b/APT.Infrastructure.Core/Structs/UpdateCodeSerialInfo.cs new file mode 100644 index 0000000..a52bf62 --- /dev/null +++ b/APT.Infrastructure.Core/Structs/UpdateCodeSerialInfo.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace APT.Infrastructure.Core +{ + public class UpdateCodeSerialInfo + { + public UpdateCodeSerialInfo() + { + this.CodeTypes = new List(); + this.IsCheckState = true; + + } + + public string DisplayCodeName { get; set; } + + public List CodeTypes { get; set; } + + public string Serial { get; set; } + + public bool IsUsed { get; set; } + + public bool IsCheckState { get; set; } + + public DateTime? Time { get; set; } + } +} diff --git a/APT.Infrastructure.Core/Structs/WeixinToken.cs b/APT.Infrastructure.Core/Structs/WeixinToken.cs new file mode 100644 index 0000000..093a623 --- /dev/null +++ b/APT.Infrastructure.Core/Structs/WeixinToken.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace APT.Infrastructure.Core +{ + public class WeixinToken + { + public string access_token { get; set; } + public int expires_in { get; set; } + public string errcode { get; set; } + public string errmsg { get; set; } + } +} diff --git a/APT.Infrastructure.Core/Table/DataUpdateRecord.cs b/APT.Infrastructure.Core/Table/DataUpdateRecord.cs new file mode 100644 index 0000000..551975f --- /dev/null +++ b/APT.Infrastructure.Core/Table/DataUpdateRecord.cs @@ -0,0 +1,40 @@ +using System; + +namespace APT.Infrastructure.Core +{ + /// + /// 数据记录 + /// + public class DataUpdateRecord : EntityBase + { + /// + /// 实体名称 + /// + public string EntityName { get; set; } + + /// + /// 实体强类型名称 + /// + public string EntityFullName { get; set; } + + /// + /// 实体ID + /// + public Guid? DataID { get; set; } + + /// + /// 更新类型 + /// + public UpdateType UpdateType { get; set; } + /// + /// 更新字段 + /// + public string UpdateFiled { get; set; } + + /// + /// 目标门店ID + /// + public Guid? TargetDepartmentID { get; set; } + } + +} diff --git a/APT.Infrastructure.Core/Table/EntityBase.cs b/APT.Infrastructure.Core/Table/EntityBase.cs new file mode 100644 index 0000000..b6a786b --- /dev/null +++ b/APT.Infrastructure.Core/Table/EntityBase.cs @@ -0,0 +1,325 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Reflection; +using System.Text; + +namespace APT.Infrastructure.Core +{ + /// + /// 实体基类 + /// + /// 主键类型 + public abstract class EntityBase : ICloneable + { + /// + /// 实体基类 + /// + public EntityBase() + { + this.FLOW_STATUS = 0;//默认为审核通过 + + } + public Object Clone() + { + return MemberwiseClone(); + } + + [Description("主键")] + public TKey ID { get; set; } + + [Description("逻辑删除")] + + public bool IS_DELETED { get; set; } + [Description("组织ID")] + + public Guid? ORG_ID { get; set; } + /// + /// EntityOrgTypeEnum + /// + [Description("实体组织类型")] + public int ENTITY_ORG_TPYE { get; set; } + + [Description("窗体模板ID")] + public Guid? FORM_ID { get; set; } + + [Description("审核状态")] + public int FLOW_STATUS { get; set; } + + [Description("送审状态")] + public int FLOW_SEND_STATUS { get; set; } + + [Description("流程ID")] + public Guid? FLOW_ID { get; set; } + + + [Description("创建时间")] + public System.DateTime? CREATE_TIME { get; set; } + [Description("修改时间")] + public System.DateTime? MODIFY_TIME { get; set; } + //[Description("时间戳")] + //public byte[] RowVersion { get; set; } + [Description("创建人")] + public Guid? CREATER_ID { get; set; } + + [Description("修改人")] + public Guid? MODIFIER_ID { get; set; } + + [Description("数据库连接")] + public string DbConn { get; set; } + + [Description("组织")] + public virtual T_FM_ORGANIZATION Nav_Org { get; set; } + + [Description("消息ID")] + public Guid TaskID { get; set; } + + /// + /// 参数 + /// + [JsonIgnore] + private ParamDynamicDictionary _parmDic = null; + [JsonIgnore] + [Description("参数")] + public dynamic SysParams + { + get + { + if (_parmDic == null) + { + if (this.Nav_SysParams == null) + this.Nav_SysParams = new List(); + _parmDic = new ParamDynamicDictionary(this.Nav_SysParams, this); + } + return _parmDic; + } + } + + [Description("系统参数")] + public virtual List Nav_SysParams { get; set; } + } + + + /// + /// 主键类型为Guid的实体基类 + /// + public abstract class MesEntityBase : EntityBase + { + public MesEntityBase() + { + this.ID = Guid.NewGuid(); + this.IS_DELETED = false; + this.CREATE_TIME = DateTime.Now; + this.MODIFY_TIME = DateTime.Now; + } + + public virtual string ToString() + { + StringBuilder sb = new StringBuilder(""); + sb.Append("{"); + Type type = this.GetType(); + PropertyInfo[] properties = type.GetProperties( + BindingFlags.GetProperty | BindingFlags.Public | BindingFlags.Instance); + + foreach (PropertyInfo property in properties) + { + object propertyValue = property.GetValue(this, null); + sb.Append("\""); + sb.Append(property.Name); + sb.Append("\":"); + if (propertyValue != null) + { + sb.Append(propertyValue.ToString()); + } + else + { + sb.Append(""); + } + sb.AppendLine(""); + } + sb.Append("}"); + return sb.ToString(); + } + + } + /// + /// int型主键基类 + /// + public abstract class MesIntEntityBase : EntityBase + { + public MesIntEntityBase() + { + this.IS_DELETED = false; + this.CREATE_TIME = DateTime.Now; + this.MODIFY_TIME = DateTime.Now; + } + + public virtual string ToString() + { + StringBuilder sb = new StringBuilder(""); + sb.Append("{"); + Type type = this.GetType(); + PropertyInfo[] properties = type.GetProperties( + BindingFlags.GetProperty | BindingFlags.Public | BindingFlags.Instance); + + foreach (PropertyInfo property in properties) + { + object propertyValue = property.GetValue(this, null); + sb.Append("\""); + sb.Append(property.Name); + sb.Append("\":"); + if (propertyValue != null) + { + sb.Append(propertyValue.ToString()); + } + else + { + sb.Append(""); + } + sb.AppendLine(""); + } + sb.Append("}"); + return sb.ToString(); + } + + } + /// + /// int型主键的树形表基类 + /// + public abstract class MesTreeIntEntityBase : MesIntEntityBase + { + /// + /// 父级ID + /// + [Description("父级ID")] + public Guid? PARENT_ID { get; set; } + /// + /// 显示名称 + /// + [Description("显示")] + public string TEXT { get; set; } + + } + /// + /// GUID主键的树形表基类 + /// + public abstract class MesTreeEntityBase : MesEntityBase + { + public MesTreeEntityBase() + { + this.IS_LEAF = true; + } + /// + /// 父级ID + /// + [Description("父级ID")] + public Guid? PARENT_ID { get; set; } + /// + /// 显示名称 + /// + [Description("父级ID")] + public string TEXT { get; set; } + + /// + /// 是否叶子节点 + /// + [Description("是否叶子节点")] + public bool IS_LEAF { get; set; } + + } + + public abstract class TreeEntityBase : MesTreeEntityBase + { + [Description("父节点")] + public virtual T Nav_Parent { get; set; } + + [Description("子节点")] + public virtual ICollection Nav_Children { get; set; } + + } + + /// + /// 审核 + /// + public abstract class AuditMesEntityBase : MesEntityBase + { + + #region + /// + /// 审核状态 + /// + [Description("审核状态")] + public int AUDIT_STATUS { get; set; } + /// + /// 当前审批子节点ID + /// + [Description("当前审批子节点")] + + public Guid? NODE_CHILD_ID { get; set; } + /// + /// 当前审批节点ID + /// + [Description("当前审批节点ID")] + + public Guid? AUDIT_NODE_ID { get; set; } + /// + /// 审批流ID + /// + [Description("审批流ID")] + public Guid? AUDIT_FLOW_ID { get; set; } + #endregion + } + public abstract class EntityBase : EntityBase + { + /// + /// 构造函数 + /// + public EntityBase() + { + this.ID = Guid.NewGuid(); + this.IS_DELETED = false; + this.CREATE_TIME = DateTime.Now; + this.MODIFY_TIME = DateTime.Now; + } + + public virtual string ToString() + { + StringBuilder sb = new StringBuilder(""); + sb.Append("{"); + Type type = this.GetType(); + PropertyInfo[] properties = type.GetProperties( + BindingFlags.GetProperty | BindingFlags.Public | BindingFlags.Instance); + + foreach (PropertyInfo property in properties) + { + object propertyValue = property.GetValue(this, null); + sb.Append("\""); + sb.Append(property.Name); + sb.Append("\":"); + if (propertyValue != null) + { + sb.Append(propertyValue.ToString()); + } + else + { + sb.Append(""); + } + sb.AppendLine(""); + } + sb.Append("}"); + return sb.ToString(); + } + } + + /// + /// 包含部门ID的实体接口 + /// + public interface IDepartmentEntity + { + /// + /// 部门ID + /// + Guid DEPARTMENT_ID { get; set; } + } +} diff --git a/APT.Infrastructure.Core/Table/T_FM_ORGANIZATION.cs b/APT.Infrastructure.Core/Table/T_FM_ORGANIZATION.cs new file mode 100644 index 0000000..43a70d0 --- /dev/null +++ b/APT.Infrastructure.Core/Table/T_FM_ORGANIZATION.cs @@ -0,0 +1,58 @@ +using APT.Infrastructure.Utility; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.ComponentModel.DataAnnotations.Schema; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace APT.Infrastructure.Core +{ + [Description("组织表")] + /// + /// + /// + [Redis("ID")] + [IgnoreT4]public partial class T_FM_ORGANIZATION : TreeEntityBase + { + + [Description("组织编码")] + /// + /// 编号 + /// + public string CODE { get; set; } + + [Description("租户编码")] + /// + /// 编号 + /// + public string TENANT_CODE { get; set; } + + [Description("组织名称")] + + /// 名称 + public string NAME { get; set; } + [Description("备注")] + /// + /// 备注 + /// + public string DESC { get; set; } + + [Description("授权选中标志")] + [DataFieldIngore] + [NotMapped] + public List CheckKeys { get; set; } + + [Description("组织授权选中标志")] + [DataFieldIngore] + [NotMapped] + public List OrgCheckKeys { get; set; } + + [Description("启用标志")] + public int ENABLE_STATUS { get; set; } + + //public virtual ICollection Fm_Organizations { get; set; } + + } +} diff --git a/APT.Infrastructure.Core/Table/T_PF_CODE_RULE_SERIAL.cs b/APT.Infrastructure.Core/Table/T_PF_CODE_RULE_SERIAL.cs new file mode 100644 index 0000000..d52255b --- /dev/null +++ b/APT.Infrastructure.Core/Table/T_PF_CODE_RULE_SERIAL.cs @@ -0,0 +1,36 @@ +using System; +using System.ComponentModel; + +namespace APT.Infrastructure.Core +{ + [Description("ˮ")] + [DataRecord(DataDirection.Push)] + public partial class T_PF_CODE_RULE_SERIAL : MesEntityBase,ICloneable,IRowVersion + { + public Object Clone() + { + return MemberwiseClone(); + } + [Description("")] + [EnumName("PFCodeRuleType")] + public int CODE_TYPE { get; set; } + [Description("ˮ")] + public string SERIAL { get; set; } + [Description("ֵ")] + public string DATE_VALUE { get; set; } + [Description("˳")] + public int NUM { get; set; } + [Description("ȡʱ")] + public DateTime? TAKE_TIME { get; set; } + [Description("ͷʱ")] + public DateTime? RELEASE_TIME { get; set; } + [Description("ʹʱ")] + public DateTime? USE_TIME { get; set; } + [Description("״̬")] + [EnumName("PFCodeRuleStatus")] + public int STATUS { get; set; } + [Description("а汾")] + public int ROW_VERSION { get; set; } + + } +} diff --git a/APT.Infrastructure.Core/Table/T_PF_PARAM.cs b/APT.Infrastructure.Core/Table/T_PF_PARAM.cs new file mode 100644 index 0000000..cd91dfa --- /dev/null +++ b/APT.Infrastructure.Core/Table/T_PF_PARAM.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace APT.Infrastructure.Core +{ + public class T_PF_PARAM + { + public T_PF_PARAM() + { + this.ID = Guid.NewGuid(); + this.CREATE_TIME = DateTime.Now; + } + public Guid ID { get; set; } + + public Guid? ENTITY_ID { get; set; } + + public string CODE { get; set; } + + public string VALUE { get; set; } + + public System.DateTime? CREATE_TIME { get; set; } + + public bool VIR_IS_DELETED { get; set; } + } +} diff --git a/APT.Infrastructure.Core/Thread/LDXThreadPool.cs b/APT.Infrastructure.Core/Thread/LDXThreadPool.cs new file mode 100644 index 0000000..534716b --- /dev/null +++ b/APT.Infrastructure.Core/Thread/LDXThreadPool.cs @@ -0,0 +1,160 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading; + +namespace APT.Infrastructure.Core +{ + public class APTThreadPool + { + private static List _workQueues = new List(); + private static List _waiAddWorkQueues = new List(); + private static List _removeList = new List(); + private static bool _isStop = false; + private static Thread _mainThread = null; + private static object _mainThreadLockObj = new object(); + private static object _addThreadLockObj = new object(); + private static int MainThreadSleepTime = 10 * 1000; + + + public static void Start(bool isMainThreadByBackground=false) + { + DoStartThread(isMainThreadByBackground); + } + + public static void Stop() + { + lock (_mainThreadLockObj) + { + _isStop = true; + } + if (_mainThread != null) + _mainThread.Abort(); + } + public static void Stop(APTThreadWork work) + { + lock (_mainThreadLockObj) + { + _removeList.Add(work); + } + } + + public static void AddWorkThread(APTThreadWork work) + { + AddWorkThread(DateTime.MinValue, work); + } + public static void AddWorkThread(DateTime runTime, APTThreadWork work) + { + if (runTime != DateTime.MinValue) + work.RunTime = runTime; + lock (_addThreadLockObj) + { + _waiAddWorkQueues.Add(work); + } + } + + + private static void DoStartThread(bool isBackground) + { + _mainThread = new Thread(DoThreadWork) { IsBackground = isBackground }; + _mainThread.Start(); + } + + + private static void DoThreadWork() + { + while (true) + { + try + { + lock (_mainThreadLockObj) + { + if (_removeList != null && _removeList.Count > 0) + { + foreach (var item in _removeList) + _workQueues.Remove(item); + _removeList.Clear(); + } + } + lock (_addThreadLockObj) + { + if (_waiAddWorkQueues != null && _waiAddWorkQueues.Count > 0) + foreach (var item in _waiAddWorkQueues) + _workQueues.Add(item); + _waiAddWorkQueues.Clear(); + } + if (_workQueues != null && _workQueues.Count > 0) + { + lock (_mainThreadLockObj) + { + DateTime nowTime = DateTime.Now.ToLocalTime(); + foreach (APTThreadWork work in _workQueues) + { + if (work == null || work.ThreadState == ThreadState.Running || work.ThreadState == ThreadState.Stop) continue; + + if (_isStop) break; + + DateTime runTime = work.RunTime; + if (runTime == DateTime.MinValue) + { + work.ThreadState = ThreadState.Stop; + _removeList.Add(work); + continue; + } + if (runTime <= nowTime) + { + work.ThreadState = ThreadState.Running; + ThreadPool.QueueUserWorkItem(new WaitCallback(InternelExecuteWork), work); + } + } + if (_isStop) break; + } + } + } + catch + { + + } + if (_workQueues == null || _workQueues.Count == 0) + Thread.Sleep(MainThreadSleepTime); + else + Thread.Sleep(3*1000);//休眠3秒钟 + } + } + + + private static string _sss = string.Empty; + public static void InternelExecuteWork(object obj) + { + APTThreadWork work = obj as APTThreadWork; + if (work == null) return; + try + { + DateTime runTime = work.RunTime; + work.ThreadState = ThreadState.Running; + work.Execute(); + if (work.NextRunTime(ref runTime)) + { + work.ThreadState = ThreadState.Wait; + work.RunTime = runTime; + } + else + { + work.ThreadState = ThreadState.Stop; + lock (_mainThreadLockObj) + { + _removeList.Add(work); + } + } + } + catch + { + lock (_mainThreadLockObj) + { + _removeList.Add(work); + } + work.ThreadState = ThreadState.Wait; + } + } + } +} diff --git a/APT.Infrastructure.Core/Thread/LDXThreadTimeRule.cs b/APT.Infrastructure.Core/Thread/LDXThreadTimeRule.cs new file mode 100644 index 0000000..2667108 --- /dev/null +++ b/APT.Infrastructure.Core/Thread/LDXThreadTimeRule.cs @@ -0,0 +1,155 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace APT.Infrastructure.Core +{ + public class APTThreadTimeRuleParam + { + private ThreadTimeRuleLoopType _type; + + public APTThreadTimeRuleParam(ThreadTimeRuleLoopType type) + { + _type = type; + } + + public ThreadTimeRuleLoopType Type { get { return _type; } } + + public int InternalTime { get; set; } + + public int FiexedDay { get; set; } + public int FiexedHour { get; set; } + public int FiexedMinute { get; set; } + public int FiexedSecond { get; set; } + public int FiexedMonth { get; set; } + public int FiexedYear { get; set; } + + public DateTime FiexedTime { get; set; } + } + public class APTThreadTimeRule + { + private ThreadTimeRuleType _rule = ThreadTimeRuleType.ExecuteOne; + private int DefaultInternal = 1; + private APTThreadTimeRuleParam _param; + + public APTThreadTimeRuleParam Param + { + get { return _param; } + } + public APTThreadTimeRule(ThreadTimeRuleType rule, APTThreadTimeRuleParam param) + { + _rule = rule; + _param = param; + } + + public bool NextRuleTime(ref DateTime time) + { + bool result = false; + DateTime t = time; + switch (_rule) + { + case ThreadTimeRuleType.EveryDayLoopByTime: + if (this.Param.Type == ThreadTimeRuleLoopType.Hour) + t = t.AddHours(this.Param.InternalTime <= 0 ? DefaultInternal : this.Param.InternalTime); + else if (this.Param.Type == ThreadTimeRuleLoopType.Second) + t = t.AddSeconds(this.Param.InternalTime <= 0 ? DefaultInternal : this.Param.InternalTime); + else if (this.Param.Type == ThreadTimeRuleLoopType.Minute) + t = t.AddMinutes( this.Param.InternalTime <= 0 ? DefaultInternal : this.Param.InternalTime); + else if (this.Param.Type == ThreadTimeRuleLoopType.Day) + t = t.AddDays(this.Param.InternalTime <= 0 ? DefaultInternal : this.Param.InternalTime); + else if (this.Param.Type == ThreadTimeRuleLoopType.Month) + t = t.AddMonths( this.Param.InternalTime <= 0 ? DefaultInternal : this.Param.InternalTime); + else if (this.Param.Type == ThreadTimeRuleLoopType.Year) + t = t.AddYears(this.Param.InternalTime <= 0 ? DefaultInternal : this.Param.InternalTime); + time = t; + result = true; + break; + case ThreadTimeRuleType.EveryDayFiexedTime: + if ( this.Param.Type == ThreadTimeRuleLoopType.Day) + { + t = t.Date.AddDays( this.Param.FiexedDay < 0 ? 1 : this.Param.FiexedDay); + t = t.AddHours(this.Param.FiexedHour < 1 || this.Param.FiexedHour >= 24 ? 12 : this.Param.FiexedHour); + t = t.AddMinutes(this.Param.FiexedMinute < 0 || this.Param.FiexedMinute >= 60 ? 0 : this.Param.FiexedMinute); + t = t.AddSeconds( this.Param.FiexedSecond < 0 || this.Param.FiexedSecond >= 60 ? 0 : this.Param.FiexedSecond); + } + else if (this.Param.Type == ThreadTimeRuleLoopType.Hour) + { + t = t.Date.AddHours(t.Hour + (this.Param.FiexedHour < 0 ? 1 : this.Param.FiexedHour)); + t = t.AddMinutes( this.Param.FiexedMinute < 0 || this.Param.FiexedMinute >= 60 ? 0 : this.Param.FiexedMinute); + t = t.AddSeconds( this.Param.FiexedSecond < 0 || this.Param.FiexedSecond >= 60 ? 0 : this.Param.FiexedSecond); + } + else if (this.Param.Type == ThreadTimeRuleLoopType.Month) + { + int day = t.Day; + t = t.Date.AddDays(-day).AddMonths(this.Param.FiexedMonth < 0 ? 1 : this.Param.FiexedMonth); + t = t.AddDays( this.Param.FiexedDay < 1 || this.Param.FiexedDay > MaxDay(t.Year, t.Month) ? 1 : this.Param.FiexedDay); + t = t.AddHours(this.Param.FiexedHour < 1 || this.Param.FiexedHour >= 24 ? 12 : this.Param.FiexedHour); + t = t.AddMinutes(this.Param.FiexedMinute < 0 || this.Param.FiexedMinute >= 60 ? 0 : this.Param.FiexedMinute); + t = t.AddSeconds( this.Param.FiexedSecond < 0 || this.Param.FiexedSecond >= 60 ? 0 : this.Param.FiexedSecond); + } + else if (this.Param.Type == ThreadTimeRuleLoopType.Year) + { + int day = t.Day; + int month = t.Month; + t = t.Date.AddMonths(-month).AddDays(-day).AddYears( this.Param.FiexedYear < 0 ? 1 : this.Param.FiexedYear); + t = t.AddMonths(this.Param.FiexedMonth < 1 || this.Param.FiexedMonth > 12 ? 1 : this.Param.FiexedMonth); + t = t.AddDays(this.Param.FiexedDay < 1 || this.Param.FiexedDay > MaxDay(t.Year, t.Month) ? 1 : this.Param.FiexedDay); + t = t.AddHours( this.Param.FiexedHour < 1 || this.Param.FiexedHour >= 24 ? 12 : this.Param.FiexedHour); + t = t.AddMinutes( this.Param.FiexedMinute < 0 || this.Param.FiexedMinute >= 60 ? 0 : this.Param.FiexedMinute); + t = t.AddSeconds(this.Param.FiexedSecond < 0 || this.Param.FiexedSecond >= 60 ? 0 : this.Param.FiexedSecond); + } + if (t > time) + { + time = t; + result = true; + } + break; + case ThreadTimeRuleType.FiexedTime: + DateTime fiexdTime = this.Param.FiexedTime == null ? DateTime.MinValue : this.Param.FiexedTime; + if (fiexdTime > t) + { + time = t; + result = true; + } + break; + case ThreadTimeRuleType.Always: + time = t; + result = true; + break; + } + return result; + } + + private int MaxDay(int year, int month) + { + int maxDay = 0;//用来标识一月几天 + if (month == 2) + { + if (year % 4 == 0)//闰年 + { + maxDay = 29; + } + else + maxDay = 28; + } + else + { + switch (month) + { + case 1: + case 3: + case 5: + case 7: + case 8: + case 10: + case 12: maxDay = 31; break; + case 4: + case 6: + case 9: + case 11: maxDay = 30; break; + } + } + return maxDay; + } + } +} diff --git a/APT.Infrastructure.Core/Thread/LDXThreadWork.cs b/APT.Infrastructure.Core/Thread/LDXThreadWork.cs new file mode 100644 index 0000000..73227e2 --- /dev/null +++ b/APT.Infrastructure.Core/Thread/LDXThreadWork.cs @@ -0,0 +1,64 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace APT.Infrastructure.Core +{ + public class APTThreadWork + { + public APTThreadWork() + : this(DateTime.Now) + { + + } + public APTThreadWork(DateTime runTime) + : this(runTime, null, null, null) + { + + } + public APTThreadWork(DateTime runTime, APTThreadTimeRule rule) + : this(runTime, rule, null, null) + { + + } + public APTThreadWork(DateTime runTime, APTThreadTimeRule rule, object executeObj, Action executeAction) + { + _runTime = runTime; + _executeAction = executeAction; + _executeObj = executeObj; + _rule = rule; + } + + private DateTime _runTime = DateTime.MinValue; + private Action _executeAction = null; + private object _executeObj = null; + private APTThreadTimeRule _rule = null; + + + internal DateTime RunTime + { + get { return _runTime; } + set { _runTime = value; } + } + + private ThreadState _threadState = ThreadState.Wait; + public ThreadState ThreadState + { + get { return _threadState; } + internal set { _threadState = value; } + } + + public virtual bool NextRunTime(ref DateTime runTime) + { + if (_rule != null) + return _rule.NextRuleTime(ref runTime); + return false; + } + + public virtual void Execute() + { + if (_executeAction != null) + _executeAction(_executeObj); + } + } +} diff --git a/APT.Infrastructure.Core/Utils/InitUtils.cs b/APT.Infrastructure.Core/Utils/InitUtils.cs new file mode 100644 index 0000000..2b7beab --- /dev/null +++ b/APT.Infrastructure.Core/Utils/InitUtils.cs @@ -0,0 +1,55 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Linq; +using System.Reflection; +using System.Xml; + +namespace APT.Infrastructure.Core.Utils +{ + public class InitUtils + { + + public static void Init() + { + DoInitMessageFormat(); + } + + /// + /// 初始化错误消息 + /// + private static void DoInitMessageFormat() + { + var files = System.IO.Directory.GetFiles(System.AppContext.BaseDirectory, "Message*.xml"); + foreach (var file in files) + { + XmlDocument xx = new XmlDocument(); + xx.Load(file); + var x1 = xx.DocumentElement; + var xs = x1.GetElementsByTagName("message"); + foreach (var x in xs) + { + var node = (XmlElement)x; + var name = node.GetAttribute("name"); + if (string.IsNullOrEmpty(name)) continue; + LibMessageFormat access = new LibMessageFormat + { + Code = name + }; + + var fields = node.GetElementsByTagName("item"); + foreach (var f in fields) + { + var fieldNode = (XmlElement)f; + var lang = fieldNode.GetAttribute("lang"); + access.AddFormat(lang, fieldNode.InnerText); + } + LibMessageFormatManager.Instance.AddMessageFormat(access); + } + } + } + + + + } +} diff --git a/APT.Infrastructure.Domain/APT.Infrastructure.Domain.csproj b/APT.Infrastructure.Domain/APT.Infrastructure.Domain.csproj new file mode 100644 index 0000000..1af5262 --- /dev/null +++ b/APT.Infrastructure.Domain/APT.Infrastructure.Domain.csproj @@ -0,0 +1,13 @@ + + + + netstandard2.1 + APT.Infrastructure.Domain + APT.Infrastructure.Domain + + + + + + + diff --git a/APT.Infrastructure.Domain/Models/DataUpdateRecord.cs b/APT.Infrastructure.Domain/Models/DataUpdateRecord.cs new file mode 100644 index 0000000..718a77e --- /dev/null +++ b/APT.Infrastructure.Domain/Models/DataUpdateRecord.cs @@ -0,0 +1,11 @@ +using APT.Infrastructure.Core; +using System; +using System.Collections.Generic; +using System.Text; + +namespace APT.Infrastructure.Domain.Models +{ + public class DataUpdateRecord : EntityBase + { + } +} diff --git a/APT.Infrastructure.EF/APT.Infrastructure.EF.csproj b/APT.Infrastructure.EF/APT.Infrastructure.EF.csproj new file mode 100644 index 0000000..652ec3e --- /dev/null +++ b/APT.Infrastructure.EF/APT.Infrastructure.EF.csproj @@ -0,0 +1,42 @@ + + + + netstandard2.1 + 2.1.4.4 + true + 2.1.4.4 + 2.1.4.4 + APT.Infrastructure.EF + Library + APT + APT + APT + + f48ded12-f765-473b-8f90-7ab9c5b278e2 + + + + + .\APT.Infrastructure.EF.xml + + + + + + + + + + + + + + + + + + + + + + diff --git a/APT.Infrastructure.EF/APT.Infrastructure.EF.xml b/APT.Infrastructure.EF/APT.Infrastructure.EF.xml new file mode 100644 index 0000000..eb7731d --- /dev/null +++ b/APT.Infrastructure.EF/APT.Infrastructure.EF.xml @@ -0,0 +1,164 @@ + + + + APT.Infrastructure.EF + + + + + 初始化一个类型的新实例 + + + + + 统一处理数据库报的异常 + + DbUpdateException + + + + 自定义报错 + + 格式化的自定义报错信息 + SqlException + + + + 根据表名获取表数据结构 + + + + + + + 根据表名、字段名称获取字段结构 + + + + + + + + 根据表名,导航名称获取外键信息 + + + + + + + + 根据表名,ID字段名称获取外键信息 + + + + + + + + 汉字转全拼 + + + + + + + 汉字转首字母 + + + + + + + 数字转换成字母(1-26) + + + + + + + 字母转换成数字(1-26) + + + + + + + 根据租户获取数据库连接 + + + + + + + 解密连接 + + + + + + + 加密连接 + + + + + + + 分级构造树的数据 + + + + + + + + + + + 构造关联的表 + + + + + + + + 构造查询条件 + + + + + + + + + + + + + 检查唯一性 + + + + + + + + + 0-新增 1-更新 2-删除 + + + + 设置首字母缩写字段 + + + + + + + 获取所有的数据库连接 + + + + + diff --git a/APT.Infrastructure.EF/ConnectionResolverType.cs b/APT.Infrastructure.EF/ConnectionResolverType.cs new file mode 100644 index 0000000..6550331 --- /dev/null +++ b/APT.Infrastructure.EF/ConnectionResolverType.cs @@ -0,0 +1,13 @@ +using System; + +namespace APT.Infrastructure.EF +{ + public enum ConnectionResolverType + { + Default = 0, + ByDatabase = 1, + ByTable = 2, + BySchema = 3 + + } +} diff --git a/APT.Infrastructure.EF/Constans.cs b/APT.Infrastructure.EF/Constans.cs new file mode 100644 index 0000000..68ffb34 --- /dev/null +++ b/APT.Infrastructure.EF/Constans.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; + +namespace APT.Infrastructure.EF +{ + public class Constants + { + internal static List specialConnectionTypes = new List + { + ConnectionResolverType.ByTable, + ConnectionResolverType.BySchema + }; + + } +} diff --git a/APT.Infrastructure.EF/CustomNpgsqlQuerySqlGenerator.cs b/APT.Infrastructure.EF/CustomNpgsqlQuerySqlGenerator.cs new file mode 100644 index 0000000..298874f --- /dev/null +++ b/APT.Infrastructure.EF/CustomNpgsqlQuerySqlGenerator.cs @@ -0,0 +1,35 @@ +using Microsoft.EntityFrameworkCore.Query; +using Microsoft.EntityFrameworkCore.Query.SqlExpressions; +using Npgsql.EntityFrameworkCore.PostgreSQL.Infrastructure.Internal; +using Npgsql.EntityFrameworkCore.PostgreSQL.Query.Internal; +using System; +using System.Collections.Generic; +using System.Linq.Expressions; +using System.Text; + +namespace APT.Infrastructure.EF +{ + public class CustomNpgsqlQuerySqlGenerator : NpgsqlQuerySqlGenerator + { + public CustomNpgsqlQuerySqlGenerator(QuerySqlGeneratorDependencies dependencies, bool reverseNullOrderingEnabled, Version postgresVersion) + : base(dependencies, reverseNullOrderingEnabled,postgresVersion) { } + protected override Expression VisitTable(TableExpression tableExpression) + { + var result = base.VisitTable(tableExpression); + Sql.Append(" WITH (NOLOCK)"); + return result; + } + } + + public class CustomNpgsqlQuerySqlGeneratorFactory : NpgsqlQuerySqlGeneratorFactory + { + private readonly QuerySqlGeneratorDependencies _dependencies; + public CustomNpgsqlQuerySqlGeneratorFactory(QuerySqlGeneratorDependencies dependencies, INpgsqlOptions npgsqlOptions) + : base(dependencies, npgsqlOptions) + { + _dependencies = dependencies; + } + public override QuerySqlGenerator Create() => + new CustomNpgsqlQuerySqlGenerator(_dependencies,true,new Version(12,2)); + } +} diff --git a/APT.Infrastructure.EF/DbIntegrationType.cs b/APT.Infrastructure.EF/DbIntegrationType.cs new file mode 100644 index 0000000..e9e701d --- /dev/null +++ b/APT.Infrastructure.EF/DbIntegrationType.cs @@ -0,0 +1,12 @@ +using System; + +namespace APT.Infrastructure.EF +{ + public enum DbIntegrationType + { + None = 0, + Mysql = 1, + SqlServer = 2, + Postgre = 3, + } +} diff --git a/APT.Infrastructure.EF/DbsetProperty.cs b/APT.Infrastructure.EF/DbsetProperty.cs new file mode 100644 index 0000000..cba92dc --- /dev/null +++ b/APT.Infrastructure.EF/DbsetProperty.cs @@ -0,0 +1,11 @@ +using System; + +namespace APT.Infrastructure.EF +{ + public class DbsetProperty + { + public Type PropertyType { get; set; } + + public string PropertyName { get; set; } + } +} diff --git a/APT.Infrastructure.EF/EFDbContextLog.cs b/APT.Infrastructure.EF/EFDbContextLog.cs new file mode 100644 index 0000000..dce1b26 --- /dev/null +++ b/APT.Infrastructure.EF/EFDbContextLog.cs @@ -0,0 +1,36 @@ +using APT.Infrastructure.Core; +using Microsoft.Extensions.Logging; +using System; +using System.Collections.Generic; +using System.Text; + +namespace APT.Infrastructure.EF +{ + public class EFDbContextLoggerProvider : ILoggerProvider + { + public ILogger CreateLogger(string categoryName) => new EFDbContextLogger(categoryName); + public void Dispose() { } + } + public class EFDbContextLogger : ILogger + { + private readonly string categoryName; + + public EFDbContextLogger(string categoryName) => this.categoryName = categoryName; + + public bool IsEnabled(LogLevel logLevel) => true; + + public void Log(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func formatter) + { + //ef core执行数据库查询时的categoryName为Microsoft.EntityFrameworkCore.Database.Command,日志级别为Information + if (categoryName == "Microsoft.EntityFrameworkCore.Database.Command") + { + var logContent = formatter(state, exception); + LoggerManager.GetLogger("SQLLog"). + Info(logContent + System.Environment.NewLine + + (exception != null ? ("Except:" + exception.Message) : string.Empty)); + } + } + + public IDisposable BeginScope(TState state) => null; + } +} diff --git a/APT.Infrastructure.EF/EfDbContext.cs b/APT.Infrastructure.EF/EfDbContext.cs new file mode 100644 index 0000000..b21e870 --- /dev/null +++ b/APT.Infrastructure.EF/EfDbContext.cs @@ -0,0 +1,1537 @@ +using APT.Infrastructure.Core; +using APT.Infrastructure.Utility; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Internal; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Metadata.Internal; +using Microsoft.EntityFrameworkCore.Query; +using Microsoft.EntityFrameworkCore.Storage; +using Microsoft.Extensions.Logging; +using System; +using System.Collections; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Data; +using System.Data.Common; +using System.IO; +using System.Linq; +using System.Linq.Expressions; +using System.Reflection; +using System.Runtime.InteropServices.ComTypes; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using System.Linq.Dynamic.Core; +using System.Collections.Concurrent; +using APT.Infrastructure.EF.Infrastructure; +using APT.Infrastructure.Api; +using System.Text.RegularExpressions; +using Microsoft.Data.SqlClient; +//using Npgsql; +using APT.Infrastructure.Core.Refctor; +using System.ComponentModel; + +namespace APT.Infrastructure.EF +{ + public class EfDbContext : TenantBaseDbContext, IUnitOfWork, IDependency + { + private readonly string namedConnection; + + private const string dbsRedisKey = "DbConn_RedisKey"; + + private static IConnectionResolver _connectionResolver; + private static IConnectionResolver ConnectionResolver + { + get + { + if (_connectionResolver == null) + { + ServiceLocator serviceLocator = ServiceLocator.Instance; + _connectionResolver = serviceLocator.GetService(); + + } + return _connectionResolver; + } + } + + //public static Action SQL_LOG { get; set; } + int _TranscationLocker = 0; + + IDbContextTransaction _dbContextTransaction; + + private static EFModel _efModel; + + + #region ctor. + public EfDbContext() : base() + { + } + /// + /// 初始化一个类型的新实例 + /// + // + // 使用连接名称或连接字符串 初始化一个 类型的新实例 + // + public EfDbContext(string nameOrConnectionString) : base() + { + this.namedConnection = nameOrConnectionString; + } + public TenantInfo TenantInfo => tenantInfo; + + private readonly TenantInfo tenantInfo; + + + public EfDbContext(DbContextOptions options, TenantInfo tenant, IServiceProvider serviceProvider) + : base(options, tenant, serviceProvider) + { + this.tenantInfo = tenant; + } + + #endregion + + #region IUnitOfWork 成员 + + public string ConnectionString + { + get + { + return ConfigurationManager.ConnectionStrings[namedConnection] ?? namedConnection; + } + } + + + public int ExecuteSqlCommand(string sql, params object[] parameters) + { + + return ExecuteSqlCommand(TransactionalBehavior.DoNotEnsureTransaction, sql, parameters); + } + + public int ExecuteSqlCommand(TransactionalBehavior transactionalBehavior, string sql, params object[] parameters) + { + return Database.ExecuteSqlRaw(sql, parameters); + } + + public void ExecuteReader(string sql, ReaderColumn[] readerColumns, Action readerAction) + { + ExecuteReader(sql, readerColumns, null, readerAction); + } + + public void ExecuteReader(string sql, ReaderColumn[] readerColumns, DbParameter[] parameters, Action readerAction) + { + ExecuteReader(CommandType.Text, sql, readerColumns, parameters, readerAction); + } + + public void ExecuteReader(CommandType commandType, string sql, ReaderColumn[] readerColumns, DbParameter[] parameters, Action readerAction) + { + var concurrencyDetector = Database.GetService(); + using (concurrencyDetector.EnterCriticalSection()) + { + IReadOnlyDictionary paramValues = null; + IRelationalCommand relationalCommand = GetRelationComman(sql, parameters, out paramValues); + + var paramObject = new RelationalCommandParameterObject( + Database.GetService(), + paramValues, readerColumns, + this, + null + ); + var relR = relationalCommand + .ExecuteReader( + paramObject); + if (relR != null && readerAction != null) + readerAction(relR.DbDataReader); + } + } + + public int ExecuteNonQuery(CommandType commandType, string sql, ReaderColumn[] readerColumns, DbParameter[] parameters) + { + var concurrencyDetector = Database.GetService(); + using (concurrencyDetector.EnterCriticalSection()) + { + IReadOnlyDictionary paramValues = null; + IRelationalCommand relationalCommand = GetRelationComman(sql, parameters, out paramValues); + + var paramObject = new RelationalCommandParameterObject( + Database.GetService(), + paramValues, readerColumns, + this, + null + ); + + var dr = relationalCommand + .ExecuteNonQuery(paramObject); + + return dr; + } + } + private IRelationalCommand GetRelationComman(string sql, object[] parameters, out IReadOnlyDictionary paramValues) + { + paramValues = null; + IRelationalCommand relationalCommand = null; + if (parameters != null && parameters.Any()) + { + var rawSqlCommand = Database + .GetService() + .Build(sql, parameters); + relationalCommand = rawSqlCommand + .RelationalCommand; + paramValues = rawSqlCommand.ParameterValues; + } + else + { + relationalCommand = Database + .GetService() + .Build(sql); + } + return relationalCommand; + } + + public IEnumerable SqlQuery(Type elementType, string sql, ReaderColumn[] readCloums, params object[] parameters) + { + var concurrencyDetector = Database.GetService(); + using (concurrencyDetector.EnterCriticalSection()) + { + IReadOnlyDictionary paramValues = null; + IRelationalCommand relationalCommand = GetRelationComman(sql, parameters, out paramValues); + + var paramObject = new RelationalCommandParameterObject( + Database.GetService(), + paramValues, readCloums, + this, + null + ); + + var dr = relationalCommand + .ExecuteReader(paramObject); + + return dr.DbDataReader; + } + } + + #region GetTreeOrderEntities + public IEnumerable> GetTreeOrderEntities(Expression> expression, BaseFilter filter, + Expression> orgExpress, out List resultList, bool isTracking = true, + params string[] paths) where T : TreeEntityBase, new() + { + List allData = new List(); + //List data = new List(); + if (filter == null) + { + filter = new BaseFilter(); + } + var selectFields = filter.SelectField; + if (selectFields.Any()) + { + if (!string.IsNullOrEmpty(filter.Sort)) + { + if (!selectFields.Contains(filter.Sort)) + selectFields = selectFields.Append(filter.Sort).ToList(); + } + else if (filter.Orders != null && filter.Orders.Any()) + { + foreach (var o in filter.Orders) + { + if (!selectFields.Contains(o.Field)) + selectFields = selectFields.Append(o.Field).ToList(); + } + } + selectFields = selectFields.Append("ORG_ID").ToList(); + } + if (filter.IsParentData) + { + if (selectFields.Any() && !selectFields.Contains("ORG_ID")) + selectFields = selectFields.Append("ORG_ID").ToList(); + allData = this.GetEntities(orgExpress, selectFields.ToArray(), isTracking, paths).ToList(); + resultList = allData.AsQueryable().Where(expression).ToList(); + var dataIds = resultList.Select(i => i.ID).ToArray(); + AddParentData(allData, resultList, dataIds); + + } + else + { + resultList = this.GetEntities(expression, selectFields.ToArray(), isTracking, paths).ToList(); + } + //有条件,需要再次查询,查询结果的父级 + var ids = resultList.Select(i => i.ID).ToArray(); + var parentData = resultList.Where(i => !ids.Contains(i.PARENT_ID ?? Guid.Empty) || i.PARENT_ID == null).ToList(); + + List> treeNodes = new List>(); + foreach (var d in parentData) + { + var node = new TreeNode(); + node.Node = d; + node.Children = new List>(); + node.Level = filter.Level < 0 ? 0 : filter.Level; + node.IsLeaf = filter.Level < 0 ? true : d.IS_LEAF; + if (filter.Level < 0)//<0 取全部数据,>=0 表示异步取数 + { + var childNodes = resultList.Where(i => i.PARENT_ID == d.ID).ToList(); + if (childNodes.Any()) + { + node.IsLeaf = false; + InitFullTree(resultList, childNodes, node, node.Level + 1); + } + } + treeNodes.Add(node); + } + + ReSort(treeNodes, filter); + return treeNodes; + } + private static void InitFullTree(List data, List childNodeList, TreeNode theNode, int level) where T : TreeEntityBase, new() + { + foreach (var d in childNodeList) + { + var node = new TreeNode(); + node.Node = d; + node.Children = new List>(); + node.Level = level; + node.IsLeaf = true; + var childNodes = data.Where(i => i.PARENT_ID == d.ID).ToList(); + if (childNodes.Any()) + { + node.IsLeaf = false; + InitFullTree(data, childNodes, node, level + 1); + } + theNode.Children.Add(node); + } + } + private static void AddParentData(List allData, List data, Guid[] dataIds) where T : TreeEntityBase, new() + { + var emptyDataIds = data.Where(i => i.PARENT_ID != null + && !dataIds.Contains(i.PARENT_ID ?? Guid.Empty)).Select(i => i.PARENT_ID ?? Guid.Empty).ToArray(); + if (emptyDataIds.Any()) + { + var emptyData = allData.Where(i => emptyDataIds.Contains(i.ID)); + if (emptyData.Any()) + { + data.AddRange(emptyData); + dataIds = data.Select(i => i.ID).ToArray(); + AddParentData(allData, data, dataIds); + } + else + { + return; + } + } + return; + } + private static void ReSort(List> treeNodes, BaseFilter filter) where T : TreeEntityBase, new() + { + SortBy(filter, treeNodes); + foreach (var node in treeNodes) + { + if (node.Children != null && node.Children.Any()) + { + ReSort(node.Children, filter); + } + } + } + private static IList SortBy(BaseFilter filter, IList parentData) where T : TreeEntityBase, new() + { + if (!string.IsNullOrEmpty(filter.Sort)) + { + if (filter.Order == DbOrder.ASC) + parentData = parentData.AsQueryable().OrderBy(filter.Sort + " asc").ToList(); + else + parentData = parentData.AsQueryable().OrderBy(filter.Sort + " desc").ToList(); + } + else + { + if (filter.Orders != null && filter.Orders.Any()) + { + var sortSql = ""; + foreach (var o in filter.Orders) + { + sortSql += o.Field + (o.Order == DbOrder.ASC ? " asc," : " desc,"); + } + sortSql = sortSql.TrimEnd(','); + parentData = parentData.AsQueryable().OrderBy(sortSql).ToList(); + } + } + + return parentData; + } + private static IList> SortBy(BaseFilter filter, List> treeNodes) where T : TreeEntityBase, new() + { + + if (!string.IsNullOrEmpty(filter.Sort)) + { + if (filter.Order == DbOrder.ASC) + { + var orderyNodes = treeNodes.AsQueryable().OrderBy("Node." + filter.Sort + " asc").ToList(); + treeNodes.Clear(); + treeNodes.AddRange(orderyNodes); + } + + else + { + var orderyNodes = treeNodes.AsQueryable().OrderBy("Node." + filter.Sort + " desc").ToList(); + treeNodes.Clear(); + treeNodes.AddRange(orderyNodes); + } + + } + else + { + if (filter.Orders != null && filter.Orders.Any()) + { + var sortSql = ""; + foreach (var o in filter.Orders) + { + sortSql += "Node." + o.Field + (o.Order == DbOrder.ASC ? " asc," : " desc,"); + } + sortSql = sortSql.TrimEnd(','); + var orderyNodes = treeNodes.AsQueryable().OrderBy(sortSql).ToList(); + treeNodes.Clear(); + treeNodes.AddRange(orderyNodes); + } + } + return treeNodes; + } + #endregion + + public override int SaveChanges() + { + var entities = from e in ChangeTracker.Entries() + where e.State == EntityState.Added + || e.State == EntityState.Modified + select e.Entity; + var delEntities = from e in ChangeTracker.Entries() + where e.State == EntityState.Deleted + select e.Entity; + List typeNames = new List(); + Dictionary DicInitTree = new Dictionary(); + var isReInitTree = false; + foreach (var entity in entities) + { + var validationContext = new ValidationContext(entity); + + var dbExceptions = new List(); + try + { + Validator.ValidateObject(entity, validationContext); + } + catch (ValidationException dbEx) + { + var errorBuilder = new StringBuilder(); + errorBuilder.AppendLine(dbEx.Message); + } + + if (dbExceptions.Count > 0) + { + var errorBuilder = new StringBuilder(); + dbExceptions.ForEach(ve => errorBuilder.AppendLine(ve.Message)); + + throw new DomainException(errorBuilder.ToString()); + } + var type = entity.GetType(); + if (!typeNames.Contains(type.Name)) + { + typeNames.Add(type.Name); + if (type.BaseType.Name.StartsWith("TreeEntityBase`1") || type.BaseType.Name.StartsWith("MesTreeEntityBase")) + { + isReInitTree = true; + var orgId = type.GetProperty("ORG_ID").GetValue(entity); + if (orgId == null) + orgId = Guid.Empty; + DicInitTree.TryAdd(type, Guid.Parse(orgId.ToString())); + } + } + } + foreach (var entity in delEntities) + { + var type = entity.GetType(); + if (!typeNames.Contains(type.Name)) + { + typeNames.Add(type.Name); + if (entity is MesTreeEntityBase) + { + isReInitTree = true; + DicInitTree.TryAdd(type, Guid.Parse(type.GetProperty("ORG_ID").GetValue(entity).ToString())); + } + } + } + try + { + var intResult = base.SaveChanges(); + if (isReInitTree) + { + foreach (var dic in DicInitTree) + { + MethodInfo methodInfo = this.GetType().GetMethod("InitTreeData", + BindingFlags.Instance | BindingFlags.Public | BindingFlags.Static); + methodInfo.MakeGenericMethod(new Type[] { dic.Key }). + Invoke(this, new object[] { dic.Value }); + } + var ret = base.SaveChanges(); + } + return intResult; + } + catch (DbUpdateException dbEx) + { + HandleDbUpdateException(dbEx); + return 0; + } + catch (Exception ex) + { + throw ex; + } + } + /// + /// 统一处理数据库报的异常 + /// + /// DbUpdateException + public void HandleDbUpdateException(DbUpdateException ex) + { + var dbType = this.DBType(); + if (ex.Entries.Count == 1) + { + var entries = ex.Entries.FirstOrDefault(); + var data = entries.Entity; + ExcetionTrow(ex, dbType, data); + + } + else + { + if (dbType == DataBaseType.Postgresql) + { + //var errMsg = ex.InnerException != null ? ex.InnerException.Message : ex.Message; + //if (ex.GetBaseException() is NpgsqlException pgException) + //{ + // var p = pgException.GetType().GetProperty("Statement"); + // if (p != null) + // { + // object stateMent = p.GetValue(pgException); + // var parameterProp = p.PropertyType.GetProperty("InputParameters"); + // if (parameterProp != null) + // { + // var parameters = parameterProp.GetValue(stateMent) as List; + // if (parameters != null && parameters.Any()) + // { + // var idstr = parameters.FirstOrDefault().NpgsqlValue.ToString(); + // foreach (var e in ex.Entries) + // { + // var entity = e.Entity; + // if (entity.GetType().GetProperty("ID").GetValue(entity).ToString() == idstr) + // { + // ExcetionTrow(ex, dbType, entity); + // break; + // } + // } + // } + + // } + // throw new DomainException(errMsg); + // } + //} + } + + throw new DomainException(ex.InnerException != null ? ex.InnerException.Message : ex.Message); + + } + } + + private void ExcetionTrow(DbUpdateException ex, DataBaseType dbType, object data) + { + var tableName = data.GetType().Name; + //var keys = GetModelForeignKey(tableName); //获取外键信息 + var id = data.GetType().GetProperty("ID").GetValue(data); + if (dbType == DataBaseType.Oracle) + { + + } + else if (dbType == DataBaseType.MySQL) + { + + } + //else if (dbType == DataBaseType.Postgresql) + //{ + // if (ex.GetBaseException() is NpgsqlException pgException) + // { + // var code = pgException.Data["SqlState"].ToString(); + // var type = ReflectHelper.FindTypeInCurrentDomain(tableName); + // var props = type.GetProperties(); + // switch (code) + // { + // //case 547: + // // //外键报错 + // // //errMsg = ForeignKeyErrorFormatter(sqlException); + // // break; + // //case 2601: + // case "23505": + // if (type != null) + // { + // //唯一约束报错 + // //var tableName = pgException.Data["TableName"].ToString(); + // var constraintName = pgException.Data["ConstraintName"].ToString(); + // var clomsMsg = "存在重复键值数据!"; + // if (constraintName.StartsWith("PK"))//主键 + // { + // clomsMsg = "主键重复。"; + // } + // else + // { + // var startIndex = constraintName.IndexOf(tableName); + // if (startIndex >= 0) + // { + // var temp = constraintName.Substring(startIndex + tableName.Length).Trim('_'); + // //var cloums = temp.Split(new char[] { '_' }, StringSplitOptions.RemoveEmptyEntries); + + // bool check = true; + // while (check && temp.Length > 0) + // { + // check = false; + // foreach (var c in props) + // { + // if (c.Name == "ID") + // continue; + // if (temp.StartsWith(c.Name)) + // { + // //var fKey = keys.FirstOrDefault(i => i.ForeignFieldName == c.Name); + // //if (fKey == null) + // //{ + // clomsMsg = GetProMsgVal(data, clomsMsg, c); + // //} + // //else + // //{ + // // var navName = fKey.ForeignNavName; + // // var navPro = props.FirstOrDefault(i => i.Name == navName); + // // if (navPro != null) + // // { + // // clomsMsg = GetProMsgVal(data, clomsMsg, navPro); + // // } + // //} + // temp = temp.Substring(c.Name.Length).Trim('_'); + // check = true; + // break; + // } + // } + // } + // } + // } + // clomsMsg = clomsMsg + "[ID]:" + id; + // throw new DomainException(clomsMsg); + // } + // break; + // case "23503": + // if (type != null) + // { + // var constraintName = pgException.Data["ConstraintName"].ToString(); + // var clomsMsg = "外键字段数据异常!"; + // if (constraintName.StartsWith("FK"))//外键FK_T_BD_ENERGY_TYPE_T_FM_ENUM_ITEM_UNIT_ENUM_ITEM_ID + // { + // var tmp = constraintName.Replace("FK_", "").Replace(tableName + "_", ""); + // var keys = GetModelForeignKey(tableName); + // if (keys != null && keys.Any()) + // { + // foreach (var key in keys) + // { + // tmp = tmp.Replace(key.ForeignTableName + "_", ""); + // } + // //if (tmp.Length > 0) + // //{ + // // clomsMsg += "[" + tmp + "]"; + // //} + // var fkProp = data.GetType().GetProperty(tmp); + // if (fkProp != null) + // { + // clomsMsg = GetProMsgVal(data, clomsMsg, fkProp); + // } + // else + // { + // clomsMsg += ex.InnerException.Message; + // } + // clomsMsg = clomsMsg.TrimEnd(','); + // throw new DomainException(clomsMsg); + // } + // } + // } + // break; + // case "22001": + // { + // var msg = pgException.Message + "."; + // foreach (var c in props) + // { + // var lengthAttribute = c.GetAttribute(); + // if (lengthAttribute != null) + // { + // var val = c.GetValue(data); + // if (val != null && lengthAttribute.Length < val.ToString().Length) + // msg += $"[{c.Name}]:{val},"; + // } + // } + // msg = msg + "[ID]:" + id; + // throw new DomainException(msg); + // } + // break; + // default: + // //自定义报错 + // //errMsg = CustomErrorFormatter(sqlException); + // break; + // } + // } + //} + else if (dbType == DataBaseType.SQL) + { + if (ex.GetBaseException() is SqlException sqlException) + { + var errMsg = ""; + switch (sqlException.Number) + { + case 547: + //外键报错 + errMsg = sqlException.Message; + break; + case 2601: + case 2627: + //唯一约束报错 + errMsg = sqlException.Message; + break; + case 50000: + //自定义报错 + errMsg = CustomErrorFormatter(sqlException); + break; + } + errMsg = errMsg + "[ID]:" + id; + throw new DomainException(errMsg); + } + } + var tmsg = ex.InnerException != null ? ex.InnerException.Message : ex.Message; + tmsg = tmsg + "[ID]:" + id; + throw new DomainException(tmsg); + } + + private static string GetProMsgVal(object data, string clomsMsg, PropertyInfo c) + { + var desc = c.GetAttribute(); + if (desc != null) + { + clomsMsg += "[" + desc.Description + "]:" + c.GetValue(data) + ","; + } + else + { + clomsMsg += "[" + c.PropertyType.Name + "]:" + c.GetValue(data) + ","; + } + + return clomsMsg; + } + + //报错信息样例:Cannot insert duplicate key row in object 'dbo.TableName' with unique index 'IX_TableName_FieldName'. The duplicate key value is (XXX). + private readonly Regex UniqueConstraintRegex_Table = new Regex(@"'dbo.(\w*)'", RegexOptions.Compiled); + public string UniqueErrorFormatter(SqlException ex) + { + var message = ex.Errors[0]?.Message; + //利用正则表达式匹配到表名 + var tableMatch = UniqueConstraintRegex_Table.Match(message); + if (!tableMatch.Success) + { + return null; + } + var tableName = tableMatch?.Groups[1]?.Value; + //默认情况下,EF Core生成的唯一索引的命名是有规律的(如果是自定义的,也必须有规律),这样就用样可以通过正则表达式匹配到外键对应的字段 + Regex UniqueConstraintRegex = new Regex("'IX_" + tableName + @"_(\w*)'", RegexOptions.Compiled); + var columnMatch = UniqueConstraintRegex.Match(message); + if (!columnMatch.Success) + { + UniqueConstraintRegex = new Regex("'AK_" + tableName + @"_(\w*)'", RegexOptions.Compiled); + columnMatch = UniqueConstraintRegex.Match(message); + if (!columnMatch.Success) + { + return null; + } + } + var columnName = columnMatch?.Groups[1]?.Value; + //外键报错末尾是“The duplicate key value is (XXX).”,可以再次通过正则表达式匹配到重复数据 + var dupPart = ""; + var openingBadValue = message.IndexOf("(", StringComparison.Ordinal); + if (openingBadValue > 0) + { + dupPart = message.Substring(openingBadValue + 1, message.Length - openingBadValue - 3); + } + //这样就解析出了报错信息,具体怎么组合就看需求了 + return "存在重复的键,字段:" + columnName + ",值:" + dupPart; + } + + private readonly Regex ForeignKeyRegex_Table = new Regex(@"table ""dbo.(\w*)""", RegexOptions.Compiled); + private readonly Regex ForeignKeyRegex_Column = new Regex(@"column '(\w*)'", RegexOptions.Compiled); + //报错样例:The INSERT statement conflicted with the FOREIGN KEY constraint "FK_XXX". The conflict occurred in database "DBName", table "dbo.TableName", column 'ColumnName'. + private readonly string Operation_Insert = "INSERT"; + private readonly string Operation_Merge = "MERGE"; + private readonly string Operation_Update = "UPDATE"; + private readonly string Operation_Delete = "DELETE"; + public string ForeignKeyErrorFormatter(SqlException ex) + { + var message = ex.Errors[0]?.Message; + //利用规则匹配到操作:The {Operation} statement + var operationName = message?.Substring(4, 6)?.Trim(); + //利用正则表达式匹配到表名 + var tableMatch = ForeignKeyRegex_Table.Match(message); + if (!tableMatch.Success) + { + return null; + } + var tableName = tableMatch?.Groups[1]?.Value; + //增改涉及到的都是表自身,到这一步就结束了 + if (operationName == Operation_Merge || operationName == Operation_Insert) + { + return "新增数据时,外键约束报错:" + tableMatch; + } + if (operationName == Operation_Update) + { + return "更新数据时,外键约束报错:" + tableMatch; + } + //删除操作,涉及到的还有影响到的表 + var columnMatch = ForeignKeyRegex_Column.Match(message); + if (!columnMatch.Success) + { + return null; + } + var columnName = columnMatch?.Groups[1]?.Value; + + Regex ForeignKeyRegex = new Regex($@"""FK_{tableName}_(\w*)_{columnName}""", RegexOptions.Compiled); + var targetTableMatch = ForeignKeyRegex.Match(message); + if (!targetTableMatch.Success) + { + return null; + } + var targetTableName = targetTableMatch?.Groups[1]?.Value; + + return "删除数据时,外键约束报错:表[" + targetTableName + "],字段:[" + columnName + "]"; + } + /// + /// 自定义报错 + /// + /// 格式化的自定义报错信息 + /// SqlException + public string CustomErrorFormatter(SqlException ex) + { + var message = ex.Errors[0]?.Message; + //这里根据自己定义的错误格式分别处理,比如说:Error:{ErrorMessage} + var customErrorCode = message?.Split(":")?.First(); + return "自定义错误:" + customErrorCode; + } + + public void InitTreeData(Guid orgId) where T : TreeEntityBase, new() + { + List updateEntites = new List(); + + //var selectFields = new string[] { "ID", "IS_LEAF" }; + var data = this.GetEntities(i => i.IS_LEAF && i.Nav_Children.Any(), null, true); + if (data.Any()) + { + data.ForEach(i => i.IS_LEAF = false); + updateEntites.AddRange(data); + } + var leafData = this.GetEntities(i => !i.IS_LEAF && !i.Nav_Children.Any(), null, true); + if (leafData.Any()) + { + leafData.ForEach(i => i.IS_LEAF = true); + updateEntites.AddRange(leafData); + } + if (updateEntites.Any()) + this.UpdateEntities(updateEntites); + } + public async Task ExecuteSqlCommandAsync(TransactionalBehavior transactionalBehavior, string sql, params object[] parameters) + { + return await Database.ExecuteSqlRawAsync(sql, parameters); + } + + public override async Task SaveChangesAsync(CancellationToken cancellationToken = default(CancellationToken)) + { + var entities = from e in ChangeTracker.Entries() + where e.State == EntityState.Added + || e.State == EntityState.Modified + select e.Entity; + foreach (var entity in entities) + { + var validationContext = new ValidationContext(entity); + + var dbExceptions = new List(); + try + { + Validator.ValidateObject(entity, validationContext); + } + catch (ValidationException dbEx) + { + var errorBuilder = new StringBuilder(); + errorBuilder.AppendLine(dbEx.Message); + } + + if (dbExceptions.Count > 0) + { + var errorBuilder = new StringBuilder(); + dbExceptions.ForEach(ve => errorBuilder.AppendLine(ve.Message)); + + throw new DomainException(errorBuilder.ToString()); + } + } + + int save = await base.SaveChangesAsync(cancellationToken); + + return save; + } + + public void BeginTransaction() + { + this._TranscationLocker++; + if (this._dbContextTransaction != null) + return; + this._dbContextTransaction = this.Database.BeginTransaction(); + + } + + public void CommitTransaction() + { + if (this._dbContextTransaction == null) + return; + this._TranscationLocker--; + if (_TranscationLocker == 0) + { + this._dbContextTransaction.Commit(); + this._dbContextTransaction.Dispose(); + this._dbContextTransaction = null; + } + } + + public void RollbackTransaction() + { + if (this._dbContextTransaction == null) + return; + this._TranscationLocker = 0; + this._dbContextTransaction.Rollback(); + this._dbContextTransaction.Dispose(); + this._dbContextTransaction = null; + } + + public T AddEntity(T entity) where T : class + { + if (entity == null) return null; + return this.Add(entity).Entity; + } + + public void AddEntities(IEnumerable entities) where T : class + { + if (entities == null || !entities.Any()) return; + this.ChangeTracker.AutoDetectChangesEnabled = false; + try + { + this.AddRange(entities); + } + finally + { + this.ChangeTracker.AutoDetectChangesEnabled = true; + } + } + public void UpdateEntity(T entity) where T : class + { + this.ChangeTracker.AutoDetectChangesEnabled = false; + try + { + this.Update(entity); + } + finally + { + this.ChangeTracker.AutoDetectChangesEnabled = true; + } + } + public void UpdateEntities(IEnumerable entities) where T : class + { + if (entities == null || !entities.Any()) return; + this.ChangeTracker.AutoDetectChangesEnabled = false; + try + { + this.UpdateRange(entities); + } + finally + { + this.ChangeTracker.AutoDetectChangesEnabled = true; + } + } + + public void UpdateEntities(IEnumerable entities, params string[] updateField) where T : class + { + if (entities == null || !entities.Any()) return; + if (updateField == null || !updateField.Any()) + { + this.ChangeTracker.AutoDetectChangesEnabled = false; + try + { + this.UpdateRange(entities); + + } + finally + { + this.ChangeTracker.AutoDetectChangesEnabled = true; + } + } + else + { + foreach (var i in entities) + { + var entitybase = this.Entry(i); + foreach (var prop in updateField) + { + //IsPrimitive=true .NET内置的类型 + if (prop != "ID") + entitybase.Property(prop).IsModified = true; + } + } + } + + } + + public void DeleteEntities(IEnumerable entities) where T : class + { + if (entities == null || !entities.Any()) return; + this.ChangeTracker.AutoDetectChangesEnabled = false; + try + { + this.RemoveRange(entities); + } + finally + { + this.ChangeTracker.AutoDetectChangesEnabled = true; + } + } + + public DataBaseType GetDataBaseType() + { + return this.DBType(); + } + public T GetEntity(Expression> expression, string[] selectField, params string[] paths) where T : class + { + return this.GetEntity(expression, selectField, false, paths); + } + public T GetEntity(Expression> expression, string[] selectField, bool isTracking = true, params string[] paths) where T : class + { + //var queryTable = this.DoGetQuerTable(expression, isTracking, paths); + Dictionary order = new Dictionary(); + order.TryAdd("ID", DbOrder.ASC); + return this.GetEntity(expression, order, selectField, isTracking, paths); + } + public T GetEntity(Expression> expression, Dictionary orders, string[] selectField, + bool isTracking = true, params string[] paths) where T : class + { + var queryTable = this.DoGetQuerTable(expression, isTracking, paths); + var linq = new Orderable(queryTable); + queryTable = linq.Queryable; + bool isThen = false; + if (orders == null) + orders = new Dictionary(); + if (!orders.Any()) + orders.TryAdd("ID", DbOrder.ASC); + if (orders != null && orders.Any()) + { + foreach (var item in orders) + { + queryTable = queryTable.SetQueryableOrder(item.Key, item.Value.GetDescription(), isThen); + isThen = true; + } + } + if (selectField != null && selectField.Any()) + queryTable = DynamicSelect(selectField, queryTable); + return queryTable.FirstOrDefault(); + } + + public int GetCount(Expression> expression) where T : class + { + var queryTable = this.DoGetQuerTable(expression); + return queryTable.Count(); + } + public IEnumerable GetEntities(Expression> expression, string[] selectField, params string[] paths) where T : class + { + return this.GetEntities(expression, selectField, true, paths); + } + public IEnumerable GetEntities(Expression> expression, string[] selectField, bool isTracking = true, params string[] paths) where T : class + { + var queryTable = this.DoGetQuerTable(expression, isTracking, paths); + if (selectField != null && selectField.Any()) + { + queryTable = DynamicSelect(selectField, queryTable); + } + return queryTable.ToList(); + } + public IEnumerable GetOrderEntities(Expression> expression, + Dictionary orders, string[] selectField, + params string[] paths) where T : class + { + return this.GetOrderEntities(expression, orders, null, selectField, true, paths); + } + + public IEnumerable GetOrderEntities(Expression> expression, + Dictionary orders, string[] selectField, + bool isTracking = true, params string[] paths) where T : class + { + return this.GetOrderEntities(expression, orders, null, selectField, isTracking, paths); + } + public IEnumerable GetOrderEntities(Expression> expression, + Dictionary orders, Action> orderBy, string[] selectField, + bool isTracking = true, params string[] paths) where T : class + { + var queryTable = this.DoGetQuerTable(expression, isTracking, paths); + var linq = new Orderable(queryTable); + if (orderBy != null) + orderBy(linq); + queryTable = linq.Queryable; + bool isThen = false; + if (orders != null && orders.Any()) + { + foreach (var item in orders) + { + queryTable = queryTable.SetQueryableOrder(item.Key, item.Value.GetDescription(), isThen); + isThen = true; + } + } + if (selectField != null && selectField.Any()) + queryTable = DynamicSelect(selectField, queryTable); + return queryTable.ToList(); + } + + public PagedResultDto GetOrderPageEntities(Expression> expression, Dictionary orders, string[] selectField, + int pageSize, int startIndex, + params string[] paths) where T : class + { + return this.GetOrderPageEntities(expression, orders, selectField, pageSize, startIndex, true, paths); + } + public PagedResultDto GetOrderPageEntities(Expression> expression, Dictionary orders, string[] selectField, + int pageSize, int startIndex, bool isTracking = true, + params string[] paths) where T : class + { + return this.GetOrderPageEntities(expression, orders, selectField, pageSize, startIndex, null, isTracking, paths); + } + + public PagedResultDto GetOrderPageEntities(Expression> expression, Dictionary orders, + int pageSize, int startIndex, Action> orderBy, bool isTracking = true, + params string[] paths) where T : class + { + if (pageSize == 0) throw new Exception("请设置PageSize"); + var queryTable = this.DoGetQuerTable(expression, isTracking, paths); + var linq = new Orderable(queryTable); + if (orderBy != null) + orderBy(linq); + queryTable = linq.Queryable; + bool isThen = false; + if (orders != null && orders.Any()) + { + foreach (var item in orders) + { + queryTable = queryTable.SetQueryableOrder(item.Key, item.Value.GetDescription(), isThen); + isThen = true; + } + } + + var result = new PagedResultDto(); + result.TotalCount = queryTable.Count(); + + result.Items = queryTable.Skip(startIndex) + .Take(pageSize) + .ToArray(); + + return result; + } + + public PagedResultDto GetOrderPageEntities(Expression> expression, Dictionary orders, string[] selectField, + int pageSize, int startIndex, Action> orderBy, bool isTracking = true, + params string[] paths) where T : class + { + if (pageSize == 0) throw new Exception("请设置PageSize"); + var queryTable = this.DoGetQuerTable(expression, isTracking, paths); + var linq = new Orderable(queryTable); + if (orderBy != null) + orderBy(linq); + queryTable = linq.Queryable; + bool isThen = false; + if (orders != null && orders.Any()) + { + foreach (var item in orders) + { + queryTable = queryTable.SetQueryableOrder(item.Key, item.Value.GetDescription(), isThen); + isThen = true; + } + } + if (selectField != null && selectField.Any()) + queryTable = DynamicSelect(selectField, queryTable); + + + var result = new PagedResultDto(); + result.TotalCount = queryTable.Count(); + + result.Items = queryTable.Skip(startIndex) + .Take(pageSize) + .ToArray(); + + return result; + } + // + public async Task> GetOrderPageEntitiesSync(Expression> expression, Dictionary orders, + int pageSize, int startIndex, + params string[] paths) where T : class + { + return await this.GetOrderPageEntitiesSync(expression, orders, pageSize, startIndex, true, paths); + } + public async Task> GetOrderPageEntitiesSync(Expression> expression, Dictionary orders, + int pageSize, int startIndex, bool isTracking = true, + params string[] paths) where T : class + { + return await this.GetOrderPageEntitiesSync(expression, orders, pageSize, startIndex, null, isTracking, paths); + } + + public async Task> GetOrderPageEntitiesSync(Expression> expression, Dictionary orders, + int pageSize, int startIndex, Action> orderBy, bool isTracking = true, + params string[] paths) where T : class + { + if (pageSize == 0) throw new Exception("请设置PageSize"); + var queryTable = this.DoGetQuerTable(expression, isTracking, paths); + var linq = new Orderable(queryTable); + if (orderBy != null) + orderBy(linq); + queryTable = linq.Queryable; + bool isThen = false; + if (orders != null && orders.Any()) + { + foreach (var item in orders) + { + queryTable = queryTable.SetQueryableOrder(item.Key, item.Value.GetDescription(), isThen); + isThen = true; + } + } + + var result = new PagedResultDto(); + result.TotalCount = await queryTable.CountAsync(); + + result.Items = await queryTable.Skip(startIndex) + .Take(pageSize) + .ToArrayAsync(); + + return result; + } + public PagedResultDto GetPageEntities(Expression> expression, Dictionary orders, string[] selectField, + int pageSize, int startIndex, Action> orderBy, bool isTracking = true, + params string[] paths) where T : class + { + if (pageSize == 0) throw new Exception("请设置PageSize"); + var queryTable = this.DoGetQuerTable(expression, isTracking, paths); + var linq = new Orderable(queryTable); + if (orderBy != null) + orderBy(linq); + queryTable = linq.Queryable; + + var result = new PagedResultDto(); + result.TotalCount = queryTable.Count(); + result.Items = queryTable.Skip(startIndex) + .Take(pageSize) + .ToArray(); + + + + + return result; + } + + private IQueryable DynamicSelect(string[] selectField, IQueryable queryTable) + { + if (!selectField.Contains("ORG_ID")) + selectField = selectField.Append("ORG_ID").ToArray(); + var selectSql = "New("; + if (selectField != null && selectField.Any()) + { + var type = typeof(T); + foreach (var s in selectField) + { + if (s.Contains(".") || type.GetProperty(s) == null) + continue; + selectSql += s + ","; + } + selectSql = selectSql.Trim(','); + selectSql += ")"; + queryTable = queryTable.Select(selectSql); + } + return queryTable; + } + private IQueryable DoGetQuerTable(Expression> expression, bool isTracking = true, params string[] paths) where T : class + { + var queryTable = this.Set().AsQueryable(); + if (expression != null) + queryTable = queryTable.Where(expression); + if (paths != null && paths.Any()) + { + foreach (var item in paths) + queryTable = queryTable.Include(item); + } + + if (!isTracking) + queryTable = queryTable.AsNoTracking(); + return queryTable; + } + + + #endregion + + #region redis + + + + + + private string GetRedisPropertyValue(T entity, string name) + { + try + { + var properties = entity.GetType().GetProperties(); + + var property = properties.FirstOrDefault(o => o.Name == name); + if (property != null) + { + return property.GetValue(entity, null).ToString(); + } + + return string.Empty; + } + catch (Exception ex) + { + return string.Empty; + } + } + #endregion + + #region methods + + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + foreach (var entityType in modelBuilder.Model.GetEntityTypes()) + { + entityType.SetTableName(entityType.DisplayName()); + entityType.GetForeignKeys() + .Where(fk => fk.DeleteBehavior == DeleteBehavior.Cascade) + .ToList() + .ForEach(fk => fk.DeleteBehavior = DeleteBehavior.Restrict); + } + + + foreach (var property in modelBuilder.Model.GetEntityTypes() + .SelectMany(t => t.GetProperties()) + .Where(p => p.ClrType == typeof(decimal))) + { + property.SetColumnType("decimal(18, 6)"); + } + + + var files = Directory.GetFiles(System.AppContext.BaseDirectory, "*.Data.dll").ToList(); + var BaseFiles = Directory.GetFiles(System.AppContext.BaseDirectory, "*APT.Infrastructure.EF.dll").ToList(); + files.AddRange(BaseFiles); + if (files.Count > 0) + { + foreach (var file in files) + { + var assembly = Assembly.LoadFrom(file); + if (assembly != null) + { + modelBuilder.ApplyConfigurationsFromAssembly(assembly); + } + } + } + + base.OnModelCreating(modelBuilder); + this.GetEfModelByModel(modelBuilder.Model); + } + + private void GetEfModelByModel(IModel model) + { + _efModel = new EFModel(); + foreach (var entity in model.GetEntityTypes()) + { + EFModelTable efTable = new EFModelTable(); + efTable.Name = entity.ClrType.Name; + + var properties = entity.GetProperties().ToList(); + foreach (var property in properties) + { + EFModelField field = new EFModelField(); + field.FieldType = property.ClrType.GetUnNullableType(); + field.IsNull = property.IsNullable; + field.Name = property.Name; + field.TypeName = field.FieldType.Name; + field.PropertyInfo = property.PropertyInfo; + efTable.Fields.Add(field); + } + + var foreignKeys = entity.GetForeignKeys().ToList(); + foreach (var fKey in foreignKeys) + { + EFModelForeignKey foreignKey = CreateEFModelForeignKey(fKey); + if (foreignKey == null) continue; + efTable.ForeignKeys.Add(foreignKey); + } + + var navigations = entity.GetNavigations().ToList(); + foreach (var nav in navigations) + { + if (nav.ForeignKey == null) continue; + EFModelForeignKey foreignKey = CreateEFModelForeignKey(nav.ForeignKey); + if (foreignKey == null) continue; + efTable.AllForeignKeys.Add(foreignKey); + } + _efModel.Tables.Add(efTable); + } + } + + + private EFModelForeignKey CreateEFModelForeignKey(IForeignKey fKey) + { + if (!fKey.Properties.Any() || + fKey.DependentToPrincipal == null && fKey.PrincipalToDependent == null) + return null; + EFModelForeignKey foreignKey = new EFModelForeignKey(); + foreignKey.ForeignFieldName = fKey.Properties[0].Name; + foreignKey.IsNull = fKey.Properties[0].IsNullable; + if (fKey.DependentToPrincipal != null) + { + foreignKey.ForeignNavName = fKey.DependentToPrincipal.Name; + foreignKey.ForeignTableName = fKey.DependentToPrincipal.PropertyInfo.PropertyType.Name; + } + if (fKey.PrincipalToDependent != null) + foreignKey.MasterNavName = fKey.PrincipalToDependent.Name; + foreignKey.ForeignKey = fKey; + return foreignKey; + } + + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) + { + + var isSqlLog = LibUtils.ToBoolean(ConfigurationManager.AppSettings["isSqlLog"]); + + var logFactory = ServiceLocator.Instance.GetService(); + var logProvider = ServiceLocator.Instance.GetService(); + if (isSqlLog && logFactory != null && logProvider != null) + { + //logFactory.AddProvider(logProvider); + optionsBuilder.EnableSensitiveDataLogging().UseLoggerFactory(logFactory); + } + //optionsBuilder.AddInterceptors(new QueryWithNoLockDbCommandInterceptor()); + + if (!string.IsNullOrWhiteSpace(namedConnection)) + { + var dbType = this.DBType(); + if (dbType == DataBaseType.Oracle) + { + //optionsBuilder + // .UseLazyLoadingProxies(false) + // .UseOracle(this.ConnectionString); + } + else if (dbType == DataBaseType.MySQL) + { + //optionsBuilder + // .UseLazyLoadingProxies(false) + // .UseMySQL(this.ConnectionString); + } + else if (dbType == DataBaseType.Postgresql) + { + //optionsBuilder + // .UseLazyLoadingProxies(false) + // .UseNpgsql(this.ConnectionString); + } + else if (dbType == DataBaseType.SQL) + { + optionsBuilder + .UseLazyLoadingProxies(false) + .UseSqlServer(this.ConnectionString); + } + } + } + + + /// + /// 根据表名获取表数据结构 + /// + /// + /// + public EFModelTable GetModelTable(string tableName) + { + //if (_efModel == null) + // this.GetEntity(t => t.CODE == "0000", null); + if (_efModel == null && this.Model != null) + this.GetEfModelByModel(this.Model); + if (_efModel == null || _efModel.Tables == null || string.IsNullOrEmpty(tableName)) return null; + return _efModel.Tables.FirstOrDefault(t => string.Compare(t.Name, tableName, true) == 0); + } + public List GetModelForeignKey(string tableName) + { + var table = this.GetModelTable(tableName); + if (table == null) return null; + var fkey = table.ForeignKeys; + return fkey; + } + /// + /// 根据表名、字段名称获取字段结构 + /// + /// + /// + /// + public EFModelField GetModelField(string tableName, string fieldName) + { + var table = this.GetModelTable(tableName); + if (table == null) return null; + return table.Fields.FirstOrDefault(t => string.Compare(t.Name, fieldName, true) == 0); + } + + /// + /// 根据表名,导航名称获取外键信息 + /// + /// + /// + /// + public EFModelForeignKey GetModelForeignKey(string tableName, string navName) + { + var table = this.GetModelTable(tableName); + if (table == null) return null; + var fkey = table.ForeignKeys.FirstOrDefault(t => string.Compare(t.ForeignNavName, navName, true) == 0); + if (fkey == null) + { + fkey = table.AllForeignKeys.FirstOrDefault(t => string.Compare(t.MasterNavName, navName, true) == 0); + } + return fkey; + } + + /// + /// 根据表名,ID字段名称获取外键信息 + /// + /// + /// + /// + public EFModelForeignKey GetModelForeignKeyById(string tableName, string idFieldName) + { + + var table = this.GetModelTable(tableName); + if (table == null) return null; + return table.ForeignKeys.FirstOrDefault(t => string.Compare(t.ForeignFieldName, idFieldName, true) == 0); + } + + #endregion + + private List RawSqlQuery(string query, Func map) + { + using (var command = this.Database.GetDbConnection().CreateCommand()) + { + command.CommandText = query; + command.CommandType = CommandType.Text; + + this.Database.OpenConnection(); + + using (var result = command.ExecuteReader()) + { + var entities = new List(); + + while (result.Read()) + { + entities.Add(map(result)); + } + + return entities; + } + } + } + } +} diff --git a/APT.Infrastructure.EF/Extension/TenantApplicationBuilderExtension.cs b/APT.Infrastructure.EF/Extension/TenantApplicationBuilderExtension.cs new file mode 100644 index 0000000..c46d6c8 --- /dev/null +++ b/APT.Infrastructure.EF/Extension/TenantApplicationBuilderExtension.cs @@ -0,0 +1,26 @@ +using Microsoft.AspNetCore.Builder; + +namespace APT.Infrastructure.EF +{ + public static class TenantApplicationBuilderExtension + { + public static IApplicationBuilder UseTenantDb(this IApplicationBuilder app) + { + // var settings = serviceProvider.GetService>(); + // setupAction?.Invoke(settings); + // if (settings.ConnectionType == ConnectionResolverType.ByTable) + // { + // settings.TableNameFunc = settings.TableNameFunc ?? ((tenantInfo, tableName) => $"{tenantInfo.Name}_{tableName}"); + + // } + // if (settings.ConnectionType == ConnectionResolverType.BySchema) + // { + // settings.TableNameFunc = settings.TableNameFunc ?? ((tenantInfo, tableName) => $"{tableName}"); + // settings.SchemaFunc = settings.SchemaFunc ?? ((tenantInfo) => tenantInfo.Name); + // } + // return settings; + + return app; + } + } +} diff --git a/APT.Infrastructure.EF/Extension/TenantCoreExtension.cs b/APT.Infrastructure.EF/Extension/TenantCoreExtension.cs new file mode 100644 index 0000000..2738ee6 --- /dev/null +++ b/APT.Infrastructure.EF/Extension/TenantCoreExtension.cs @@ -0,0 +1,184 @@ +using System; +using System.Collections.Generic; +using APT.Infrastructure.Api; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; + +namespace APT.Infrastructure.EF +{ + public static class TenantCoreExtension + { + public static IServiceCollection AddDbPerConnection(this IServiceCollection services, + DbIntegrationType dbType, string key = "default", + string connectionPrefix = "tenanted", + Action optionAction = null, + Action dbContextSetup = null) + where TDbContext : DbContext, ITenantDbContext + { + var settings = new TenantSettings() + { + Key = key, + DbType = dbType, + ConnectionPrefix = connectionPrefix, + ConnectionType = ConnectionResolverType.ByDatabase, + DbContextOptionAction = optionAction, + DbContextSetup = dbContextSetup + }; + + return services.AddTenantedDatabase(settings); + } + + public static IServiceCollection AddDbPerConnection(this IServiceCollection services, + Action> setupAction = null) + where TDbContext : DbContext, ITenantDbContext + { + var settings = new TenantSettings() + { + ConnectionType = ConnectionResolverType.ByDatabase + }; + return services.AddTenantedDatabase(settings, setupAction); + } + + public static IServiceCollection AddDbPerTable(this IServiceCollection services, + DbIntegrationType dbType, string key = "default", + string connectionName = "tenantConnection", + Action optionAction = null, + Action dbContextSetup = null) + where TDbContext : DbContext, ITenantDbContext + { + var settings = new TenantSettings() + { + Key = key, + DbType = dbType, + ConnectionName = connectionName, + ConnectionType = ConnectionResolverType.ByTable, + DbContextOptionAction = optionAction, + DbContextSetup = dbContextSetup + }; + + return services.AddTenantedDatabase(settings); + } + + public static IServiceCollection AddDbPerTable(this IServiceCollection services, + Action> setupAction = null) + where TDbContext : DbContext, ITenantDbContext + { + var settings = new TenantSettings() + { + ConnectionType = ConnectionResolverType.ByTable + }; + return services.AddTenantedDatabase(settings, setupAction); + } + + public static IServiceCollection AddDbPerSchema(this IServiceCollection services, + DbIntegrationType dbType, string key = "default", + string connectionName = "tenantConnection", + Action optionAction = null, + Action dbContextSetup = null) + where TDbContext : DbContext, ITenantDbContext + { + var settings = new TenantSettings() + { + Key = key, + DbType = dbType, + ConnectionName = connectionName, + ConnectionType = ConnectionResolverType.BySchema, + DbContextOptionAction = optionAction, + DbContextSetup = dbContextSetup + }; + + return services.AddTenantedDatabase(settings); + } + + public static IServiceCollection AddDbPerSchema(this IServiceCollection services, + Action> setupAction = null) + where TDbContext : DbContext, ITenantDbContext + { + var settings = new TenantSettings() + { + ConnectionType = ConnectionResolverType.BySchema + }; + return services.AddTenantedDatabase(settings, setupAction); + } + + public static IServiceCollection AddTenantedDatabase(this IServiceCollection services, + TenantSettings settings, Action> setupAction = null) + where TDbContext : DbContext, ITenantDbContext + { + services.AddScoped(); + services.AddScoped(); + services.TryAddScoped(); + services.TryAddScoped, TenantConnectionResolver>(); + services.TryAddScoped, TenantEntityBuilder>(); + services.TryAddScoped, SimpleEntityScaner>(); + services.AddScoped(); + services.InitSettings(settings, setupAction); + + services.AddTenantDbContext(); + + + return services; + } + + internal static IServiceCollection AddTenantDbContext(this IServiceCollection services) + where TDbContext : DbContext, ITenantDbContext + { + services.AddDbContext((serviceProvider, options) => + { + var settings = serviceProvider.GetService>(); + var connectionResolver = serviceProvider.GetService>(); + var tenant = serviceProvider.GetService(); + settings.DbContextSetup?.Invoke(serviceProvider, connectionResolver.GetConnection(), options); + options.ReplaceServiceTenanted(settings); + settings.DbContextOptionAction?.Invoke(options); + + }); + return services; + } + + internal static IServiceCollection InitSettings(this IServiceCollection services, + TenantSettings settings, Action> setupAction) + where TDbContext : DbContext, ITenantDbContext + { + services.AddSingleton((sp) => + { + var rct = settings ?? new TenantSettings(); + setupAction?.Invoke(rct); + return rct; + }); + return services; + } + + public static void ReplaceServiceTenanted(this DbContextOptionsBuilder dbOptions, + TenantSettings settings) + where TDbContext : DbContext, ITenantDbContext + { + if (Constants.specialConnectionTypes.Contains(settings.ConnectionType)) + { + dbOptions.ReplaceService>(); + dbOptions.ReplaceService(); + } + } + + + public static void TenantBuilderSetup(this RelationalDbContextOptionsBuilder builder, + IServiceProvider serviceProvider, TenantSettings settings, TenantInfo tenant) + where TDbContext : DbContext, ITenantDbContext + where TBuilder : RelationalDbContextOptionsBuilder + where TExtension : RelationalOptionsExtension, new() + { + if (settings.ConnectionType == ConnectionResolverType.ByTable) + { + builder.MigrationsHistoryTable($"{tenant.Name}__EFMigrationsHistory"); + } + if (settings.ConnectionType == ConnectionResolverType.BySchema) + { + builder.MigrationsHistoryTable("__EFMigrationHistory", $"{(settings.SchemaFunc?.Invoke(tenant) ?? (tenant?.Name ?? "dbo"))}"); + } + } + } + + +} diff --git a/APT.Infrastructure.EF/Extensions/DataBaseTypeExtension.cs b/APT.Infrastructure.EF/Extensions/DataBaseTypeExtension.cs new file mode 100644 index 0000000..e661217 --- /dev/null +++ b/APT.Infrastructure.EF/Extensions/DataBaseTypeExtension.cs @@ -0,0 +1,31 @@ +using APT.Infrastructure.Api; +using APT.Infrastructure.Core; +namespace APT.Infrastructure.EF +{ + public static class DataBaseTypeExtension + { + public static DataBaseType DBType(this EfDbContext dbcontext) + { + DataBaseType type = DataBaseType.Oracle; + var databaseName = ConfigurationManager.AppSettings["DataBaseType"].Trim().ToLower(); + switch (databaseName) + { + case "mysql": + type = DataBaseType.MySQL; + break; + case "sqlserver": + type = DataBaseType.SQL; + break; + case "postgresql": + type = DataBaseType.Postgresql; + break; + default: + type = DataBaseType.Oracle; + break; + + } + + return type; + } + } +} diff --git a/APT.Infrastructure.EF/Extensions/IQueryableSelectorExtension.cs b/APT.Infrastructure.EF/Extensions/IQueryableSelectorExtension.cs new file mode 100644 index 0000000..7fabd74 --- /dev/null +++ b/APT.Infrastructure.EF/Extensions/IQueryableSelectorExtension.cs @@ -0,0 +1,62 @@ +using System; +using System.Collections.Generic; +using System.Linq.Expressions; +using System.Reflection; +using System.Text; + +namespace APT.Infrastructure.EF.Extensions +{ + public class IQueryableSelectorExtension + { + public static Expression> CreateSelecter(List columns) + { + Expression> selector = null; + +            //(rec) +            ParameterExpression param = Expression.Parameter(typeof(TSource), "rec"); +            //new ParadigmSearchListData +            var v0 = Expression.New(typeof(TResult)); + + var memberBindings = new List(); + foreach (var column in columns) + { + var left = typeof(TResult).GetProperty(column); + + var right = Expression.Property(param, typeof(TSource).GetProperty(column)); + + memberBindings.Add(Expression.Bind(left, right)); + } + + Expression body = Expression.MemberInit(v0, + //{ Number = rec.NUMBER, Name = rec.RES_NAME } + memberBindings.ToArray()); + + selector = (Expression>)Expression.Lambda(body, param); + + return selector; + } + + private static MemberAssignment GetPropertyLambdaExpression(ParameterExpression param, string field) + { + string[] propertyNames = field.Split('.'); + Expression propertyAccess = param; + Type type = param.Type; + PropertyInfo property; + foreach (string propertyName in propertyNames) + { + property = type.GetProperty(propertyName); + if (property != null) + { + type = property.PropertyType; + propertyAccess = Expression.MakeMemberAccess(propertyAccess, property); + } + } + + //var left = typeof(TResult).GetProperty(column); + //return Expression.Bind(property, Expression.Lambda(propertyAccess, param)); + //return Expression.Lambda(propertyAccess, param); + + return null; + } + } +} diff --git a/APT.Infrastructure.EF/Extensions/MySqlTenantExtension.cs b/APT.Infrastructure.EF/Extensions/MySqlTenantExtension.cs new file mode 100644 index 0000000..9c82738 --- /dev/null +++ b/APT.Infrastructure.EF/Extensions/MySqlTenantExtension.cs @@ -0,0 +1,71 @@ +using System; +using APT.Infrastructure.Api; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.DependencyInjection; + +namespace APT.Infrastructure.EF.Extensions +{ + public static class MySqlTenantExtension + { + public static IServiceCollection AddMySqlPerConnection(this IServiceCollection services, + string key = "default", + string connectionPrefix = "tenanted", + Action optionAction = null, + Action dbContextSetup = null) + where TDbContext : DbContext, ITenantDbContext + { + return services.AddDbPerConnection(DbIntegrationType.Mysql, key, connectionPrefix, + optionAction, dbContextSetup ?? SetUpMySql); + } + + public static IServiceCollection AddMySqlPerConnection(this IServiceCollection services, + Action> setupAction = null) + where TDbContext : DbContext, ITenantDbContext + { + return services.AddDbPerConnection(CombineSettings(setupAction)); + } + + public static IServiceCollection AddMySqlPerTable(this IServiceCollection services, + string key = "default", + string connectionName = "tenanted", + Action optionAction = null, + Action dbContextSetup = null) + where TDbContext : DbContext, ITenantDbContext + { + return services.AddDbPerTable(DbIntegrationType.Mysql, key, connectionName, + optionAction, dbContextSetup ?? SetUpMySql); + } + + public static IServiceCollection AddMySqlPerTable(this IServiceCollection services, + Action> setupAction = null) + where TDbContext : DbContext, ITenantDbContext + { + return services.AddDbPerTable(CombineSettings(setupAction)); + } + + static Action> CombineSettings( + Action> setupAction = null) + where TDbContext : DbContext, ITenantDbContext + { + return (settings) => + { + settings.DbContextSetup = SetUpMySql; + setupAction?.Invoke(settings); + }; + } + + internal static void SetUpMySql(IServiceProvider serviceProvider, string connectionString, + DbContextOptionsBuilder optionsBuilder) + where TDbContext : DbContext, ITenantDbContext + { + var settings = serviceProvider.GetService>(); + var tenant = serviceProvider.GetService(); + optionsBuilder.UseMySql(connectionString, builder => + { + builder.TenantBuilderSetup(serviceProvider, settings, tenant); + }); + } + + } + +} diff --git a/APT.Infrastructure.EF/Extensions/PostgreTenantExtension.cs b/APT.Infrastructure.EF/Extensions/PostgreTenantExtension.cs new file mode 100644 index 0000000..bb48282 --- /dev/null +++ b/APT.Infrastructure.EF/Extensions/PostgreTenantExtension.cs @@ -0,0 +1,93 @@ +using System; +using APT.Infrastructure.Api; +using APT.Infrastructure.Core; +using Castle.Core.Logging; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; + +namespace APT.Infrastructure.EF.Extensions +{ + public static class PostgreTenantExtension + { + public static IServiceCollection AddPostgrePerConnection(this IServiceCollection services, + string key = "default", + string connectionPrefix = "tenanted", + Action optionAction = null, + Action dbContextSetup = null) + where TDbContext : DbContext, ITenantDbContext + { + return services.AddDbPerConnection(DbIntegrationType.Postgre, key, connectionPrefix, + optionAction, dbContextSetup ?? SetUpPostgre); + } + + public static IServiceCollection AddPostgrePerConnection(this IServiceCollection services, + Action> setupAction = null) + where TDbContext : DbContext, ITenantDbContext + { + return services.AddDbPerConnection(CombineSettings(setupAction)); + } + + public static IServiceCollection AddPostgrePerTable(this IServiceCollection services, + string key = "default", + string connectionName = "tenanted", + Action optionAction = null, + Action dbContextSetup = null) + where TDbContext : DbContext, ITenantDbContext + { + return services.AddDbPerTable(DbIntegrationType.Postgre, key, connectionName, + optionAction, dbContextSetup ?? SetUpPostgre); + } + + public static IServiceCollection AddPostgrePerTable(this IServiceCollection services, + Action> setupAction = null) + where TDbContext : DbContext, ITenantDbContext + { + return services.AddDbPerTable(CombineSettings(setupAction)); + } + + public static IServiceCollection AddPostgrePerSchema(this IServiceCollection services, + string key = "default", + string connectionName = "tenanted", + Action optionAction = null, + Action dbContextSetup = null) + where TDbContext : DbContext, ITenantDbContext + { + return services.AddDbPerSchema(DbIntegrationType.Postgre, key, connectionName, + optionAction, dbContextSetup ?? SetUpPostgre); + } + + public static IServiceCollection AddPostgrePerSchema(this IServiceCollection services, + Action> setupAction = null) + where TDbContext : DbContext, ITenantDbContext + { + return services.AddDbPerSchema(CombineSettings(setupAction)); + } + + + static Action> CombineSettings( + Action> setupAction = null) + where TDbContext : DbContext, ITenantDbContext + { + return (settings) => + { + settings.DbContextSetup = SetUpPostgre; + setupAction?.Invoke(settings); + }; + } + + internal static void SetUpPostgre(IServiceProvider serviceProvider, string connectionString, + DbContextOptionsBuilder optionsBuilder) + where TDbContext : DbContext, ITenantDbContext + { + //if(string.IsNullOrEmpty(connectionString)) + // connectionString= + var settings = serviceProvider.GetService>(); + var tenant = serviceProvider.GetService(); + optionsBuilder.UseNpgsql(connectionString, builder => + { + builder.TenantBuilderSetup(serviceProvider, settings, tenant); + }); + } + } +} diff --git a/APT.Infrastructure.EF/Extensions/SqlServerTenantExtension.cs b/APT.Infrastructure.EF/Extensions/SqlServerTenantExtension.cs new file mode 100644 index 0000000..ed878ae --- /dev/null +++ b/APT.Infrastructure.EF/Extensions/SqlServerTenantExtension.cs @@ -0,0 +1,88 @@ +using System; +using APT.Infrastructure.Api; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.DependencyInjection; + +namespace APT.Infrastructure.EF.Extensions +{ + public static class SqlServerTenantExtension + { + public static IServiceCollection AddSqlServerPerConnection(this IServiceCollection services, + string key = "default", + string connectionPrefix = "tenanted", + Action optionAction = null, + Action dbContextSetup = null) + where TDbContext : DbContext, ITenantDbContext + { + return services.AddDbPerConnection(DbIntegrationType.SqlServer, key, connectionPrefix, + optionAction, dbContextSetup ?? SetUpSqlServer); + } + + public static IServiceCollection AddSqlServerPerConnection(this IServiceCollection services, + Action> setupAction = null) + where TDbContext : DbContext, ITenantDbContext + { + return services.AddDbPerConnection(CombineSettings(setupAction)); + } + + public static IServiceCollection AddSqlServerPerTable(this IServiceCollection services, + string key = "default", + string connectionName = "tenanted", + Action optionAction = null, + Action dbContextSetup = null) + where TDbContext : DbContext, ITenantDbContext + { + return services.AddDbPerTable(DbIntegrationType.SqlServer, key, connectionName, + optionAction, dbContextSetup ?? SetUpSqlServer); + } + + public static IServiceCollection AddSqlServerPerTable(this IServiceCollection services, + Action> setupAction = null) + where TDbContext : DbContext, ITenantDbContext + { + return services.AddDbPerTable(CombineSettings(setupAction)); + } + + public static IServiceCollection AddSqlServerPerSchema(this IServiceCollection services, + string key = "default", + string connectionName = "tenanted", + Action optionAction = null, + Action dbContextSetup = null) + where TDbContext : DbContext, ITenantDbContext + { + return services.AddDbPerSchema(DbIntegrationType.SqlServer, key, connectionName, + optionAction, dbContextSetup ?? SetUpSqlServer); + } + + public static IServiceCollection AddSqlServerPerSchema(this IServiceCollection services, + Action> setupAction = null) + where TDbContext : DbContext, ITenantDbContext + { + return services.AddDbPerSchema(CombineSettings(setupAction)); + } + + static Action> CombineSettings( + Action> setupAction = null) + where TDbContext : DbContext, ITenantDbContext + { + return (settings) => + { + settings.DbContextSetup = SetUpSqlServer; + setupAction?.Invoke(settings); + }; + } + + internal static void SetUpSqlServer(IServiceProvider serviceProvider, string connectionString, + DbContextOptionsBuilder optionsBuilder) + where TDbContext : DbContext, ITenantDbContext + { + var settings = serviceProvider.GetService>(); + var tenant = serviceProvider.GetService(); + optionsBuilder.UseSqlServer(connectionString, builder => + { + builder.TenantBuilderSetup(serviceProvider, settings, tenant); + }); + } + + } +} diff --git a/APT.Infrastructure.EF/Helper/AcronymHelper.cs b/APT.Infrastructure.EF/Helper/AcronymHelper.cs new file mode 100644 index 0000000..8253a07 --- /dev/null +++ b/APT.Infrastructure.EF/Helper/AcronymHelper.cs @@ -0,0 +1,114 @@ +using APT.Infrastructure.Core; +using System; +using System.Text; + +namespace APT.Infrastructure.EF +{ + public static class AcronymHelper + { + // private static Encoding gb2312 = Encoding.GetEncoding("GB2312"); + + /// + /// 汉字转全拼 + /// + /// + /// + public static string ConvertToAllSpell(string strChinese) + { + try + { + if (strChinese.Length != 0) + { + StringBuilder fullSpell = new StringBuilder(); + for (int i = 0; i < strChinese.Length; i++) + { + var chr = strChinese[i]; + fullSpell.Append(GetSpell(chr)); + } + return fullSpell.ToString(); + } + } + catch (Exception e) + { + LoggerManager.GetLogger().Info("全拼转化出错!" + e.Message); + } + return string.Empty; + } + + /// + /// 汉字转首字母 + /// + /// + /// + public static string ConvertToFirstSpell(string strChinese) + { + try + { + if (strChinese.Length != 0) + { + StringBuilder fullSpell = new StringBuilder(); + for (int i = 0; i < strChinese.Length; i++) + { + var chr = strChinese[i]; + fullSpell.Append(GetSpell(chr)[0]); + } + return fullSpell.ToString(); + } + } + catch (Exception e) + { + LoggerManager.GetLogger().Info("首字母转化出错!" + e.Message); + } + return string.Empty; + } + + private static string GetSpell(char chr) + { + //var coverchr = NPinyin.Pinyin.GetPinyin(chr); + //bool isChineses = ChineseChar.IsValidChar(coverchr[0]); + //if (isChineses) + //{ + // ChineseChar chineseChar = new ChineseChar(coverchr[0]); + // foreach (string value in chineseChar.Pinyins) + // { + // if (!string.IsNullOrEmpty(value)) + // { + // return value.Remove(value.Length - 1, 1); + // } + // } + //} + //return coverchr; + return ""; + } + + /// + /// 数字转换成字母(1-26) + /// + /// + /// + public static string NumToChar(int number) + { + number = number + 64; + if (65 <= number && 90 >= number) + { + System.Text.ASCIIEncoding asciiEncoding = new System.Text.ASCIIEncoding(); + byte[] btNumber = new byte[] { (byte)number }; + return asciiEncoding.GetString(btNumber).ToLower(); + } + return "数字不在转换范围内"; + } + + /// + /// 字母转换成数字(1-26) + /// + /// + /// + public static string CharToNum(char chr) + { + byte[] array = new byte[1]; + array = System.Text.Encoding.ASCII.GetBytes(chr.ToString().ToUpper()); + int asciicode = (short)(array[0]) - 64; + return Convert.ToString(asciicode); + } + } +} diff --git a/APT.Infrastructure.EF/Impl/MigrationByTenantAssembly.cs b/APT.Infrastructure.EF/Impl/MigrationByTenantAssembly.cs new file mode 100644 index 0000000..3d5cb9c --- /dev/null +++ b/APT.Infrastructure.EF/Impl/MigrationByTenantAssembly.cs @@ -0,0 +1,42 @@ +using System; +using System.Reflection; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Diagnostics; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Migrations.Internal; + +namespace APT.Infrastructure.EF +{ + public class MigrationByTenantAssembly : MigrationsAssembly + { + private readonly Microsoft.EntityFrameworkCore.DbContext context; + + public MigrationByTenantAssembly(ICurrentDbContext currentContext, + IDbContextOptions options, IMigrationsIdGenerator idGenerator, + IDiagnosticsLogger logger) + : base(currentContext, options, idGenerator, logger) + { + context = currentContext.Context; + } + + public override Migration CreateMigration(TypeInfo migrationClass, + string activeProvider) + { + if (activeProvider == null) + throw new ArgumentNullException($"{nameof(activeProvider)} argument is null"); + + var hasCtorWithSchema = migrationClass + .GetConstructor(new[] { typeof(string) }) != null; + + if (hasCtorWithSchema && context is ITenantDbContext tenantDbContext) + { + var instance = (Migration)Activator.CreateInstance(migrationClass.AsType(), tenantDbContext?.Tenant?.Name); + instance.ActiveProvider = activeProvider; + return instance; + } + + return base.CreateMigration(migrationClass, activeProvider); + } + } +} diff --git a/APT.Infrastructure.EF/Impl/NamedConnectionGenerator.cs b/APT.Infrastructure.EF/Impl/NamedConnectionGenerator.cs new file mode 100644 index 0000000..fd44e6e --- /dev/null +++ b/APT.Infrastructure.EF/Impl/NamedConnectionGenerator.cs @@ -0,0 +1,39 @@ +using System; +using APT.Infrastructure.Api; +using Microsoft.Extensions.Configuration; + +namespace APT.Infrastructure.EF +{ + public class NamedConnectionGenerator : IConnectionGenerator + { + private readonly IConfiguration configuration; + public string TenantKey => "unknow"; + + public NamedConnectionGenerator(IConfiguration configuration) + { + this.configuration = configuration; + } + + public string GetConnection(TenantOption option, TenantInfo tenantInfo) + { + string connectionString = null; + switch (option.ConnectionType) + { + case ConnectionResolverType.ByDatabase: + connectionString = configuration.GetConnectionString($"{option.ConnectionPrefix}{tenantInfo.Name}"); + break; + case ConnectionResolverType.ByTable: + case ConnectionResolverType.BySchema: + connectionString = configuration.GetConnectionString(option.ConnectionName); + break; + } + + return connectionString; + } + + public bool MatchTenantKey(string tenantKey) + { + return false; + } + } +} diff --git a/APT.Infrastructure.EF/Impl/SimpleHeaderTenantInfoGenerator.cs b/APT.Infrastructure.EF/Impl/SimpleHeaderTenantInfoGenerator.cs new file mode 100644 index 0000000..f4793fa --- /dev/null +++ b/APT.Infrastructure.EF/Impl/SimpleHeaderTenantInfoGenerator.cs @@ -0,0 +1,30 @@ +using Microsoft.AspNetCore.Http; +using APT.Infrastructure.Api; +namespace APT.Infrastructure.EF +{ + public class SimpleHeaderTenantInfoGenerator : ITenantInfoGenerator + { + private readonly TenantInfo tenantInfo; + public SimpleHeaderTenantInfoGenerator(TenantInfo tenantInfo) + { + this.tenantInfo = tenantInfo; + } + + public TenantInfo GenerateTenant(object sender, Microsoft.AspNetCore.Http.HttpContext httpContext) + { + if (!this.tenantInfo.IsPresent) + { + var tenantName = httpContext?.Request?.Headers["TenantName"]; + + if (!string.IsNullOrEmpty(tenantName)) + { + this.tenantInfo.IsPresent = true; + this.tenantInfo.Name = tenantName; + this.tenantInfo.Generator = this; + } + } + + return this.tenantInfo; + } + } +} diff --git a/APT.Infrastructure.EF/Impl/TenantConnectionResolver.cs b/APT.Infrastructure.EF/Impl/TenantConnectionResolver.cs new file mode 100644 index 0000000..7e098a5 --- /dev/null +++ b/APT.Infrastructure.EF/Impl/TenantConnectionResolver.cs @@ -0,0 +1,58 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.DependencyInjection; +using System; +using System.Linq; +using APT.Infrastructure.Api; + +namespace APT.Infrastructure.EF +{ + public class TenantConnectionResolver : ITenantConnectionResolver + where TDbContext : DbContext + { + private readonly TenantSettings setting; + private readonly TenantInfo tenantInfo; + private readonly IServiceProvider serviceProvider; + private readonly TenantOption tenantOption; + + public TenantConnectionResolver(TenantSettings setting, TenantInfo tenantInfo, + TenantOption tenantOption, IServiceProvider serviceProvider) + { + this.tenantOption = tenantOption; + this.setting = setting; + this.tenantInfo = tenantInfo; + this.serviceProvider = serviceProvider; + } + + public string GetConnection() + { + var connectionGenerator = this.GetConnectionGenerator(); + var option = GenerateOption(); + + return connectionGenerator.GetConnection(option, tenantInfo); + + } + + IConnectionGenerator GetConnectionGenerator() + { + IConnectionGenerator connectionGenerator = this.setting.ConnectionGenerator?.Invoke() + ?? serviceProvider.GetServices() + .FirstOrDefault(r => r.TenantKey == this.setting.Key || r.MatchTenantKey(this.setting.Key)) + ?? serviceProvider.GetService(); + + return connectionGenerator; + } + + TenantOption GenerateOption() + { + tenantOption.Key = setting.Key; + tenantOption.ConnectionType = setting.ConnectionType; + tenantOption.DbType = setting.DbType; + tenantOption.TableNameFunc = setting.TableNameFunc; + tenantOption.SchemaFunc = setting.SchemaFunc; + tenantOption.ConnectionPrefix = setting.ConnectionPrefix; + tenantOption.ConnectionName = setting.ConnectionName; + + return this.tenantOption; + } + } +} diff --git a/APT.Infrastructure.EF/Infrastructure/CombindedConnectionGenerator.cs b/APT.Infrastructure.EF/Infrastructure/CombindedConnectionGenerator.cs new file mode 100644 index 0000000..bdeb715 --- /dev/null +++ b/APT.Infrastructure.EF/Infrastructure/CombindedConnectionGenerator.cs @@ -0,0 +1,71 @@ +using System; +using System.Collections.Generic; +using System.Net.Http; +using APT.Infrastructure.EF; +using Microsoft.Extensions.Configuration; +using APT.Infrastructure.Api; +using System.Configuration; + +namespace APT.Infrastructure.EF +{ + public class CombindedConnectionGenerator : IConnectionGenerator + { + static Lazy random = new Lazy(); + private readonly IConfiguration configuration; + public string TenantKey => ""; + public string defaultstr = "User ID=postgres;Password=123456;Host=192.168.2.98;Port=5432;Database=opt_energy;CommandTimeout=1024;"; + public CombindedConnectionGenerator(IConfiguration configuration) + { + this.configuration = configuration; + } + + + public string GetConnection(TenantOption option, TenantInfo tenantInfo) + { + if (tenantInfo == null) + tenantInfo = new TenantInfo(); + if (string.IsNullOrEmpty(tenantInfo?.Conn)) + tenantInfo.Conn = defaultstr; + return tenantInfo.Conn; + //var webapiUrl = "http://localhost:5001/api/DbConfigs"; + //var httpResponseMsg = new HttpResponseMessage(); + + //using (var httpClient = new HttpClient()) + //{ + // httpResponseMsg = httpClient.GetAsync(webapiUrl).Result; + + // var retrnUrl = httpResponseMsg.Content.ReadAsStringAsync().Result; + // dynamic urls = Newtonsoft.Json.JsonConvert.DeserializeObject(retrnUrl); + // if (urls != null) + // { + + // List connList = new List(); + // foreach (dynamic url in urls) + // { + // if (url.name == span) + // { + // connList.Add(url.conn); + // } + // } + // if (connList.Count > 0) + // { + // var mod = (random.Value.Next(100) % connList.Count); + // return connList[mod]; + // } + // } + //} + + //if (span.Length > 4 && int.TryParse(span[5].ToString(), out var number)) + //{ + //var mod = (random.Value.Next(1000) % 3)+1; + // return configuration.GetConnectionString($"{option.ConnectionPrefix}{mod}"); + //} + throw new NotSupportedException("Ϣ"); + }// + + public bool MatchTenantKey(string tenantKey) + { + return true; + } + } +} \ No newline at end of file diff --git a/APT.Infrastructure.EF/Infrastructure/ConnectionResolver.cs b/APT.Infrastructure.EF/Infrastructure/ConnectionResolver.cs new file mode 100644 index 0000000..7bbef78 --- /dev/null +++ b/APT.Infrastructure.EF/Infrastructure/ConnectionResolver.cs @@ -0,0 +1,34 @@ +using System; +using APT.Infrastructure.Api; +using Microsoft.Extensions.Configuration; + +namespace APT.Infrastructure.EF.Infrastructure +{ + public interface IConnectionResolver + { + string GetConnection(); + + } + + public class HttpHeaderSqlConnectionResolver : IConnectionResolver + { + private readonly TenantInfo tenantInfo; + private readonly IConfiguration configuration; + + public HttpHeaderSqlConnectionResolver(TenantInfo tenantInfo, IConfiguration configuration) + { + this.tenantInfo = tenantInfo; + this.configuration = configuration; + } + public string GetConnection() + { + var connectionString = string.Empty; + if (!string.IsNullOrEmpty(this.tenantInfo?.Conn)) + { + return this.tenantInfo?.Conn; + } + + return connectionString; + } + } +} \ No newline at end of file diff --git a/APT.Infrastructure.EF/Infrastructure/IConnectionGenerator.cs b/APT.Infrastructure.EF/Infrastructure/IConnectionGenerator.cs new file mode 100644 index 0000000..21679cd --- /dev/null +++ b/APT.Infrastructure.EF/Infrastructure/IConnectionGenerator.cs @@ -0,0 +1,13 @@ +using System; +using APT.Infrastructure.Api; +namespace APT.Infrastructure.EF +{ + public interface IConnectionGenerator + { + string TenantKey { get;} + + bool MatchTenantKey(string tenantKey); + + string GetConnection(TenantOption option, TenantInfo tenantInfo); + } +} diff --git a/APT.Infrastructure.EF/Infrastructure/IEntityScaner.cs b/APT.Infrastructure.EF/Infrastructure/IEntityScaner.cs new file mode 100644 index 0000000..fd6fa2b --- /dev/null +++ b/APT.Infrastructure.EF/Infrastructure/IEntityScaner.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using Microsoft.EntityFrameworkCore; + +namespace APT.Infrastructure.EF +{ + public interface IEntityScaner + where TDbContext: DbContext + { + IList ScanEntityTypes(); + + // IList ScanEntities(IList types, ModelBuilder modelBuilder); + } +} diff --git a/APT.Infrastructure.EF/Infrastructure/ITenantConnectionResolver.cs b/APT.Infrastructure.EF/Infrastructure/ITenantConnectionResolver.cs new file mode 100644 index 0000000..5ca624c --- /dev/null +++ b/APT.Infrastructure.EF/Infrastructure/ITenantConnectionResolver.cs @@ -0,0 +1,9 @@ +using System; + +namespace APT.Infrastructure.EF +{ + public interface ITenantConnectionResolver + { + string GetConnection(); + } +} diff --git a/APT.Infrastructure.EF/Infrastructure/ITenantDbContext.cs b/APT.Infrastructure.EF/Infrastructure/ITenantDbContext.cs new file mode 100644 index 0000000..a676aec --- /dev/null +++ b/APT.Infrastructure.EF/Infrastructure/ITenantDbContext.cs @@ -0,0 +1,10 @@ +using APT.Infrastructure.Api; +using System; + +namespace APT.Infrastructure.EF +{ + public interface ITenantDbContext + { + TenantInfo Tenant { get;} + } +} diff --git a/APT.Infrastructure.EF/Infrastructure/ITenantEntityBuilder.cs b/APT.Infrastructure.EF/Infrastructure/ITenantEntityBuilder.cs new file mode 100644 index 0000000..ed93c33 --- /dev/null +++ b/APT.Infrastructure.EF/Infrastructure/ITenantEntityBuilder.cs @@ -0,0 +1,15 @@ +using System; +using Microsoft.EntityFrameworkCore; + +namespace APT.Infrastructure.EF +{ + public interface ITenantEntityBuilder + { + void UpdateEntities(ModelBuilder modelBuilder); + } + public interface ITenantEntityBuilder : ITenantEntityBuilder + where TDbContext : DbContext + { + + } +} diff --git a/APT.Infrastructure.EF/Infrastructure/ITenantInfoGenerator.cs b/APT.Infrastructure.EF/Infrastructure/ITenantInfoGenerator.cs new file mode 100644 index 0000000..4662bb0 --- /dev/null +++ b/APT.Infrastructure.EF/Infrastructure/ITenantInfoGenerator.cs @@ -0,0 +1,10 @@ +using Microsoft.AspNetCore.Http; +using APT.Infrastructure.Api; +namespace APT.Infrastructure.EF +{ + public interface ITenantInfoGenerator + { + TenantInfo GenerateTenant(object sender, Microsoft.AspNetCore.Http.HttpContext httpContext); + } + +} diff --git a/APT.Infrastructure.EF/Infrastructure/TenantInfo.cs b/APT.Infrastructure.EF/Infrastructure/TenantInfo.cs new file mode 100644 index 0000000..76a8124 --- /dev/null +++ b/APT.Infrastructure.EF/Infrastructure/TenantInfo.cs @@ -0,0 +1,11 @@ +using System; + +namespace APT.Infrastructure.EF.Infrastructure +{ + public class TenantInfo + { + public string Name { get; set; } + + public string Conn { get; set; } + } +} diff --git a/APT.Infrastructure.EF/Infrastructure/TenantInfoMiddleware.cs b/APT.Infrastructure.EF/Infrastructure/TenantInfoMiddleware.cs new file mode 100644 index 0000000..ab73e2c --- /dev/null +++ b/APT.Infrastructure.EF/Infrastructure/TenantInfoMiddleware.cs @@ -0,0 +1,113 @@ +using System; +using System.Configuration; +using System.Threading.Tasks; +using APT.Infrastructure.Api; +using APT.Infrastructure.Api.Redis; +using APT.Infrastructure.Core; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.DependencyInjection; +using ConfigurationManager = APT.Infrastructure.Api.ConfigurationManager; + +namespace APT.Infrastructure.EF +{ + public class TenantInfoMiddleware + { + private readonly RequestDelegate _next; + //private string TenantConnKey = "TenantConnKey_"; + public TenantInfoMiddleware(RequestDelegate next) + { + _next = next; + } + + public async Task InvokeAsync(Microsoft.AspNetCore.Http.HttpContext context) + { + + var tenantInfo = context.RequestServices.GetRequiredService(); + var tenantName = context.Request.Headers["Tenant"]; + APT.Infrastructure.Api.AppContext.CurrentSession.RootOrgId = null; + + if (string.IsNullOrEmpty(tenantName) || tenantName == "null") + { + tenantInfo.Name = tenantName; + tenantInfo.Conn = ConfigurationManager.ConnectionStrings["default"]; + } + else + { + if (tenantInfo.Name != tenantName) + { + tenantInfo.Conn = GetDbConn(tenantName); + } + + + } + + await _next(context); + } + + /// + /// ⻧ȡݿ + /// + /// + /// + public static string GetDbConn(string tenantName) + { + //redisȡ + var deskey = APT.Infrastructure.Api.ConfigurationManager.AppSettings["ConnDataKey"]; + var tenantConnKey = APT.Infrastructure.Api.ConfigurationManager.AppSettings["TenantConnKey"]; + var env = ConfigurationManager.AppSettings["Env"]; + if (string.IsNullOrEmpty(deskey)) + deskey = "optenergy2021001"; + if (string.IsNullOrEmpty(tenantConnKey)) + tenantConnKey = "optiems"; + var tenantKey = tenantConnKey + tenantName + "_" + env; + if (CsRedisManager.KeyExists(tenantKey)) + { + var conns = CsRedisManager.StringGet(tenantKey); + var retConn = conns == "null" ? null : EncryptHelper.AesDecrypt(conns, deskey); + return retConn; + } + else + { + var url = APT.Infrastructure.Api.ConfigurationManager.AppSettings["ConnApiUrl"]; + if (!string.IsNullOrEmpty(url)) + { + url += $"?code={tenantName}&deskey={deskey}&tenantKey={tenantConnKey}"; + var deData = WebUtils.Get(url, ""); + //LoggerManager.GetLogger().Info($"TenantData:{deData}"); + return EncryptHelper.AesDecrypt(deData, deskey); + } + } + return ConfigurationManager.ConnectionStrings["default"]; + } + + /// + /// + /// + /// + /// + public static string DesDbConn(string conn) + { + //redisȡ + var deskey = APT.Infrastructure.Api.ConfigurationManager.AppSettings["ConnDataKey"]; + if (string.IsNullOrEmpty(deskey)) + deskey = "optenergy2021001"; + //LoggerManager.GetLogger().Info($"TenantData:{deData}"); + return EncryptHelper.AesDecrypt(conn, deskey); + } + + /// + /// + /// + /// + /// + public static string EnDbConn(string conn) + { + //redisȡ + var deskey = APT.Infrastructure.Api.ConfigurationManager.AppSettings["ConnDataKey"]; + if (string.IsNullOrEmpty(deskey)) + deskey = "optenergy2021001"; + //LoggerManager.GetLogger().Info($"TenantData:{deData}"); + return EncryptHelper.AesEncrypt(conn, deskey); + } + } +} diff --git a/APT.Infrastructure.EF/Map/DataUpdateRecordMap.cs b/APT.Infrastructure.EF/Map/DataUpdateRecordMap.cs new file mode 100644 index 0000000..bf8658e --- /dev/null +++ b/APT.Infrastructure.EF/Map/DataUpdateRecordMap.cs @@ -0,0 +1,30 @@ +using APT.Infrastructure.Core; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace APT.Infrastructure.EF.Map +{ + public class DataUpdateRecordMap : EntityBaseMap + { + public override void Configure(EntityTypeBuilder builder) + { + base.Configure(builder); + + builder.Property(t => t.EntityName) + //.IsRequired() + .HasMaxLength(50); + + builder.Property(t => t.EntityFullName) + //.IsRequired() + .HasMaxLength(200); + + builder.Property(t => t.UpdateFiled) + //.IsRequired() + .HasMaxLength(2000); + builder.Property(t => t.ENTITY_ORG_TPYE); + + } + } + + +} diff --git a/APT.Infrastructure.EF/Map/EntityBaseMap.cs b/APT.Infrastructure.EF/Map/EntityBaseMap.cs new file mode 100644 index 0000000..cda949d --- /dev/null +++ b/APT.Infrastructure.EF/Map/EntityBaseMap.cs @@ -0,0 +1,29 @@ +using APT.Infrastructure.Core; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace APT.Infrastructure.EF.Map +{ + public abstract class EntityBaseMap : IEntityTypeConfiguration where T : EntityBase + { + public virtual void Configure(EntityTypeBuilder builder) + { + builder.HasKey(t => t.ID); + builder.Property(t => t.ORG_ID).IsRequired(); + builder.Property(t => t.ENTITY_ORG_TPYE); + builder.Property(t => t.IS_DELETED); + builder.Property(t => t.CREATER_ID); + builder.Property(t => t.CREATE_TIME); + builder.Property(t => t.FLOW_STATUS); + builder.Property(t => t.MODIFIER_ID); + builder.Property(t => t.MODIFY_TIME); + builder.Property(t => t.FLOW_SEND_STATUS); + builder.Property(t => t.FLOW_ID); + builder.HasOne(t => t.Nav_Org).WithMany().HasForeignKey(t => t.ORG_ID).OnDelete(DeleteBehavior.Restrict); + builder.Ignore(t => t.SysParams); + builder.Ignore(t => t.Nav_SysParams);//.WithOptional().HasForeignKey(t => t.ENTITY_ID).WillCascadeOnDelete(true); + builder.Ignore(t => t.DbConn); + builder.Ignore(t => t.TaskID); + } + } +} diff --git a/APT.Infrastructure.EF/Map/FMOrganizationMap.cs b/APT.Infrastructure.EF/Map/FMOrganizationMap.cs new file mode 100644 index 0000000..6da62a3 --- /dev/null +++ b/APT.Infrastructure.EF/Map/FMOrganizationMap.cs @@ -0,0 +1,23 @@ +using APT.Infrastructure.Core; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace APT.Infrastructure.EF.Map +{ + public class FMOrganizationMap : TreeEntityBaseMap + { + public void Configure(EntityTypeBuilder builder) + { + base.Configure(builder); + builder.Property(t => t.CODE).HasMaxLength(50); + builder.Property(t => t.TENANT_CODE).HasMaxLength(10); + builder.Property(t => t.NAME).HasMaxLength(50); + builder.Property(t => t.DESC).HasMaxLength(100); + //builder.HasOne(t => t.Nav_Org).WithMany(o => o.Fm_Organizations).HasForeignKey(t => t.ORG_ID); + builder.Ignore(t => t.CheckKeys); + builder.Ignore(t => t.OrgCheckKeys); + builder.Ignore(t => t.SysParams); + builder.Ignore(t => t.Nav_SysParams);//.WithOptional().HasForeignKey(t => t.ENTITY_ID).WillCascadeOnDelete(true); + } + } +} \ No newline at end of file diff --git a/APT.Infrastructure.EF/Map/LDXEntityBaseMap.cs b/APT.Infrastructure.EF/Map/LDXEntityBaseMap.cs new file mode 100644 index 0000000..1a9bc08 --- /dev/null +++ b/APT.Infrastructure.EF/Map/LDXEntityBaseMap.cs @@ -0,0 +1,20 @@ +using APT.Infrastructure.Core; +using Microsoft.EntityFrameworkCore.Metadata.Builders; +using System; + +namespace APT.Infrastructure.EF.Map +{ + public abstract class APTEntityBaseMap : EntityBaseMap where T :MesEntityBase + { + public override void Configure(EntityTypeBuilder builder) + { + base.Configure(builder); + + builder.Property(t => t.CREATE_TIME); + + + builder.Property(t => t.MODIFY_TIME); + + } + } +} diff --git a/APT.Infrastructure.EF/Map/LDXTreeEntityBaseMap.cs b/APT.Infrastructure.EF/Map/LDXTreeEntityBaseMap.cs new file mode 100644 index 0000000..ca168df --- /dev/null +++ b/APT.Infrastructure.EF/Map/LDXTreeEntityBaseMap.cs @@ -0,0 +1,26 @@ +using APT.Infrastructure.Core; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace APT.Infrastructure.EF.Map +{ + public abstract class APTTreeEntityBaseMap: APTEntityBaseMap where T :MesTreeEntityBase + { + public override void Configure(EntityTypeBuilder builder) + { + base.Configure(builder); + builder.Property(t => t.TEXT).HasMaxLength(50); + builder.Property(t => t.PARENT_ID); + builder.Property(t => t.IS_LEAF); + } + } + + public abstract class TreeEntityBaseMap : APTTreeEntityBaseMap where T : TreeEntityBase + { + public override void Configure(EntityTypeBuilder builder) + { + base.Configure(builder); + builder.HasOne(t => t.Nav_Parent).WithMany(t=>t.Nav_Children).HasForeignKey(t => t.PARENT_ID).OnDelete(DeleteBehavior.Restrict); + } + } +} diff --git a/APT.Infrastructure.EF/Map/PFCodeRuleSerialMap.cs b/APT.Infrastructure.EF/Map/PFCodeRuleSerialMap.cs new file mode 100644 index 0000000..d94dd96 --- /dev/null +++ b/APT.Infrastructure.EF/Map/PFCodeRuleSerialMap.cs @@ -0,0 +1,23 @@ + +using APT.Infrastructure.Core; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace APT.Infrastructure.EF.Map +{ + public class PFCodeRuleSerialMap : APTEntityBaseMap + { + public override void Configure(EntityTypeBuilder builder) + { + base.Configure(builder); + builder.Property(t => t.SERIAL) + .HasMaxLength(50); + builder.Property(t => t.DATE_VALUE) + .HasMaxLength(30); + builder.HasIndex("ORG_ID", "CODE_TYPE", "SERIAL"); + builder.HasIndex("ORG_ID","CODE_TYPE","STATUS", "NUM"); + builder.HasIndex("ORG_ID", "CODE_TYPE", "DATE_VALUE", "SERIAL"); + builder.HasIndex("ORG_ID", "CODE_TYPE", "DATE_VALUE", "STATUS", "NUM"); + } + + } +} diff --git a/APT.Infrastructure.EF/Map/PFParamMap.cs b/APT.Infrastructure.EF/Map/PFParamMap.cs new file mode 100644 index 0000000..b19065c --- /dev/null +++ b/APT.Infrastructure.EF/Map/PFParamMap.cs @@ -0,0 +1,19 @@ +using APT.Infrastructure.Core; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace APT.Infrastructure.EF.Map +{ + public class PFParamMap : IEntityTypeConfiguration + { + public void Configure(EntityTypeBuilder builder) + { + builder.HasKey(t => t.ID); + builder.Property(t => t.CODE).HasMaxLength(60); + builder.Property(t => t.VALUE).HasMaxLength(600); + builder.Property(t => t.CREATE_TIME); + builder.Ignore(t => t.VIR_IS_DELETED); + //this.Property(t => t.ENTITY_ID); + } + } +} diff --git a/APT.Infrastructure.EF/Properties/serviceDependencies.json b/APT.Infrastructure.EF/Properties/serviceDependencies.json new file mode 100644 index 0000000..a4e7aa3 --- /dev/null +++ b/APT.Infrastructure.EF/Properties/serviceDependencies.json @@ -0,0 +1,7 @@ +{ + "dependencies": { + "secrets1": { + "type": "secrets" + } + } +} \ No newline at end of file diff --git a/APT.Infrastructure.EF/Properties/serviceDependencies.local.json b/APT.Infrastructure.EF/Properties/serviceDependencies.local.json new file mode 100644 index 0000000..09b109b --- /dev/null +++ b/APT.Infrastructure.EF/Properties/serviceDependencies.local.json @@ -0,0 +1,7 @@ +{ + "dependencies": { + "secrets1": { + "type": "secrets.user" + } + } +} \ No newline at end of file diff --git a/APT.Infrastructure.EF/QueryWithNoLockDbCommandInterceptor.cs b/APT.Infrastructure.EF/QueryWithNoLockDbCommandInterceptor.cs new file mode 100644 index 0000000..caaa61c --- /dev/null +++ b/APT.Infrastructure.EF/QueryWithNoLockDbCommandInterceptor.cs @@ -0,0 +1,56 @@ +using Microsoft.EntityFrameworkCore.Diagnostics; +using System; +using System.Collections.Generic; +using System.Data.Common; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading; +using System.Threading.Tasks; + +namespace APT.Infrastructure.EF +{ + public class QueryWithNoLockDbCommandInterceptor : DbCommandInterceptor + { + private static readonly Regex TableAliasRegex = + new Regex(@"(?AS \[[a-zA-Z]\w*\](?! WITH \(NOLOCK\)))", + RegexOptions.Multiline | RegexOptions.Compiled | RegexOptions.IgnoreCase); + + public override InterceptionResult ScalarExecuting(DbCommand command, CommandEventData eventData, InterceptionResult result) + { + command.CommandText = TableAliasRegex.Replace( + command.CommandText, + "${tableAlias} WITH (NOLOCK)" + ); + return base.ScalarExecuting(command, eventData, result); + } + + public override ValueTask> ScalarExecutingAsync(DbCommand command, CommandEventData eventData, InterceptionResult result, + CancellationToken cancellationToken = new CancellationToken()) + { + command.CommandText = TableAliasRegex.Replace( + command.CommandText, + "${tableAlias} WITH (NOLOCK)" + ); + return base.ScalarExecutingAsync(command, eventData, result, cancellationToken); + } + + public override InterceptionResult ReaderExecuting(DbCommand command, CommandEventData eventData, InterceptionResult result) + { + command.CommandText = TableAliasRegex.Replace( + command.CommandText, + "${tableAlias} WITH (NOLOCK)" + ); + return result; + } + + public override ValueTask> ReaderExecutingAsync(DbCommand command, CommandEventData eventData, InterceptionResult result, + CancellationToken cancellationToken = new CancellationToken()) + { + command.CommandText = TableAliasRegex.Replace( + command.CommandText, + "${tableAlias} WITH (NOLOCK)" + ); + return base.ReaderExecutingAsync(command, eventData, result, cancellationToken); + } + } +} diff --git a/APT.Infrastructure.EF/Repository.cs b/APT.Infrastructure.EF/Repository.cs new file mode 100644 index 0000000..8c06eec --- /dev/null +++ b/APT.Infrastructure.EF/Repository.cs @@ -0,0 +1,4398 @@ +using APT.Infrastructure.Core; +using APT.Infrastructure.Core.Extensions; +using APT.Infrastructure.Utility; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.ChangeTracking; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Storage; +using StackExchange.Redis; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.IO; +using System.Linq; +using System.Linq.Expressions; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Text; +using System.Threading.Tasks; +using System.Linq.Dynamic.Core; +//using Npgsql; +using System.Collections; +using APT.Infrastructure.Core.Refctor; +using Castle.Core.Internal; +using System.Collections.ObjectModel; +using System.Text.RegularExpressions; +using Microsoft.EntityFrameworkCore.Internal; +using APT.Infrastructure.Api.Redis; +using System.Collections.Concurrent; +using System.Linq.Dynamic.Core; +using APT.Infrastructure.Api; + +namespace APT.Infrastructure.EF +{ + + public class Repository : IRepository + { + private readonly IUnitOfWork _unitOfWork; + private DataBaseType _dataBaseType = DataBaseType.SQL; + private const string dbsRedisKey = "DbConn_RedisKey"; + public Repository(IUnitOfWork unitOfWork) + { + this._unitOfWork = unitOfWork; + //this._dbContext = (DbContext)unitOfWork; + _dataBaseType = unitOfWork.GetDataBaseType(); + + } + + private string DesKey + { + get + { + var desKey = APT.Infrastructure.Api.ConfigurationManager.AppSettings["ConnDataKey"]; + if (string.IsNullOrEmpty(desKey)) + desKey = "optenergy2021001"; + return desKey; + } + } + public IUnitOfWork UnitOfWork { get { return this._unitOfWork; } } + + + public void AddEntity(T entity, bool isSave = true) where T : MesEntityBase, new() + { + if (entity == null) + return; + List list = new List(); + list.Add(entity); + this.AddEntities(list, isSave); + } + + public T AddAndGetEntity(T entity, bool isSave = true) where T : MesEntityBase, new() + { + if (entity == null) + return null; + List list = new List(); + List updateSerialInfos = new List(); + var type = typeof(T); + if (Api.AppContext.CurrentSession.RootOrgId != null && type.GetAttribute() != null) + { + entity.ORG_ID = Api.AppContext.CurrentSession.RootOrgId; + } + list.Add(entity); + var sysParams = GetSysParams(list); + CheckUnique(list, null); + var nowTime = DateTime.Parse(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")); + this.UpdateSerialUsedStatus(list, 0, updateSerialInfos); + var userId = Api.AppContext.CurrentSession != null ? Api.AppContext.CurrentSession.UserID : null; + entity.CREATE_TIME = nowTime; + entity.MODIFY_TIME = nowTime; + entity.CREATER_ID = userId; + entity.MODIFIER_ID = userId; + this.FillAcronymFieldData(list); + var dbEntity = this.UnitOfWork.AddEntity(entity); + this.SaveSysParams(sysParams); + //DoSetIsLeaf(list, null, true); + this.ExcuteUpdateSerialInfos(updateSerialInfos); + if (isSave) + this.UnitOfWork.SaveChanges(); + SetRedis(entity, RedisHanddle.Add); + return dbEntity; + } + + public T AddAndGetEntity_noneBase(T entity) where T : class + { + if (entity == null) + return null; + + var dbEntity = this.UnitOfWork.AddEntity(entity); + this.UnitOfWork.SaveChanges(); + return dbEntity; + } + + + public void AddEntities_noneBase(IEnumerable entities) where T : class + { + if (entities == null || !entities.Any()) + return; + this.UnitOfWork.AddEntities(entities); + this.UnitOfWork.SaveChanges(); + + } + + public T GetEntity_noneBase(Expression> expressions) where T : class + { + var entity = this.UnitOfWork.GetEntity(expressions, null); + return entity; + } + + public List GetEntities_noneBase(Expression> expressions) where T : class + { + var entities = this.UnitOfWork.GetEntities(expressions, null); + return entities.ToList(); + } + + public void UpdateEntities_noneBase(IEnumerable entities) where T : class + { + if (entities == null || !entities.Any()) + return; + + this.UnitOfWork.UpdateEntities(entities); + this.UnitOfWork.SaveChanges(); + + } + + public void DeleteEntity_noneBase(Expression> expression) where T : class + { + var entities = this.UnitOfWork.GetEntities(expression, null); + if (entities.Any()) + { + UnitOfWork.DeleteEntities(entities); + this.UnitOfWork.SaveChanges(); + } + } + + #region nocomit + + public void AddEntityNoCommit(T entity) where T : MesEntityBase, new() + { + if (entity == null) + return; + List list = new List(); + list.Add(entity); + this.AddEntitiesNoCommit(list); + } + + public void AddEntitiesNoCommit(IEnumerable entities) where T : MesEntityBase, new() + { + AddEntities(entities, false); + } + + + public void UpdateEntitiesNoCommit(IEnumerable entities) where T : MesEntityBase, new() + { + this.UpdateEntities(entities, false); + } + + public bool UpdateEntityNoCommit(T entity, params string[] updateField) where T : MesEntityBase, new() + { + return this.UpdateEntity(entity, false, updateField); + } + + + public void UpdateEntitiesNoCommit(IEnumerable entities, params string[] updateField) where T : MesEntityBase, new() + { + this.UpdateEntities(entities, false, updateField); + } + + //private void InitIsLeaf(IEnumerable entities, List delteIds) where T : MesEntityBase, new() + //{ + // var def = entities.FirstOrDefault(); + // if (def != null && def is MesTreeEntityBase) + // { + // List addParentIds = new List(); + // List deleteParentIds = new List(); + // //DoSetIsLeafByUpdate(entities, addParentIds, deleteParentIds, delteIds); + // deleteParentIds.RemoveAll(i => addParentIds.Contains(i)); + + // if (addParentIds.Any()) + // { + // MethodInfo methodInfo = this.GetType().GetMethod("SetParentIsLeaf", + // BindingFlags.Instance | BindingFlags.Public | BindingFlags.Static); + // methodInfo.MakeGenericMethod(new Type[] { entities.FirstOrDefault().GetType() }). + // Invoke(this, new object[] { addParentIds, null, true }); + // } + // if (deleteParentIds.Any()) + // { + // MethodInfo methodInfo = this.GetType().GetMethod("SetParentIsLeaf", + // BindingFlags.Instance | BindingFlags.Public | BindingFlags.Static); + // methodInfo.MakeGenericMethod(new Type[] { entities.FirstOrDefault().GetType() }). + // Invoke(this, new object[] { deleteParentIds, delteIds, false }); + + // } + // } + //} + + public void DeleteEntityNoCommit(Expression> expression) where T : MesEntityBase, new() + { + var entities = this.UnitOfWork.GetEntities(expression, null); + if (entities.Any()) + { + foreach (var e in entities) + { + SetRedis(e, RedisHanddle.Delete); + } + this.DeleteEntitiesNoCommit(entities); + } + } + + public void DeleteEntityNoCommit(T entity) where T : MesEntityBase, new() + { + this.DeleteEntityNoCommit(i => i.ID == entity.ID); + } + + public void DeleteEntityNoCommit(Guid id) where T : MesEntityBase, new() + { + var entity = this.GetEntity(id); + this.DeleteEntityNoCommit(i => i.ID == id); + } + + public void DeleteEntitiesNoCommit(IEnumerable entities) where T : MesEntityBase, new() + { + this.DeleteEntities(entities, false); + } + + public void SaveEntitiesNoCommit(IEnumerable entities) where T : MesEntityBase, new() + { + this.SaveEntities(entities, false); + } + + public T AddAndGetEntityNoCommit(T entity) where T : MesEntityBase, new() + { + return AddAndGetEntity(entity, false); + } + + #region 指定库更新,删除 + + public void AddEntityByConn(T entity, string conn) where T : MesEntityBase, new() + { + if (entity == null) + return; + List list = new List(); + list.Add(entity); + this.AddEntitiesByConn(list, conn); + } + + public void UpdateEntitiesByConn(IEnumerable entities, string conn) where T : MesEntityBase, new() + { + this.UpdateEntitiesByConn(entities, conn); + } + + public void UpdateEntityByConn(T entity, string conn, params string[] updateField) where T : MesEntityBase, new() + { + List entities = new List(); + entities.Add(entity); + this.UpdateEntitiesByConn(entities, conn, updateField); + } + + public void DeleteEntityByConn(Expression> expression, string conn) where T : MesEntityBase, new() + { + var dbconn = TenantInfoMiddleware.DesDbConn(conn); + if (string.IsNullOrEmpty(dbconn)) + { + dbconn = ConfigurationManager.ConnectionStrings["default"]; + } + List entities = new List(); + using (var context = new EfDbContext(dbconn)) + { + entities = context.GetEntities(expression, null).ToList(); + } + if (entities.Any()) + { + foreach (var e in entities) + { + SetRedis(e, RedisHanddle.Delete); + } + this.DeleteEntitiesByConn(entities, conn); + } + + + } + + public void DeleteEntityByConn(T entity, string conn) where T : MesEntityBase, new() + { + this.DeleteEntityByConn(i => i.ID == entity.ID, conn); + } + public void DeleteEntityByConn(Guid id, string conn) where T : MesEntityBase, new() + { + var entity = this.GetEntity(id); + this.DeleteEntityByConn(i => i.ID == id, conn); + } + + //统一处理 + + public void DeleteEntitiesByConn(IEnumerable entities, string conn) where T : MesEntityBase, new() + { + if (entities == null || !entities.Any()) + return; + if (string.IsNullOrEmpty(conn)) + conn = ConfigurationManager.ConnectionStrings["default"]; + else + conn = TenantInfoMiddleware.DesDbConn(conn); + if (!string.IsNullOrEmpty(conn)) + { + try + { + DelRedis(entities); + using (var context = new EfDbContext(conn)) + { + context.DeleteEntities(entities); + context.SaveChanges(); + } + } + catch (Exception ex) + { + if (ex.Message != null && ex.Message.IndexOf("约束", StringComparison.OrdinalIgnoreCase) > -1) + throw new Exception("存在资料已被用,不允许执行此操作"); + throw ex; + } + foreach (var entity in entities) + SetRedis(entity, RedisHanddle.Delete); + + } + else + { + if (string.IsNullOrEmpty(conn)) + throw new Exception("无法获取数据库连接"); + } + } + public void AddEntitiesByConn(IEnumerable entities, string conn) where T : MesEntityBase, new() + { + if (entities == null || !entities.Any()) + return; + var userId = Api.AppContext.CurrentSession != null ? Api.AppContext.CurrentSession.UserID : null; + var type = typeof(T); + var rootOrgReplace = false; + if (Api.AppContext.CurrentSession.RootOrgId != null && type.GetAttribute() != null) + { + rootOrgReplace = true; + } + var nowTime = DateTime.Parse(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")); + entities.ForEach(i => + { + i.CREATE_TIME = nowTime; + i.MODIFY_TIME = nowTime; + if (userId != null) + { + i.CREATER_ID = userId; + i.MODIFIER_ID = userId; + } + + if (rootOrgReplace) + { + i.ORG_ID = Api.AppContext.CurrentSession.RootOrgId; + } + + }); + this.FillAcronymFieldData(entities); + List updateSerialInfos = new List(); + + if (string.IsNullOrEmpty(conn)) + conn = ConfigurationManager.ConnectionStrings["default"]; + else + conn = TenantInfoMiddleware.DesDbConn(conn); + + if (!string.IsNullOrEmpty(conn)) + { + if (string.IsNullOrEmpty(conn)) + throw new Exception("无法获取数据库连接"); + else + { + using (var context = new EfDbContext(conn)) + { + context.AddEntities(entities); + context.SaveChanges(); + } + } + + } + else + { + throw new Exception("数据库连接不能为空"); + } + + foreach (var entity in entities) + { + SetRedis(entity, RedisHanddle.Add); + } + DelRedisGroup(entities.FirstOrDefault().ORG_ID ?? Guid.Empty); + var def = entities.FirstOrDefault(); + } + public void UpdateEntitiesByConn(IEnumerable entities, string conn, params string[] updateField) where T : MesEntityBase, new() + { + if (entities == null || !entities.Any()) + return; + if (string.IsNullOrEmpty(conn)) + conn = ConfigurationManager.ConnectionStrings["default"]; + else + conn = TenantInfoMiddleware.DesDbConn(conn); + + if (!string.IsNullOrEmpty(conn)) + { + if (string.IsNullOrEmpty(conn)) + throw new Exception("无法获取数据库连接"); + else + { + //数据处理 + var deleteEntities = entities.Where(t => t.IS_DELETED).ToList(); + var updateEntities = entities.Where(t => !t.IS_DELETED).ToList(); + //更新别名 + this.FillAcronymFieldData(updateEntities, updateField); + //数据处理 + var type = typeof(T); + var rootOrgReplace = false; + if (Api.AppContext.CurrentSession.RootOrgId != null && type.GetAttribute() != null) + { + rootOrgReplace = true; + } + if (updateField != null && updateField.Any()) + { + updateField = updateField.Append("ID").ToArray(); + } + bool isRedis = false; + var redisClass = CsRedisHelper.GetRedisClass(); + if (redisClass != null) + { + isRedis = true; + } + Guid? currentUserId = null; + if (Api.AppContext.CurrentSession != null && !string.IsNullOrEmpty(Api.AppContext.CurrentSession.UserId)) + currentUserId = new Guid(Api.AppContext.CurrentSession.UserId); + var nowTime = DateTime.Parse(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")); + foreach (var i in updateEntities) + { + i.MODIFY_TIME = nowTime; + if (rootOrgReplace) + { + i.ORG_ID = Api.AppContext.CurrentSession.RootOrgId; + } + + if (currentUserId != null) + { + i.MODIFIER_ID = currentUserId; + } + } + //redis数据删除 + if (isRedis) + { + DelRedis(entities); + } + + using (var context = new EfDbContext(conn)) + { + CheckRowVersion(entities, context); + context.UpdateEntities(updateEntities, updateField); + context.DeleteEntities(deleteEntities); + context.SaveChanges(); + } + } + + } + else + { + throw new Exception("数据库连接不能为空"); + } + + + } + + + public void AddEntityByTenant(T entity, string tenant) where T : MesEntityBase, new() + { + if (entity == null) + return; + List list = new List(); + list.Add(entity); + this.AddEntitiesByTenant(list, tenant); + } + + public void UpdateEntitiesByTenant(IEnumerable entities, string tenant) where T : MesEntityBase, new() + { + this.UpdateEntitiesByTenant(entities, tenant); + } + + public void UpdateEntityByTenant(T entity, string tenant, params string[] updateField) where T : MesEntityBase, new() + { + List entities = new List(); + entities.Add(entity); + this.UpdateEntitiesByTenant(entities, tenant, updateField); + } + + public void DeleteEntityByTenant(Expression> expression, string tenant) where T : MesEntityBase, new() + { + var dbconn = ""; + if (string.IsNullOrEmpty(tenant)) + dbconn = ConfigurationManager.ConnectionStrings["default"]; + else + dbconn = TenantInfoMiddleware.GetDbConn(tenant); + List entities = new List(); + using (var context = new EfDbContext(dbconn)) + { + entities = context.GetEntities(expression, null).ToList(); + } + if (entities.Any()) + { + foreach (var e in entities) + { + SetRedis(e, RedisHanddle.Delete); + } + this.DeleteEntitiesByTenant(entities, tenant); + } + } + + public void DeleteEntityByTenant(T entity, string tenant) where T : MesEntityBase, new() + { + this.DeleteEntityByConn(i => i.ID == entity.ID, tenant); + } + public void DeleteEntityByTenant(Guid id, string tenant) where T : MesEntityBase, new() + { + var entity = this.GetEntity(id); + this.DeleteEntityByConn(i => i.ID == id, tenant); + } + + //统一处理 + + public void DeleteEntitiesByTenant(IEnumerable entities, string tenant) where T : MesEntityBase, new() + { + if (entities == null || !entities.Any()) + return; + var dbconn = ""; + if (string.IsNullOrEmpty(tenant)) + dbconn = ConfigurationManager.ConnectionStrings["default"]; + else + dbconn = TenantInfoMiddleware.GetDbConn(tenant); + if (!string.IsNullOrEmpty(tenant)) + { + if (string.IsNullOrEmpty(dbconn)) + throw new Exception("无法获取数据库连接"); + else + { + try + { + DelRedis(entities); + using (var context = new EfDbContext(dbconn)) + { + context.DeleteEntities(entities); + context.SaveChanges(); + } + } + catch (Exception ex) + { + if (ex.Message != null && ex.Message.IndexOf("约束", StringComparison.OrdinalIgnoreCase) > -1) + throw new Exception("存在资料已被用,不允许执行此操作"); + throw ex; + } + foreach (var entity in entities) + SetRedis(entity, RedisHanddle.Delete); + + } + + } + else + { + throw new Exception("数据库连接不能为空"); + } + } + public void AddEntitiesByTenant(IEnumerable entities, string tenant) where T : MesEntityBase, new() + { + if (entities == null || !entities.Any()) + return; + var userId = Api.AppContext.CurrentSession != null ? Api.AppContext.CurrentSession.UserID : null; + var type = typeof(T); + var rootOrgReplace = false; + if (Api.AppContext.CurrentSession.RootOrgId != null && type.GetAttribute() != null) + { + rootOrgReplace = true; + } + var nowTime = DateTime.Parse(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")); + entities.ForEach(i => + { + i.CREATE_TIME = nowTime; + i.MODIFY_TIME = nowTime; + if (userId != null) + { + i.CREATER_ID = userId; + i.MODIFIER_ID = userId; + } + + if (rootOrgReplace) + { + i.ORG_ID = Api.AppContext.CurrentSession.RootOrgId; + } + + }); + this.FillAcronymFieldData(entities); + List updateSerialInfos = new List(); + + var dbconn = ""; + if (string.IsNullOrEmpty(tenant)) + dbconn = ConfigurationManager.ConnectionStrings["default"]; + else + dbconn = TenantInfoMiddleware.GetDbConn(tenant); + + if (!string.IsNullOrEmpty(tenant)) + { + if (string.IsNullOrEmpty(dbconn)) + throw new Exception("无法获取数据库连接"); + else + { + using (var context = new EfDbContext(dbconn)) + { + context.AddEntities(entities); + context.SaveChanges(); + } + } + + } + else + { + throw new Exception("数据库连接不能为空"); + } + + foreach (var entity in entities) + { + SetRedis(entity, RedisHanddle.Add); + } + DelRedisGroup(entities.FirstOrDefault().ORG_ID ?? Guid.Empty); + var def = entities.FirstOrDefault(); + } + public void UpdateEntitiesByTenant(IEnumerable entities, string tenant, params string[] updateField) where T : MesEntityBase, new() + { + if (entities == null || !entities.Any()) + return; + var dbconn = ""; + if (string.IsNullOrEmpty(tenant)) + dbconn = ConfigurationManager.ConnectionStrings["default"]; + else + dbconn = TenantInfoMiddleware.GetDbConn(tenant); + + if (!string.IsNullOrEmpty(tenant)) + { + if (string.IsNullOrEmpty(dbconn)) + throw new Exception("无法获取数据库连接"); + else + { + //数据处理 + var deleteEntities = entities.Where(t => t.IS_DELETED).ToList(); + var updateEntities = entities.Where(t => !t.IS_DELETED).ToList(); + //更新别名 + this.FillAcronymFieldData(updateEntities, updateField); + //数据处理 + var type = typeof(T); + var rootOrgReplace = false; + if (Api.AppContext.CurrentSession.RootOrgId != null && type.GetAttribute() != null) + { + rootOrgReplace = true; + } + if (updateField != null && updateField.Any()) + { + updateField = updateField.Append("ID").ToArray(); + } + bool isRedis = false; + var redisClass = CsRedisHelper.GetRedisClass(); + if (redisClass != null) + { + isRedis = true; + } + Guid? currentUserId = null; + if (Api.AppContext.CurrentSession != null && !string.IsNullOrEmpty(Api.AppContext.CurrentSession.UserId)) + currentUserId = new Guid(Api.AppContext.CurrentSession.UserId); + var nowTime = DateTime.Parse(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")); + foreach (var i in updateEntities) + { + i.MODIFY_TIME = nowTime; + if (rootOrgReplace) + { + i.ORG_ID = Api.AppContext.CurrentSession.RootOrgId; + } + + if (currentUserId != null) + { + i.MODIFIER_ID = currentUserId; + } + } + //redis数据删除 + if (isRedis) + { + DelRedis(entities); + } + + using (var context = new EfDbContext(dbconn)) + { + CheckRowVersion(entities, context); + context.UpdateEntities(updateEntities, updateField); + context.DeleteEntities(deleteEntities); + context.SaveChanges(); + } + } + + } + else + { + throw new Exception("数据库连接不能为空"); + } + + + } + + + #endregion + + #endregion + + + public void AddEntities(IEnumerable entities, bool isSave = true) where T : MesEntityBase, new() + { + if (entities == null || !entities.Any()) + return; + this.CheckUnique(entities, null); + var userId = Api.AppContext.CurrentSession != null ? Api.AppContext.CurrentSession.UserID : null; + var type = typeof(T); + var rootOrgReplace = false; + if (Api.AppContext.CurrentSession.RootOrgId != null && type.GetAttribute() != null) + { + rootOrgReplace = true; + } + var nowTime = DateTime.Parse(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")); + entities.ForEach(i => + { + i.CREATE_TIME = nowTime; + i.MODIFY_TIME = nowTime; + if (userId != null) + { + i.CREATER_ID = userId; + i.MODIFIER_ID = userId; + } + + if (rootOrgReplace) + { + i.ORG_ID = Api.AppContext.CurrentSession.RootOrgId; + } + + }); + this.FillAcronymFieldData(entities); + List updateSerialInfos = new List(); + this.UpdateSerialUsedStatus(entities, 0, updateSerialInfos); + var sysParams = GetSysParams(entities); + this.UnitOfWork.AddEntities(entities); + foreach (var entity in entities) + { + SetRedis(entity, RedisHanddle.Add); + } + DelRedisGroup(entities.FirstOrDefault().ORG_ID ?? Guid.Empty); + SaveSysParams(sysParams); + //DoSetIsLeaf(entities, null, true); + var def = entities.FirstOrDefault(); + + this.ExcuteUpdateSerialInfos(updateSerialInfos); + if (isSave) + { + this.UnitOfWork.SaveChanges(); + } + } + + public void DeleteEntity(T entity, bool isSave = true) where T : MesEntityBase, new() + { + this.DeleteEntity(entity.ID, isSave); + + } + + public void DeleteEntity(Guid key, bool isSave = true) where T : MesEntityBase, new() + { + var entity = this.GetEntity(key); + this.DeleteEntity(t => t.ID == key, isSave); + + } + + public void DeleteEntity(Expression> predicate, bool isSave = true) where T : MesEntityBase, new() + { + var entities = this.UnitOfWork.GetEntities(predicate, null); + + if (entities.Any()) + { + this.DeleteEntities(entities, isSave); + } + } + + + public void DeleteEntities(IEnumerable entities, bool isSave = true) where T : MesEntityBase, new() + { + if (entities == null || !entities.Any()) + return; + List updateSerialInfos = new List(); + var sysParams = GetSysParams(entities, true); + + this.UpdateSerialUsedStatus(entities, 2, updateSerialInfos); + this.UnitOfWork.DeleteEntities(entities); + + //DoSetIsLeaf(entities, entities.Select(i => i.ID).ToList(), false); + this.SaveSysParams(sysParams); + this.ExcuteUpdateSerialInfos(updateSerialInfos); + DelRedis(entities); + try + { + if (isSave) + { + + this.UnitOfWork.SaveChanges(); + } + + } + catch (Exception ex) + { + if (ex.Message != null && ex.Message.IndexOf("约束", StringComparison.OrdinalIgnoreCase) > -1) + throw new Exception("存在资料已被用,不允许执行此操作"); + throw ex; + } + foreach (var entity in entities) + SetRedis(entity, RedisHanddle.Delete); + + } + + + public bool UpdateEntity(T entity, bool isSave = true, params string[] updateField) where T : MesEntityBase, new() + { + if (entity == null) + return false; + if (entity.IS_DELETED) + this.DeleteEntity(entity); + else + { + List entities = new List(); + entities.Add(entity); + if (updateField == null || !updateField.Any()) + this.SaveEntities(entities, isSave); + else + { + this.UpdateEntities(entities, isSave, updateField); + } + + } + return true; + } + + public void UpdateEntities(IEnumerable entities, bool isSave = true, params string[] updateField) where T : MesEntityBase, new() + { + if (entities == null || !entities.Any()) + return; + CheckRowVersion(entities); + + + List updateSerialInfos = new List(); + var sysParams = GetSysParams(entities); + var deleteEntities = entities.Where(t => t.IS_DELETED).ToList(); + var updateEntities = entities.Where(t => !t.IS_DELETED).ToList(); + CheckUnique(entities, deleteEntities); + //List addParentIds = new List(); + //List deleteParentIds = new List(); + //List deleteIds = new List(); + //DoSetIsLeafByUpdate(updateEntities, addParentIds, deleteParentIds, deleteIds); + //更新别名 + this.FillAcronymFieldData(updateEntities, updateField); + //数据处理 + var type = typeof(T); + var rootOrgReplace = false; + if (Api.AppContext.CurrentSession.RootOrgId != null && type.GetAttribute() != null) + { + rootOrgReplace = true; + } + if (updateField != null && updateField.Any()) + { + updateField = updateField.Append("ID").ToArray(); + } + bool isRedis = false; + var redisClass = CsRedisHelper.GetRedisClass(); + if (redisClass != null) + { + isRedis = true; + } + Guid? currentUserId = null; + if (Api.AppContext.CurrentSession != null && !string.IsNullOrEmpty(Api.AppContext.CurrentSession.UserId)) + currentUserId = new Guid(Api.AppContext.CurrentSession.UserId); + var nowTime = DateTime.Parse(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")); + foreach (var i in updateEntities) + { + i.MODIFY_TIME = nowTime; + if (rootOrgReplace) + { + i.ORG_ID = Api.AppContext.CurrentSession.RootOrgId; + } + + if (currentUserId != null) + { + i.MODIFIER_ID = currentUserId; + } + } + if (isRedis) + { + //CsRedisManager.GetClient().Del(updateEntities.Select(i => i.ID.ToString()).ToArray()); + DelRedis(entities); + } + this.UpdateSerialUsedStatus(updateEntities, 1, updateSerialInfos); + this.UpdateSerialUsedStatus(deleteEntities, 2, updateSerialInfos); + this.UnitOfWork.UpdateEntities(updateEntities, updateField); + this.UnitOfWork.DeleteEntities(deleteEntities); + // + //deleteParentIds.RemoveAll(i => addParentIds.Contains(i)); + + //if (addParentIds.Any()) + //{ + // MethodInfo methodInfo = this.GetType().GetMethod("SetParentIsLeaf", + // BindingFlags.Instance | BindingFlags.Public | BindingFlags.Static); + // methodInfo.MakeGenericMethod(new Type[] { entities.FirstOrDefault().GetType() }). + // Invoke(this, new object[] { addParentIds, deleteIds, true }); + //} + //if (deleteParentIds.Any()) + //{ + // MethodInfo methodInfo = this.GetType().GetMethod("SetParentIsLeaf", + // BindingFlags.Instance | BindingFlags.Public | BindingFlags.Static); + // methodInfo.MakeGenericMethod(new Type[] { entities.FirstOrDefault().GetType() }). + // Invoke(this, new object[] { deleteParentIds, deleteIds, false }); + //} + this.SaveSysParams(sysParams); + this.ExcuteUpdateSerialInfos(updateSerialInfos); + if (isSave) + this.UnitOfWork.SaveChanges(); + + } + + public void SaveEntities(IEnumerable entities, bool isSave = true) where T : MesEntityBase, new() + { + if (entities == null || !entities.Any()) + return; + var type = typeof(T); + var rootOrgReplace = false; + if (Api.AppContext.CurrentSession.RootOrgId != null && type.GetAttribute() != null) + { + rootOrgReplace = true; + } + + CheckRowVersion(entities); + + + var sysParams = GetSysParams(entities); + var deleteEntities = entities.Where(t => t.IS_DELETED).ToList(); + var saveEntities = entities.Where(t => !t.IS_DELETED).ToList(); + List updateEntities = new List(); + List addEntities = new List(); + List deleteIds = new List(); + List updateSerialInfos = new List(); + var def = entities.FirstOrDefault(); + List addParentIds = new List(); + List deleteParentIds = new List(); + if (deleteEntities.Any()) + { + this.UpdateSerialUsedStatus(deleteEntities, 2, updateSerialInfos); + var delIds = deleteEntities.Select(i => i.ID).ToArray(); + var dbDelEntities = this.UnitOfWork.GetEntities(t => delIds.Contains(t.ID), null, true).ToList(); + this.UnitOfWork.DeleteEntities(dbDelEntities); + //if (def != null && def is MesTreeEntityBase) + //{ + // var deleteTreeEntitis = deleteEntities as List; + // var deletePIds = deleteTreeEntitis.Select(i => i.PARENT_ID ?? Guid.Empty).Distinct().ToList(); + // deleteIds = deleteTreeEntitis.Select(i => i.ID).Distinct().ToList(); + // deleteParentIds.AddRange(deletePIds); + //} + } + if (saveEntities.Any()) + { + this.CheckUnique(saveEntities, deleteEntities); + //DoSetIsLeafByUpdate(saveEntities, addParentIds, deleteParentIds, deleteIds); + var ids = saveEntities.Select(t => t.ID).ToList(); + List dbUpdateEntities = this.UnitOfWork.GetEntities(t => ids.Contains(t.ID), null, true).ToList(); + var dbContext = (DbContext)this.UnitOfWork; + var nowTime = DateTime.Parse(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")); + foreach (var entity in saveEntities) + { + if (rootOrgReplace) + { + entity.ORG_ID = Api.AppContext.CurrentSession.RootOrgId; + } + var dbEntity = dbUpdateEntities.FirstOrDefault(t => t.ID.ToString() == entity.ID.ToString()); + if (dbEntity != null) + { + entity.MODIFY_TIME = nowTime; + if (Api.AppContext.CurrentSession != null && !string.IsNullOrEmpty(Api.AppContext.CurrentSession.UserId)) + { + entity.MODIFIER_ID = new Guid(Api.AppContext.CurrentSession.UserId); + } + var oldContexEntity = dbContext.Entry(dbEntity); + oldContexEntity.CurrentValues.SetValues(entity); + updateEntities.Add(dbEntity); + //SetRedis(entity, RedisHanddle.Update); + } + else + { + entity.MODIFY_TIME = nowTime; + entity.CREATE_TIME = nowTime; + if (Api.AppContext.CurrentSession != null && !string.IsNullOrEmpty(Api.AppContext.CurrentSession.UserId)) + { + entity.MODIFIER_ID = new Guid(Api.AppContext.CurrentSession.UserId); + entity.CREATER_ID = new Guid(Api.AppContext.CurrentSession.UserId); + } + addEntities.Add(entity); + //SetRedis(entity, RedisHanddle.Add); + } + deleteParentIds.RemoveAll(i => addParentIds.Contains(i)); + } + DelRedis(entities); + + this.FillAcronymFieldData(saveEntities); + this.UnitOfWork.UpdateEntities(updateEntities); + this.UnitOfWork.AddEntities(addEntities); + this.UpdateSerialUsedStatus(addEntities, 0, updateSerialInfos); + this.UpdateSerialUsedStatus(updateEntities, 1, updateSerialInfos); + } + + this.SaveSysParams(sysParams); + this.ExcuteUpdateSerialInfos(updateSerialInfos); + try + { + if (isSave) + { + this.UnitOfWork.SaveChanges(); + } + + } + catch (Exception ex) + { + //if (ex.Message != null && ex.Message.IndexOf("约束", StringComparison.OrdinalIgnoreCase) > -1) + // throw new Exception("存在资料已被用,不允许执行此操作"); + throw ex; + } + + } + + public T GetEntity(Guid id, params string[] paths) + where T : MesEntityBase, new() + { + return this.GetEntity(t => t.ID == id, null, paths); + } + + public T GetEntity(Expression> expression, BaseFilter filter, params string[] paths) + where T : MesEntityBase, new() + { + return this.GetEntity(expression, filter, (!filter?.IsNoTranking) ?? true, paths); + } + public T GetEntity(Expression> expression, BaseFilter filter, bool isTracking = true, params string[] paths) + where T : MesEntityBase, new() + { + if (filter != null && Api.AppContext.CurrentSession.DataRule != null && !filter.IgnoreDataRule && !filter.DataRule.Any()) + { + filter.DataRule = Api.AppContext.CurrentSession.DataRule; + } + string[] realPaths = null; + Dictionary realOrders = null; + Expression> orgExpression; + var exp = DoGetEntityExp(expression, filter, paths, null, out orgExpression, out realPaths, out realOrders, false); + List selectFields = new List(); + T ret = null; + if (filter != null && filter.SelectField != null && filter.SelectField.Any()) + { + selectFields = filter.SelectField.ToList(); + AppendSelectedField(selectFields); + } + //多库联合查询 + if (filter != null) + { + if (filter.IsMultipleDb) + { + var conns = GetAllDbConns();//查询redis里面的数据库连接 + foreach (var conn in conns) + { + using (var context = new EfDbContext(conn)) + { + ret = context.GetEntity(exp, realOrders, selectFields.ToArray(), isTracking, realPaths); + if (ret != null) + { + var dbConn = TenantInfoMiddleware.EnDbConn(conn); + ret.DbConn = dbConn; + break; + } + + } + } + } + else if (filter.IsSpecifyDb) + { + string enConn = GetSpecifyDb(filter); + using (var context = new EfDbContext(enConn)) + { + ret = context.GetEntity(exp, realOrders, selectFields.ToArray(), isTracking, realPaths); + if (ret != null) + { + ret.DbConn = filter.SpecifyDbConn; + } + } + } + else + { + ret = this.UnitOfWork.GetEntity(exp, realOrders, selectFields.ToArray(), isTracking, realPaths); + } + + } + else + { + ret = this.UnitOfWork.GetEntity(exp, realOrders, selectFields.ToArray(), isTracking, realPaths); + } + //导航属性 + if (ret != null) + { + List list = new List(); + list.Add(ret); + this.FillGetEntitySysParam(list, filter, paths); + if (selectFields != null && selectFields.Any()) + { + realPaths = SelectFieldInclude(realPaths, selectFields); + NavigationDeal(realPaths, list, selectFields.ToArray(), filter.DataRule.ToArray(), filter.OrgRule, filter.OrgId, filter.IgnoreOrgRule, + filter.IgnoreDataRule, isTracking, + filter.IsMultipleDb, filter.IsSpecifyDb, filter.SpecifyDbConn); + } + } + return ret; + } + public IEnumerable GetEntities(Expression> expression, BaseFilter filter, + params string[] paths) where T : MesEntityBase, new() + { + return this.GetEntities(expression, filter, (!filter?.IsNoTranking) ?? true, paths); + } + + + private IEnumerable GetEntities(BaseFilter filter) where T : MesEntityBase, new() + { + return this.GetEntities(null, filter); + } + public IEnumerable GetEntities(Expression> expression, BaseFilter filter, + bool isTracking = true, params string[] paths) where T : MesEntityBase, new() + { + string[] realPaths = null; + Dictionary realOrders = null; + Expression> orgExpression; + var exp = DoGetEntityExp(expression, filter, paths, null, out orgExpression, out realPaths, out realOrders, false); + List selectFields = new List(); + if (filter != null && Api.AppContext.CurrentSession.DataRule != null && !filter.IgnoreDataRule && !filter.DataRule.Any()) + { + filter.DataRule = Api.AppContext.CurrentSession.DataRule; + } + if (filter != null && filter.SelectField != null && filter.SelectField.Any()) + { + selectFields = filter.SelectField.ToList(); + AppendSelectedField(selectFields); + } + //支持多库联合查询 + var entities = new List(); + if (filter != null) + { + if (filter.IsMultipleDb) + { + var conns = GetAllDbConns();//查询redis里面的数据库连接 + foreach (var conn in conns) + { + using (var context = new EfDbContext(conn)) + { + var contextEntities = context.GetEntities(exp, selectFields.ToArray(), isTracking, realPaths); + if (contextEntities.Any()) + { + var dbConn = TenantInfoMiddleware.EnDbConn(conn); + contextEntities.ForEach(i => i.DbConn = dbConn); + entities.AddRange(contextEntities); + } + } + } + } + else if (filter.IsSpecifyDb) + { + string enConn = GetSpecifyDb(filter); + using (var context = new EfDbContext(enConn)) + { + entities = context.GetEntities(exp, selectFields.ToArray(), isTracking, realPaths).ToList(); + } + } + else + { + entities = this.UnitOfWork.GetEntities(exp, selectFields.ToArray(), isTracking, realPaths).ToList(); + } + } + else + { + entities = this.UnitOfWork.GetEntities(exp, selectFields.ToArray(), isTracking, realPaths).ToList(); + } + if (entities != null && entities.Any()) + this.FillGetEntitySysParam(entities, filter, paths); + //导航属性处理 + if (selectFields != null && selectFields.Any()) + { + realPaths = SelectFieldInclude(realPaths, selectFields); + NavigationDeal(realPaths, entities, selectFields.ToArray(), + filter.DataRule.ToArray(), filter.OrgRule, filter.OrgId, filter.IgnoreOrgRule, + filter.IgnoreDataRule, isTracking, filter.IsMultipleDb, filter.IsSpecifyDb, filter.SpecifyDbConn); + } + + return entities; + } + + private static string[] SelectFieldInclude(string[] realPaths, List selectFields) + { + List tmp = new List(); + if (realPaths != null) + { + tmp = new List(realPaths); + } + foreach (var field in selectFields) + { + if (field.IndexOf(".") > 0) + { + var index = field.LastIndexOf("."); + var includPath = field.Substring(0, index); + if (!tmp.Contains(includPath)) + { + tmp.Add(includPath); + } + } + } + realPaths = tmp.ToArray(); + return realPaths; + } + + public IEnumerable GetOrderEntities(Expression> expression, BaseFilter filter, + params string[] paths) where T : MesEntityBase, new() + { + return this.GetOrderEntities(expression, filter, null, (!filter?.IsNoTranking) ?? true, paths); + } + + public IEnumerable GetTree(string id, bool containCurrent = true, BaseFilter filter = null, + params string[] paths) where T : TreeEntityBase, new() + { + var gid = new Guid(id); + List guidList = new List(); + List allList = new List(); + guidList.Add(gid); + if (containCurrent) + { + if (filter != null) + { + if (filter.IsMultipleDb) + { + var conns = GetAllDbConns();//查询redis里面的数据库连接 + foreach (var conn in conns) + { + using (var context = new EfDbContext(conn)) + { + var top = context.GetEntity(i => i.ID == gid, filter.SelectField?.ToArray(), paths); + if (top != null) + { + allList.Add(top); + var dbConn = TenantInfoMiddleware.EnDbConn(conn); + top.DbConn = dbConn; + break; + } + } + } + } + else if (filter.IsSpecifyDb) + { + string enConn = GetSpecifyDb(filter); + using (var context = new EfDbContext(enConn)) + { + var top = context.GetEntity(i => i.ID == gid, filter.SelectField?.ToArray(), paths); + if (top != null) + { + allList.Add(top); + } + } + } + else + { + var top = this.GetEntity(gid, paths); + if (top != null) + allList.Add(top); + } + } + else + { + var top = this.GetEntity(gid, paths); + if (top != null) + allList.Add(top); + } + } + GetChildEntity(paths, filter, guidList, allList); + return allList; + } + + private void AppendSelectedField(List selectFields) + { + if (selectFields != null && selectFields.Any()) + { + var type = typeof(T); + var keys = this.UnitOfWork.GetModelForeignKey(type.Name); + foreach (var fkey in keys) + { + if (fkey.ForeignNavName == null || selectFields.Contains(fkey.ForeignFieldName) + || !selectFields.Any(i => i.Contains(fkey.ForeignNavName))) + continue; + var prop = type.GetProperty(fkey.ForeignNavName); + if (prop != null && !typeof(System.Collections.IEnumerable).IsAssignableFrom(prop.PropertyType)) + { + selectFields.Add(fkey.ForeignFieldName); + } + } + if (!selectFields.Contains("ID")) + { + selectFields.Add("ID"); + } + } + } + private void GetChildEntity(string[] paths, BaseFilter filter, List guidList, List allList) where T : TreeEntityBase, new() + { + var top = new List(); + if (filter != null) + { + if (filter.IsMultipleDb) + { + var conns = GetAllDbConns();//查询redis里面的数据库连接 + foreach (var conn in conns) + { + using (var context = new EfDbContext(conn)) + { + var contexEntities = context.GetEntities(i => guidList.Contains(i.PARENT_ID ?? Guid.Empty), filter.SelectField?.ToArray(), paths).ToList(); + if (contexEntities != null && contexEntities.Any()) + { + var dbConn = TenantInfoMiddleware.EnDbConn(conn); + contexEntities.ForEach(i => i.DbConn = dbConn); + top.AddRange(contexEntities); + } + } + } + } + else if (filter.IsSpecifyDb) + { + string enConn = GetSpecifyDb(filter); + using (var context = new EfDbContext(enConn)) + { + var contexEntities = context.GetEntities(i => guidList.Contains(i.PARENT_ID ?? Guid.Empty), filter.SelectField?.ToArray(), paths).ToList(); + if (contexEntities != null && contexEntities.Any()) + { + top.AddRange(contexEntities); + } + } + } + else + { + top = this.GetEntities(i => guidList.Contains(i.PARENT_ID ?? Guid.Empty), new BaseFilter(), paths).ToList(); + } + } + else + { + top = this.GetEntities(i => guidList.Contains(i.PARENT_ID ?? Guid.Empty), new BaseFilter(), paths).ToList(); ; + } + if (top.Any()) + { + allList.AddRange(top); + var childGuidList = top.Select(i => i.ID).ToList(); + GetChildEntity(paths, filter, childGuidList, allList); + } + } + + public IEnumerable> GetTreeOrderEntities(Expression> expression, BaseFilter filter, bool isTracking = true, + params string[] paths) where T : TreeEntityBase, new() + { + if (filter != null && Api.AppContext.CurrentSession.DataRule != null && !filter.IgnoreDataRule && !filter.DataRule.Any()) + { + filter.DataRule = Api.AppContext.CurrentSession.DataRule; + } + string[] realPaths = null; + Dictionary realOrders = null; + Expression> orgExpression; + var exp = DoGetEntityExp(expression, filter, paths, null, out orgExpression, out realPaths, out realOrders, false); + List resultList = null; + List> data = new List>(); + if (filter != null) + { + if (filter.IsMultipleDb) + { + var conns = GetAllDbConns();//查询redis里面的数据库连接 + foreach (var conn in conns) + { + using (var context = new EfDbContext(conn)) + { + var contextEntities = context.GetTreeOrderEntities(exp, filter, orgExpression, out resultList, isTracking, realPaths); + if (contextEntities.Any()) + { + var dbConn = TenantInfoMiddleware.EnDbConn(conn); + contextEntities.ForEach(i => i.Node.DbConn = dbConn); + data.AddRange(contextEntities); + } + + } + } + } + else if (filter.IsSpecifyDb) + { + string enConn = GetSpecifyDb(filter); + using (var context = new EfDbContext(enConn)) + { + var contexEntities = context.GetTreeOrderEntities(exp, filter, orgExpression, out resultList, isTracking, realPaths); + if (contexEntities != null && contexEntities.Any()) + { + data.AddRange(contexEntities); + } + } + } + else + { + data = this.UnitOfWork.GetTreeOrderEntities(exp, filter, orgExpression, out resultList, isTracking, realPaths).ToList(); + } + } + else + { + data = this.UnitOfWork.GetTreeOrderEntities(exp, filter, orgExpression, out resultList, isTracking, realPaths).ToList(); + } + if (filter != null && filter.SelectField.Any()) + { + realPaths = SelectFieldInclude(realPaths, filter.SelectField.ToList()); + NavigationDeal(realPaths, resultList, filter.SelectField.ToArray(), filter.DataRule.ToArray(), + filter.OrgRule, filter.OrgId, filter.IgnoreOrgRule, filter.IgnoreDataRule, + isTracking, filter.IsMultipleDb, filter.IsSpecifyDb, filter.SpecifyDbConn); + } + return data; + } + + private void InitTreeNode(List> dataLists, TreeNode parentNode) where T + : TreeEntityBase, new() + { + + if (dataLists.Count <= parentNode.Level) + return; + List levalData = new List(); + if (parentNode.Node != null) + { + levalData = dataLists[parentNode.Level].Where(i => i.PARENT_ID == parentNode.Node.ID).ToList(); + } + else + { + levalData = dataLists[parentNode.Level].ToList(); + } + IList childData = new List(); + if (parentNode.Level < dataLists.Count - 1) + { + childData = dataLists[parentNode.Level + 1]; + } + //构造node节点 + foreach (var d in levalData) + { + TreeNode node = new Core.TreeNode(); + parentNode.Children.Add(node); + node.Node = d; + node.Level = parentNode.Level + 1; + node.IsLeaf = d.IS_LEAF; + node.Children = new List>(); + if (childData.Any(i => i.PARENT_ID == d.ID)) + { + node.IsLeaf = false; + InitTreeNode(dataLists, node); + + } + } + } + /// + /// 分级构造树的数据 + /// + /// + /// + /// + /// + /// + /// + private void InitDownTree(Expression> expression, BaseFilter filter, string[] paths, IList data, List> dataLists) where T : TreeEntityBase, new() + { + dataLists.Add(data); + if (dataLists.Count < filter.Level || filter.Level == -1) + { + var dataIds = dataLists[dataLists.Count - 1].Select(i => i.ID).ToList(); + var secExpression = expression.And(i => dataIds.Contains(i.PARENT_ID ?? Guid.Empty)); + var childData = this.GetOrderEntities(secExpression, filter, null, (!filter?.IsNoTranking) ?? true, paths).ToList(); + if (childData.Any()) + { + InitDownTree(expression, filter, paths, childData, dataLists); + } + } + } + + public IEnumerable GetOrderEntities(Expression> expression, BaseFilter filter, + bool isTracking = true, params string[] paths) where T : MesEntityBase, new() + { + return this.GetOrderEntities(expression, filter, null, isTracking, paths); + } + public IEnumerable GetOrderEntities(Expression> expression, BaseFilter filter, Dictionary orders, + bool isTracking = true, params string[] paths) where T : MesEntityBase, new() + { + return this.GetOrderEntities(expression, filter, orders, null, isTracking, paths); + } + + public IEnumerable GetOrderEntities(Expression> expression, BaseFilter filter, Dictionary orders, + Action> orderBy, + bool isTracking = true, params string[] paths) where T : MesEntityBase, new() + { + string[] realPaths = null; + Dictionary realOrders = null; + Expression> orgExpression; + var exp = DoGetEntityExp(expression, filter, paths, orders, out orgExpression, out realPaths, out realOrders, false); + List selectFields = new List(); + if (filter != null && Api.AppContext.CurrentSession.DataRule != null && !filter.IgnoreDataRule && !filter.DataRule.Any()) + { + filter.DataRule = Api.AppContext.CurrentSession.DataRule; + } + if (filter != null && filter.SelectField != null && filter.SelectField.Any()) + { + selectFields = filter.SelectField.ToList(); + AppendSelectedField(selectFields); + } + //支持多库联合查询 + var entities = new List(); + if (filter != null) + { + if (filter.IsMultipleDb) + { + var conns = GetAllDbConns();//查询redis里面的数据库连接 + foreach (var conn in conns) + { + using (var context = new EfDbContext(conn)) + { + var contextEntities = context.GetOrderEntities(exp, realOrders, orderBy, filter == null ? null : selectFields.ToArray(), isTracking, realPaths); + if (contextEntities.Any()) + { + var dbConn = TenantInfoMiddleware.EnDbConn(conn); + contextEntities.ForEach(i => i.DbConn = dbConn); + entities.AddRange(contextEntities); + } + + } + } + } + else if (filter.IsSpecifyDb) + { + string enConn = GetSpecifyDb(filter); + using (var context = new EfDbContext(enConn)) + { + entities = context.GetOrderEntities(exp, realOrders, orderBy, filter == null ? null : selectFields.ToArray(), isTracking, realPaths).ToList(); + } + } + else + { + entities = this.UnitOfWork.GetOrderEntities(exp, realOrders, orderBy, filter == null ? null : selectFields.ToArray(), isTracking, realPaths).ToList(); + } + } + else + { + entities = this.UnitOfWork.GetOrderEntities(exp, realOrders, orderBy, filter == null ? null : selectFields.ToArray(), isTracking, realPaths).ToList(); + } + + //导航属性 + if (filter != null && filter.SelectField.ToArray().Any()) + { + realPaths = SelectFieldInclude(realPaths, filter.SelectField.ToList()); + NavigationDeal(realPaths, entities.ToList(), filter.SelectField.ToArray(), filter.DataRule.ToArray(), + filter.OrgRule, filter.OrgId, filter.IgnoreOrgRule, filter.IgnoreDataRule, isTracking, + filter.IsMultipleDb, filter.IsSpecifyDb, filter.SpecifyDbConn); + } + if (entities != null && entities.Any()) + this.FillGetEntitySysParam(entities, filter, paths); + return entities; + } + + private string GetSpecifyDb(BaseFilter filter) + { + var enConn = ""; + if (!string.IsNullOrEmpty(filter.SpecifyTenant)) + { + enConn = TenantInfoMiddleware.GetDbConn(filter.SpecifyTenant); + } + else if (!string.IsNullOrEmpty(filter.SpecifyDbConn)) + { + enConn = EncryptHelper.AesDecrypt(filter.SpecifyDbConn, DesKey); + } + else + { + enConn = ConfigurationManager.ConnectionStrings["default"]; + } + return enConn; + } + + public PagedResultDto GetPageEntities(Expression> expression, BasePageFilter pageFilter, + params string[] paths) where T : MesEntityBase, new() + { + return this.GetPageEntities(expression, pageFilter, paths); + } + + public PagedResultDto GetOrderPageEntities(Expression> expression, BasePageFilter pageFilter, + params string[] paths) where T : MesEntityBase, new() + { + return this.GetOrderPageEntities(expression, pageFilter, 0, 0, paths); + } + public PagedResultDto GetOrderPageEntities(Expression> expression, BasePageFilter pageFilter, + int pageSize, int startIndex, + params string[] paths) where T : MesEntityBase, new() + { + return this.GetOrderPageEntities(expression, pageFilter, pageSize, startIndex, (!pageFilter?.IsNoTranking) ?? true, paths); + } + + public PagedResultDto GetMultipleDbPageEntities(Expression> expression, BasePageFilter pageFilter, + params string[] paths) where T : MesEntityBase, new() + { + if (pageFilter == null) + throw new Exception("Filter参数不能为空"); + if (expression == null) + expression = t => true; + pageFilter.IsMultipleDb = true; + //expression = expression.And(i => i.CREATE_TIME > pageFilter.StartTime); + return this.GetOrderPageEntities(expression, pageFilter, null, pageFilter.Limit, pageFilter.Start, null, (!pageFilter?.IsNoTranking) ?? true, paths); + } + + + public PagedResultDto GetOrderPageEntities(Expression> expression, BasePageFilter pageFilter, + int pageSize, int startIndex, bool isTracking = true, + params string[] paths) where T : MesEntityBase, new() + { + return this.GetOrderPageEntities(expression, pageFilter, null, pageSize, startIndex, isTracking, paths); + } + public PagedResultDto GetOrderPageEntities(Expression> expression, BasePageFilter pageFilter, + Dictionary orders, + int pageSize, int startIndex, bool isTracking = true, + params string[] paths) where T : MesEntityBase, new() + { + return this.GetOrderPageEntities(expression, pageFilter, orders, pageSize, startIndex, null, isTracking, paths); + } + + public PagedResultDto GetOrderPageEntities(Expression> expression, BasePageFilter pageFilter, + Dictionary orders, + int pageSize, int startIndex, Action> orderBy, bool isTracking = true, + params string[] paths) where T : MesEntityBase, new() + { + PagedResultDto ret = new PagedResultDto(); + //查询所有数据 + if (pageFilter != null && pageFilter.IsAllLoad) + { + var data = this.GetOrderEntities(expression, pageFilter, orders, isTracking, paths).ToList(); + ret.Items = data; + ret.TotalCount = data.Count; + return ret; + } + if (pageFilter != null && !pageFilter.IgnoreDataRule && !pageFilter.DataRule.Any()) + { + pageFilter.DataRule = Api.AppContext.CurrentSession.DataRule; + } + //分页查询 + string[] realPaths = null; + Dictionary realOrders = null; + Expression> orgExpression; + var exp = DoGetEntityExp(expression, pageFilter, paths, orders, out orgExpression, out realPaths, out realOrders, false); + int tempPageSize = 0; + int tempStartIndex = 0; + List selectFields = new List(); + //分页参数 + if (pageSize != 0) + { + tempPageSize = pageSize; + tempStartIndex = startIndex; + } + else if (pageFilter != null) + { + tempStartIndex = pageFilter.Start; + tempPageSize = pageFilter.Limit; + } + //查询字段处理 + if (pageFilter != null && pageFilter.SelectField != null && pageFilter.SelectField.Any()) + { + selectFields = pageFilter.SelectField.ToList(); + AppendSelectedField(selectFields); + } + //支持多库联合查询 + ret = MutilDbOrderPaged(pageFilter, pageSize, startIndex, orderBy, isTracking, realPaths, realOrders, + exp, tempPageSize, tempStartIndex, selectFields); + //字段查询导航处理 + if (selectFields.Any()) + { + //导航属性 + realPaths = SelectFieldInclude(realPaths, pageFilter.SelectField.ToList()); + NavigationDeal(realPaths, ret.Items, pageFilter.SelectField.ToArray(), pageFilter.DataRule.ToArray(), + pageFilter.OrgRule, pageFilter.OrgId, pageFilter.IgnoreOrgRule, pageFilter.IgnoreDataRule, isTracking, + pageFilter.IsMultipleDb, pageFilter.IsSpecifyDb, pageFilter.SpecifyDbConn); + } + //系统属性 + if (ret != null && ret.Items.Any()) + this.FillGetEntitySysParam(ret.Items, pageFilter, paths); + return ret; + } + + private PagedResultDto MutilDbOrderPaged(BasePageFilter pageFilter, int pageSize, int startIndex, Action> orderBy, + + bool isTracking, string[] realPaths, Dictionary realOrders, Expression> exp, + + int tempPageSize, int tempStartIndex, List selectFields) where T : MesEntityBase, new() + + { + + PagedResultDto ret = new PagedResultDto(); + + var entities = new List(); + + var totalCount = 0; + + if (pageFilter != null) + + { + if (pageFilter.IsMultipleDb) + { + + + var conns = GetAllDbConns();//查询redis里面的数据库连接 + + var dbCount = conns.Count; + + if (dbCount == 0) + + return ret; + + //Action> multipleOrderBy = i => i.Asc(p => p.CREATE_TIME); + + + + if (realOrders == null || !realOrders.Any()) + { + + realOrders = new Dictionary + { + { "CREATE_TIME", DbOrder.DESC } + }; + + } + + + if (dbCount == 1 || tempStartIndex == 0) + { + + foreach (var conn in conns) + { + using (var context = new EfDbContext(conn)) + { + + var contextEntities = context.GetOrderPageEntities(exp, realOrders, selectFields?.ToArray(), tempPageSize, + tempStartIndex, null, isTracking, realPaths); + totalCount += contextEntities.TotalCount; + if (contextEntities.Items.Any()) + { + var dbConn = TenantInfoMiddleware.EnDbConn(conn); + contextEntities.Items.ForEach(i => i.DbConn = dbConn); + entities.AddRange(contextEntities.Items); + } + + } + + } + + //排序 + if (dbCount > 1) + { + entities = ReOrderBy(realOrders, entities); + entities = entities.Skip(tempStartIndex).Take(tempPageSize).ToList(); + } + + } + + else + { + + var perStartIndex = tempStartIndex / dbCount; + + Dictionary> dbEntities = new Dictionary>(); + + Dictionary entityCount = new Dictionary(); + + //第一次查询确定范围 + + var connIndex = 0; + + var type = typeof(T); + + var order = realOrders.FirstOrDefault(); + //获取字段 + var prop = type.GetProperty(order.Key); + + var propType = prop.PropertyType; + //GetGenericTypeDefinition + if (propType.FullName.Contains(typeof(Nullable).ToString())) + { + propType = Nullable.GetUnderlyingType(propType); + } + + var totalEnties = new List(); + + foreach (var conn in conns) + { + using (var context = new EfDbContext(conn)) + { + var contextEntities = context.GetOrderPageEntities(exp, realOrders, selectFields?.ToArray(), tempPageSize, perStartIndex, null, isTracking, realPaths); + totalCount += contextEntities.TotalCount; + if (contextEntities.Items.Any()) + { + dbEntities.Add(connIndex, contextEntities.Items.ToList()); + entityCount.Add(connIndex, contextEntities.Items.Count()); + totalEnties.AddRange(contextEntities.Items); + } + else + { + dbEntities.Add(connIndex, new List()); + entityCount.Add(connIndex, 0); + } + + } + + connIndex++; + } + + //重新排序 + if (totalEnties.Count > 0) + { + totalEnties = ReOrderBy(realOrders, totalEnties); + //最小/最大 + if (exp == null) + exp = t => true; + var pointTime = DateTime.Now; + FilterRule rule = new FilterRule(); + rule.Field = order.Key; + if (propType.Name == "DateTime") + { + rule.Value = ((DateTime)prop.GetValue(totalEnties.FirstOrDefault())).ToString("yyyy-MM-dd HH:mm:ss.ffffff"); + } + else + { + rule.Value = prop.GetValue(totalEnties.FirstOrDefault()).ToString(); + } + + if (order.Value.ToString() == "DESC") + { + rule.Operate = FilterOperate.LessThanOrEqual; + } + else + { + rule.Operate = FilterOperate.GreaterThanOrEqual; + } + var filterExp = rule.BuildExpression(); + + exp = exp.And(filterExp); + } + + //第二次查询 + + connIndex = 0; + + totalEnties.Clear(); + + var oldOffSet = perStartIndex * dbCount; + + foreach (var conn in conns) + { + var express = exp; + using (var context = new EfDbContext(conn)) + { + if (dbEntities[connIndex].Count > 0) + { + FilterRule rule = new FilterRule(); + rule.Field = order.Key; + + if (propType.Name == "DateTime") + { + rule.Value = ((DateTime)prop.GetValue(dbEntities[connIndex].LastOrDefault())).ToString("yyyy-MM-dd HH:mm:ss.ffffff"); + } + else + { + rule.Value = prop.GetValue(dbEntities[connIndex].LastOrDefault()).ToString(); + } + if (order.Value.ToString() == "DESC") + { + rule.Operate = FilterOperate.GreaterThanOrEqual; + } + else + { + rule.Operate = FilterOperate.LessThanOrEqual; + } + var filterExp = rule.BuildExpression(); + express = express.And(filterExp); + } + + var contextEntities = context.GetEntities(express, selectFields?.ToArray(), isTracking, realPaths); + if (contextEntities.Any()) + { + totalEnties.AddRange(contextEntities); + } + var moreEntitiesCount = contextEntities.Count() - entityCount[connIndex];//多出的数据条数 + oldOffSet -= moreEntitiesCount; + } + connIndex++; + } + //确定全局的OffSet后,返回数据 + totalEnties = ReOrderBy(realOrders, totalEnties); + entities = totalEnties.Skip((tempStartIndex - oldOffSet)).Take(tempPageSize).ToList(); + } + } + else if (pageFilter.IsSpecifyDb) + { + string enConn = GetSpecifyDb(pageFilter); + using (var context = new EfDbContext(enConn)) + { + var contextEntities = context.GetOrderPageEntities(exp, realOrders, selectFields?.ToArray(), tempPageSize, + tempStartIndex, orderBy, isTracking, realPaths); + totalCount = contextEntities.TotalCount; + if (contextEntities.Items.Any()) + entities.AddRange(contextEntities.Items); + } + } + else + { + totalCount = UnitWorkOrderPaged(orderBy, isTracking, realPaths, realOrders, exp, tempPageSize, tempStartIndex, selectFields, entities); + } + } + else + + { + + totalCount = UnitWorkOrderPaged(orderBy, isTracking, realPaths, realOrders, exp, tempPageSize, tempStartIndex, selectFields, entities); + } + ret.Items = entities; + ret.TotalCount = totalCount; + return ret; + + } + + private int UnitWorkOrderPaged(Action> orderBy, bool isTracking, string[] realPaths, Dictionary realOrders, Expression> exp, int tempPageSize, int tempStartIndex, List selectFields, List entities) where T : MesEntityBase, new() + { + int totalCount; + var contextEntities = this.UnitOfWork.GetOrderPageEntities(exp, realOrders, selectFields?.ToArray(), tempPageSize, + tempStartIndex, orderBy, isTracking, realPaths); + totalCount = contextEntities.TotalCount; + if (contextEntities.Items.Any()) + { + entities.AddRange(contextEntities.Items); + } + + return totalCount; + } + + private static List ReOrderBy(Dictionary realOrders, List entities) where T : MesEntityBase, new() + { + var queryable = entities.AsQueryable(); + + queryable = queryable.SetQueryableOrder(realOrders.FirstOrDefault().Key, realOrders.FirstOrDefault().Value.ToString()); + + var linq = new Orderable(queryable); + + queryable = linq.Queryable; + + entities = queryable.ToList(); + return entities; + } + + public PagedResultDto GetOrderPageEntities(Expression> expression, BasePageFilter pageFilter, string[] selectField, + params string[] paths) where T : MesEntityBase, new() + { + if (pageFilter == null) + pageFilter = new BasePageFilter(); + pageFilter.SelectField = selectField; + return this.GetOrderPageEntities(expression, pageFilter, paths); + } + + private void NavigationDeal(string[] realPaths, IEnumerable list, string[] selecedFields, string[] dataRules, List orgRules, Guid? orgId, + bool isIgnoreOrgRule, bool isIgnoreDataRule, bool isNoTranking, bool isMultipleDb, bool isSpecifyDb, string specifyDbConn) where T : MesEntityBase, new() + { + if (realPaths != null && realPaths.Any()) + { + //var tmpList = list; + var hasDataList = new Hashtable(); + hasDataList["."] = list; + var hasDealNavPath = new List(); + foreach (var path in realPaths) + { + var splitPaths = path.Split('.').ToArray(); + var type = typeof(T); + var curentPath = "."; + var isICollection = false; + var navTableName = ""; + foreach (var spath in splitPaths) + { + navTableName += spath + "."; + dynamic curentList = hasDataList[curentPath]; + if (curentList == null) + break; + + PropertyInfo navProp = null; + PropertyInfo idProp = null; + var fieldInfos = type.GetProperties(); + var theType = type; + EFModelForeignKey foreignKey = null; + var isOneOnOne = false; + + foreach (var p in fieldInfos) + { + if (p.Name == spath) + { + navProp = p; + type = p.PropertyType; + isICollection = false; + foreignKey = this.UnitOfWork.GetModelForeignKey(theType.Name, spath); + if (typeof(System.Collections.IEnumerable).IsAssignableFrom(type)) + { + isICollection = true; + var generTypeFullName = type.GenericTypeArguments[0].FullName; + type = ReflectHelper.FindTypeInCurrentDomain(generTypeFullName); + idProp = type.GetProperty(foreignKey.ForeignFieldName); + } + else + { + idProp = theType.GetProperty(foreignKey.ForeignFieldName); + if (idProp == null) + { + idProp = theType.GetProperty("ID"); + isOneOnOne = true; + } + } + break; + } + } + if (idProp == null || navProp == null) + throw new Exception($"导航属性{path}中的{spath}属性异常,请确认"); + curentPath += "/" + navProp.Name; + if (!hasDealNavPath.Contains(navTableName)) + { + //筛选字段 + List typeSelectFields = new List(); + foreach (var f in selecedFields) + { + //导航属性 + if (f.StartsWith(navTableName)) + { + var tmpField = f.Replace(navTableName, ""); + if (tmpField.IndexOf(".") < 0) + typeSelectFields.Add(tmpField); + else + { + //为了增加下级的导航属性 + var nextNavIndex = tmpField.IndexOf("."); + var navField = tmpField.Substring(0, nextNavIndex); + if (!typeSelectFields.Contains(navField)) + typeSelectFields.Add(navField); + } + } + } + + BaseFilter filter = new BaseFilter(); + filter.SelectField = typeSelectFields; + filter.DataRule = dataRules; + filter.IgnoreDataRule = isIgnoreDataRule; + filter.IsNoTranking = isNoTranking; + filter.OrgId = orgId; + filter.IgnoreOrgRule = isIgnoreOrgRule; + filter.OrgRule = orgRules; + filter.IsMultipleDb = isMultipleDb; + filter.IsSpecifyDb = isSpecifyDb; + filter.SpecifyDbConn = specifyDbConn; + List ids = new List(); + if (!typeSelectFields.Contains("ID")) + typeSelectFields.Add("ID"); + if (isOneOnOne) + typeSelectFields.Add(foreignKey.ForeignFieldName); + //增加外键的查询 + var methodInfo = this.GetType().GetMethod("AppendSelectedField", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Static); + if (methodInfo != null) + { + methodInfo.MakeGenericMethod(type).Invoke(this, new object[] { typeSelectFields }); + } + //this.GetType().GetMethod("AppendSelectedField", new Type[] { typeof(string[]) }) + // .MakeGenericMethod(type).Invoke(this, new object[] { selecedFields }); + //集合 + //var filterGroup = new FilterGroup(); + //filter.FilterGroup.Groups.Add(filterGroup); + //filterGroup.IsAnd = false; + List filterRules = new List(); + bool searchFlag = false; + if (isICollection)//对多 + { + if (!typeSelectFields.Contains(idProp.Name)) + typeSelectFields.Add(idProp.Name); + + foreach (var obj in curentList) + { + if (obj.ID != null) + { + var val = Convert.ToString(obj.ID); + if (!string.IsNullOrEmpty(val) && !filterRules.Any(x => x.Value.ToString() == val)) + { + FilterRule rule = new FilterRule(); + rule.Field = idProp.Name; + rule.Operate = FilterOperate.Equal; + rule.Value = val; + //filterGroup.Rules.Add(rule); + filterRules.Add(rule); + searchFlag = true; + } + } + + + } + } + else//对1 + { + foreach (var obj in curentList) + { + var objVal = theType.GetProperty(idProp.Name).GetValue(obj); + if (objVal != null) + { + var val = Convert.ToString(objVal); + if (!string.IsNullOrEmpty(val) && !filterRules.Any(x => x.Value.ToString() == val)) + { + FilterRule newRule = new FilterRule(); + newRule.Field = "ID"; + if (isOneOnOne) + { + newRule.Field = foreignKey.ForeignFieldName; + } + newRule.Operate = FilterOperate.Equal; + newRule.Value = val; + //filterGroup.Rules.Add(newRule); + filterRules.Add(newRule); + searchFlag = true; + } + } + + } + } + if (!searchFlag) + break; + var getEntities = this.GetType().GetMethod("GetEntities", BindingFlags.Instance | BindingFlags.NonPublic); + if (getEntities == null) + { + throw new Exception("GetEntities不存在此方法"); + } + List navLists = new List(); + if (navProp != null && idProp != null) + { + //500查一次 + int ruleLimit = 1000; + var startRule = 0; + var filterGroup = new FilterGroup(); + filterGroup.IsAnd = false; + foreach (var rule in filterRules) + { + startRule++; + filterGroup.Rules.Add(rule); + if (startRule >= ruleLimit) + { + GetRroupRules(type, filter, getEntities, navLists, filterGroup); + filterGroup.Rules.Clear(); + startRule = 0; + } + } + if (filterGroup.Rules.Count > 0) + GetRroupRules(type, filter, getEntities, navLists, filterGroup); + hasDataList[curentPath] = navLists; + foreach (var t in curentList) + { + //对1导航 + if (!isICollection) + { + var objVal = t.GetType().GetProperty(idProp.Name).GetValue(t); + if (objVal == null) + continue; + var navId = Convert.ToString(objVal); + if (string.IsNullOrEmpty(navId)) + continue; + foreach (var s in navLists) + { + if (!isOneOnOne) + { + if (s.ID.ToString() == navId) + { + t.GetType().GetProperty(navProp.Name).SetValue(t, s); + break; + } + } + else + { + var val = s.GetType().GetProperty(foreignKey.ForeignFieldName).GetValue(s); + if (val != null && val.ToString() == navId) + { + t.GetType().GetProperty(navProp.Name).SetValue(t, s); + } + } + + } + } //对多导航 + else + { + var id = t.ID.ToString(); + var colNavList = type.GetListObject(); + foreach (var s in navLists) + { + var objVal = s.GetType().GetProperty(idProp.Name).GetValue(s); + if (objVal == null) + continue; + var navId = Convert.ToString(objVal); + if (string.IsNullOrEmpty(navId)) + continue; + if (navId == id) + { + var methodInfos = colNavList.GetType().GetMethod("Add"); + methodInfos.Invoke(colNavList, new object[] { s }); + } + } + t.GetType().GetProperty(navProp.Name).SetValue(t, colNavList); + } + } + + + } + else + { + break; + } + hasDealNavPath.Add(navTableName); + } + + } + } + } + } + + private void GetRroupRules(Type type, BaseFilter filter, MethodInfo getEntities, List navLists, FilterGroup filterGroup) + { + filter.FilterGroup.Groups.Add(filterGroup); + dynamic navGroupList = getEntities.MakeGenericMethod(type).Invoke(this, new object[] { filter }); + if (navGroupList != null) + { + navLists.AddRange(navGroupList); + } + } + + // + public async Task> GetOrderPageEntitiesSync(Expression> expression, BasePageFilter pageFilter, + params string[] paths) where T : MesEntityBase, new() + { + return await this.GetOrderPageEntitiesSync(expression, pageFilter, 0, 0, paths); + } + public async Task> GetOrderPageEntitiesSync(Expression> expression, BasePageFilter pageFilter, + int pageSize, int startIndex, + params string[] paths) where T : MesEntityBase, new() + { + return await this.GetOrderPageEntitiesSync(expression, pageFilter, pageSize, startIndex, (!pageFilter?.IsNoTranking) ?? true, paths); + } + + public async Task> GetOrderPageEntitiesSync(Expression> expression, BasePageFilter pageFilter, + int pageSize, int startIndex, bool isTracking = true, + params string[] paths) where T : MesEntityBase, new() + { + return await this.GetOrderPageEntitiesSync(expression, pageFilter, null, pageSize, startIndex, isTracking, paths); + } + public async Task> GetOrderPageEntitiesSync(Expression> expression, BasePageFilter pageFilter, + Dictionary orders, + int pageSize, int startIndex, bool isTracking = true, + params string[] paths) where T : MesEntityBase, new() + { + return await this.GetOrderPageEntitiesSync(expression, pageFilter, orders, pageSize, startIndex, null, isTracking, paths); + } + + public async Task> GetOrderPageEntitiesSync(Expression> expression, BasePageFilter pageFilter, + Dictionary orders, + int pageSize, int startIndex, Action> orderBy, bool isTracking = true, + params string[] paths) where T : MesEntityBase, new() + { + string[] realPaths = null; + Dictionary realOrders = null; + Expression> orgExpression; + var exp = DoGetEntityExp(expression, pageFilter, paths, orders, out orgExpression, out realPaths, out realOrders, false); + int tempPageSize = 0; + int tempStartIndex = 0; + if (pageSize != 0) + { + tempPageSize = pageSize; + tempStartIndex = startIndex; + } + else if (pageFilter != null) + { + tempStartIndex = pageFilter.Start; + tempPageSize = pageFilter.Limit; + } + var ret = await this.UnitOfWork.GetOrderPageEntitiesSync(exp, realOrders, tempPageSize, + tempStartIndex, orderBy, isTracking, realPaths); + if (ret != null && ret.Items.Any()) + this.FillGetEntitySysParam(ret.Items, pageFilter, paths); + return ret; + } + + + + public T GetEntityByRedis(string key, Guid orgid) where T : MesEntityBase, new() + { + var realOrgId = Api.AppContext.CurrentSession?.RootOrgId ?? orgid; + Guid guidKey = Guid.Empty; + if (Guid.TryParse(key, out guidKey)) + { + return GetEntityByRedisMethod(key, realOrgId, true).Result; + } + else + { + return GetEntityByRedisMethod(key, realOrgId, false).Result; + } + + + + } + public T GetEntityByRedis(Guid key, Guid orgid) where T : MesEntityBase, new() + { + var realOrgId = Api.AppContext.CurrentSession?.RootOrgId ?? orgid; + return GetEntityByRedisMethod(key.ToString(), realOrgId, true).Result; + + } + + private async Task GetEntityByRedisMethod(string key, Guid orgid, bool isGuid) where T : MesEntityBase, new() + { + + // CsRedisManager manager = ServiceLocator.Instance.GetService(); + var type = typeof(T); + //manager. + var perKey = "{" + type.Name + "}"; + var keys = perKey + "_" + key + "_" + orgid; + T entity = null; + if (CsRedisManager.KeyExists(keys) && ConfigurationManager.IsRedis) + entity = await CsRedisManager.StringGetAsync(keys); + else + { + var baseFilter = new BaseFilter(orgid); + baseFilter.IsNoTranking = true; + baseFilter.IgnoreDataRule = true; + var redisClass = CsRedisHelper.GetRedisClass(); + if (redisClass != null) + { + + if (redisClass.DicKeys.Any()) + { + var filterGroup = new FilterGroup(); + filterGroup.IsAnd = false; + foreach (var redisKey in redisClass.DicKeys) + { + + if (!isGuid && redisKey.Key.EndsWith("ID")) + { + //不是ID类型,并且是ID字段,则不增加条件 + } + else + { + filterGroup.Rules.Add(new FilterRule(redisKey.Key, key, FilterOperate.Equal)); + } + + } + baseFilter.FilterGroup.Groups.Add(filterGroup); + } + else + { + throw new Exception("未配置rediskey"); + } + + } + else + { + throw new Exception("未配置成redis类型"); + } + entity = this.GetEntity(null, baseFilter); + if (entity != null && ConfigurationManager.IsRedis) + { + await CsRedisManager.StringSetAsync(keys, entity); + } + } + return entity; + + } + + public List GetEntitiesByRedis(Expression> expression, BaseFilter filter) where T : MesEntityBase, new() + { + filter.SelectField = new string[] { }; + var realOrgId = Api.AppContext.CurrentSession?.RootOrgId ?? filter.OrgId; + filter.OrgId = realOrgId; + var list = GetEntitiesByRedis(filter).Result; + if (expression != null) + list = list.Where(expression.Compile()).ToList(); + return list; + } + public bool IsAny(Expression> expression, BaseFilter filter) where T : MesEntityBase, new() + { + string[] realPaths = null; + Dictionary realOrders = null; + Expression> orgExpression; + var exp = DoGetEntityExp(expression, filter, null, null, out orgExpression, out realPaths, out realOrders, false); + return this.UnitOfWork.GetCount(exp) > 0; + } + + + public int GetCount(Expression> expression, BaseFilter filter) where T : MesEntityBase, new() + { + string[] realPaths = null; + Dictionary realOrders = null; + Expression> orgExpression; + var exp = DoGetEntityExp(expression, filter, null, null, out orgExpression, out realPaths, out realOrders, false); + return this.UnitOfWork.GetCount(exp); + } + + + + public async Task> GetEntitiesTableByRedis(Expression> expression, BaseFilter filter, + params string[] paths) where T : MesEntityBase, new() + { + filter.SelectField = new string[] { }; + var realOrgId = Api.AppContext.CurrentSession?.RootOrgId ?? filter.GetOrgId(); + if (!ConfigurationManager.IsRedis) + { + return this.GetOrderEntities(expression, filter, (!filter?.IsNoTranking) ?? true, paths).ToList(); + } + string[] realPaths = null; + Dictionary realOrders = null; + Expression> orgExpression; + var exp = DoGetEntityExp(expression, filter, paths, null, out orgExpression, out realPaths, out realOrders, true); + + var list = await GetEntitiesByRedis(filter); + if (list == null || !list.Any()) + return list; + if (realPaths != null && realPaths.Any()) + { + //var tmpList = list; + var hasDataList = new Hashtable(); + hasDataList["."] = list; + foreach (var path in realPaths) + { + var splitPaths = path.Split('.').ToArray(); + var type = typeof(T); + var hasDealNavPath = new List(); + var curentPath = "."; + var isICollection = false; + foreach (var spath in splitPaths) + { + dynamic curentList = hasDataList[curentPath]; + if (curentList == null) + break; + if (!hasDealNavPath.Contains(spath)) + { + PropertyInfo navProp = null; + PropertyInfo idProp = null; + var fieldInfos = type.GetProperties(); + var theType = type; + foreach (var p in fieldInfos) + { + if (p.Name == spath) + { + navProp = p; + type = p.PropertyType; + isICollection = false; + var foreignKey = this.UnitOfWork.GetModelForeignKey(theType.Name, spath); + if (typeof(System.Collections.IEnumerable).IsAssignableFrom(type)) + { + isICollection = true; + var generTypeFullName = type.GenericTypeArguments[0].FullName; + type = ReflectHelper.FindTypeInCurrentDomain(generTypeFullName); + idProp = type.GetProperty(foreignKey.ForeignFieldName); + } + else + { + idProp = theType.GetProperty(foreignKey.ForeignFieldName); + } + break; + } + } + + if (navProp != null && idProp != null) + { + var methodInfo = (Task)this.GetType().GetMethod("GetEntitiesByRedis", new Type[] { typeof(BaseFilter) }) + .MakeGenericMethod(type).Invoke(this, new object[] { filter }); + //dynamic navLists = methodInfo.MakeGenericMethod(type).Invoke(this, new object[] { filter.OrgId }); + await methodInfo; + dynamic navLists = methodInfo.GetType().GetProperty("Result").GetValue(methodInfo); + List navList = new List(); + curentPath += "/" + navProp.Name; + hasDataList[curentPath] = navList; + + foreach (var t in curentList) + { + //对1导航 + if (!isICollection) + { + var navId = t.GetType().GetProperty(idProp.Name).GetValue(t).ToString(); + foreach (var s in navLists) + { + if (s.ID.ToString() == navId) + { + navList.Add(s); + t.GetType().GetProperty(navProp.Name).SetValue(t, s); + break; + } + } + } //对多导航 + else + { + var id = t.ID.ToString(); + var colNavList = type.GetListObject(); + foreach (var s in navLists) + { + if (s.GetType().GetProperty(idProp.Name).GetValue(s).ToString() == id) + { + var methodInfos = colNavList.GetType().GetMethod("Add"); + methodInfos.Invoke(colNavList, new object[] { s }); + navList.Add(s); + } + } + t.GetType().GetProperty(navProp.Name).SetValue(t, colNavList); + } + } + + + } + else + { + break; + } + hasDealNavPath.Add(spath); + } + + } + } + } + + //排序和过滤 + + if (exp != null) + { + list = list.Where(exp.Compile()).ToList(); + } + + if (!string.IsNullOrEmpty(filter.Sort)) + { + if (filter.Order == DbOrder.ASC) + { + var query = list.AsQueryable().OrderByName(filter.Sort); + list = query.ToList(); + } + else + { + var query = list.AsQueryable().OrderByName(filter.Sort, true); + list = query.ToList(); + } + } + return list; + } + + public async Task> GetEntitiesByRedis(Expression> expression, BaseFilter filter, string groupValue, + params string[] paths) where T : MesEntityBase, new() + { + filter.SelectField = new string[] { }; + var realOrgId = Api.AppContext.CurrentSession?.RootOrgId ?? filter.GetOrgId(); + filter.OrgId = realOrgId; + if (!ConfigurationManager.IsRedis) + { + var redisClass = CsRedisHelper.GetRedisClass(); + if (redisClass == null) + { + throw new Exception("实体未配置成redis类型"); + } + var groupId = redisClass.GroupName; + if (!string.IsNullOrEmpty(groupValue)) + { + FilterRule rule = new FilterRule(); + rule.Field = groupId; + rule.Operate = FilterOperate.Equal; + rule.Value = groupValue; + filter.FilterGroup.Rules.Add(rule); + } + return this.GetEntities(expression, filter, false, paths).ToList(); + } + string[] realPaths = null; + Dictionary realOrders = null; + Expression> orgExpression; + var exp = DoGetEntityExp(expression, filter, paths, null, out orgExpression, out realPaths, out realOrders, true); + List list; + if (string.IsNullOrEmpty(groupValue)) + list = await GetEntitiesByRedis(filter); + else + list = await GetEntitiesByGroupRedis(filter, groupValue); + if (list == null || !list.Any()) + return list; + if (realPaths != null && realPaths.Any()) + { + //var tmpList = list; + var hasDataList = new Hashtable(); + hasDataList["."] = list; + foreach (var path in realPaths) + { + var splitPaths = path.Split('.').ToArray(); + var type = typeof(T); + var hasDealNavPath = new List(); + var curentPath = "."; + var isICollection = false; + foreach (var spath in splitPaths) + { + dynamic curentList = hasDataList[curentPath]; + if (curentList == null) + break; + if (!hasDealNavPath.Contains(spath)) + { + PropertyInfo navProp = null; + PropertyInfo idProp = null; + var fieldInfos = type.GetProperties(); + var theType = type; + foreach (var p in fieldInfos) + { + if (p.Name == spath) + { + navProp = p; + type = p.PropertyType; + isICollection = false; + var foreignKey = this.UnitOfWork.GetModelForeignKey(theType.Name, spath); + if (typeof(System.Collections.IEnumerable).IsAssignableFrom(type)) + { + isICollection = true; + var generTypeFullName = type.GenericTypeArguments[0].FullName; + type = ReflectHelper.FindTypeInCurrentDomain(generTypeFullName); + idProp = type.GetProperty(foreignKey.ForeignFieldName); + } + else + { + idProp = theType.GetProperty(foreignKey.ForeignFieldName); + } + break; + } + } + + if (navProp != null && idProp != null) + { + var methodInfo = (Task)this.GetType().GetMethod("GetEntitiesByRedis", new Type[] { typeof(BaseFilter) }) + .MakeGenericMethod(type).Invoke(this, new object[] { filter }); + //dynamic navLists = methodInfo.MakeGenericMethod(type).Invoke(this, new object[] { filter.OrgId }); + await methodInfo; + dynamic navLists = methodInfo.GetType().GetProperty("Result").GetValue(methodInfo); + List navList = new List(); + curentPath += "/" + navProp.Name; + hasDataList[curentPath] = navList; + + foreach (var t in curentList) + { + //对1导航 + if (!isICollection) + { + var navIdObj = t.GetType().GetProperty(idProp.Name).GetValue(t); + if (navIdObj != null) + { + foreach (var s in navLists) + { + if (s.ID.ToString() == navIdObj.ToString()) + { + navList.Add(s); + t.GetType().GetProperty(navProp.Name).SetValue(t, s); + break; + } + } + } + + } //对多导航 + else + { + var id = t.ID.ToString(); + var colNavList = type.GetListObject(); + foreach (var s in navLists) + { + var idObj = s.GetType().GetProperty(idProp.Name).GetValue(s); + if (idObj != null) + { + if (id == idObj.ToString()) + { + var methodInfos = colNavList.GetType().GetMethod("Add"); + methodInfos.Invoke(colNavList, new object[] { s }); + navList.Add(s); + } + } + } + t.GetType().GetProperty(navProp.Name).SetValue(t, colNavList); + } + } + + + } + else + { + break; + } + hasDealNavPath.Add(spath); + } + + } + } + } + + //排序和过滤 + + if (exp != null) + { + var filterList = list.Where(exp.Compile()); + if (filterList != null && filterList.Any()) + list = filterList.ToList(); + else + list = new List(); + } + + if (!string.IsNullOrEmpty(filter.Sort)) + { + if (filter.Order == DbOrder.ASC) + { + var query = list.AsQueryable().OrderByName(filter.Sort); + list = query.ToList(); + } + else + { + var query = list.AsQueryable().OrderByName(filter.Sort, true); + list = query.ToList(); + } + } + return list; + } + + public PagedResultDto GetOrderPageByRedis(Expression> expression, BasePageFilter pageFilter, + params string[] paths) where T : MesEntityBase, new() + { + + var list = GetEntitiesTableByRedis(expression, pageFilter, paths).Result; + + var returnDto = new PagedResultDto(); + returnDto.TotalCount = list.Count(); + returnDto.Items = list.Skip(pageFilter.Start).Take(pageFilter.Limit).ToList(); + return returnDto; + } + + + + static IEnumerable GetExtensionMethods(Assembly assembly, Type extendedType) + { + var query = from type in assembly.GetTypes() + where !type.IsGenericType && !type.IsNested + from method in type.GetMethods(BindingFlags.Static + | BindingFlags.Public | BindingFlags.NonPublic) + where method.IsDefined(typeof(System.Runtime.CompilerServices.ExtensionAttribute), false) + where method.GetParameters()[0].ParameterType == extendedType + select method; + return query; + } + + public async Task> GetEntitiesByRedis(BaseFilter filter) where T : MesEntityBase, new() + { + filter.SelectField = new string[] { }; + var orgid = Api.AppContext.CurrentSession?.RootOrgId ?? filter.OrgId; + filter.OrgId = orgid; + var tmpFilter = filter.DeepCloneObject(); + if (filter != null && Api.AppContext.CurrentSession.DataRule != null && !filter.IgnoreDataRule && !filter.DataRule.Any()) + { + filter.DataRule = Api.AppContext.CurrentSession.DataRule; + } + if (!ConfigurationManager.IsRedis) + { + return this.GetEntities(null, tmpFilter, false).ToList(); + } + var redisClass = CsRedisHelper.GetRedisClass(); + if (redisClass == null) + { + throw new Exception("实体未配置成redis类型"); + } + var groupId = redisClass.GroupName; + //CsRedisManager manager = ServiceLocator.Instance.GetService(); + var type = typeof(T); + var perKey = type.Name; + var list = new List(); + var isUpdateRedis = false; + if (!string.IsNullOrEmpty(groupId) && groupId != "ID") + { + var groupkeys = "opt_grouplist_" + perKey + "_" + orgid; + if (CsRedisManager.KeyExists(groupkeys)) + { + var keyList = await CsRedisManager.GetClient().HGetAllAsync(groupkeys); + var baseFilter = new BaseFilter(orgid); + baseFilter.DataRule = tmpFilter.DataRule; + baseFilter.IgnoreDataRule = tmpFilter.IgnoreDataRule; + foreach (var k in keyList) + { + //var datakeys = "sort_" + perKey + "_" + k.Value + "_" + orgid; + List keyData; + try + { + if (CsRedisManager.KeyExists(k.Value)) + { + keyData = await CsRedisManager.StringGetAsync>(k.Value); + if (keyData != null && keyData.Any()) + list.AddRange(keyData); + } + else + { + FilterRule rule = new FilterRule(); + rule.Field = groupId; + rule.Operate = FilterOperate.Equal; + rule.Value = k.Key; + baseFilter.FilterGroup.Rules.Add(rule); + keyData = this.GetEntities(null, baseFilter, false).ToList(); + if (keyData != null && keyData.Any()) + { + list.AddRange(keyData); + isUpdateRedis = true; + } + + } + } + catch (Exception) + { + if (CsRedisManager.GetClient().HExists(groupkeys, k.Key)) + { + await CsRedisManager.GetClient().HDelAsync(groupkeys, k.Key); + } + continue; + } + } + if (isUpdateRedis) + { + var groupList = list.GroupByMany(groupId); + foreach (var item in groupList) + { + if (item.Key != null) + { + string datakey = string.Join(',', item.Key); + var keys = "sort_" + redisClass.ClassName + "_" + datakey + "_" + orgid; + await CsRedisManager.StringSetAsync(keys, item.Items); + //var groupkey = "opt_grouplist_" + type.Name + "_" + orgid; + await CsRedisManager.GetClient().HSetAsync(groupkeys, datakey, keys); + } + } + } + + } + else + { + list = await SetRedisValue(tmpFilter, type, null); + } + } + else + { + var keys = "sort_" + perKey + "_" + orgid; + if (CsRedisManager.KeyExists(keys)) + { + list = await CsRedisManager.StringGetAsync>(keys); + if (list != null) + { + list = list.Where(i => i != null).ToList(); + } + else + { + await CsRedisManager.KeyDeleteAsync(keys); + list = await SetRedisValue(tmpFilter, type, null); + } + } + else + { + list = await SetRedisValue(tmpFilter, type, null); + } + //var distinctList = list.Distinct().ToList(); + var cList = list.Where((x, i) => list.FindIndex(z => z.ID == x.ID) == i).ToList(); + if (list.Count != cList.Count) + { + await CsRedisManager.KeyDeleteAsync(keys); + list = await SetRedisValue(tmpFilter, type, null); + } + } + + + //manager. + + + return list; + + } + public async Task> GetEntitiesByGroupRedis(BaseFilter filter, string groupValue) where T : MesEntityBase, new() + { + filter.SelectField = new string[] { }; + var orgid = Api.AppContext.CurrentSession?.RootOrgId ?? filter.OrgId; + filter.OrgId = orgid; + var tmpFilter = filter.DeepCloneObject(); + var redisClass = CsRedisHelper.GetRedisClass(); + if (redisClass == null) + { + throw new Exception("实体未配置成redis类型"); + } + var groupId = redisClass.GroupName; + if (!ConfigurationManager.IsRedis) + { + //BaseFilter filter = new BaseFilter(orgid); + if (!string.IsNullOrEmpty(groupId) && groupId != "ID") + { + if (!string.IsNullOrEmpty(groupValue)) + { + + FilterRule rule = new FilterRule(); + rule.Field = groupId; + rule.Operate = FilterOperate.Equal; + rule.Value = groupValue; + tmpFilter.FilterGroup.Rules.Add(rule); + } + } + return this.GetEntities(null, tmpFilter, false).ToList(); + } + + //CsRedisManager manager = ServiceLocator.Instance.GetService(); + var type = typeof(T); + var perKey = type.Name; + var list = new List(); + if (!string.IsNullOrEmpty(groupId) && groupId != "ID") + { + var groupkeys = "opt_grouplist_" + perKey + "_" + orgid; + if (CsRedisManager.KeyExists(groupkeys)) + { + //var datakeys = "sort_" + perKey + "_" + groupValue + "_" + orgid; + if (CsRedisManager.GetClient().HExists(groupkeys, groupValue)) + { + var data = await CsRedisManager.GetClient().HGetAsync(groupkeys, groupValue); + if (!string.IsNullOrEmpty(data)) + { + try + { + List keyData = await CsRedisManager.StringGetAsync>(data); + if (keyData != null && keyData.Any()) + list.AddRange(keyData); + else + { + await CsRedisManager.GetClient().DelAsync(groupkeys); + list = await SetRedisValue(tmpFilter, type, groupValue); + } + } + catch + { + + await CsRedisManager.GetClient().DelAsync(groupkeys); + list = await SetRedisValue(tmpFilter, type, groupValue); + } + + } + else + { + await CsRedisManager.GetClient().DelAsync(groupkeys); + } + } + else + { + list = await SetRedisValue(tmpFilter, type, groupValue); + } + } + else + { + list = await SetRedisValue(tmpFilter, type, groupValue); + } + } + else + { + list = await SetRedisValue(tmpFilter, type, ""); + } + + + //manager. + + + return list; + + } + + + + private async Task> SetRedisValue(BaseFilter filter, Type type, string groupValue) where T : MesEntityBase, new() + { + var tmpFilter = filter.DeepCloneObject(); + var orgid = Api.AppContext.CurrentSession?.RootOrgId ?? filter.OrgId; + tmpFilter.OrgId = orgid; + //var filter = new BaseFilter(orgid); + var redisClass = CsRedisHelper.GetRedisClass(); + if (redisClass == null) + { + throw new Exception("实体未配置成redis类型"); + } + var groupId = redisClass.GroupName; + + if (!ConfigurationManager.IsRedis) + { + if (!string.IsNullOrEmpty(groupValue)) + { + + FilterRule rule = new FilterRule(); + rule.Field = groupId; + rule.Operate = FilterOperate.Equal; + rule.Value = groupValue; + tmpFilter.FilterGroup.Rules.Add(rule); + } + return this.GetEntities(null, tmpFilter, false).ToList(); + } + List list; + + var keys = "sort_" + redisClass.ClassName + "_" + orgid; + if (!string.IsNullOrEmpty(groupId) && groupId != "ID") + { + if (!string.IsNullOrEmpty(groupValue)) + { + + FilterRule rule = new FilterRule(); + rule.Field = groupId; + rule.Operate = FilterOperate.Equal; + rule.Value = groupValue; + tmpFilter.FilterGroup.Rules.Add(rule); + } + list = this.GetEntities(null, tmpFilter, false).ToList(); + var groupList = list.GroupByMany(groupId); + if (!string.IsNullOrEmpty(groupValue)) + { + if (!groupList.Any(x => Convert.ToString(x.Key) == groupValue)) + { + keys = "sort_" + redisClass.ClassName + "_" + groupValue + "_" + orgid; + await CsRedisManager.StringSetAsync(keys, new List()); + var groupkeys = "opt_grouplist_" + type.Name + "_" + orgid; + await CsRedisManager.GetClient().HSetAsync(groupkeys, groupValue, keys); + } + } + foreach (var item in groupList) + { + //string datakey = string.Join(',', item.Key); + string datakey = item.Key == null ? "" : item.Key.ToString(); + keys = "sort_" + redisClass.ClassName + "_" + datakey + "_" + orgid; + await CsRedisManager.StringSetAsync(keys, item.Items); + var groupkeys = "opt_grouplist_" + type.Name + "_" + orgid; + await CsRedisManager.GetClient().HSetAsync(groupkeys, datakey, keys); + + } + + + } + else + { + list = this.GetEntities(null, tmpFilter, false).ToList(); + await CsRedisManager.StringSetAsync(keys, list); + await CsRedisManager.GetClient().HSetAsync("opt_list_" + orgid, type.Name, keys); + } + + + return list; + } + + + private void SetRedis(T entity, RedisHanddle handdle) where T : MesEntityBase, new() + { + if (!ConfigurationManager.IsRedis) + return; + try + { + //CsRedisManager redisHelper = ServiceLocator.Instance.GetService(); + var redisClass = CsRedisHelper.GetRedisClass(); + if (redisClass != null) + { + var type = typeof(T); + //manager. + var perKey = "{" + type.Name + "}"; + //1.处理 redisstring + if (!redisClass.DicKeys.Any()) + { + redisClass.DicKeys.Add("ID", "GUID"); + } + var redisKeys = redisClass.DicKeys.Distinct(); + foreach (var redisKey in redisKeys) + { + var propvalue = type.GetProperty(redisKey.Key).GetValue(entity); + var filedKey = perKey + "_" + propvalue + "_" + entity.ORG_ID;//string + if (handdle == RedisHanddle.Update || handdle == RedisHanddle.Add) + { + CsRedisManager.StringSetAsync(filedKey, entity).Wait(); + } + else if (handdle == RedisHanddle.Delete) + { + CsRedisManager.KeyDeleteAsync(filedKey).Wait(); + } + else + { + CsRedisManager.StringSetAsync(filedKey, entity).Wait(); + } + } + + //2.处理sortlist + + //SetRedisValue(entity.ORG_ID ?? Guid.Empty, redisHelper, type, keys).Wait(); + var groupValue = redisClass.GroupName; + //CsRedisManager manager = ServiceLocator.Instance.GetService(); + if (!string.IsNullOrEmpty(groupValue) && groupValue != "ID") + { + var keys = "sort_" + redisClass.ClassName + "_" + groupValue + "_" + entity.ORG_ID; + if (CsRedisManager.KeyExists(keys)) + CsRedisManager.KeyDelete(keys); + var groupkeys = "opt_grouplist_" + type.Name + "_" + entity.ORG_ID; + if (CsRedisManager.KeyExists(groupkeys)) + { + CsRedisManager.KeyDelete(groupkeys); + } + //因为数据库可能还没提交,所以不能更新redis + //SetRedisValue(entity.ORG_ID ?? Guid.Empty, redisHelper, type, + //type.GetProperty(groupValue).GetValue(entity).ToString()).Wait(); + } + else + { + var keys = "sort_" + redisClass.ClassName + "_" + entity.ORG_ID; + var listKeys = "opt_list_" + entity.ORG_ID; + if (CsRedisManager.KeyExists(keys)) + CsRedisManager.KeyDeleteAsync(keys).Wait(); + if (CsRedisManager.GetClient().HExists(listKeys, perKey)) + { + CsRedisManager.GetClient().HDelAsync(listKeys, perKey).Wait(); + } + //SetRedisValue(entity.ORG_ID ?? Guid.Empty, redisHelper, type, null).Wait(); + } + //if (redisHelper.KeyExists(keys)) + // redisHelper.KeyDeleteAsync(keys).Wait(); + /* redis数据不一致的问题,一旦出现变更,则清除redis*/ + /* + var sortFile = redisClass.SortField; + if (string.IsNullOrEmpty(sortFile)) + sortFile = "ID"; + double souces = 0; + if (redisClass.DicKeys.Any()) + { + var propvalue = type.GetProperty(sortFile).GetValue(entity).ToString(); + double.TryParse(propvalue, out souces); + } + if (handdle == RedisHanddle.Update || handdle == RedisHanddle.Add) + { + var lists = redisHelper.SortedSetRangeByRank(keys); + var oldEntitys = lists.Where(i => i.ID == entity.ID).ToList(); + if (oldEntitys.Any()) + { + oldEntitys = oldEntitys.OrderBy(i => i.MODIFY_TIME).ToList(); + SortedSetEntry oldRd = new SortedSetEntry(); + for (var o = 0; o < oldEntitys.Count; o++) + { + if (souces == 0) + { + if (o == oldEntitys.Count - 1) + { + var json = redisHelper.ConvertJson(oldEntitys[o]); + oldRd = redisHelper.SortedSetScan(keys, json).FirstOrDefault(); + if (oldRd != null) + { + souces = oldRd.Score; + } + } + } + redisHelper.SortedSetRemove(keys, oldEntitys[o]); + } + } + if (souces == 0) + { + redisHelper.SortedSetAdd(keys, entity, lists.Count + 1); + } + else + { + redisHelper.SortedSetAdd(keys, entity, souces); + } + + } + else if (handdle == RedisHanddle.Delete) + { + var lists = redisHelper.SortedSetRangeByRank(keys); + var oldEntity = lists.Where(i => i.ID == entity.ID).ToList(); + if (oldEntity.Any()) + { + foreach (var en in oldEntity) + { + redisHelper.SortedSetRemove(keys, en); + } + + } + } + else + { + redisHelper.SortedSetAdd(keys, entity, souces); + }*/ + } + } + catch (Exception ex) + { + throw ex; + } + } + + private List DynamicSelect(string[] selectField, IQueryable queryTable) + { + var selectSql = "New("; + foreach (var s in selectField) + { + selectSql += s + ","; + } + selectSql = selectSql.Trim(','); + selectSql += ")"; + var result = queryTable.Select(selectSql).ToDynamicList(); + + return result; + } + private void DelRedis(IEnumerable entitys) where T : MesEntityBase, new() + { + if (!ConfigurationManager.IsRedis || entitys == null || !entitys.Any()) + return; + try + { + //CsRedisManager redisHelper = ServiceLocator.Instance.GetService(); + var redisClass = CsRedisHelper.GetRedisClass(); + if (redisClass != null) + { + var type = typeof(T); + //manager. + var perKey = "{" + type.Name + "}"; + //1.处理 redisstring + if (!redisClass.DicKeys.Any()) + { + redisClass.DicKeys.Add("ID", "GUID"); + } + var redisKeys = redisClass.DicKeys.Distinct(); + + var selectEntiys = DynamicSelect(redisKeys.Select(i => i.Key).ToArray(), entitys.AsQueryable()); + List keys = new List(); + var dyType = selectEntiys.FirstOrDefault().GetType(); + var orgId = entitys.FirstOrDefault().ORG_ID?.ToString(); + foreach (var d in selectEntiys) + { + foreach (var key in redisKeys) + { + keys.Add(perKey + "_" + dyType.GetProperty(key.Key).GetValue(d) + "_" + orgId); + } + } + + CsRedisManager.GetClient().Del(keys.ToArray()); + + + + + //2.处理sortlist + + //SetRedisValue(entity.ORG_ID ?? Guid.Empty, redisHelper, type, keys).Wait(); + var groupValue = redisClass.GroupName; + //CsRedisManager manager = ServiceLocator.Instance.GetService(); + if (!string.IsNullOrEmpty(groupValue) && groupValue != "ID") + { + var gkeys = "sort_" + redisClass.ClassName + "_" + groupValue + "_" + orgId; + if (CsRedisManager.KeyExists(gkeys)) + CsRedisManager.KeyDelete(gkeys); + var groupkeys = "opt_grouplist_" + type.Name + "_" + orgId; + if (CsRedisManager.KeyExists(groupkeys)) + { + CsRedisManager.KeyDelete(groupkeys); + } + //因为数据库可能还没提交,所以不能更新redis + //SetRedisValue(entity.ORG_ID ?? Guid.Empty, redisHelper, type, + //type.GetProperty(groupValue).GetValue(entity).ToString()).Wait(); + } + else + { + var gkeys = "sort_" + redisClass.ClassName + "_" + orgId; + var listKeys = "opt_list_" + orgId; + if (CsRedisManager.KeyExists(gkeys)) + CsRedisManager.KeyDeleteAsync(gkeys).Wait(); + if (CsRedisManager.GetClient().HExists(listKeys, perKey)) + { + CsRedisManager.GetClient().HDelAsync(listKeys, perKey).Wait(); + } + } + } + } + catch (Exception ex) + { + throw ex; + } + } + + + private void DelRedisGroup(Guid orgId) where T : MesEntityBase, new() + { + if (!ConfigurationManager.IsRedis) + return; + try + { + //CsRedisManager redisHelper = ServiceLocator.Instance.GetService(); + var redisClass = CsRedisHelper.GetRedisClass(); + if (redisClass != null) + { + var type = typeof(T); + //manager. + var perKey = type.Name; + + + //2.处理sortlist + + //SetRedisValue(entity.ORG_ID ?? Guid.Empty, redisHelper, type, keys).Wait(); + var groupValue = redisClass.GroupName; + //CsRedisManager manager = ServiceLocator.Instance.GetService(); + if (!string.IsNullOrEmpty(groupValue) && groupValue != "ID") + { + var gkeys = "sort_" + redisClass.ClassName + "_" + groupValue + "_" + orgId; + if (CsRedisManager.KeyExists(gkeys)) + CsRedisManager.KeyDelete(gkeys); + var groupkeys = "opt_grouplist_" + type.Name + "_" + orgId; + if (CsRedisManager.KeyExists(groupkeys)) + { + CsRedisManager.KeyDelete(groupkeys); + } + //因为数据库可能还没提交,所以不能更新redis + //SetRedisValue(entity.ORG_ID ?? Guid.Empty, redisHelper, type, + //type.GetProperty(groupValue).GetValue(entity).ToString()).Wait(); + } + else + { + var gkeys = "sort_" + redisClass.ClassName + "_" + orgId; + var listKeys = "opt_list_" + orgId; + if (CsRedisManager.KeyExists(gkeys)) + CsRedisManager.KeyDeleteAsync(gkeys).Wait(); + if (CsRedisManager.GetClient().HExists(listKeys, perKey)) + { + CsRedisManager.GetClient().HDelAsync(listKeys, perKey).Wait(); + } + } + } + } + catch (Exception ex) + { + throw ex; + } + } + + #region 系统参数 + + + + public void FillGetEntitySysParam(IEnumerable entities, BaseFilter filter, string[] includes) + { + List allIncludes = new List(); + if (includes != null && includes.Any()) + allIncludes.AddRange(includes); + if (filter != null && filter.Include != null && filter.Include.Any()) + allIncludes.AddRange(filter.Include); + if (entities == null || !entities.Any() || allIncludes == null || !allIncludes.Any()) return; + var first = entities.FirstOrDefault(); + if (!(first is MesEntityBase)) return; + + List mesEntityBases = new List(); + entities.ForEach(t => + { + mesEntityBases.Add(t as MesEntityBase); + }); + List ids = new List(); + DoForEachEntitiesOnIncludes(mesEntityBases, null, string.Empty, allIncludes, (idPropertyInfo, obj) => + { + if (obj != null) + { + var idObj = idPropertyInfo.GetValue(obj); + if (idObj != null) + ids.Add(new Guid(idObj.ToString())); + } + }); + if (!ids.Any()) return; + + var sysParams = this.UnitOfWork.GetEntities(t => ids.Contains(t.ENTITY_ID ?? Guid.Empty), null, false).ToList(); + if (sysParams != null && sysParams.Any()) + { + DoForEachEntitiesOnIncludes(mesEntityBases, null, string.Empty, allIncludes, (idPropertyInfo, obj) => + { + if (obj != null) + { + var idObj = idPropertyInfo.GetValue(obj); + if (idObj != null) + { + var id = new Guid(idObj.ToString()); + var tempSysParams = sysParams.Where(t => t.ENTITY_ID == id).ToList(); + if (tempSysParams != null && tempSysParams.Any()) + { + var navSysParamProperty = obj.GetType().GetProperty("Nav_SysParams"); + if (navSysParamProperty != null) + navSysParamProperty.SetValue(obj, tempSysParams); + } + } + } + }); + } + } + + + private List GetSysParams(IEnumerable entities, bool isDelete = false) where T : MesEntityBase, new() + { + if (entities == null || !entities.Any()) return null; + var first = entities.FirstOrDefault(); + if (!(first is MesEntityBase)) return null; + if (isDelete) + { + var ids = entities.Select(t => new Guid(t.ID.ToString())).ToList(); + var dbParams = this.UnitOfWork.GetEntities(t => ids.Contains(t.ENTITY_ID ?? Guid.Empty), null, false).ToList(); + if (dbParams.Any()) + return dbParams; + } + List pfParams = new List(); + foreach (var item in entities) + { + if (item.Nav_SysParams != null && item.Nav_SysParams.Any()) + { + pfParams.AddRange(item.Nav_SysParams); + item.Nav_SysParams.ForEach(t => t.VIR_IS_DELETED = item.IS_DELETED); + item.Nav_SysParams = null; + + } + } + return pfParams; + } + + private string GetRealInclude(string p) + { + if (!string.IsNullOrEmpty(p)) + p = p.Trim(); + if (string.IsNullOrEmpty(p)) return p; + int index = p.IndexOf("Nav_SysParams", StringComparison.OrdinalIgnoreCase); + if (index > -1) + { + if (index > 0) + return p.Substring(0, index - 1); + else + return string.Empty; + } + return p; + } + /// + /// 构造关联的表 + /// + /// + /// + /// + private string[] GetIncludes(BaseFilter baseFilter, params string[] paths) + { + Dictionary dic = new Dictionary(); + if (paths != null) + { + foreach (string path in paths) + { + var temp = GetRealInclude(path); + if (!string.IsNullOrEmpty(temp) && !dic.ContainsKey(temp)) + dic[temp] = 0; + } + } + if (baseFilter != null && baseFilter.Include != null) + { + foreach (var path in baseFilter.Include) + { + var temp = GetRealInclude(path); + if (!string.IsNullOrEmpty(temp) && !dic.ContainsKey(temp)) + dic[temp] = 0; + } + foreach (var path in baseFilter.SelectField.Where(i => i.IndexOf(".") > 0)) + { + var index = path.LastIndexOf("."); + var temp = GetRealInclude(path.Substring(0, index)); + if (!string.IsNullOrEmpty(temp) && !dic.ContainsKey(temp)) + dic[temp] = 0; + } + } + if (dic.Any()) + return dic.Keys.ToArray(); + return null; + } + /// + /// 构造查询条件 + /// + /// + /// + /// + /// + /// + /// + /// + /// + private Expression> DoGetEntityExp + (Expression> expression, BaseFilter parmFilter, + string[] paths, + IDictionary orders, out Expression> orgExpression, out string[] realPaths, out Dictionary realOrders, bool appendDataNav) + where T : MesEntityBase, new() + { + orgExpression = t => true; + BaseFilter filter = parmFilter; + if (expression == null) + expression = t => !t.IS_DELETED; + else + expression = expression.And(t => !t.IS_DELETED); + var dataNavField = ""; + if (filter != null) + { + //OrgId的过滤条件 + var orgIdExpression = this.GetPermissionExpression(filter, out orgExpression); + if (orgIdExpression != null) + { + expression = expression.And(orgIdExpression); + } + //原filter过滤条件 + expression = expression.And(filter.BuildExpression(this.UnitOfWork)); + //数据权限处理 + var type = typeof(T); + var dataFieldAttr = type.GetAttribute(); + if (dataFieldAttr != null && !parmFilter.IgnoreDataRule) + { + Guid? nullGuid = null; + var dataFieldfilter = new BaseFilter(); + FilterGroup group = new FilterGroup(); + group.IsAnd = false; + dataFieldfilter.FilterGroup.Groups.Add(group); + + var splitAttrs = dataFieldAttr.FileName.Split(new char[] { '.' }); + var tmpType = type; + var tmpFiled = ""; + if (appendDataNav) + { + var dataNavFieldIndex = dataFieldAttr.FileName.LastIndexOf('.'); + if (dataNavFieldIndex > 0) + { + dataNavField = dataFieldAttr.FileName.Substring(0, dataNavFieldIndex); + } + } + foreach (var a in splitAttrs) + { + var property = tmpType.GetProperty(a); + var propertyClass = property.PropertyType; + if (property.Name.StartsWith("Nav_")) + { + var keys = this.UnitOfWork.GetModelForeignKey(tmpType.Name); + var key = keys.FirstOrDefault(x => x.ForeignNavName == property.Name); + if (key != null) + { + var keyProp = tmpType.GetProperty(key.ForeignFieldName); + if (keyProp != null && keyProp.PropertyType.IsNullableType()) + { + var emptyRule = new FilterRule(); + emptyRule.Field = tmpFiled + keyProp.Name; + emptyRule.Operate = FilterOperate.Equal; + emptyRule.Value = nullGuid; + group.Rules.Add(emptyRule); + } + } + } + else + { + if (property.PropertyType.IsNullableType()) + { + var emptyRule = new FilterRule(); + emptyRule.Field = tmpFiled + property.Name; + emptyRule.Operate = FilterOperate.Equal; + emptyRule.Value = nullGuid; + group.Rules.Add(emptyRule); + } + } + tmpFiled += property.Name + "."; + tmpType = propertyClass; + } + //数据权限的过滤条件 + if (filter.DataRule.Any()) + { + foreach (var data in filter.DataRule) + { + var rule = new FilterRule(); + rule.Field = dataFieldAttr.FileName; + rule.Operate = FilterOperate.Equal; + rule.Value = data; + group.Rules.Add(rule); + } + expression = expression.And(dataFieldfilter.BuildExpression(this.UnitOfWork)); + } + else + { + expression = expression.And(t => false); + } + + } + + } + else + { + if (APT.Infrastructure.Api.AppContext.CurrentSession.RootOrgId != null) + { + //expression = expression.And(t => t.ORG_ID == APT.Infrastructure.Api.AppContext.CurrentSession.RootOrgId); + //orgExpression = orgExpression.And(t => t.ORG_ID == APT.Infrastructure.Api.AppContext.CurrentSession.RootOrgId); + } + else + { + } + } + realPaths = this.GetIncludes(filter, paths); + + if (!string.IsNullOrEmpty(dataNavField)) + { + if (realPaths == null) + realPaths = new string[] { dataNavField }; + else + realPaths = realPaths.Append(dataNavField).ToArray(); + } + + realOrders = new Dictionary(); + if (filter != null) + { + if (!string.IsNullOrEmpty(filter.Sort)) + realOrders[filter.Sort] = filter.Order; + if (filter.Orders != null && filter.Orders.Any()) + foreach (var item in filter.Orders) + realOrders[item.Field] = item.Order; + } + if (orders != null && orders.Any()) + { + foreach (var item in orders) + { + DbOrder dbOrder = DbOrder.ASC; + if (item.Value == "DESC") + dbOrder = DbOrder.DESC; + realOrders[item.Key] = dbOrder; + } + } + return expression; + } + + private Expression> GetPermissionExpression(BaseFilter filter, out Expression> orgExpression) where T : MesEntityBase, new() + { + orgExpression = t => true; + Expression> expression = t => true; + + if (filter.IgnoreOrgRule) + { + return null; + if (filter.OrgId == null) + return null; + expression = t => t.ORG_ID == filter.OrgId; + orgExpression = orgExpression.And(t => t.ORG_ID == filter.OrgId); + } + else + { + var currtOrgId = filter?.OrgId; + Expression> orgPress = t => false; + if (filter != null && filter.OrgRule.Any()) + { + foreach (var s in filter.OrgRule) + { + orgPress = orgPress.Or(t => t.ORG_ID == s); + } + } + if (currtOrgId != null) + orgPress = orgPress.Or(t => t.ORG_ID == currtOrgId); + expression = expression.And(orgPress); + orgExpression = orgExpression.And(orgPress); + } + return expression; + + #region 原组织权限模式 + /* + if (filter.OrgType == FilterOrgTypeEnum.默认) + { + var sysPermission = APT.Infrastructure.Api.AppContext.SysPermission; + List parentOrgIds = new List(); + List childrenOrgIds = new List(); + OrgCache orgCache = null; + UserOrgCache userOrgCache = null; + if (sysPermission != null) + { + if (sysPermission.OrgCaches != null) + { + if (sysPermission.OrgCaches.TryGetValue(filter.OrgId.Value, out orgCache)) + { + if (orgCache.AllChildrenIds != null && orgCache.AllChildrenIds.Any()) + childrenOrgIds.AddRange(orgCache.AllChildrenIds); + if (orgCache.AllParentIds != null && orgCache.AllParentIds.Any()) + parentOrgIds.AddRange(orgCache.AllParentIds); + } + } + if (sysPermission.UserOrgCaches != null && APT.Infrastructure.Api.AppContext.CurrentSession != null && + APT.Infrastructure.Api.AppContext.CurrentSession.UserID != null) + { + if (sysPermission.UserOrgCaches.TryGetValue(APT.Infrastructure.Api.AppContext.CurrentSession.UserID.Value, out userOrgCache)) + { + if (userOrgCache.Orgs != null && userOrgCache.Orgs.Any()) + { + foreach (var org in userOrgCache.Orgs) + { + if (sysPermission.OrgCaches.TryGetValue(org, out orgCache)) + { + if (orgCache.AllChildrenIds != null && orgCache.AllChildrenIds.Any()) + { + var remains = orgCache.AllChildrenIds.Where(t => !childrenOrgIds.Contains(t)).ToList(); + if (remains != null && remains.Any()) + childrenOrgIds.AddRange(remains); + } + if (orgCache.AllParentIds != null && orgCache.AllParentIds.Any()) + { + var remains = orgCache.AllParentIds.Where(t => !parentOrgIds.Contains(t)).ToList(); + if (remains != null && remains.Any()) + parentOrgIds.AddRange(remains); + } + } + } + } + } + } + } + expression = t => ((t.ENTITY_ORG_TPYE == 0 || t.ENTITY_ORG_TPYE == 1) && (t.ORG_ID == filter.OrgId || childrenOrgIds.Contains(t.ORG_ID ?? Guid.Empty))) || + (t.ENTITY_ORG_TPYE == 1 && (parentOrgIds.Contains(t.ORG_ID ?? Guid.Empty))) || + (t.ENTITY_ORG_TPYE == 2) || + (t.ENTITY_ORG_TPYE == 3 && t.ORG_ID == filter.OrgId); + + } + else if (filter.OrgType == FilterOrgTypeEnum.仅本组织) + { + expression = t => t.ORG_ID == filter.OrgId; + } + if (expression != null) + { + var sysPermission = APT.Infrastructure.Api.AppContext.SysPermission; + if (!string.IsNullOrEmpty(filter.AuthOrgCodes) && sysPermission != null) + { + var authOrgIds = new List(); + var c = filter.AuthOrgCodes.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); + foreach (var i in c) + { + Guid orgId; + if (sysPermission.OrgCodeCaches.TryGetValue(i, out orgId)) + authOrgIds.Add(orgId); + } + if (authOrgIds.Any()) + expression = expression.Or(t => authOrgIds.Contains(t.ORG_ID ?? Guid.Empty)); + } + } + return expression; + */ + #endregion + + + } + + + /// + /// 检查唯一性 + /// + /// + private void CheckUnique(IEnumerable entities, IEnumerable deleteEntities) where T : MesEntityBase, new() + { + if (entities == null || !entities.Any()) return; + List delIds = new List(); + if (deleteEntities != null && deleteEntities.Any()) + delIds = deleteEntities.Select(i => i.ID).ToList(); + Type type = typeof(T); + + foreach (PropertyInfo item in type.GetProperties()) + { + CUniqueAttribute cUniqueAttr = null; + object[] attrs = item.GetCustomAttributes(typeof(CUniqueAttribute), true); + if (attrs.Length == 1) + cUniqueAttr = (CUniqueAttribute)attrs[0]; + + if (cUniqueAttr == null) continue; + + var groupByOrgIds = entities.GroupBy(t => t.ORG_ID).ToList(); + foreach (var oId in groupByOrgIds) + { + BaseFilter filter = new BaseFilter(); + FilterGroup filterGroup = new FilterGroup(false); + Guid? orgId = oId.Key; + var temps = oId.ToList();// entities.Where(t => t.ORG_ID == oId).ToList(); + bool checkSelf = temps.Count() == 1 ? false : true; + int count = 0; + foreach (var entity in temps) + { + PropertyInfo propertyInfo = type.GetProperty("ID"); + if (propertyInfo == null) continue; + object id = propertyInfo.GetValue(entity, null); + if (id == null) continue; + if (orgId == null) + { + propertyInfo = type.GetProperty("ORG_ID"); //获取指定名称的属性 + if (propertyInfo == null) continue; + + object tmpOrgId = propertyInfo.GetValue(entity, null); //获取属性值 + if (tmpOrgId != null) + orgId = (Guid)tmpOrgId; + } + FilterGroup tmp = new FilterGroup(); + object obj = item.GetValue(entity, null); + if ((obj == null || string.IsNullOrEmpty(obj.ToString())) && !cUniqueAttr.IsCheckEmpty) continue; + tmp.Rules.Add(new FilterRule("ID", id, FilterOperate.NotEqual)); + tmp.Rules.Add(new FilterRule(item.Name, obj, FilterOperate.Equal)); + filterGroup.Groups.Add(tmp); + count++; + if (count >= 100) + { + filter.FilterGroup.Groups.Add(filterGroup); + DoCheckUnique(item, cUniqueAttr, filter, checkSelf, orgId, temps, entities, delIds); + filter = new BaseFilter(); + filterGroup = new FilterGroup(false); + count = 0; + } + } + if (filterGroup.Groups.Any()) + { + filter.FilterGroup.Groups.Add(filterGroup); + DoCheckUnique(item, cUniqueAttr, filter, checkSelf, orgId, temps, entities, delIds); + } + + } + } + } + + private void DoCheckUnique(PropertyInfo item, CUniqueAttribute cUniqueAttr, BaseFilter filter, bool checkSelf, + Guid? orgId, IEnumerable temps, IEnumerable entities, List delIds) where T : MesEntityBase, new() + { + //Expression> express = null; + //if (cUniqueAttr.IsCheckOrg) + // express = t => t.ORG_ID == orgId; + //else + // express = t => true; + //if (delIds.Any()) + // express = t => !delIds.Contains(t.ID); + //express = express.And(filter.BuildExpression(this.UnitOfWork)); + //T dbEntity = null; + //var hasExistRecord = false; + //if (checkSelf) + //{ + // if (cUniqueAttr.IsCheckOrg) + // hasExistRecord = temps.Where(express.Compile()).Any(); + // else + // hasExistRecord = entities.Where(express.Compile()).Any(); + //} + + ////if (!hasExistRecord) + ////{ + //dbEntity = this.UnitOfWork.GetEntity(express, null, false); + //hasExistRecord = dbEntity != null; + ////} + + //if (hasExistRecord) + //{ + // if (cUniqueAttr.IsCheckOrg) + // { + // var dbId = dbEntity.ID; + // var entity = temps.FirstOrDefault(i => i.ID == dbId); + // if (entity != null) + // return; + // } + // else + // { + // var dbId = dbEntity.ID; + // var entity = entities.FirstOrDefault(i => i.ID == dbId); + // if (entity != null) + // return; + // } + // string displayName = string.Empty; + // if (cUniqueAttr != null && !string.IsNullOrEmpty(cUniqueAttr.DisplayName)) + // displayName = cUniqueAttr.DisplayName; + // if (string.IsNullOrEmpty(displayName)) + // { + // object[] tmps = item.GetCustomAttributes(typeof(DescriptionAttribute), true); + // if (tmps.Length >= 1) + // { + // var descAttr = (DescriptionAttribute)tmps[0]; + // displayName = "字段【" + descAttr.Description + "】"; + // } + // } + // throw new Exception(displayName + "已存在其他记录,请确认"); + //} + } + + + + + //private void DoSetIsLeafByUpdate(IEnumerable entities, List addParentIds, List deleteParentIds, List deleteIds) + // where T : MesEntityBase, new() + //{ + // if (entities != null) + // { + // var def = entities.FirstOrDefault(); + // if (def != null && def is MesTreeEntityBase) + // { + // var ids = entities.Select(t => t.ID).ToList(); + // List dbUpdateEntities = this.UnitOfWork.GetEntities(t => ids.Contains(t.ID), null, false).ToList(); + // foreach (var entity in entities) + // { + // var dbEntity = dbUpdateEntities.FirstOrDefault(t => t.ID.ToString() == entity.ID.ToString()); + // if (dbEntity != null) + // { + // var entityTree = entity as MesTreeEntityBase; + // var dbEntityTree = dbEntity as MesTreeEntityBase; + // if (entityTree.PARENT_ID != dbEntityTree.PARENT_ID) + // { + // if (entityTree.PARENT_ID != null) + // addParentIds.Add(entityTree.PARENT_ID.Value); + // if (dbEntityTree.PARENT_ID != null) + // { + // deleteParentIds.Add(dbEntityTree.PARENT_ID.Value); + // deleteIds.Add(dbEntity.ID); + // } + + // } + // } + // else + // { + // var entityTree = entity as MesTreeEntityBase; + // if (entityTree.PARENT_ID != null) + // addParentIds.Add(entityTree.PARENT_ID.Value); + // } + // } + // } + // } + //} + + + //private void DoSetIsLeaf(IEnumerable entities, List deleteIds, bool isAdd) + //{ + // if (entities != null) + // { + // var def = entities.FirstOrDefault(); + // if (def != null && def is MesTreeEntityBase) + // { + // List parentIds = new List(); + // foreach (var item in entities) + // { + // var treeEntity = item as MesTreeEntityBase; + // if (treeEntity.PARENT_ID != null) + // { + // parentIds.Add(treeEntity.PARENT_ID.Value); + // } + // } + // MethodInfo methodInfo = this.GetType().GetMethod("SetParentIsLeaf", + // BindingFlags.Instance | BindingFlags.Public | BindingFlags.Static); + // methodInfo.MakeGenericMethod(new Type[] { def.GetType() }). + // Invoke(this, new object[] { parentIds, deleteIds, isAdd }); + + // } + // } + + //} + + + private void SaveSysParams(List pfParams) + { + if (pfParams == null || !pfParams.Any()) return; + + var ids = pfParams.Select(t => t.ID).ToList(); + var dbParams = this.UnitOfWork.GetEntities(t => ids.Contains(t.ID), null, false).ToList(); + List updateParams = new List(); + List deleteParams = new List(); + List addParams = new List(); + foreach (var item in pfParams) + { + var dbP = dbParams.FirstOrDefault(t => t.ID == item.ID); + if (dbP != null) + { + if (item.VIR_IS_DELETED) + { + //var entry1 = this._pfParamDataSet.GetContext().Entry(dbP); + // entry1.State = EntityState.Deleted; + deleteParams.Add(dbP); + continue; + } + dbP.ENTITY_ID = item.ENTITY_ID; + dbP.CODE = item.CODE; + dbP.VALUE = item.VALUE; + //var entry = this._pfParamDataSet.GetContext().Entry(dbP); + //entry.State = EntityState.Modified; + updateParams.Add(dbP); + } + else + { + if (item.VIR_IS_DELETED) continue; + //var entry = this._pfParamDataSet.GetContext().Entry(item); + //entry.State = EntityState.Added; + addParams.Add(item); + } + } + if (addParams.Any()) + this.UnitOfWork.AddEntities(addParams); + if (updateParams.Any()) + this.UnitOfWork.UpdateEntities(updateParams); + if (deleteParams.Any()) + this.UnitOfWork.DeleteEntities(deleteParams); + } + + //public void SetParentIsLeaf(List parentIds, List deleteIds, bool isAdd) where T : MesTreeEntityBase, new() + //{ + // if (parentIds != null && parentIds.Any()) + // { + // if (isAdd) + // { + // var parentEntities = this.UnitOfWork.GetEntities(t => parentIds.Contains(t.ID), null, true).ToList(); + // parentEntities.ForEach(item => + // { + // item.IS_LEAF = false; + // }); + // foreach (var item in parentEntities) + // { + // this.SetRedis(item, RedisHanddle.Update); + // } + // this.UnitOfWork.UpdateEntities(parentEntities); + // } + // else + // { + // var parentEntities = this.UnitOfWork.GetEntities(t => parentIds.Contains(t.ID), null, true).ToList(); + // var childEntities = this.UnitOfWork.GetEntities(t => t.PARENT_ID != null && parentIds.Contains(t.PARENT_ID ?? Guid.Empty), null, true).ToList(); + // List updateEntities = new List(); + // parentEntities.ForEach(item => + // { + // var theChilds = childEntities.Where(i => i.PARENT_ID == item.ID).ToList(); + // var theChildIds = theChilds.Select(i => i.ID).ToList(); + // theChildIds.RemoveAll(i => deleteIds.Contains(i)); + // if (!theChildIds.Any() && !item.IS_LEAF) + // { + // item.IS_LEAF = true; + // updateEntities.Add(item); + // } + // }); + // if (updateEntities.Count > 0) + // { + // foreach (var item in updateEntities) + // { + // this.SetRedis(item, RedisHanddle.Update); + // } + // this.UnitOfWork.UpdateEntities(updateEntities); + // } + + + // } + // } + //} + + + + /// + /// + /// + /// + /// 0-新增 1-更新 2-删除 + private void UpdateSerialUsedStatus(IEnumerable entities, int updateType, List updateSerialInfos) where T : MesEntityBase, new() + { + return; + if (entities == null || !entities.Any()) return; + + Type type = typeof(T); + bool checkSelf = entities.Count() == 1 ? false : true; + // List updateSerialInfos = new List(); + + List dbEntities = null; + if (updateType == 1) + { + var ids = entities.Select(t => t.ID).ToList(); + dbEntities = this.UnitOfWork.GetEntities(t => ids.Contains(t.ID), null, false).ToList(); + } + foreach (PropertyInfo item in type.GetProperties()) + { + CodeRuleAttribute cUniqueAttr = null; + object[] attrs = item.GetCustomAttributes(typeof(CodeRuleAttribute), true); + if (attrs.Length == 1) + cUniqueAttr = (CodeRuleAttribute)attrs[0]; + + if (cUniqueAttr == null) continue; + + + string displayName = string.Empty; + object[] tmps = item.GetCustomAttributes(typeof(CUniqueAttribute), true); + if (tmps != null && tmps.Any()) + { + var descAttr = (CUniqueAttribute)tmps[0]; + displayName = "字段【" + descAttr.DisplayName + "】"; + } + if (string.IsNullOrWhiteSpace(displayName)) + { + tmps = item.GetCustomAttributes(typeof(DescriptionAttribute), true); + if (tmps != null && tmps.Any()) + { + var descAttr = (DescriptionAttribute)tmps[0]; + displayName = "字段【" + descAttr.Description + "】"; + } + } + + + foreach (var entity in entities) + { + object obj = item.GetValue(entity, null); + if (updateType == 0 || updateType == 2) + { + if (obj == null) continue; + var code = obj.ToString(); + if (string.IsNullOrEmpty(code)) continue; + this.UpdateSerialUsedStatusSql(updateSerialInfos, cUniqueAttr, displayName, code, updateType == 0); + + } + else + { + var dbEntity = dbEntities == null ? null : dbEntities.FirstOrDefault(t => t.ID.ToString() == entity.ID.ToString()); + if (dbEntity != null) + { + object dbObj = item.GetValue(dbEntity, null); + string code = obj == null ? string.Empty : obj.ToString(); + string dbCode = dbObj == null ? string.Empty : dbObj.ToString(); + if (string.Compare(code, dbCode, true) != 0) + { + if (string.IsNullOrEmpty(dbCode)) + this.UpdateSerialUsedStatusSql(updateSerialInfos, cUniqueAttr, displayName, dbCode, false); + if (string.IsNullOrEmpty(code)) + this.UpdateSerialUsedStatusSql(updateSerialInfos, cUniqueAttr, displayName, code, true); + } + } + } + } + + } + + } + + private void ExcuteUpdateSerialInfos(List updateSerialInfos) + { + + if (updateSerialInfos != null && updateSerialInfos.Any()) + { + List types = updateSerialInfos.SelectMany(t => t.CodeTypes).Distinct().ToList(); + List serials = updateSerialInfos.Select(t => t.Serial).Distinct().ToList(); + var dbSerials = this.UnitOfWork.GetEntities(t => types.Contains(t.CODE_TYPE) && serials.Contains(t.SERIAL), null, false).ToList(); + List updateCodeRuleSerials = new List(); + var nowTime = DateTime.Parse(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")); + foreach (var item in updateSerialInfos) + { + var ss = dbSerials.Where(t => item.CodeTypes.Contains(t.CODE_TYPE) && t.SERIAL == item.Serial).ToList(); + if (ss != null && ss.Any()) + { + ss.ForEach(t => + { + if (t.STATUS == 2 && item.IsUsed && item.IsCheckState) + throw new Exception((string.IsNullOrEmpty(item.DisplayCodeName) ? "编号" : item.DisplayCodeName) + + t.SERIAL + "已被其他用户使用,请稍后重试"); + + t.STATUS = item.IsUsed ? 2 : 0; + t.USE_TIME = item.IsUsed ? item.Time : null; + t.ROW_VERSION++; + t.MODIFY_TIME = nowTime; + }); + updateCodeRuleSerials.AddRange(ss); + } + } + if (updateCodeRuleSerials.Any()) + this.UnitOfWork.UpdateEntities(updateCodeRuleSerials); + } + + } + + private void UpdateSerialUsedStatusSql(List updateSerialInfos, CodeRuleAttribute codeRuleAttr, string displayName, string code, bool isUsed) + { + if (codeRuleAttr != null && codeRuleAttr.CodeRuleTypes != null && codeRuleAttr.CodeRuleTypes.Any()) + { + UpdateCodeSerialInfo info = new UpdateCodeSerialInfo(); + info.Serial = code; + info.CodeTypes.AddRange(codeRuleAttr.CodeRuleTypes); + info.IsUsed = isUsed; + info.Time = DateTime.Parse(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")); ; + info.DisplayCodeName = displayName; + info.IsCheckState = codeRuleAttr.IsCheckState; + updateSerialInfos.Add(info); + + } + } + + + void CheckRowVersion(IEnumerable entities) where T : MesEntityBase, new() + { + if (entities == null || !entities.Any()) return; + + bool isRowVersion = false; + foreach (var item in entities) + { + isRowVersion = item is IRowVersion; + break; + } + if (!isRowVersion) return; + var ids = entities.Select(t => t.ID).ToList(); + var dbEntities = this.UnitOfWork.GetEntities(t => ids.Contains(t.ID), null, false).ToList(); + foreach (var entity in entities) + { + var dbEntity = dbEntities.Where(t => t.ID.ToString() == entity.ID.ToString()).FirstOrDefault(); + if (dbEntity != null) + { + IRowVersion rowVersion = entity as IRowVersion; + IRowVersion dbRowVersion = dbEntity as IRowVersion; + if (rowVersion.ROW_VERSION != dbRowVersion.ROW_VERSION) + throw new RowVersionException("当前数据已发生修改,请先执行查询操作"); + rowVersion.ROW_VERSION += 1; + } + } + + } + + void CheckRowVersion(IEnumerable entities, EfDbContext contex) where T : MesEntityBase, new() + { + if (entities == null || !entities.Any()) return; + + bool isRowVersion = false; + foreach (var item in entities) + { + isRowVersion = item is IRowVersion; + break; + } + if (!isRowVersion) return; + var ids = entities.Select(t => t.ID).ToList(); + var dbEntities = contex.GetEntities(t => ids.Contains(t.ID), null, false).ToList(); + foreach (var entity in entities) + { + var dbEntity = dbEntities.Where(t => t.ID.ToString() == entity.ID.ToString()).FirstOrDefault(); + if (dbEntity != null) + { + IRowVersion rowVersion = entity as IRowVersion; + IRowVersion dbRowVersion = dbEntity as IRowVersion; + if (rowVersion.ROW_VERSION != dbRowVersion.ROW_VERSION) + throw new RowVersionException("当前数据已发生修改,请先执行查询操作"); + rowVersion.ROW_VERSION += 1; + } + } + + } + private void DoGetSysParamByEntity(MesEntityBase entityBase, MesEntityBase parentEntityBase, string parentInclude, + List includes, Action action) + { + string path = parentInclude; + if (!string.IsNullOrEmpty(path)) + path += "."; + path += "Nav_SysParams"; + bool isInclude = includes.Contains(path); + var type = entityBase.GetType(); + if (isInclude) + { + action(type.GetProperty("ID"), entityBase); + } + foreach (var propertyInfo in type.GetProperties()) + { + var propertyType = propertyInfo.PropertyType; + if (propertyType.IsGenericType) + { + var types = propertyType.GetGenericArguments(); + Type realType = null; + if (types != null && types.Any()) + realType = types[0]; + if (realType.IsClass) + { + var baseType = realType.BaseType; + if (baseType == typeof(MesEntityBase) || baseType == typeof(MesTreeEntityBase)) + { + object obj = propertyInfo.GetValue(entityBase, null); + if (obj != null && obj is System.Collections.IList) + { + List testBases = new List(); + System.Collections.IList enumerator = obj as System.Collections.IList; + for (int i = 0; i < enumerator.Count; i++) + { + var ix = enumerator[i]; + testBases.Add(ix as MesEntityBase); + } + if (testBases.Any()) + DoForEachEntitiesOnIncludes(testBases, entityBase, string.IsNullOrEmpty(parentInclude) ? + propertyInfo.Name : (parentInclude + "." + propertyInfo.Name), includes, action); + } + } + } + } + else if (propertyType.IsClass) + { + var baseType = propertyType.BaseType; + if (baseType == typeof(MesEntityBase) || baseType == typeof(MesTreeEntityBase)) + { + var obj = propertyInfo.GetValue(entityBase, null); + if (obj != null) + { + var temp = obj as MesEntityBase; + if (parentEntityBase == null || parentEntityBase.ID != temp.ID) + DoGetSysParamByEntity(temp, entityBase, string.IsNullOrEmpty(parentInclude) ? + propertyInfo.Name : (parentInclude + "." + propertyInfo.Name), includes, action); + } + } + } + } + } + + private void DoForEachEntitiesOnIncludes(IEnumerable entities, MesEntityBase parentEntityBase, string parentInclude, List includes, + Action action) + { + if (entities == null || !entities.Any() || includes == null || !includes.Any() || + !includes.Any(t => t.IndexOf("Nav_SysParams", StringComparison.OrdinalIgnoreCase) > -1)) return; + + foreach (var item in entities) + DoGetSysParamByEntity(item, parentEntityBase, parentInclude, includes, action); + + + } + /// + /// 设置首字母缩写字段 + /// + /// + /// + private void FillAcronymFieldData(IEnumerable entities, params string[] updateField) where T : MesEntityBase, new() + { + if (entities == null || !entities.Any()) return; + Type type = typeof(T); + foreach (var p in type.GetProperties()) + { + AcronymFieldAttribute acronymAttr = null; + object[] attrs = p.GetCustomAttributes(typeof(AcronymFieldAttribute), true); + if (attrs.Length == 1) + acronymAttr = (AcronymFieldAttribute)attrs[0]; + if (acronymAttr == null || string.IsNullOrEmpty(acronymAttr.AcronymFieldName)) continue; + var acronymP = type.GetProperty(acronymAttr.AcronymFieldName); + if (acronymP == null) continue; + updateField.Append(p.Name); + foreach (var entity in entities) + { + try + { + string aValue = null; + var o = p.GetValue(entity, null); + if (o != null) + { + var allSpell = AcronymHelper.ConvertToAllSpell(o.ToString()); + var first = AcronymHelper.ConvertToFirstSpell(o.ToString()); + aValue = first + ";" + allSpell; + } + acronymP.SetValue(entity, aValue); + } + catch { } + } + } + } + + /// + /// 获取所有的数据库连接 + /// + /// + private List GetAllDbConns() + { + List dbs = new List(); + List conns = new List(); + //取redis + var tenantConnKey = ConfigurationManager.AppSettings["TenantConnKey"] + "_All_" + ConfigurationManager.AppSettings["Env"]; + if (CsRedisManager.KeyExists(tenantConnKey)) + { + conns = CsRedisManager.StringGet>(tenantConnKey); + + } + //查询 + else + { + var url = APT.Infrastructure.Api.ConfigurationManager.AppSettings["AllConnApiUrl"]; + if (!string.IsNullOrEmpty(url)) + { + url += $"?deskey={DesKey}"; + conns = WebUtils.Get>(url, ""); + + } + } + if (conns != null && conns.Any()) + { + foreach (var conn in conns) + { + dbs.Add(EncryptHelper.AesDecrypt(conn, DesKey)); + } + } + return dbs; + } + } + #endregion + +} \ No newline at end of file diff --git a/APT.Infrastructure.EF/SimpleEntityScaner.cs b/APT.Infrastructure.EF/SimpleEntityScaner.cs new file mode 100644 index 0000000..6a96b40 --- /dev/null +++ b/APT.Infrastructure.EF/SimpleEntityScaner.cs @@ -0,0 +1,53 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace APT.Infrastructure.EF +{ + public class SimpleEntityScaner : IEntityScaner + where TDbContext : DbContext + { + private static List dbProperties; + private static object locker = new object(); + + public IList ScanEntityTypes() + { + if (dbProperties == null) + { + lock (locker) + { + if (dbProperties == null) + { + var contextType = typeof(TDbContext); + var properties = contextType.GetProperties(); + var entityProperties = properties.Where(r => IsDbSet(r)).ToList(); + + dbProperties = new List(); + foreach (var property in entityProperties) + { + dbProperties.Add(new DbsetProperty + { + PropertyName = property.Name, + PropertyType = property.PropertyType.GetGenericArguments()[0] + }); + } + } + } + } + return dbProperties; + } + + bool IsDbSet(PropertyInfo property) + { + if (property.CanRead && property.PropertyType.IsGenericType + && typeof(DbSet<>).GetGenericTypeDefinition().Equals(property.PropertyType.GetGenericTypeDefinition())) + { + return true; + } + return false; + } + } +} diff --git a/APT.Infrastructure.EF/TenantBaseDbContext.cs b/APT.Infrastructure.EF/TenantBaseDbContext.cs new file mode 100644 index 0000000..95216c8 --- /dev/null +++ b/APT.Infrastructure.EF/TenantBaseDbContext.cs @@ -0,0 +1,39 @@ +using System; +using APT.Infrastructure.Api; +using Microsoft.EntityFrameworkCore; + +namespace APT.Infrastructure.EF +{ + public abstract class TenantBaseDbContext : DbContext, ITenantDbContext + { + public TenantInfo Tenant { get; protected internal set; } + private readonly IServiceProvider serviceProvider; + public TenantBaseDbContext(DbContextOptions options, TenantInfo tenant, IServiceProvider serviceProvider) + : base(options) + { + this.serviceProvider = serviceProvider; + this.Tenant = tenant; + } + public TenantBaseDbContext() + : base() + { + } + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + if (!string.IsNullOrEmpty(Tenant?.Conn)) + { + var builderType = typeof(ITenantEntityBuilder<>).MakeGenericType(this.GetType()); + + ITenantEntityBuilder entityBuilder = (ITenantEntityBuilder)serviceProvider.GetService(builderType); + + entityBuilder.UpdateEntities(modelBuilder); + } + else + { + base.OnModelCreating(modelBuilder); + } + + } + } +} diff --git a/APT.Infrastructure.EF/TenantEntityBuilder.cs b/APT.Infrastructure.EF/TenantEntityBuilder.cs new file mode 100644 index 0000000..b469e48 --- /dev/null +++ b/APT.Infrastructure.EF/TenantEntityBuilder.cs @@ -0,0 +1,48 @@ +using System; +using Microsoft.EntityFrameworkCore; +using APT.Infrastructure.Api; +namespace APT.Infrastructure.EF +{ + public class TenantEntityBuilder : ITenantEntityBuilder + where TDbContext : DbContext + { + private readonly IEntityScaner entityScaner; + private readonly TenantOption tenantOption; + + private readonly TenantInfo tenantInfo; + public TenantEntityBuilder(IEntityScaner entityScaner, TenantOption tenantOption, TenantInfo tenantInfo) + { + this.tenantInfo = tenantInfo; + this.tenantOption = tenantOption; + this.entityScaner = entityScaner; + } + + public void UpdateEntities(ModelBuilder modelBuilder) + { + var dbsetProperties = entityScaner.ScanEntityTypes(); + + foreach (var property in dbsetProperties) + { + var entity = modelBuilder.Entity(property.PropertyType); + switch (this.tenantOption.ConnectionType) + { + case ConnectionResolverType.BySchema: + var tableName = this.tenantOption.TableNameFunc?.Invoke(this.tenantInfo, property.PropertyName) + ?? property.PropertyName; + var schemaName = this.tenantOption.SchemaFunc?.Invoke(this.tenantInfo) + ?? this.tenantInfo.Name; + entity.ToTable(tableName, schemaName); + break; + case ConnectionResolverType.ByTable: + tableName = this.tenantOption.TableNameFunc?.Invoke(this.tenantInfo, property.PropertyName) + ?? $"{this.tenantInfo.Name}_{property.PropertyName}"; + entity.ToTable(tableName); + break; + default: + break; + } + } + } + + } +} diff --git a/APT.Infrastructure.EF/TenantModelCacheKey.cs b/APT.Infrastructure.EF/TenantModelCacheKey.cs new file mode 100644 index 0000000..97f5f4a --- /dev/null +++ b/APT.Infrastructure.EF/TenantModelCacheKey.cs @@ -0,0 +1,34 @@ +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; + +namespace APT.Infrastructure.EF +{ + internal sealed class TenantModelCacheKey : ModelCacheKey + where TDbContext : DbContext, ITenantDbContext + { + private readonly TDbContext context; + private readonly string identifier; + public TenantModelCacheKey(TDbContext context, string identifier) : base(context) + { + this.context = context; + this.identifier = identifier; + } + + protected override bool Equals(ModelCacheKey other) + { + return base.Equals(other) && (other as TenantModelCacheKey)?.identifier == identifier; + } + + public override int GetHashCode() + { + var hashCode = base.GetHashCode(); + if (identifier != null) + { + hashCode ^= identifier.GetHashCode(); + } + + return hashCode; + } + } +} diff --git a/APT.Infrastructure.EF/TenantModelCacheKeyFactory.cs b/APT.Infrastructure.EF/TenantModelCacheKeyFactory.cs new file mode 100644 index 0000000..9407613 --- /dev/null +++ b/APT.Infrastructure.EF/TenantModelCacheKeyFactory.cs @@ -0,0 +1,21 @@ +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; + +namespace APT.Infrastructure.EF +{ + public sealed class TenantModelCacheKeyFactory : ModelCacheKeyFactory + where TDbContext : DbContext, ITenantDbContext + { + + public override object Create(DbContext context) + { + var dbContext = context as TDbContext; + return new TenantModelCacheKey(dbContext, dbContext?.Tenant?.Name ?? "no_tenant_identifier"); + } + + public TenantModelCacheKeyFactory(ModelCacheKeyFactoryDependencies dependencies) : base(dependencies) + { + } + } +} diff --git a/APT.Infrastructure.EF/TenantOption.cs b/APT.Infrastructure.EF/TenantOption.cs new file mode 100644 index 0000000..92fc344 --- /dev/null +++ b/APT.Infrastructure.EF/TenantOption.cs @@ -0,0 +1,29 @@ +using System; +using APT.Infrastructure.Api; +namespace APT.Infrastructure.EF +{ + public class TenantOption + { + public TenantOption() + { + ConnectionType = ConnectionResolverType.ByDatabase; + DbType = DbIntegrationType.Postgre; + ConnectionName = "default"; + ConnectionPrefix = ""; + } + + public string Key { get; set; } + + public ConnectionResolverType ConnectionType { get; set; } + + public DbIntegrationType DbType { get; set; } + + public string ConnectionName { get; set; } + + public string ConnectionPrefix { get; set; } + + public Func TableNameFunc { get; set; } + + public Func SchemaFunc { get; set; } + } +} diff --git a/APT.Infrastructure.EF/TenantSettings.cs b/APT.Infrastructure.EF/TenantSettings.cs new file mode 100644 index 0000000..4db5432 --- /dev/null +++ b/APT.Infrastructure.EF/TenantSettings.cs @@ -0,0 +1,53 @@ +using System; +using APT.Infrastructure.Api; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; + +namespace APT.Infrastructure.EF +{ + public abstract class TenantSettings + { + public string Key { get; set; } + + public ConnectionResolverType ConnectionType { get; set; } + + public DbIntegrationType DbType { get; set; } + + public Func ConnectionGenerator { get; set; } + + public string ConnectionName { get; set; } + + public string ConnectionPrefix { get; set; } + + public Action DbContextOptionAction { get; set; } + + public Func TableNameFunc { get; set; } + + public Func SchemaFunc { get; set; } + + public Action DbContextSetup { get; set; } + } + public class TenantSettings + where TDbContext : DbContext + { + public string Key { get; set; } + + public ConnectionResolverType ConnectionType { get; set; } + + public DbIntegrationType DbType { get; set; } + + public Func ConnectionGenerator { get; set; } + + public string ConnectionName { get; set; } + + public string ConnectionPrefix { get; set; } + + public Action DbContextOptionAction { get; set; } + + public Func TableNameFunc { get; set; } + + public Func SchemaFunc { get; set; } + + public Action DbContextSetup { get; set; } + } +} diff --git a/APT.Infrastructure.Redis/APT.Infrastructure.Redis.csproj b/APT.Infrastructure.Redis/APT.Infrastructure.Redis.csproj new file mode 100644 index 0000000..2241a0e --- /dev/null +++ b/APT.Infrastructure.Redis/APT.Infrastructure.Redis.csproj @@ -0,0 +1,19 @@ + + + + netstandard2.1 + 1.0.0.18 + true + 1.0.0.18 + 1.0.0.18 + + + + + + + + + + + diff --git a/APT.Infrastructure.Redis/AppConfig.cs b/APT.Infrastructure.Redis/AppConfig.cs new file mode 100644 index 0000000..2d0374f --- /dev/null +++ b/APT.Infrastructure.Redis/AppConfig.cs @@ -0,0 +1,32 @@ +using APT.Redis.Configurations; +using Microsoft.Extensions.Configuration; +using System.Linq; + +namespace APT.Redis +{ + //public class AppConfig + //{ + // public static IConfigurationRoot Configuration { get; set; } + // // private static RedisOption _redisOptions; + // public static RedisOption RedisOption + // { + // get + // { + // var s = Configuration.GetSection("RedisConfig").GetChildren(); + // var conn = s.Any(i => i.Key == "RedisConnectionString")? s.FirstOrDefault(i => i.Key == "RedisConnectionString").Value:""; + // var pwd = s.Any(i => i.Key == "RedisConnectionPwd") ? s.FirstOrDefault(i => i.Key == "RedisConnectionPwd").Value : ""; + // var pKey = s.Any(i => i.Key == "RedisPrefixKey") ? s.FirstOrDefault(i => i.Key == "RedisPrefixKey").Value : ""; + // return new RedisOption() + // { + // RedisConnectionString = conn, + // RedisConnectionPwd =pwd, + // RedisPrefixKey = pKey + // }; + // } + // //internal set + // //{ + // // _redisOptions = value; + // //} + // } + //} +} diff --git a/APT.Infrastructure.Redis/Configurations/RedisConfig.cs b/APT.Infrastructure.Redis/Configurations/RedisConfig.cs new file mode 100644 index 0000000..6fe1975 --- /dev/null +++ b/APT.Infrastructure.Redis/Configurations/RedisConfig.cs @@ -0,0 +1,170 @@ +using APT.Redis.Configurations; +using StackExchange.Redis; +using System; +using System.Collections.Concurrent; + +namespace APT.Infrastructure.Core +{ + public class RedisConfig + { + //系统自定义Key前缀 + public static string SysCustomKey = ""; + //"127.0.0.1:6379,allowadmin=true + private static string RedisConnectionString = "192.168.0.167:6340,allowadmin=true"; + private static string RedisPwd = "redis123"; + + private static readonly ConcurrentDictionary ConnectionCache = new ConcurrentDictionary(); + private static readonly object Locker = new object(); + private static ConnectionMultiplexer _instance; + + static RedisConfig() + { + RedisOption option = ConfigurationManager.RedisOption; + if (option != null) + { + SysCustomKey = option.RedisPrefixKey; + RedisConnectionString = option.RedisConnectionString; + RedisPwd = option.RedisConnectionPwd; + } + else + { + throw new Exception($"未加载redis.json文件"); + } + } + + /// + /// 单例获取 + /// + public static ConnectionMultiplexer Instance + { + get + { + + if (_instance == null) + { + lock (Locker) + { + if (_instance == null || !_instance.IsConnected) + { + try + { + _instance = GetManager(); + } + catch (Exception ex) + { + throw new Exception("初始化Redis缓存错误," + ex.Message); + } + } + } + } + return _instance; + + } + } + + /// + /// 缓存获取 + /// + /// + /// + public static ConnectionMultiplexer GetConnectionMultiplexer(string connectionString) + { + if (!ConnectionCache.ContainsKey(connectionString)) + { + ConnectionCache[connectionString] = GetManager(connectionString); + } + return ConnectionCache[connectionString]; + } + + /// + /// + /// + /// + /// + private static ConnectionMultiplexer GetManager(string connectionString = null) + { + connectionString = connectionString ?? RedisConnectionString; + + var options = ConfigurationOptions.Parse(connectionString); + //options.ClientName = "root"; + options.AbortOnConnectFail = false; + options.Password = RedisPwd; + var connect = ConnectionMultiplexer.Connect(options); + + //注册如下事件 + connect.ConnectionFailed += MuxerConnectionFailed; + connect.ConnectionRestored += MuxerConnectionRestored; + connect.ErrorMessage += MuxerErrorMessage; + connect.ConfigurationChanged += MuxerConfigurationChanged; + connect.HashSlotMoved += MuxerHashSlotMoved; + connect.InternalError += MuxerInternalError; + return connect; + } + + + #region 事件 + /// + /// 配置更改时 + /// + /// + /// + private static void MuxerConfigurationChanged(object sender, EndPointEventArgs e) + { + System.Console.WriteLine("Configuration changed: " + e.EndPoint); + } + + /// + /// 发生错误时 + /// + /// + /// + private static void MuxerErrorMessage(object sender, RedisErrorEventArgs e) + { + System.Console.WriteLine("ErrorMessage: " + e.Message); + } + + /// + /// 重新建立连接之前的错误 + /// + /// + /// + private static void MuxerConnectionRestored(object sender, ConnectionFailedEventArgs e) + { + System.Console.WriteLine("ConnectionRestored: " + e.EndPoint); + } + + /// + /// 连接失败 , 如果重新连接成功你将不会收到这个通知 + /// + /// + /// + private static void MuxerConnectionFailed(object sender, ConnectionFailedEventArgs e) + { + System.Console.WriteLine("重新连接:Endpoint failed: " + e.EndPoint + ", " + e.FailureType + (e.Exception == null ? "" : (", " + e.Exception.Message))); + } + + /// + /// 更改集群 + /// + /// + /// + private static void MuxerHashSlotMoved(object sender, HashSlotMovedEventArgs e) + { + System.Console.WriteLine("HashSlotMoved:NewEndPoint" + e.NewEndPoint + ", OldEndPoint" + e.OldEndPoint); + } + + /// + /// redis类库错误 + /// + /// + /// + private static void MuxerInternalError(object sender, InternalErrorEventArgs e) + { + System.Console.WriteLine("InternalError:Message" + e.Exception.Message); + } + + #endregion 事件 + + + } +} diff --git a/APT.Infrastructure.Redis/Configurations/RedisConfigurationExtensions.cs b/APT.Infrastructure.Redis/Configurations/RedisConfigurationExtensions.cs new file mode 100644 index 0000000..de098de --- /dev/null +++ b/APT.Infrastructure.Redis/Configurations/RedisConfigurationExtensions.cs @@ -0,0 +1,42 @@ +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Configuration.Json; +using Microsoft.Extensions.FileProviders; +using System; +using System.Collections.Generic; +using System.Text; + +namespace APT.Redis.Configurations +{ + public static class RedisConfigurationExtensions + { + public static IConfigurationBuilder AddRedisFile(this IConfigurationBuilder builder, string path) + { + return AddRedisFile(builder, provider: null, path: path, optional: false, reloadOnChange: false); + } + + public static IConfigurationBuilder AddRedisFile(this IConfigurationBuilder builder, string path, bool optional) + { + return AddRedisFile(builder, provider: null, path: path, optional: optional, reloadOnChange: false); + } + + public static IConfigurationBuilder AddRedisFile(this IConfigurationBuilder builder, string path, bool optional, bool reloadOnChange) + { + return AddRedisFile(builder, provider: null, path: path, optional: optional, reloadOnChange: reloadOnChange); + } + + public static IConfigurationBuilder AddRedisFile(this IConfigurationBuilder builder, IFileProvider provider, string path, bool optional, bool reloadOnChange) + { + var source = new JsonConfigurationSource() + { + FileProvider = provider, + Path = path, + Optional = optional, + ReloadOnChange = reloadOnChange + }; + builder.Add(source); + //AppConfig.Configuration = builder.Build(); + //AppConfig.RedisOption = AppConfig.Configuration.GetSection("RedisConfig").Get(); + return builder; + } + } +} diff --git a/APT.Infrastructure.Redis/Configurations/RedisOption.cs b/APT.Infrastructure.Redis/Configurations/RedisOption.cs new file mode 100644 index 0000000..edd9d2a --- /dev/null +++ b/APT.Infrastructure.Redis/Configurations/RedisOption.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace APT.Redis.Configurations +{ + public class RedisOption + { + /// + /// Redis服务器 + /// + public string RedisConnectionString { get; set; } + + /// + /// Redis密码 + /// + public string RedisConnectionPwd { get; set; } + + /// + /// 系统自定义Key前缀 + /// + public string RedisPrefixKey { get; set; } + } +} diff --git a/APT.Infrastructure.Redis/RedisConfig.cs b/APT.Infrastructure.Redis/RedisConfig.cs new file mode 100644 index 0000000..f7afe46 --- /dev/null +++ b/APT.Infrastructure.Redis/RedisConfig.cs @@ -0,0 +1,170 @@ +using APT.Redis.Configurations; +using StackExchange.Redis; +using System; +using System.Collections.Concurrent; + +namespace APT.Redis +{ + public class RedisConfig + { + //系统自定义Key前缀 + public static string SysCustomKey = ""; + //"127.0.0.1:6379,allowadmin=true + private static string RedisConnectionString = "192.168.0.167:6340,allowadmin=true"; + private static string RedisPwd = "redis123"; + + private static readonly ConcurrentDictionary ConnectionCache = new ConcurrentDictionary(); + private static readonly object Locker = new object(); + private static ConnectionMultiplexer _instance; + + static RedisConfig() + { + RedisOption option = AppConfig.RedisOption; + if (option != null) + { + SysCustomKey = option.RedisPrefixKey; + RedisConnectionString = option.RedisConnectionString; + RedisPwd = option.RedisConnectionPwd; + } + else + { + throw new Exception($"未加载redis.json文件"); + } + } + + /// + /// 单例获取 + /// + public static ConnectionMultiplexer Instance + { + get + { + + if (_instance == null) + { + lock (Locker) + { + if (_instance == null || !_instance.IsConnected) + { + try + { + _instance = GetManager(); + } + catch (Exception ex) + { + throw new Exception("初始化Redis缓存错误," + ex.Message); + } + } + } + } + return _instance; + + } + } + + /// + /// 缓存获取 + /// + /// + /// + public static ConnectionMultiplexer GetConnectionMultiplexer(string connectionString) + { + if (!ConnectionCache.ContainsKey(connectionString)) + { + ConnectionCache[connectionString] = GetManager(connectionString); + } + return ConnectionCache[connectionString]; + } + + /// + /// + /// + /// + /// + private static ConnectionMultiplexer GetManager(string connectionString = null) + { + connectionString = connectionString ?? RedisConnectionString; + + var options = ConfigurationOptions.Parse(connectionString); + //options.ClientName = "root"; + options.AbortOnConnectFail = false; + options.Password = RedisPwd; + var connect = ConnectionMultiplexer.Connect(options); + + //注册如下事件 + connect.ConnectionFailed += MuxerConnectionFailed; + connect.ConnectionRestored += MuxerConnectionRestored; + connect.ErrorMessage += MuxerErrorMessage; + connect.ConfigurationChanged += MuxerConfigurationChanged; + connect.HashSlotMoved += MuxerHashSlotMoved; + connect.InternalError += MuxerInternalError; + return connect; + } + + + #region 事件 + /// + /// 配置更改时 + /// + /// + /// + private static void MuxerConfigurationChanged(object sender, EndPointEventArgs e) + { + System.Console.WriteLine("Configuration changed: " + e.EndPoint); + } + + /// + /// 发生错误时 + /// + /// + /// + private static void MuxerErrorMessage(object sender, RedisErrorEventArgs e) + { + System.Console.WriteLine("ErrorMessage: " + e.Message); + } + + /// + /// 重新建立连接之前的错误 + /// + /// + /// + private static void MuxerConnectionRestored(object sender, ConnectionFailedEventArgs e) + { + System.Console.WriteLine("ConnectionRestored: " + e.EndPoint); + } + + /// + /// 连接失败 , 如果重新连接成功你将不会收到这个通知 + /// + /// + /// + private static void MuxerConnectionFailed(object sender, ConnectionFailedEventArgs e) + { + System.Console.WriteLine("重新连接:Endpoint failed: " + e.EndPoint + ", " + e.FailureType + (e.Exception == null ? "" : (", " + e.Exception.Message))); + } + + /// + /// 更改集群 + /// + /// + /// + private static void MuxerHashSlotMoved(object sender, HashSlotMovedEventArgs e) + { + System.Console.WriteLine("HashSlotMoved:NewEndPoint" + e.NewEndPoint + ", OldEndPoint" + e.OldEndPoint); + } + + /// + /// redis类库错误 + /// + /// + /// + private static void MuxerInternalError(object sender, InternalErrorEventArgs e) + { + System.Console.WriteLine("InternalError:Message" + e.Exception.Message); + } + + #endregion 事件 + + + } +} diff --git a/APT.Infrastructure.Redis/RedisManager.cs b/APT.Infrastructure.Redis/RedisManager.cs new file mode 100644 index 0000000..83d06b3 --- /dev/null +++ b/APT.Infrastructure.Redis/RedisManager.cs @@ -0,0 +1,1225 @@ + +using Newtonsoft.Json; +using StackExchange.Redis; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Threading.Tasks; + +namespace APT.Redis +{ + /// + /// 缓存管理 + /// 1.要可以查看所有的缓存 + /// 2.要可以管理缓存中的数据,如清空,删除等 + /// 3.可以预先加载 + /// + public class RedisManager + { + public int DbNum { get; } + public ConnectionMultiplexer _conn; + + JsonSerializerSettings _jsonSetting; + + #region 构造函数 + + public RedisManager(int dbNum = 0) + { + DbNum = dbNum; + _conn = RedisConfig.Instance; + _jsonSetting = new JsonSerializerSettings(); + _jsonSetting.ReferenceLoopHandling = ReferenceLoopHandling.Ignore; + } + #endregion 构造函数 + + #region String + #region 同步方法 + + /// + /// 保存单个key value + /// + /// Redis Key + /// 保存的值 + /// 过期时间 + /// + public bool StringSet(string key, string value, TimeSpan? expiry = default(TimeSpan?)) + { + key = AddSysCustomKey(key); + return Do(db => db.StringSet(key, value, expiry)); + } + + /// + /// 保存多个key value + /// + /// 键值对 + /// + public bool StringSet(List> keyValues) + { + List> newkeyValues = + keyValues.Select(p => new KeyValuePair(AddSysCustomKey(p.Key), p.Value)).ToList(); + return Do(db => db.StringSet(newkeyValues.ToArray())); + } + + /// + /// 保存一个对象 + /// + /// + /// + /// + /// + /// + public bool StringSet(string key, T obj, TimeSpan? expiry = default(TimeSpan?)) + { + key = AddSysCustomKey(key); + string json = ConvertJson(obj); + return Do(db => db.StringSet(key, json, expiry)); + } + + /// + /// 保存一个对象 + /// + /// + /// + /// + /// + /// + public bool StringSet(string key, T obj, DateTime expiry) + { + key = AddSysCustomKey(key); + string json = ConvertJson(obj); + return Do(db => db.StringSet(key, json, expiry - DateTime.Now)); + } + + /// + /// 获取单个key的值 + /// + /// Redis Key + /// + public string StringGet(string key) + { + key = AddSysCustomKey(key); + return Do(db => db.StringGet(key)); + } + + /// + /// 获取多个Key + /// + /// Redis Key集合 + /// + public RedisValue[] StringGet(List listKey) + { + List newKeys = listKey.Select(AddSysCustomKey).ToList(); + return Do(db => db.StringGet(ConvertRedisKeys(newKeys))); + } + + /// + /// 获取一个key的对象 + /// + /// + /// + /// + public T StringGet(string key) + { + key = AddSysCustomKey(key); + return Do(db => ConvertObj(db.StringGet(key))); + } + + /// + /// 为数字增长val + /// + /// + /// 可以为负 + /// 增长后的值 + public double StringIncrement(string key, double val = 1) + { + key = AddSysCustomKey(key); + return Do(db => db.StringIncrement(key, val)); + } + + /// + /// 为数字减少val + /// + /// + /// 可以为负 + /// 减少后的值 + public double StringDecrement(string key, double val = 1) + { + key = AddSysCustomKey(key); + return Do(db => db.StringDecrement(key, val)); + } + + #endregion 同步方法 + + #region 异步方法 + + /// + /// 保存单个key value + /// + /// Redis Key + /// 保存的值 + /// 过期时间 + /// + public async Task StringSetAsync(string key, string value, TimeSpan? expiry = default(TimeSpan?)) + { + key = AddSysCustomKey(key); + return await Do(db => db.StringSetAsync(key, value, expiry)); + } + + /// + /// 保存多个key value + /// + /// 键值对 + /// + public async Task StringSetAsync(List> keyValues) + { + List> newkeyValues = + keyValues.Select(p => new KeyValuePair(AddSysCustomKey(p.Key), p.Value)).ToList(); + return await Do(db => db.StringSetAsync(newkeyValues.ToArray())); + } + + /// + /// 保存一个对象 + /// + /// + /// + /// + /// + /// + public async Task StringSetAsync(string key, T obj, TimeSpan? expiry = default(TimeSpan?)) + { + key = AddSysCustomKey(key); + string json = ConvertJson(obj); + return await Do(db => db.StringSetAsync(key, json, expiry)); + } + + /// + /// 获取单个key的值 + /// + /// Redis Key + /// + public async Task StringGetAsync(string key) + { + key = AddSysCustomKey(key); + return await Do(db => db.StringGetAsync(key)); + } + + /// + /// 获取多个Key + /// + /// Redis Key集合 + /// + public async Task StringGetAsync(List listKey) + { + List newKeys = listKey.Select(AddSysCustomKey).ToList(); + return await Do(db => db.StringGetAsync(ConvertRedisKeys(newKeys))); + } + + /// + /// 获取一个key的对象 + /// + /// + /// + /// + public async Task StringGetAsync(string key) + { + key = AddSysCustomKey(key); + string result = await Do(db => db.StringGetAsync(key)); + return ConvertObj(result); + + } + + /// + /// 为数字增长val + /// + /// + /// 可以为负 + /// 增长后的值 + public async Task StringIncrementAsync(string key, double val = 1) + { + key = AddSysCustomKey(key); + return await Do(db => db.StringIncrementAsync(key, val)); + } + + /// + /// 为数字减少val + /// + /// + /// 可以为负 + /// 减少后的值 + public async Task StringDecrementAsync(string key, double val = 1) + { + key = AddSysCustomKey(key); + return await Do(db => db.StringDecrementAsync(key, val)); + } + + #endregion 异步方法 + + #endregion String + + #region Hash + + #region 同步方法 + + /// + /// 判断某个数据是否已经被缓存 + /// + /// + /// + /// + public bool HashExists(string key, string dataKey) + { + key = AddSysCustomKey(key); + return Do(db => db.HashExists(key, dataKey)); + } + + /// + /// 存储数据到hash表 + /// + /// + /// + /// + /// + /// + public bool HashSet(string key, string dataKey, T t) + { + key = AddSysCustomKey(key); + return Do(db => + { + string json = ConvertJson(t); + return db.HashSet(key, dataKey, json); + }); + } + + /// + /// 移除hash中的某值 + /// + /// + /// + /// + public bool HashDelete(string key, string dataKey) + { + key = AddSysCustomKey(key); + return Do(db => db.HashDelete(key, dataKey)); + } + + /// + /// 移除hash中的多个值 + /// + /// + /// + /// + public long HashDelete(string key, List dataKeys) + { + key = AddSysCustomKey(key); + //List dataKeys1 = new List() {"1","2"}; + return Do(db => db.HashDelete(key, dataKeys.ToArray())); + } + + /// + /// 从hash表获取数据 + /// + /// + /// + /// + /// + public T HashGet(string key, string dataKey) + { + key = AddSysCustomKey(key); + return Do(db => + { + string value = db.HashGet(key, dataKey); + return ConvertObj(value); + }); + } + + /// + /// 为数字增长val + /// + /// + /// + /// 可以为负 + /// 增长后的值 + public double HashIncrement(string key, string dataKey, double val = 1) + { + key = AddSysCustomKey(key); + return Do(db => db.HashIncrement(key, dataKey, val)); + } + + /// + /// 为数字减少val + /// + /// + /// + /// 可以为负 + /// 减少后的值 + public double HashDecrement(string key, string dataKey, double val = 1) + { + key = AddSysCustomKey(key); + return Do(db => db.HashDecrement(key, dataKey, val)); + } + + /// + /// 获取hashkey所有Redis key + /// + /// + /// + /// + public List HashKeys(string key) + { + key = AddSysCustomKey(key); + return Do(db => + { + RedisValue[] values = db.HashKeys(key); + return ConvetList(values); + }); + } + + /// + /// + /// + /// + /// + /// + public List HashValues(string key) + { + var result = new List(); + key = AddSysCustomKey(key); + return Do(db => + { + HashEntry[] arr = db.HashGetAll(key); + foreach (var item in arr) + { + if (!item.Value.IsNullOrEmpty) + { + result.Add(JsonConvert.DeserializeObject(item.Value)); + } + } + return result; + }); + } + + public HashEntry[] HashValueAll(string key) + { + key = AddSysCustomKey(key); + return Do(db => + { + HashEntry[] arr = db.HashGetAll(key); + return arr; + }); + } + + #endregion 同步方法 + + #region 异步方法 + + /// + /// 判断某个数据是否已经被缓存 + /// + /// + /// + /// + public async Task HashExistsAsync(string key, string dataKey) + { + key = AddSysCustomKey(key); + return await Do(db => db.HashExistsAsync(key, dataKey)); + } + + /// + /// 存储数据到hash表 + /// + /// + /// + /// + /// + /// + public async Task HashSetAsync(string key, string dataKey, T t) + { + key = AddSysCustomKey(key); + return await Do(db => + { + string json = ConvertJson(t); + return db.HashSetAsync(key, dataKey, json); + }); + } + + /// + /// 移除hash中的某值 + /// + /// + /// + /// + public async Task HashDeleteAsync(string key, string dataKey) + { + key = AddSysCustomKey(key); + return await Do(db => db.HashDeleteAsync(key, dataKey)); + } + + /// + /// 移除hash中的多个值 + /// + /// + /// + /// + public async Task HashDeleteAsync(string key, List dataKeys) + { + key = AddSysCustomKey(key); + //List dataKeys1 = new List() {"1","2"}; + return await Do(db => db.HashDeleteAsync(key, dataKeys.ToArray())); + } + + /// + /// 从hash表获取数据 + /// + /// + /// + /// + /// + public async Task HashGetAsync(string key, string dataKey) + { + key = AddSysCustomKey(key); + string value = await Do(db => db.HashGetAsync(key, dataKey)); + return ConvertObj(value); + + } + + /// + /// 为数字增长val + /// + /// + /// + /// 可以为负 + /// 增长后的值 + public async Task HashIncrementAsync(string key, string dataKey, double val = 1) + { + key = AddSysCustomKey(key); + return await Do(db => db.HashIncrementAsync(key, dataKey, val)); + } + + /// + /// 为数字减少val + /// + /// + /// + /// 可以为负 + /// 减少后的值 + public async Task HashDecrementAsync(string key, string dataKey, double val = 1) + { + key = AddSysCustomKey(key); + return await Do(db => db.HashDecrementAsync(key, dataKey, val)); + } + + /// + /// 获取hashkey所有Redis key + /// + /// + /// + /// + public async Task> HashKeysAsync(string key) + { + key = AddSysCustomKey(key); + RedisValue[] values = await Do(db => db.HashKeysAsync(key)); + return ConvetList(values); + } + + /// + /// + /// + /// + /// + /// + public async Task> HashValuesAsync(string key) + { + var result = new List(); + key = AddSysCustomKey(key); + HashEntry[] arr = await Do(db => db.HashGetAllAsync(key)); + foreach (var item in arr) + { + string values = item.Name; + if (!item.Value.IsNullOrEmpty) + { + result.Add(JsonConvert.DeserializeObject(item.Value)); + } + } + return result; + } + /// + /// + /// + /// + /// + /// + public async Task HashValueAllAsync(string key) + { + key = AddSysCustomKey(key); + HashEntry[] arr = await Do(db => db.HashGetAllAsync(key)); + return arr; + } + #endregion 异步方法 + + #endregion Hash + + #region List + + #region 同步方法 + + /// + /// 移除指定ListId的内部List的值 + /// + /// + /// + public void ListRemove(string key, T value) + { + key = AddSysCustomKey(key); + Do(db => db.ListRemove(key, ConvertJson(value))); + } + + /// + /// 获取指定key的List + /// + /// + /// + public List ListRange(string key) + { + key = AddSysCustomKey(key); + return Do(redis => + { + var values = redis.ListRange(key); + return ConvetList(values); + }); + } + + /// + /// 入队 + /// + /// + /// + public void ListRightPush(string key, T value) + { + key = AddSysCustomKey(key); + Do(db => db.ListRightPush(key, ConvertJson(value))); + } + + /// + /// 出队 + /// + /// + /// + /// + public T ListRightPop(string key) + { + key = AddSysCustomKey(key); + return Do(db => + { + var value = db.ListRightPop(key); + return ConvertObj(value); + }); + } + + /// + /// 入栈 + /// + /// + /// + /// + public void ListLeftPush(string key, T value) + { + key = AddSysCustomKey(key); + Do(db => db.ListLeftPush(key, ConvertJson(value))); + } + + /// + /// 出栈 + /// + /// + /// + /// + public T ListLeftPop(string key) + { + key = AddSysCustomKey(key); + return Do(db => + { + var value = db.ListLeftPop(key); + return ConvertObj(value); + }); + } + + /// + /// 获取集合中的数量 + /// + /// + /// + public long ListLength(string key) + { + key = AddSysCustomKey(key); + return Do(redis => redis.ListLength(key)); + } + + #endregion 同步方法 + + #region 异步方法 + + /// + /// 移除指定ListId的内部List的值 + /// + /// + /// + public async Task ListRemoveAsync(string key, T value) + { + key = AddSysCustomKey(key); + return await Do(db => db.ListRemoveAsync(key, ConvertJson(value))); + } + + /// + /// 获取指定key的List + /// + /// + /// + public async Task> ListRangeAsync(string key) + { + key = AddSysCustomKey(key); + var values = await Do(redis => redis.ListRangeAsync(key)); + return ConvetList(values); + } + + /// + /// 入队 + /// + /// + /// + public async Task ListRightPushAsync(string key, T value) + { + key = AddSysCustomKey(key); + return await Do(db => db.ListRightPushAsync(key, ConvertJson(value))); + } + + /// + /// 出队 + /// + /// + /// + /// + public async Task ListRightPopAsync(string key) + { + key = AddSysCustomKey(key); + var value = await Do(db => db.ListRightPopAsync(key)); + return ConvertObj(value); + } + + /// + /// 入栈 + /// + /// + /// + /// + public async Task ListLeftPushAsync(string key, T value) + { + key = AddSysCustomKey(key); + return await Do(db => db.ListLeftPushAsync(key, ConvertJson(value))); + } + + /// + /// 出栈 + /// + /// + /// + /// + public async Task ListLeftPopAsync(string key) + { + key = AddSysCustomKey(key); + var value = await Do(db => db.ListLeftPopAsync(key)); + return ConvertObj(value); + } + + /// + /// 获取集合中的数量 + /// + /// + /// + public async Task ListLengthAsync(string key) + { + key = AddSysCustomKey(key); + return await Do(redis => redis.ListLengthAsync(key)); + } + + #endregion 异步方法 + + #endregion List + + #region SortedSet 有序集合 + + #region 同步方法 + + /// + /// 添加 + /// + /// + /// + /// + public bool SortedSetAdd(string key, T value, double score) + { + key = AddSysCustomKey(key); + + return Do(redis => redis.SortedSetAdd(key, ConvertJson(value), score)); + } + + /// + /// 添加???????? + /// + /// + /// + /// + public double SortedSetIncrement(string key, T value, double score) + { + key = AddSysCustomKey(key); + + return Do(redis => redis.SortedSetIncrement(key, ConvertJson(value), score)); + } + + public bool SortedSetAdd(string key, SortedSetEntry[] values) + { + key = AddSysCustomKey(key); + Do(redis => redis.SortedSetAdd(key, values, CommandFlags.None)); + return true; + } + public async Task SortedSetAddAsync(string key, SortedSetEntry[] values) + { + key = AddSysCustomKey(key); + await Do(redis => redis.SortedSetAddAsync(key, values)); + return true; + } + /// + /// 删除 + /// + /// + /// + public bool SortedSetRemove(string key, T value) + { + key = AddSysCustomKey(key); + return Do(redis => redis.SortedSetRemove(key, ConvertJson(value))); + } + + /// + /// 获取全部 + /// + /// + /// + public List SortedSetRangeByRank(string key) + { + key = AddSysCustomKey(key); + return Do(redis => + { + var values = redis.SortedSetRangeByRank(key); + return ConvetList(values); + }); + } + + /// + /// 获取全部 + /// + /// + /// + public RedisValue[] SortedSetRangeByRank(string key) + { + key = AddSysCustomKey(key); + return Do(redis => + { + return redis.SortedSetRangeByRank(key); + + }); + } + + public IEnumerable SortedSetScan(string key, RedisValue pattern = default) + { + key = AddSysCustomKey(key); + return Do(redis => + { + return redis.SortedSetScan(key, pattern); + }); + } + public async Task> SortedSetScanAsync(string key, RedisValue pattern = default) + { + key = AddSysCustomKey(key); + return Do(redis => + { + return redis.SortedSetScanAsync(key,pattern); + }); + } + + + /// + /// 获取集合中的数量 + /// + /// + /// + public long SortedSetLength(string key) + { + key = AddSysCustomKey(key); + return Do(redis => redis.SortedSetLength(key)); + } + + #endregion 同步方法 + + #region 异步方法 + + /// + /// 添加 + /// + /// + /// + /// + public async Task SortedSetAddAsync(string key, T value, double score) + { + key = AddSysCustomKey(key); + return await Do(redis => redis.SortedSetAddAsync(key, ConvertJson(value), score)); + } + + /// + /// 删除 + /// + /// + /// + public async Task SortedSetRemoveAsync(string key, T value) + { + key = AddSysCustomKey(key); + return await Do(redis => redis.SortedSetRemoveAsync(key, ConvertJson(value))); + } + + /// + /// 获取全部 + /// + /// + /// + public async Task> SortedSetRangeByRankAsync(string key) + { + key = AddSysCustomKey(key); + var values = await Do(redis => redis.SortedSetRangeByRankAsync(key)); + return ConvetList(values); + } + + /// + /// 获取集合中的数量 + /// + /// + /// + public async Task SortedSetLengthAsync(string key) + { + key = AddSysCustomKey(key); + return await Do(redis => redis.SortedSetLengthAsync(key)); + } + + #endregion 异步方法 + + #endregion SortedSet 有序集合 + + #region key + + /// + /// 删除单个key + /// + /// redis key + /// 是否删除成功 + public bool KeyDelete(string key) + { + key = AddSysCustomKey(key); + return Do(db => db.KeyDelete(key)); + } + public async Task KeyDeleteAsync(string key) + { + key = AddSysCustomKey(key); + return await Do(db => db.KeyDeleteAsync(key)); + } + /// + /// 删除多个key + /// + /// rediskey + /// 成功删除的个数 + public long KeyDelete(List keys) + { + List newKeys = keys.Select(AddSysCustomKey).ToList(); + return Do(db => db.KeyDelete(ConvertRedisKeys(newKeys))); + } + + /// + /// 判断key是否存储 + /// + /// redis key + /// + public bool KeyExists(string key) + { + key = AddSysCustomKey(key); + return Do(db => db.KeyExists(key)); + } + + /// + /// 重新命名key + /// + /// 就的redis key + /// 新的redis key + /// + public bool KeyRename(string key, string newKey) + { + key = AddSysCustomKey(key); + return Do(db => db.KeyRename(key, newKey)); + } + + /// + /// 设置Key的时间 + /// + /// redis key + /// + /// + public bool KeyExpire(string key, TimeSpan? expiry = default(TimeSpan?)) + { + key = AddSysCustomKey(key); + return Do(db => db.KeyExpire(key, expiry)); + } + + /// + /// 获取所有KEY + /// + /// + public List GetAllCacheKeys() + { + try + { + var result = new List(); + var endpoints = _conn.GetEndPoints(true); + foreach (var endpoint in endpoints) + { + var server = _conn.GetServer(endpoint); + result.AddRange(server.Keys(DbNum).Select(x => x.ToString())); + } + return result.Distinct().ToList(); + } + catch + { + return null; + } + } + + /// + /// 获取所有KEY-Value + /// + /// + public IDictionary GetAll() + { + try + { + var result = new Dictionary(); + IDatabase idb = _conn.GetDatabase(DbNum); + var endpoints = _conn.GetEndPoints(true); + foreach (var endpoint in endpoints) + { + var server = _conn.GetServer(endpoint); + foreach (var item in server.Keys(DbNum)) + { + result.Add(item.ToString(), idb.StringGet(item.ToString())); + } + } + return result; + } + catch + { + return null; + } + } + + + #endregion key + + #region 发布订阅 + + /// + /// Redis发布订阅 订阅 + /// + /// + /// + public void Subscribe(string subChannel, Action handler = null) + { + ISubscriber sub = _conn.GetSubscriber(); + sub.Subscribe(subChannel, (channel, message) => + { + if (handler == null) + { + Console.WriteLine(subChannel + " 订阅收到消息:" + message); + } + else + { + handler(channel, message); + } + }); + } + + /// + /// Redis发布订阅 发布 + /// + /// + /// + /// + /// + public long Publish(string channel, T msg) + { + ISubscriber sub = _conn.GetSubscriber(); + return sub.Publish(channel, ConvertJson(msg)); + } + + /// + /// Redis发布订阅 取消订阅 + /// + /// + public void Unsubscribe(string channel) + { + ISubscriber sub = _conn.GetSubscriber(); + sub.Unsubscribe(channel); + } + + /// + /// Redis发布订阅 取消全部订阅 + /// + public void UnsubscribeAll() + { + ISubscriber sub = _conn.GetSubscriber(); + sub.UnsubscribeAll(); + } + + #endregion 发布订阅 + + #region 其他 + /// + /// 获取list的redis + /// + /// + /// + public List GetListKeys(Guid orgid) + { + return this.HashValueAll("opt_list_" + orgid).ToList(); + } + /// + /// 删除list中的某张表数据 + /// + /// + /// + /// + public bool DeleteListKeys(Guid orgid, string name) + { + if (this.HashExists("opt_list_" + orgid, name)) + { + return this.HashDelete("opt_list_" + orgid, name); + } + return true; + } + /// + /// 是否存在 + /// + /// + /// + /// + public bool ExistsListKeys(Guid orgid, string name) + { + return this.HashExists("opt_list_" + orgid, name); + } + /// + /// 获取list中表的rediskey + /// + /// + /// + /// + public string GetListKey(Guid orgid, string name) + { + return this.HashGet("opt_list_" + orgid, name); + } + + public ITransaction CreateTransaction() + { + return GetDatabase().CreateTransaction(); + } + + public IDatabase GetDatabase() + { + return _conn.GetDatabase(DbNum); + } + + public IServer GetServer(string hostAndPort) + { + return _conn.GetServer(hostAndPort); + } + #endregion 其他 + + #region 辅助方法 + + private string AddSysCustomKey(string oldKey) + { + var prefixKey = RedisConfig.SysCustomKey; + return prefixKey + oldKey; + } + + private T Do(Func func) + { + try + { + var database = _conn.GetDatabase(DbNum); + return func(database); + } + catch (Exception ex) + { + Console.WriteLine($"reids.do:{ex.Message}"); + return default(T); + } + } + + public string ConvertJson(T value) + { + string result = value is string ? value.ToString() : JsonConvert.SerializeObject(value, _jsonSetting); + return result; + } + + //private T ConvertObj(RedisValue value) + //{ + // if (value.HasValue) + // { + // // return SerializerJson.DeserializeObject(value); + // return Newtonsoft.Json.JsonConvert.DeserializeObject(value); + // //return SerializerJson.DeserializeObject(value); + // } + // return default(T); + //} + + private T ConvertObj(RedisValue value) + { + if (typeof(T).Name.Equals(typeof(string).Name)) + { + return JsonConvert.DeserializeObject($"'{value}'"); + } + else + { + T t = JsonConvert.DeserializeObject(value); + if (t == null) + { + Console.WriteLine($"reids.ConvertObj.t:{null}"); + } + return t; + } + } + + + private List ConvetList(RedisValue[] values) + { + List result = new List(); + foreach (var item in values) + { + var model = ConvertObj(item); + result.Add(model); + } + return result; + } + + private RedisKey[] ConvertRedisKeys(List redisKeys) + { + return redisKeys.Select(redisKey => (RedisKey)redisKey).ToArray(); + } + + #endregion 辅助方法 + + } +} diff --git a/APT.Migrations/APT.Migrations.csproj b/APT.Migrations/APT.Migrations.csproj new file mode 100644 index 0000000..93e40c7 --- /dev/null +++ b/APT.Migrations/APT.Migrations.csproj @@ -0,0 +1,24 @@ + + + + net5.0 + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + diff --git a/APT.Migrations/MigrationContext.cs b/APT.Migrations/MigrationContext.cs new file mode 100644 index 0000000..6f32b8f --- /dev/null +++ b/APT.Migrations/MigrationContext.cs @@ -0,0 +1,23 @@ +using APT.Infrastructure.Core; +using APT.Infrastructure.EF; +using Microsoft.EntityFrameworkCore; + +namespace APT.Migrations +{ + public class MigrationContext + { + private readonly string connectionString; + + public MigrationContext() + : this("default") + { + + } + + public MigrationContext(string connectionString) + { + this.connectionString = connectionString; + } + + } +} diff --git a/APT.Migrations/Migrations/MigrationContextModelSnapshot.cs b/APT.Migrations/Migrations/MigrationContextModelSnapshot.cs new file mode 100644 index 0000000..b91d73b --- /dev/null +++ b/APT.Migrations/Migrations/MigrationContextModelSnapshot.cs @@ -0,0 +1,562 @@ +// +using System; +using APT.Migrations; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +namespace APT.Migrations.Migrations +{ + [DbContext(typeof(MigrationContext))] + partial class MigrationContextModelSnapshot : ModelSnapshot + { + protected override void BuildModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn) + .HasAnnotation("ProductVersion", "3.1.2") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + modelBuilder.Entity("APT.Domain.APT_Test_Course", b => + { + b.Property("ID") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CREATER_ID") + .HasColumnType("uuid"); + + b.Property("CREATE_TIME") + .HasColumnType("timestamp without time zone"); + + b.Property("ClassTime") + .HasColumnType("text"); + + b.Property("ENTITY_ORG_TPYE") + .HasColumnType("integer"); + + b.Property("FLOW_ID") + .HasColumnType("uuid"); + + b.Property("FLOW_SEND_STATUS") + .HasColumnType("integer"); + + b.Property("FLOW_STATUS") + .HasColumnType("integer"); + + b.Property("FORM_ID") + .HasColumnType("uuid"); + + b.Property("IS_DELETED") + .HasColumnType("boolean"); + + b.Property("MODIFIER_ID") + .HasColumnType("uuid"); + + b.Property("MODIFY_TIME") + .HasColumnType("timestamp without time zone"); + + b.Property("Name") + .HasColumnType("text"); + + b.Property("Nav_OrgID") + .HasColumnType("uuid"); + + b.Property("ORG_ID") + .HasColumnType("uuid"); + + b.Property("Score") + .HasColumnType("integer"); + + b.Property("TeacherName") + .HasColumnType("text"); + + b.Property("UserID") + .HasColumnType("uuid"); + + b.HasKey("ID"); + + b.HasIndex("Nav_OrgID"); + + b.HasIndex("UserID"); + + b.ToTable("APT_Test_Course"); + }); + + modelBuilder.Entity("APT.Domain.APT_Test_Phone", b => + { + b.Property("ID") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Brand") + .HasColumnType("text"); + + b.Property("CREATER_ID") + .HasColumnType("uuid"); + + b.Property("CREATE_TIME") + .HasColumnType("timestamp without time zone"); + + b.Property("ENTITY_ORG_TPYE") + .HasColumnType("integer"); + + b.Property("FLOW_ID") + .HasColumnType("uuid"); + + b.Property("FLOW_SEND_STATUS") + .HasColumnType("integer"); + + b.Property("FLOW_STATUS") + .HasColumnType("integer"); + + b.Property("FORM_ID") + .HasColumnType("uuid"); + + b.Property("IS_DELETED") + .HasColumnType("boolean"); + + b.Property("MODIFIER_ID") + .HasColumnType("uuid"); + + b.Property("MODIFY_TIME") + .HasColumnType("timestamp without time zone"); + + b.Property("Model") + .HasColumnType("text"); + + b.Property("Nav_OrgID") + .HasColumnType("uuid"); + + b.Property("Number") + .HasColumnType("integer"); + + b.Property("ORG_ID") + .HasColumnType("uuid"); + + b.Property("Price") + .HasColumnType("numeric"); + + b.Property("TestUser_ID") + .HasColumnType("uuid"); + + b.HasKey("ID"); + + b.HasIndex("Nav_OrgID"); + + b.HasIndex("TestUser_ID"); + + b.ToTable("APT_Test_Phone"); + }); + + modelBuilder.Entity("APT.Domain.APT_Test_User", b => + { + b.Property("ID") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CREATER_ID") + .HasColumnType("uuid"); + + b.Property("CREATE_TIME") + .HasColumnType("timestamp without time zone"); + + b.Property("Country") + .HasColumnType("text"); + + b.Property("ENTITY_ORG_TPYE") + .HasColumnType("integer"); + + b.Property("FLOW_ID") + .HasColumnType("uuid"); + + b.Property("FLOW_SEND_STATUS") + .HasColumnType("integer"); + + b.Property("FLOW_STATUS") + .HasColumnType("integer"); + + b.Property("FORM_ID") + .HasColumnType("uuid"); + + b.Property("FirstName") + .HasColumnType("text"); + + b.Property("IS_DELETED") + .HasColumnType("boolean"); + + b.Property("LastName") + .HasColumnType("text"); + + b.Property("MODIFIER_ID") + .HasColumnType("uuid"); + + b.Property("MODIFY_TIME") + .HasColumnType("timestamp without time zone"); + + b.Property("Nav_OrgID") + .HasColumnType("uuid"); + + b.Property("ORG_ID") + .HasColumnType("uuid"); + + b.HasKey("ID"); + + b.HasIndex("Nav_OrgID"); + + b.ToTable("APT_Test_User"); + }); + + modelBuilder.Entity("APT.Domain.TestNoneBaseModel", b => + { + b.Property("ID") + .HasColumnType("text"); + + b.Property("Name") + .HasColumnType("text"); + + b.HasKey("ID"); + + b.ToTable("TestNoneBaseModel"); + }); + + modelBuilder.Entity("APT.Infrastructure.Core.DataUpdateRecord", b => + { + b.Property("ID") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + b.Property("CREATER_ID") + .HasColumnType("uuid"); + + b.Property("CREATE_TIME") + .HasColumnType("timestamp without time zone"); + + b.Property("DataID") + .HasColumnType("uuid"); + + b.Property("ENTITY_ORG_TPYE") + .HasColumnType("integer"); + + b.Property("EntityFullName") + .HasColumnType("character varying(200)") + .HasMaxLength(200); + + b.Property("EntityName") + .HasColumnType("character varying(50)") + .HasMaxLength(50); + + b.Property("FLOW_ID") + .HasColumnType("uuid"); + + b.Property("FLOW_SEND_STATUS") + .HasColumnType("integer"); + + b.Property("FLOW_STATUS") + .HasColumnType("integer"); + + b.Property("FORM_ID") + .HasColumnType("uuid"); + + b.Property("IS_DELETED") + .HasColumnType("boolean"); + + b.Property("MODIFIER_ID") + .HasColumnType("uuid"); + + b.Property("MODIFY_TIME") + .HasColumnType("timestamp without time zone"); + + b.Property("Nav_OrgID") + .HasColumnType("uuid"); + + b.Property("ORG_ID") + .HasColumnType("uuid"); + + b.Property("TargetDepartmentID") + .HasColumnType("uuid"); + + b.Property("UpdateFiled") + .HasColumnType("character varying(2000)") + .HasMaxLength(2000); + + b.Property("UpdateType") + .HasColumnType("integer"); + + b.HasKey("ID"); + + b.HasIndex("Nav_OrgID"); + + b.ToTable("DataUpdateRecord"); + }); + + modelBuilder.Entity("APT.Infrastructure.Core.T_FM_ORGANIZATION", b => + { + b.Property("ID") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CODE") + .HasColumnType("character varying(100)") + .HasMaxLength(100); + + b.Property("CREATER_ID") + .HasColumnType("uuid"); + + b.Property("CREATE_TIME") + .HasColumnType("timestamp without time zone"); + + b.Property("DESC") + .HasColumnType("character varying(400)") + .HasMaxLength(400); + + b.Property("ENABLE_STATUS") + .HasColumnType("integer"); + + b.Property("ENTITY_ORG_TPYE") + .HasColumnType("integer"); + + b.Property("FLOW_ID") + .HasColumnType("uuid"); + + b.Property("FLOW_SEND_STATUS") + .HasColumnType("integer"); + + b.Property("FLOW_STATUS") + .HasColumnType("integer"); + + b.Property("FORM_ID") + .HasColumnType("uuid"); + + b.Property("IS_DELETED") + .HasColumnType("boolean"); + + b.Property("IS_LEAF") + .HasColumnType("boolean"); + + b.Property("MODIFIER_ID") + .HasColumnType("uuid"); + + b.Property("MODIFY_TIME") + .HasColumnType("timestamp without time zone"); + + b.Property("NAME") + .HasColumnType("character varying(200)") + .HasMaxLength(200); + + b.Property("ORG_ID") + .HasColumnType("uuid"); + + b.Property("PARENT_ID") + .HasColumnType("uuid"); + + b.Property("TEXT") + .HasColumnType("character varying(50)") + .HasMaxLength(50); + + b.HasKey("ID"); + + b.HasIndex("ORG_ID"); + + b.ToTable("T_FM_ORGANIZATION"); + }); + + modelBuilder.Entity("APT.Infrastructure.Core.T_PF_CODE_RULE_SERIAL", b => + { + b.Property("ID") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CODE_TYPE") + .HasColumnType("integer"); + + b.Property("CREATER_ID") + .HasColumnType("uuid"); + + b.Property("CREATE_TIME") + .HasColumnType("timestamp without time zone"); + + b.Property("DATE_VALUE") + .HasColumnType("character varying(30)") + .HasMaxLength(30); + + b.Property("ENTITY_ORG_TPYE") + .HasColumnType("integer"); + + b.Property("FLOW_ID") + .HasColumnType("uuid"); + + b.Property("FLOW_SEND_STATUS") + .HasColumnType("integer"); + + b.Property("FLOW_STATUS") + .HasColumnType("integer"); + + b.Property("FORM_ID") + .HasColumnType("uuid"); + + b.Property("IS_DELETED") + .HasColumnType("boolean"); + + b.Property("MODIFIER_ID") + .HasColumnType("uuid"); + + b.Property("MODIFY_TIME") + .HasColumnType("timestamp without time zone"); + + b.Property("NUM") + .HasColumnType("integer"); + + b.Property("ORG_ID") + .IsRequired() + .HasColumnType("uuid"); + + b.Property("RELEASE_TIME") + .HasColumnType("timestamp without time zone"); + + b.Property("ROW_VERSION") + .HasColumnType("integer"); + + b.Property("SERIAL") + .HasColumnType("character varying(50)") + .HasMaxLength(50); + + b.Property("STATUS") + .HasColumnType("integer"); + + b.Property("TAKE_TIME") + .HasColumnType("timestamp without time zone"); + + b.Property("USE_TIME") + .HasColumnType("timestamp without time zone"); + + b.HasKey("ID"); + + b.HasIndex("ORG_ID", "CODE_TYPE", "SERIAL"); + + b.HasIndex("ORG_ID", "CODE_TYPE", "DATE_VALUE", "SERIAL"); + + b.HasIndex("ORG_ID", "CODE_TYPE", "STATUS", "NUM"); + + b.HasIndex("ORG_ID", "CODE_TYPE", "DATE_VALUE", "STATUS", "NUM"); + + b.ToTable("T_PF_CODE_RULE_SERIAL"); + }); + + modelBuilder.Entity("APT.Infrastructure.Core.T_PF_PARAM", b => + { + b.Property("ID") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("APT_Test_CourseID") + .HasColumnType("uuid"); + + b.Property("APT_Test_PhoneID") + .HasColumnType("uuid"); + + b.Property("APT_Test_UserID") + .HasColumnType("uuid"); + + b.Property("CODE") + .HasColumnType("character varying(60)") + .HasMaxLength(60); + + b.Property("CREATE_TIME") + .HasColumnType("timestamp without time zone"); + + b.Property("ENTITY_ID") + .HasColumnType("uuid"); + + b.Property("VALUE") + .HasColumnType("character varying(600)") + .HasMaxLength(600); + + b.HasKey("ID"); + + b.HasIndex("APT_Test_CourseID"); + + b.HasIndex("APT_Test_PhoneID"); + + b.HasIndex("APT_Test_UserID"); + + b.ToTable("T_PF_PARAM"); + }); + + modelBuilder.Entity("APT.Domain.APT_Test_Course", b => + { + b.HasOne("APT.Infrastructure.Core.T_FM_ORGANIZATION", "Nav_Org") + .WithMany() + .HasForeignKey("Nav_OrgID"); + + b.HasOne("APT.Domain.APT_Test_User", "TestUser") + .WithMany("Courses") + .HasForeignKey("UserID") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("APT.Domain.APT_Test_Phone", b => + { + b.HasOne("APT.Infrastructure.Core.T_FM_ORGANIZATION", "Nav_Org") + .WithMany() + .HasForeignKey("Nav_OrgID"); + + b.HasOne("APT.Domain.APT_Test_User", "Nav_TestUser") + .WithMany() + .HasForeignKey("TestUser_ID") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("APT.Domain.APT_Test_User", b => + { + b.HasOne("APT.Infrastructure.Core.T_FM_ORGANIZATION", "Nav_Org") + .WithMany() + .HasForeignKey("Nav_OrgID"); + }); + + modelBuilder.Entity("APT.Infrastructure.Core.DataUpdateRecord", b => + { + b.HasOne("APT.Infrastructure.Core.T_FM_ORGANIZATION", "Nav_Org") + .WithMany() + .HasForeignKey("Nav_OrgID"); + }); + + modelBuilder.Entity("APT.Infrastructure.Core.T_FM_ORGANIZATION", b => + { + b.HasOne("APT.Infrastructure.Core.T_FM_ORGANIZATION", "Nav_Org") + .WithMany("Fm_Organizations") + .HasForeignKey("ORG_ID"); + }); + + modelBuilder.Entity("APT.Infrastructure.Core.T_PF_CODE_RULE_SERIAL", b => + { + b.HasOne("APT.Infrastructure.Core.T_FM_ORGANIZATION", "Nav_Org") + .WithMany() + .HasForeignKey("ORG_ID") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("APT.Infrastructure.Core.T_PF_PARAM", b => + { + b.HasOne("APT.Domain.APT_Test_Course", null) + .WithMany("Nav_SysParams") + .HasForeignKey("APT_Test_CourseID"); + + b.HasOne("APT.Domain.APT_Test_Phone", null) + .WithMany("Nav_SysParams") + .HasForeignKey("APT_Test_PhoneID"); + + b.HasOne("APT.Domain.APT_Test_User", null) + .WithMany("Nav_SysParams") + .HasForeignKey("APT_Test_UserID"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Apt.Infrastructure.Utility/APT.Infrastructure.Utility.csproj b/Apt.Infrastructure.Utility/APT.Infrastructure.Utility.csproj new file mode 100644 index 0000000..6f37e33 --- /dev/null +++ b/Apt.Infrastructure.Utility/APT.Infrastructure.Utility.csproj @@ -0,0 +1,20 @@ + + + + netstandard2.1 + 1.1.0.20 + 1.1.0.20 + 1.1.0.20 + true + + + + + + + + + + + + diff --git a/Apt.Infrastructure.Utility/Kafka/KafkaHelper.cs b/Apt.Infrastructure.Utility/Kafka/KafkaHelper.cs new file mode 100644 index 0000000..28d643c --- /dev/null +++ b/Apt.Infrastructure.Utility/Kafka/KafkaHelper.cs @@ -0,0 +1,344 @@ +//using Confluent.Kafka; +//using Confluent.Kafka.Admin; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net.Http.Headers; +using System.Runtime.CompilerServices; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace APT.Infrastructure.Utility +{ + /// + /// kafka操作类 + /// + //public static class KafkaHelper + //{ + // /// + // /// 生产 + // /// + // /// 服务器ip + // /// topic + // /// 消息key + // /// 消息内容 + // /// + // public static async Task Produce(string broker, string topic, string key, string text) + // { + + // var config = new ProducerConfig { BootstrapServers = broker }; + + // using (var producer = new ProducerBuilder(config).Build()) + // { + + + // if (text == null) + // { + // throw (new Exception("内容不可为空")); + + // } + // try + // { + // // Note: Awaiting the asynchronous produce request below prevents flow of execution + // // from proceeding until the acknowledgement from the broker is received (at the + // // expense of low throughput). + // var deliveryReport = await producer.ProduceAsync( + // topic, new Message { Key = key, Value = text }); + + // } + // catch (ProduceException e) + // { + // throw (new Exception($"failed to deliver message: {e.Message} [{e.Error.Code}]")); + // } + + // // Since we are producing synchronously, at this point there will be no messages + // // in-flight and no delivery reports waiting to be acknowledged, so there is no + // // need to call producer.Flush before disposing the producer. + // } + // } + + // /// + // /// 消费 + // /// + // /// 服务器ip + // /// topic + // /// 取消令牌 + // /// 接收消息处理事件 + // /// 每几条接收一次消息 + // /// 用户组 + // /// 是否持续读取 + // /// + // public static async Task Consume(string broker, string topic, CancellationTokenSource cts, Action> action, + // int commitPeriod = 5, string groupId = "optKafkaGroup", bool isContinue = false) + // { + // var config = new ProducerConfig { BootstrapServers = broker }; + // RunConsume(broker, new List { topic }, cts.Token, commitPeriod, groupId, action, isContinue); + // } + + // public static async Task ConsumeParallel(string broker, string topic, CancellationTokenSource cts, Action> action, + // int commitPeriod = 5, string groupId = "optKafkaGroup") + // { + // var config = new ProducerConfig { BootstrapServers = broker }; + // RunConsumeParallel(broker, new List { topic }, cts.Token, commitPeriod, groupId, action); + // } + + // /// + // /// 创建消息分类 + // /// + // /// 服务器 + // /// topic + // /// 备份数 + // /// patition数 + // /// + // public static async Task CreateTopicAsync(string broker, string topic, short replicationFactor = 1, short numPartitions = 1) + // { + // using (var adminClient = new AdminClientBuilder(new AdminClientConfig { BootstrapServers = broker }).Build()) + // { + // try + // { + // await adminClient.CreateTopicsAsync(new TopicSpecification[] { + // new TopicSpecification { Name = topic, ReplicationFactor = replicationFactor, NumPartitions =numPartitions } }); + // } + // catch (CreateTopicsException e) + // { + // Console.WriteLine($"An error occured creating topic {e.Results[0].Topic}: {e.Results[0].Error.Reason}"); + // throw e; + // } + // } + // } + + // private static void RunConsume(string brokerList, List topics, CancellationToken cancellationToken, int commitPeriod, string groupId, + // Action> Action, bool isContinue) + // { + // var config = new ConsumerConfig + // { + // BootstrapServers = brokerList, + // GroupId = groupId, + // EnableAutoCommit = false, + // StatisticsIntervalMs = 5000, + // SessionTimeoutMs = 6000, + // AutoOffsetReset = AutoOffsetReset.Earliest, + // EnablePartitionEof = true + // }; + + // //const int commitPeriod = 5; + + // // Note: If a key or value deserializer is not set (as is the case below), the + // // deserializer corresponding to the appropriate type from Confluent.Kafka.Deserializers + // // will be used automatically (where available). The default deserializer for string + // // is UTF8. The default deserializer for Ignore returns null for all input data + + // // (including non-null data). + // using (var consumer = new ConsumerBuilder(config) + // // Note: All handlers are called on the main .Consume thread. + // .SetErrorHandler((_, e) => Console.WriteLine($"Error: {e.Reason}")) + // .SetStatisticsHandler((_, json) => Console.WriteLine($"Statistics: {json}")) + // .SetPartitionsAssignedHandler((c, partitions) => + // { + // Console.WriteLine($"Assigned partitions: [{string.Join(", ", partitions)}]"); + // // possibly manually specify start offsets or override the partition assignment provided by + // // the consumer group by returning a list of topic/partition/offsets to assign to, e.g.: + // // + // // return partitions.Select(tp => new TopicPartitionOffset(tp, externalOffsets[tp])); + // }) + // .SetPartitionsRevokedHandler((c, partitions) => + // { + // Console.WriteLine($"Revoking assignment: [{string.Join(", ", partitions)}]"); + // }) + // .Build()) + // { + // consumer.Subscribe(topics); + // ConsumeResult consumeResult = null; + // ConsumeResult lastConsumeResult = null; + // List ReciveMessage = new List(); + + // try + // { + // while (true) + // { + + // try + // { + // consumeResult = consumer.Consume(cancellationToken); + // if (consumeResult.IsPartitionEOF) + // { + // //Console.WriteLine( + // //$"Reached end of topic {consumeResult.Topic}, partition {consumeResult.Partition}, offset {consumeResult.Offset}."); + // if (lastConsumeResult != null) + // { + // Action(ReciveMessage);//执行方法 + // try + // { + // consumer.Commit(lastConsumeResult); + + // } + // catch (KafkaException e) + // { + // Console.WriteLine($"Commit error: {e.Error.Reason}"); + // throw (e); + // } + // finally + // { + // ReciveMessage.Clear(); + // } + + // } + // if (isContinue) + // continue; + // else + // break; + // } + // ReciveMessage.Add(consumeResult.Message.Value); + // //Console.WriteLine($"Received message at {consumeResult.TopicPartitionOffset}: {consumeResult.Message.Value}"); + + // if (ReciveMessage.Count % commitPeriod == 0) + // { + // // The Commit method sends a "commit offsets" request to the Kafka + // // cluster and synchronously waits for the response. This is very + // // slow compared to the rate at which the consumer is capable of + // // consuming messages. A high performance application will typically + // // commit offsets relatively infrequently and be designed handle + // // duplicate messages in the event of failure. + // Action(ReciveMessage);//执行方法 + // try + // { + // consumer.Commit(consumeResult); + + // } + // catch (KafkaException e) + // { + // Console.WriteLine($"Commit error: {e.Error.Reason}"); + // throw (e); + // } + // finally + // { + // ReciveMessage.Clear(); + // } + // if (isContinue) + // continue; + // else + // break; + + // } + // lastConsumeResult = consumeResult; + // } + // catch (ConsumeException e) + // { + // Console.WriteLine($"Consume error: {e.Error.Reason}"); + // throw (e); + // } + // } + // } + // catch (OperationCanceledException e) + // { + // Console.WriteLine("Closing consumer."); + // consumer.Close(); + // throw (e); + // } + // catch (Exception e) + // { + // throw (e); + // } + // } + // } + + // private static void RunConsumeParallel(string brokerList, List topics, CancellationToken cancellationToken, int commitPeriod, string groupId, + // Action> Action) + // { + // var config = new ConsumerConfig + // { + // BootstrapServers = brokerList, + // GroupId = groupId, + // EnableAutoCommit = false, + // StatisticsIntervalMs = 5000, + // SessionTimeoutMs = 6000, + // AutoOffsetReset = AutoOffsetReset.Earliest, + // EnablePartitionEof = true + // }; + + // //const int commitPeriod = 5; + + // // Note: If a key or value deserializer is not set (as is the case below), the + // // deserializer corresponding to the appropriate type from Confluent.Kafka.Deserializers + // // will be used automatically (where available). The default deserializer for string + // // is UTF8. The default deserializer for Ignore returns null for all input data + + // // (including non-null data). + // using (var consumer = new ConsumerBuilder(config) + // // Note: All handlers are called on the main .Consume thread. + // .SetErrorHandler((_, e) => Console.WriteLine($"Error: {e.Reason}")) + // .SetStatisticsHandler((_, json) => Console.WriteLine($"Statistics: {json}")) + // .SetPartitionsAssignedHandler((c, partitions) => + // { + // Console.WriteLine($"Assigned partitions: [{string.Join(", ", partitions)}]"); + // // possibly manually specify start offsets or override the partition assignment provided by + // // the consumer group by returning a list of topic/partition/offsets to assign to, e.g.: + // // + // // return partitions.Select(tp => new TopicPartitionOffset(tp, externalOffsets[tp])); + // }) + // .SetPartitionsRevokedHandler((c, partitions) => + // { + // Console.WriteLine($"Revoking assignment: [{string.Join(", ", partitions)}]"); + // }) + // .Build()) + // { + // consumer.Subscribe(topics); + // List> consumeResultList = new List>(); + // ConsumeResult consumeResult = null; + // ConsumeResult lastConsumeResult = null; + // List ReciveMessage = new List(); + + // try + // { + // Task[] tasks = new Task[commitPeriod]; + // for (var x = 0; x < commitPeriod; x++) + // { + // tasks[x] = Task.Factory.StartNew(() => + // { + // try + // { + // consumeResult = consumer.Consume(cancellationToken); + // consumeResultList.Add(consumeResult); + // if (consumeResult.IsPartitionEOF) + // { + + // } + // } + // catch (ConsumeException e) + // { + // Console.WriteLine($"Consume error: {e.Error.Reason}"); + // throw (e); + // }; + // }); + // } + // Task.WaitAll(tasks); + // consumeResultList = consumeResultList.OrderBy(i => i.Offset.Value).ToList(); + // foreach (var s in consumeResultList) + // { + // if (s.Message != null && !string.IsNullOrEmpty(s.Message.Value)) + // { + // ReciveMessage.Add(s.Message.Value); + // } + // } + // if (ReciveMessage.Any()) + // { + // consumer.Commit(consumeResultList.LastOrDefault()); + // Action(ReciveMessage);//执行方法 + // } + + // } + // catch (OperationCanceledException e) + // { + // Console.WriteLine("Closing consumer."); + // consumer.Close(); + // throw (e); + // } + // catch (Exception e) + // { + // throw (e); + // } + // } + // } + //} +} diff --git a/Apt.Infrastructure.Utility/Redis/CsRedisHelper.cs b/Apt.Infrastructure.Utility/Redis/CsRedisHelper.cs new file mode 100644 index 0000000..4da5401 --- /dev/null +++ b/Apt.Infrastructure.Utility/Redis/CsRedisHelper.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Text; + +namespace APT.Infrastructure.Utility +{ + public static class CsRedisHelper where T : class + { + public static RedisClass GetRedisClass() + { + var type = typeof(T); + var attribute = type.GetCustomAttributes(typeof(RedisAttribute), false).FirstOrDefault() as RedisAttribute; + if (attribute == null) + { + return null; + } + + var attributelist = type.GetCustomAttributes(typeof(RedisAttribute), false).FirstOrDefault() as RedisAttribute; + if (attribute == null) + { + return null; + } + + var key = attribute.Key; + var props = type.GetProperties(); + var redisClass = new RedisClass(); + redisClass.ClassName = type.Name; + redisClass.GroupName = attribute.GroupField; + redisClass.DicKeys = new Dictionary(); + if (key.Any()) + { + foreach (var k in key) + { + var prp = props.FirstOrDefault(i => i.Name == k); + redisClass.DicKeys.Add(k, prp.PropertyType.Name); + } + + } + else + { + redisClass.DicKeys.Add("ID", "GUID"); + } + + return redisClass; + } + + } + + public class RedisClass + { + public string ClassName { get; set; } + + public string GroupName { get; set; } + public Dictionary DicKeys { get; set; } + } + +} diff --git a/Apt.Infrastructure.Utility/Redis/RedisAttributes.cs b/Apt.Infrastructure.Utility/Redis/RedisAttributes.cs new file mode 100644 index 0000000..1d15390 --- /dev/null +++ b/Apt.Infrastructure.Utility/Redis/RedisAttributes.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace APT.Infrastructure.Utility +{ + public class RedisAttribute : Attribute + { + private string[] _key; + private string _groupField; + + public string[] Key + { + get { return _key; } + } + public string GroupField + { + get { return _groupField; } + } + + + public RedisAttribute(string groupField, params string[] key) + { + _key = key; + _groupField = groupField; + } + } + + +} diff --git a/Apt.Infrastructure.Utility/Redis/RedisCache.cs b/Apt.Infrastructure.Utility/Redis/RedisCache.cs new file mode 100644 index 0000000..a24fb50 --- /dev/null +++ b/Apt.Infrastructure.Utility/Redis/RedisCache.cs @@ -0,0 +1,203 @@ +using Newtonsoft.Json; +using System; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace APT.Infrastructure.Utility +{ + public class RedisCache + { + public string GetString(string key) + { + return GetStringAsync(key).Result; + } + + public async Task GetStringAsync(string key) + { + try + { + string ReturnString = null; + var val = await RedisHelper.GetAsync(key); + + if (!string.IsNullOrEmpty(val)) + { + ReturnString = val; + } + + return ReturnString; + } + catch (Exception ex) + { + //LoggerManager.GetLogger().Error(ex.ToString()); + return null; + } + } + + public T Get(string key) + { + return GetAsync(key).Result; + } + + public async Task GetAsync(string key) + { + try + { + var value = await GetStringAsync(key); + if (!string.IsNullOrEmpty(value)) + { + return JsonConvert.DeserializeObject(value); + } + + return default(T); + } + catch (Exception ex) + { + //LoggerManager.GetLogger().Error(ex.ToString()); + return default(T); + } + } + + public T GetWithConfig(string key) where T : class + { + return this.GetWithConfigAsync(key).Result; + } + + public async Task GetWithConfigAsync(string key) where T : class + { + try + { + var redisclass = CsRedisHelper.GetRedisClass(); + var value = await GetStringAsync($"{redisclass.ClassName}_{key}"); + + if (!string.IsNullOrEmpty(value)) + { + return JsonConvert.DeserializeObject(value); + } + + return default(T); + } + catch (Exception ex) + { + //LoggerManager.GetLogger().Error(ex.ToString()); + return default(T); + } + } + + public void SetString(string key, string value, TimeSpan? expiredSpan = null) + { + this.SetStringAsync(key, value, expiredSpan).Wait(); + } + + public async Task SetStringAsync(string key, string value, TimeSpan? expiredSpan = null) + { + try + { + if (expiredSpan == null) + expiredSpan = new TimeSpan(90, 0, 0, 0);//默认90天 + + var expir = GetExpir(expiredSpan); + + await RedisHelper.SetAsync(key, value, expir); + } + catch (Exception ex) + { + //LoggerManager.GetLogger().Error(ex.ToString()); + } + } + + public void SetString(string key, T value, TimeSpan? expiredSpan = null) + { + this.SetStringAsync(key, value, expiredSpan).Wait(); + } + + public async Task SetStringAsync(string key, T value, TimeSpan? expiredSpan = null) + { + try + { + if (value == null) + { + return; + } + if (expiredSpan == null) + expiredSpan = new TimeSpan(90, 0, 0, 0);//默认90天 + + var val = SerializeObject(value); + + var expir = GetExpir(expiredSpan); + + await RedisHelper.SetAsync(key, val, expir); + } + catch (Exception ex) + { + //LoggerManager.GetLogger().Error(ex.ToString()); + } + } + + public bool Remove(string key) + { + return this.RemoveAsync(key).Result; + } + + public async Task RemoveAsync(string key) + { + try + { + bool ReturnBool = false; + if (key != "" || key != null) + { + await RedisHelper.DelAsync(key); + if (Exists(key) == false) + { + ReturnBool = true; + } + } + + return ReturnBool; + } + catch (Exception ex) + { + //LoggerManager.GetLogger().Error(ex.ToString()); + return false; + } + } + + public bool Exists(string key) + { + try + { + bool ReturnBool = true; + var val = RedisHelper.Get(key); + if (string.IsNullOrEmpty(val)) + { + ReturnBool = false; + } + + return ReturnBool; + } + catch (Exception ex) + { + //LoggerManager.GetLogger().Error(ex.ToString()); + return false; + } + } + + private string SerializeObject(T t) + { + return JsonConvert.SerializeObject(t, Formatting.Indented, + new JsonSerializerSettings { ReferenceLoopHandling = ReferenceLoopHandling.Ignore }); + } + + private int GetExpir(TimeSpan? expiredSpan) + { + var days = expiredSpan.Value.Days; + var hours = expiredSpan.Value.Hours; + var Minutes = expiredSpan.Value.Minutes; + var seconds = expiredSpan.Value.Seconds; + + var expir = days * 24 * 60 * 60 + hours * 60 * 60 + Minutes * 60 + seconds; + + return expir; + } + } +} diff --git a/Apt.Infrastructure.Utility/Redis/RedisHanddle.cs b/Apt.Infrastructure.Utility/Redis/RedisHanddle.cs new file mode 100644 index 0000000..def4baf --- /dev/null +++ b/Apt.Infrastructure.Utility/Redis/RedisHanddle.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace APT.Infrastructure.Utility +{ + public enum RedisHanddle + { + Query, + Add, + Update, + Delete + } + public enum RedisTypeEnum + { + String, + SortSet, + Set, + } + +}