From 1a729477407d9f78345c3beb52f510dc339a8269 Mon Sep 17 00:00:00 2001 From: root <8907060@qq.com> Date: Mon, 20 Jun 2022 12:38:59 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0util=206.x?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + Util.sln | 304 +- build/Build.csproj | 2 +- build/BuildScript.cs | 98 +- sample/Util.WebApi.Sample/Program.cs | 31 + .../Properties/AssemblyInfo.cs | 2 + .../Properties/launchSettings.json | 31 + .../Util.WebApi.Sample.csproj | 21 + .../appsettings.Development.json | 8 + sample/Util.WebApi.Sample/appsettings.json | 10 + solutions/Util.Data.slnf | 57 + solutions/Util.Localization.slnf | 19 + ...e.csproj => 03-Util.Aop.AspectCore.csproj} | 0 .../AopOptionsExtension.cs | 42 +- .../HostBuilderExtensions.cs | 19 - src/Util.Aop.AspectCore/OptionsExtensions.cs | 8 +- .../ServiceCollectionExtensions.cs | 43 - .../CrudServiceBase.cs | 2 +- .../Controllers/QueryControllerBase.cs | 6 +- .../Controllers/WebApiControllerBase.cs | 22 +- .../Filters/ExceptionHandlerAttribute.cs | 42 +- src/Util.Application.WebApi/IResultFactory.cs | 18 + .../Infrastructure/WebApiServiceRegistrar.cs | 15 +- src/Util.Application.WebApi/Result.cs | 28 +- .../Util.Application.WebApi.csproj | 2 +- src/Util.Application/Dtos/RequestBase.cs | 17 +- src/Util.Application/ExceptionExtensions.cs | 30 + src/Util.Application/StateCode.cs | 8 +- src/Util.Application/Util.Application.csproj | 1 + ...tCore.csproj => 07-Util.AspNetCore.csproj} | 0 src/Util.AspNetCore/Helpers/Web.cs | 12 + src/Util.AspNetCore/Http/HttpRequest.cs | 12 +- .../AspNetCoreServiceRegistrar.cs | 19 +- .../Security/DataProtectionEncryptor.cs | 36 + src/Util.Core/01-Util.Core.csproj | 14 +- src/Util.Core/Configs/IOptionsExtension.cs | 20 +- src/Util.Core/Configs/OptionsBase.cs | 6 +- src/Util.Core/Configs/OptionsExtensionBase.cs | 22 + src/Util.Core/Configs/PreOptions.cs | 7 + src/Util.Core/DateTimeExtensions.cs | 31 +- src/Util.Core/Dates/OptionsExtensions.cs | 18 + src/Util.Core/Dates/TimeOptions.cs | 11 + .../Exceptions/ConcurrencyException.cs | 24 +- src/Util.Core/Exceptions/Warning.cs | 28 +- src/Util.Core/Helpers/Common.cs | 2 +- src/Util.Core/Helpers/Config.cs | 40 +- src/Util.Core/Helpers/Convert.cs | 28 +- src/Util.Core/Helpers/Culture.cs | 38 + src/Util.Core/Helpers/Enum.cs | 4 +- src/Util.Core/Helpers/Environment.cs | 60 + src/Util.Core/Helpers/Id.cs | 13 +- src/Util.Core/Helpers/Json.cs | 40 + src/Util.Core/Helpers/Platform.cs | 6 +- src/Util.Core/Helpers/Time.cs | 60 +- src/Util.Core/HostBuilderExtensions.cs | 59 + src/Util.Core/Infrastructure/Bootstrapper.cs | 47 +- .../DependencyServiceRegistrar.cs | 15 +- .../Infrastructure/IServiceRegistrar.cs | 18 +- src/Util.Core/Properties/R.Designer.cs | 101 +- src/Util.Core/Properties/R.resx | 33 + .../Properties/UtilCoreResource.Designer.cs | 162 - src/Util.Core/Security/IEncryptor.cs | 17 + src/Util.Core/Security/NullEncryptor.cs | 27 + src/Util.Core/ServiceCollectionExtensions.cs | 35 +- .../SystemTextJson/DateTimeJsonConverter.cs | 52 + .../NullableDateTimeJsonConverter.cs | 56 + .../Stores/IQueryStore.cs | 2 +- src/Util.Data.Abstractions/Stores/IStore.cs | 46 +- src/Util.Data.Core/01-Util.Data.Core.csproj | 4 +- src/Util.Data.Core/IUnitOfWork.cs | 4 - .../Conditions/WhereIfNotEmptyCondition.cs | 2 +- src/Util.Data.Core/Trees/TreeCondition.cs | 3 - .../05-Util.Data.Dapper.All.csproj | 35 + .../Infrastructure/DapperServiceRegistrar.cs | 41 + .../ServiceRegistrarConfigExtensions.cs | 26 + .../Metadata/MetadataServiceFactory.cs | 72 + .../Metadata/TypeConverterFactory.cs | 24 + .../01-Util.Data.Dapper.Core.csproj | 53 + .../UtilDataDapperResource.Designer.cs | 81 + .../Properties/UtilDataDapperResource.resx} | 35 +- .../Sql/SqlExecutorBase.cs | 78 + src/Util.Data.Dapper.Core/Sql/SqlQueryBase.cs | 1411 +++ .../04-Util.Data.Dapper.MySql.csproj | 37 + .../Metadata/MySqlMetadataService.cs | 79 + .../Metadata/MySqlTypeConverter.cs | 55 + .../Sql/Builders/MySqlBuilder.cs | 39 + .../Sql/Builders/MySqlColumnCache.cs | 36 + .../Sql/Builders/MySqlDialect.cs | 34 + .../Sql/Builders/MySqlExistsSqlBuilder.cs | 52 + .../Sql/MySqlDatabaseFactory.cs | 16 + .../Sql/MySqlExecutor.cs | 18 + .../Sql/MySqlExecutorBase.cs | 39 + .../Sql/MySqlExecutorOptionsExtension.cs | 32 + src/Util.Data.Dapper.MySql/Sql/MySqlQuery.cs | 18 + .../Sql/MySqlQueryBase.cs | 33 + .../Sql/MySqlQueryOptionsExtension.cs | 32 + .../Sql/OptionsExtensions.cs | 120 + .../03-Util.Data.Dapper.PostgreSql.csproj | 37 + .../Metadata/PostgreSqlMetadataService.cs | 101 + .../Metadata/PostgreSqlTypeConverter.cs | 53 + .../Sql/Builders/PostgreSqlBuilder.cs | 39 + .../Sql/Builders/PostgreSqlColumnCache.cs | 36 + .../Sql/Builders/PostgreSqlDialect.cs | 34 + .../Builders/PostgreSqlExistsSqlBuilder.cs | 52 + .../Sql/OptionsExtensions.cs | 120 + .../Sql/PostgreSqlDatabaseFactory.cs | 16 + .../Sql/PostgreSqlExecutor.cs | 18 + .../Sql/PostgreSqlExecutorBase.cs | 67 + .../Sql/PostgreSqlExecutorOptionsExtension.cs | 32 + .../Sql/PostgreSqlQuery.cs | 18 + .../Sql/PostgreSqlQueryBase.cs | 56 + .../Sql/PostgreSqlQueryOptionsExtension.cs | 32 + .../02-Util.Data.Dapper.SqlServer.csproj | 37 + .../Metadata/SqlServerMetadataService.cs | 110 + .../Metadata/SqlServerTypeConverter.cs | 71 + .../Sql/Builders/SqlServerBuilder.cs | 39 + .../Sql/Builders/SqlServerColumnCache.cs | 36 + .../Sql/Builders/SqlServerDialect.cs | 34 + .../Sql/Builders/SqlServerExistsSqlBuilder.cs | 52 + .../Sql/OptionsExtensions.cs | 120 + .../Sql/SqlServerDatabaseFactory.cs | 16 + .../Sql/SqlServerSqlExecutor.cs | 18 + .../Sql/SqlServerSqlExecutorBase.cs | 39 + .../SqlServerSqlExecutorOptionsExtension.cs | 32 + .../Sql/SqlServerSqlQuery.cs | 18 + .../Sql/SqlServerSqlQueryBase.cs | 33 + .../Sql/SqlServerSqlQueryOptionsExtension.cs | 32 + ...Util.Data.EntityFrameworkCore.MySql.csproj | 37 + .../MySqlOptionsExtension.cs | 62 + .../MySqlUnitOfWorkBase.cs | 18 + .../OptionsExtensions.cs | 51 + ...til.Data.EntityFrameworkCore.Oracle.csproj | 37 + .../OptionsExtensions.cs | 51 + .../OracleOptionsExtension.cs | 61 + .../OracleUnitOfWorkBase.cs | 18 + ...Data.EntityFrameworkCore.PostgreSql.csproj | 8 +- .../PgSqlOptionsExtension.cs | 12 +- ....Data.EntityFrameworkCore.SqlServer.csproj | 4 +- .../SqlServerOptionsExtension.cs | 12 +- ...til.Data.EntityFrameworkCore.Sqlite.csproj | 37 + .../OptionsExtensions.cs | 51 + .../SqliteOptionsExtension.cs | 61 + .../SqliteUnitOfWorkBase.cs | 18 + .../01-Util.Data.EntityFrameworkCore.csproj | 6 +- .../EntityFrameworkServiceRegistrar.cs | 8 +- .../StoreBase.cs | 228 +- .../UnitOfWorkBase.cs | 68 +- .../ValueConverters/DateTimeValueConverter.cs | 20 + .../ExtraPropertiesValueConverter.cs | 3 +- .../03-Util.Data.Metadata.csproj | 32 + src/Util.Data.Metadata/ColumnInfo.cs | 47 + src/Util.Data.Metadata/DatabaseInfo.cs | 28 + src/Util.Data.Metadata/IMetadataService.cs | 11 + .../IMetadataServiceFactory.cs | 13 + src/Util.Data.Metadata/ITypeConverter.cs | 15 + .../ITypeConverterFactory.cs | 12 + src/Util.Data.Metadata/TableInfo.cs | 36 + src/Util.Data.Sql/02-Util.Data.Sql.csproj | 34 + .../Builders/Caches/ColumnCacheBase.cs | 63 + .../Builders/Caches/IColumnCache.cs | 17 + .../Builders/Clauses/ClauseBase.cs | 34 + .../Builders/Clauses/EndClause.cs | 209 + .../Builders/Clauses/FromClause.cs | 127 + .../Builders/Clauses/GroupByClause.cs | 157 + .../Builders/Clauses/IEndClause.cs | 43 + .../Builders/Clauses/IFromClause.cs | 41 + .../Builders/Clauses/IGroupByClause.cs | 41 + .../Builders/Clauses/IInsertClause.cs | 39 + .../Builders/Clauses/IJoinClause.cs | 101 + .../Builders/Clauses/IOrderByClause.cs | 27 + .../Builders/Clauses/ISelectClause.cs | 55 + .../Builders/Clauses/ISqlClause.cs | 11 + .../Builders/Clauses/IStartClause.cs | 38 + .../Builders/Clauses/IWhereClause.cs | 129 + .../Builders/Clauses/InsertClause.cs | 181 + .../Builders/Clauses/JoinClause.cs | 323 + .../Builders/Clauses/OrderByClause.cs | 115 + .../Builders/Clauses/SelectClause.cs | 161 + .../Builders/Clauses/StartClause.cs | 198 + .../Builders/Clauses/WhereClause.cs | 308 + .../Builders/Conditions/AndCondition.cs | 52 + .../Builders/Conditions/ContainsCondition.cs | 41 + .../Builders/Conditions/EndsCondition.cs | 41 + .../Builders/Conditions/EqualCondition.cs | 51 + .../Builders/Conditions/ExistsCondition.cs | 35 + .../Builders/Conditions/GreaterCondition.cs | 39 + .../Conditions/GreaterEqualCondition.cs | 39 + .../Builders/Conditions/InCondition.cs | 136 + .../Builders/Conditions/IsNotNullCondition.cs | 31 + .../Builders/Conditions/IsNullCondition.cs | 31 + .../Builders/Conditions/LessCondition.cs | 39 + .../Builders/Conditions/LessEqualCondition.cs | 39 + .../Builders/Conditions/NotEqualCondition.cs | 51 + .../Builders/Conditions/NotExistsCondition.cs | 35 + .../Builders/Conditions/NotInCondition.cs | 26 + .../Builders/Conditions/NullCondition.cs | 26 + .../Builders/Conditions/OrCondition.cs | 85 + .../Builders/Conditions/SegmentCondition.cs | 96 + .../Builders/Conditions/SqlCondition.cs | 29 + .../Builders/Conditions/SqlConditionBase.cs | 110 + .../Builders/Conditions/StartsCondition.cs | 41 + src/Util.Data.Sql/Builders/Core/ColumnItem.cs | 94 + src/Util.Data.Sql/Builders/Core/CteItem.cs | 33 + .../Builders/Core/DialectBase.cs | 62 + src/Util.Data.Sql/Builders/Core/NameItem.cs | 69 + .../Builders/Core/OrderByItem.cs | 34 + src/Util.Data.Sql/Builders/Core/SplitItem.cs | 37 + .../Builders/Core/SqlBuilderItem.cs | 46 + src/Util.Data.Sql/Builders/Core/TableItem.cs | 101 + .../Builders/IConditionFactory.cs | 26 + src/Util.Data.Sql/Builders/IDialect.cs | 29 + .../Builders/IExistsSqlBuilder.cs | 11 + src/Util.Data.Sql/Builders/ISqlContent.cs | 14 + .../Builders/ISqlPartAccessor.cs | 59 + src/Util.Data.Sql/Builders/Operations/IEnd.cs | 7 + .../Builders/Operations/IFrom.cs | 7 + .../Builders/Operations/IGroupBy.cs | 7 + .../Builders/Operations/IInsert.cs | 7 + .../Builders/Operations/IJoin.cs | 7 + .../Builders/Operations/IOrderBy.cs | 7 + .../Builders/Operations/ISelect.cs | 7 + src/Util.Data.Sql/Builders/Operations/ISet.cs | 7 + .../Builders/Operations/ISqlOperation.cs | 7 + .../Builders/Operations/ISqlParameter.cs | 7 + .../Builders/Operations/ISqlQueryOperation.cs | 7 + .../Builders/Operations/IStart.cs | 7 + .../Builders/Operations/IWhere.cs | 7 + .../Builders/Params/IClearParameters.cs | 11 + .../Builders/Params/IGetParameter.cs | 13 + .../Builders/Params/IParamLiteralsResolver.cs | 12 + .../Builders/Params/IParameterManager.cs | 66 + .../Builders/Params/ParamLiteralsResolver.cs | 28 + .../Builders/Params/ParameterManager.cs | 157 + src/Util.Data.Sql/Builders/Params/SqlParam.cs | 57 + .../Builders/Sets/ISqlBuilderSet.cs | 62 + .../Builders/Sets/SqlBuilderSet.cs | 254 + .../Builders/Sets/SqlBuilderSetItem.cs | 33 + src/Util.Data.Sql/Builders/SqlBuilderBase.cs | 349 + .../Builders/SqlBuilderResult.cs | 79 + .../Builders/SqlConditionFactory.cs | 77 + src/Util.Data.Sql/Configs/ISqlOptions.cs | 7 + .../Configs/ISqlOptionsAccessor.cs | 11 + .../Database/IConnectionManager.cs | 18 + .../Database/ITransactionManager.cs | 35 + src/Util.Data.Sql/EndClauseExtensions.cs | 106 + src/Util.Data.Sql/FromClauseExtensions.cs | 85 + src/Util.Data.Sql/GroupByClauseExtensions.cs | 94 + src/Util.Data.Sql/ISqlBuilder.cs | 26 + src/Util.Data.Sql/ISqlCondition.cs | 9 + src/Util.Data.Sql/ISqlExecutor.cs | 21 + src/Util.Data.Sql/ISqlQuery.cs | 468 + src/Util.Data.Sql/InsertClauseExtensions.cs | 98 + src/Util.Data.Sql/JoinClauseExtensions.cs | 239 + src/Util.Data.Sql/OrderByClauseExtensions.cs | 58 + src/Util.Data.Sql/ParameterExtensions.cs | 132 + src/Util.Data.Sql/SelectClauseExtensions.cs | 120 + src/Util.Data.Sql/SqlBuilderSetExtensions.cs | 138 + src/Util.Data.Sql/SqlExecutorExtensions.cs | 143 + src/Util.Data.Sql/SqlOptions.cs | 27 + src/Util.Data.Sql/SqlOptionsExtensions.cs | 54 + src/Util.Data.Sql/SqlQueryExtensions.Query.cs | 303 + .../SqlQueryExtensions.Scalar.cs | 457 + src/Util.Data.Sql/SqlQueryExtensions.cs | 68 + src/Util.Data.Sql/StartClauseExtensions.cs | 105 + src/Util.Data.Sql/WhereClauseExtensions.cs | 374 + .../Auditing/CreationAuditedSetter.cs | 14 +- .../Auditing/ModificationAuditedSetter.cs | 14 +- src/Util.Domain/Entities/EntityBase.cs | 2 +- src/Util.Domain/Extending/ExtraProperty.cs | 2 +- src/Util.Events/01-Util.Events.csproj | 4 +- .../LocalEventBusServiceRegistrar.cs | 13 +- .../04-Util.Localization.csproj | 36 + src/Util.Localization/Json/IPathResolver.cs | 34 + .../Json/JsonStringLocalizer.cs | 156 + .../Json/JsonStringLocalizerFactory.cs | 62 + .../JsonStringLocalizerLoggerExtensions.cs | 23 + src/Util.Localization/Json/PathResolver.cs | 49 + src/Util.Localization/Json/StringLocalizer.cs | 43 + .../JsonLocalizationOptionsExtension.cs | 38 + src/Util.Localization/OptionsExtensions.cs | 18 + ...-Util.Logging.Serilog.Exceptionless.csproj | 4 +- .../ExceptionlessOptionsExtension.cs | 14 +- .../OptionsExtensions.cs | 4 +- .../02-Util.Logging.Serilog.csproj | 2 +- .../SerilogOptionsExtension.cs | 14 +- src/Util.Logging/ILogExtensions.cs | 58 +- src/Util.Logging/Log.cs | 9 + src/Util.Logging/NullLog.cs | 80 + ...> 02-Util.ObjectMapping.AutoMapper.csproj} | 2 +- .../AutoMapperServiceRegistrar.cs | 10 +- .../ObjectMapper.cs | 14 +- .../03-Util.Templates.Handlebars.csproj | 2 +- .../HandlebarsServiceRegistrar.cs | 13 +- .../02-Util.Templates.Razor.csproj | 5 +- .../Infrastructure/RazorServiceRegistrar.cs | 11 +- src/Util.Validation/05-Util.Validation.csproj | 2 +- test/Util.Aop.AspectCore.Tests/Startup.cs | 10 +- .../Util.Aop.AspectCore.Tests.csproj | 14 +- .../Startup.cs | 54 + .../Tests/CustomerQueryServiceTest.cs | 215 + .../Tests/CustomerServiceTest.cs | 40 + .../Tests/ProductServiceTest.cs | 217 + ...ameworkCore.MySql.Tests.Integration.csproj | 39 + .../appsettings.Development.json | 11 + .../appsettings.json | 11 + .../Startup.cs | 56 + .../Tests/CustomerQueryServiceTest.cs | 215 + .../Tests/CustomerServiceTest.cs | 40 + .../Tests/ProductServiceTest.cs | 217 + ...rkCore.PostgreSql.Tests.Integration.csproj | 39 + .../appsettings.Development.json | 11 + .../appsettings.json | 11 + .../Models/Customer.cs | 116 - .../Models/Product.cs | 127 - .../Models/ProductItem.cs | 15 - .../Models/ProductItem2.cs | 15 - .../Repositories/ICustomerRepository.cs | 10 - .../Services/CustomerService.cs | 23 - .../Services/ICustomerService.cs | 10 - .../Services/IProductService.cs | 10 - .../Startup.cs | 25 +- .../Tests/CustomerQueryServiceTest.cs | 40 +- .../Tests/CustomerServiceTest.cs | 4 +- .../Tests/ProductServiceTest.cs | 46 +- .../UnitOfWorks/ISqlServerUnitOfWork.cs | 9 - .../UnitOfWorks/SqlServerUnitOfWork.cs | 18 - ...orkCore.SqlServer.Tests.Integration.csproj | 36 +- .../appsettings.Development.json | 11 + .../appsettings.json | 8 +- .../Util.Application.Tests.csproj | 8 +- .../Properties/launchSettings.json | 12 + .../Startup.cs | 21 +- .../Tests/CustomerControllerTest.cs | 20 +- .../Tests/ProductControllerTest.cs | 10 +- ...tion.WebApi.MySql.Tests.Integration.csproj | 42 + .../appsettings.Development.json | 11 + .../appsettings.json | 11 + .../Properties/launchSettings.json | 12 + .../Startup.cs | 72 + .../Tests/CustomerControllerTest.cs | 115 + .../Tests/ProductControllerTest.cs | 132 + ...WebApi.PostgreSql.Tests.Integration.csproj | 42 + .../appsettings.Development.json | 11 + .../appsettings.json | 11 + .../Properties/launchSettings.json | 0 .../Startup.cs | 70 + .../Tests/CustomerControllerTest.cs | 115 + .../Tests/ProductControllerTest.cs | 132 + ...WebApi.SqlServer.Tests.Integration.csproj} | 27 +- .../appsettings.Development.json} | 8 +- .../appsettings.json | 11 + .../Dtos/CustomerDto.cs | 87 - .../Dtos/ProductDto.cs | 71 - .../Fakes/CustomerFakeService.cs | 49 - .../Fakes/ProductFakeService.cs | 49 - .../Models/Customer.cs | 116 - .../Models/Product.cs | 97 - .../Queries/CustomerQuery.cs | 85 - .../Queries/ProductQuery.cs | 67 - .../Repositories/IProductRepository.cs | 15 - .../Services/ProductService.cs | 22 - .../UnitOfWorks/ISqlServerUnitOfWork.cs | 9 - .../UnitOfWorks/SqlServerUnitOfWork.cs | 18 - .../Samples/Certificate/apiclient_cert.p12 | Bin 0 -> 2710 bytes .../Samples/Certificate/apiclient_cert.pem | 23 + .../Samples/Certificate/apiclient_key.pem | 28 + test/Util.AspNetCore.Tests/Startup.cs | 4 +- .../Util.AspNetCore.Tests.csproj | 16 +- .../Helpers/ConfigTest.cs | 10 - .../Infrastructure/BootstrapperTest.cs | 34 +- .../DependencyServiceRegistrarTest.cs | 32 +- .../Samples/TestOptionsExtension.cs | 6 +- .../Samples/TestServiceRegistrar.cs | 27 +- .../Util.Core.Tests.Integration.csproj | 13 +- .../appsettings2.json | 6 - .../Util.Core.Tests/Exceptions/WarningTest.cs | 8 +- .../Extensions/DateTimeExtensionsTest.cs | 150 +- test/Util.Core.Tests/Helpers/ConvertTest.cs | 21 +- test/Util.Core.Tests/Helpers/CultureTest.cs | 22 + test/Util.Core.Tests/Helpers/JsonTest.cs | 118 +- test/Util.Core.Tests/Helpers/TimeTest.cs | 211 +- .../Util.Core.Tests/Samples/JsonTestSample.cs | 12 +- test/Util.Core.Tests/Util.Core.Tests.csproj | 8 +- .../Infrastructure/DatabaseScript.cs | 126 + .../Metadata/MySqlMetadataServiceTest.cs | 112 + .../SqlBuilders/MySqlExistsSqlBuilderTest.cs | 48 + .../SqlExecutor/MySqlExecutorTest.Execute.cs | 28 + .../SqlExecutor/MySqlExecutorTest.Id.cs | 67 + .../SqlExecutor/MySqlExecutorTest.Insert.cs | 83 + .../SqlExecutor/MySqlExecutorTest.Param.cs | 81 + .../MySqlExecutorTest.Procedure.cs | 35 + .../MySqlExecutorTest.Transaction.cs | 250 + .../SqlExecutor/MySqlExecutorTest.cs | 31 + .../SqlQuery/MySqlQueryTest.Exists.cs | 48 + .../SqlQuery/MySqlQueryTest.Procedure.cs | 301 + .../SqlQuery/MySqlQueryTest.Query.cs | 388 + .../SqlQuery/MySqlQueryTest.Scalar.cs | 629 ++ .../SqlQuery/MySqlQueryTest.Single.cs | 52 + .../SqlQuery/MySqlQueryTest.cs | 25 + .../Startup.cs | 63 + ...Data.Dapper.MySql.Tests.Integration.csproj | 43 + .../appsettings.Development.json | 11 + .../appsettings.json | 11 + .../Infrastructure/DatabaseScript.cs | 125 + .../Metadata/PostgreSqlMetadataServiceTest.cs | 99 + .../PostgreSqlExistsSqlBuilderTest.cs | 48 + .../PostgreSqlExecutorTest.Execute.cs | 28 + .../SqlExecutor/PostgreSqlExecutorTest.Id.cs | 67 + .../PostgreSqlExecutorTest.Insert.cs | 83 + .../PostgreSqlExecutorTest.Param.cs | 86 + .../PostgreSqlExecutorTest.Procedure.cs | 35 + .../SqlExecutor/PostgreSqlExecutorTest.cs | 31 + .../SqlServerSqlExecutorTest.Transaction.cs | 206 + .../SqlQuery/PostgreSqlQueryTest.Exists.cs | 48 + .../SqlQuery/PostgreSqlQueryTest.Procedure.cs | 233 + .../SqlQuery/PostgreSqlQueryTest.Query.cs | 388 + .../SqlQuery/PostgreSqlQueryTest.Scalar.cs | 629 ++ .../SqlQuery/PostgreSqlQueryTest.Single.cs | 52 + .../SqlQuery/PostgreSqlQueryTest.cs | 25 + .../Startup.cs | 65 + ...Dapper.PostgreSql.Tests.Integration.csproj | 43 + .../appsettings.Development.json | 11 + .../appsettings.json | 11 + .../Infrastructure/DatabaseScript.cs | 138 + .../Metadata/SqlServerMetadataServiceTest.cs | 99 + .../SqlServerExistsSqlBuilderTest.cs | 48 + .../SqlServerSqlExecutorTest.Execute.cs | 28 + .../SqlServerSqlExecutorTest.Id.cs | 67 + .../SqlServerSqlExecutorTest.Insert.cs | 83 + .../SqlServerSqlExecutorTest.Param.cs | 102 + .../SqlServerSqlExecutorTest.Procedure.cs | 35 + .../SqlServerSqlExecutorTest.Transaction.cs | 206 + .../SqlExecutor/SqlServerSqlExecutorTest.cs | 31 + .../SqlQuery/SqlServerSqlQueryTest.Exists.cs | 48 + .../SqlServerSqlQueryTest.Procedure.cs | 303 + .../SqlQuery/SqlServerSqlQueryTest.Query.cs | 388 + .../SqlQuery/SqlServerSqlQueryTest.Scalar.cs | 629 ++ .../SqlQuery/SqlServerSqlQueryTest.Single.cs | 52 + .../SqlQuery/SqlServerSqlQueryTest.cs | 25 + .../Startup.cs | 63 + ....Dapper.SqlServer.Tests.Integration.csproj | 43 + .../appsettings.Development.json | 11 + .../appsettings.json | 11 + .../Filters/DeleteFilterTest.cs | 2 +- .../Filters/FilterManagerTest.cs | 4 +- .../Startup.cs | 16 +- .../Tests/CustomerRepositoryTest.cs | 190 +- .../Tests/EntityEventsTest.cs | 103 +- .../Tests/OperationLogRepositoryTest.cs | 29 +- .../Tests/OrderRepositoryTest.cs | 56 +- .../Tests/PostRepositoryTest.cs | 10 +- .../Tests/ProductRepositoryTest.Queryable.cs | 115 +- .../Tests/ProductRepositoryTest.cs | 1408 +++ .../Tests/TagRepositoryTest.cs | 10 +- ...ameworkCore.MySql.Tests.Integration.csproj | 39 + .../appsettings.Development.json | 11 + .../appsettings.json | 11 + .../Filters/DeleteFilterTest.cs | 81 + .../Filters/FilterManagerTest.cs | 101 + .../Startup.cs | 16 +- .../Tests/CustomerRepositoryTest.cs | 196 +- .../Tests/EntityEventsTest.cs | 211 + .../Tests/OperationLogRepositoryTest.cs | 31 +- .../Tests/OrderRepositoryTest.cs | 56 +- .../Tests/PostRepositoryTest.cs | 54 + .../Tests/ProductRepositoryTest.Queryable.cs | 120 +- .../Tests/ProductRepositoryTest.cs | 1408 +++ .../Tests/TagRepositoryTest.cs | 41 + ...meworkCore.Oracle.Tests.Integration.csproj | 40 + .../appsettings.Development.json | 11 + .../appsettings.json | 11 + .../Filters/DeleteFilterTest.cs | 81 + .../Filters/FilterManagerTest.cs | 101 + .../Startup.cs | 55 + .../Tests/CustomerRepositoryTest.cs | 604 ++ .../Tests/EntityEventsTest.cs | 211 + .../Tests/OperationLogRepositoryTest.cs | 63 + .../Tests/OrderRepositoryTest.cs | 130 + .../Tests/PostRepositoryTest.cs | 54 + .../Tests/ProductRepositoryTest.Queryable.cs | 390 + .../Tests/ProductRepositoryTest.cs | 756 +- .../Tests/TagRepositoryTest.cs | 41 + ...rkCore.PostgreSql.Tests.Integration.csproj | 39 + .../appsettings.Development.json | 11 + .../appsettings.json | 11 + .../Fakes/CustomerFakeService.cs | 33 - .../Fakes/OrderFakeService.cs | 29 - .../Fakes/ProductFakeService.cs | 31 - .../Infrastructure/TestBase.cs | 20 - .../Infrastructure/TestSession.cs | 26 - .../Models/OperationLog.cs | 66 - .../Models/ProductItem.cs | 19 - .../Models/ProductItem2.cs | 25 - .../Repositories/ICustomerRepository.cs | 10 - .../Repositories/IOperationLogRepository.cs | 10 - .../Repositories/IOrderRepository.cs | 10 - .../Repositories/IProductRepository.cs | 15 - .../UnitOfWorks/IPgSqlUnitOfWork.cs | 7 - ...ntityFrameworkCore.PostgreSql.Tests.csproj | 44 - .../appsettings.json | 5 - .../Filters/DeleteFilterTest.cs | 81 + .../Filters/FilterManagerTest.cs | 101 + .../Startup.cs | 54 + .../Tests/CustomerRepositoryTest.cs | 604 ++ .../Tests/EntityEventsTest.cs | 211 + .../Tests/OperationLogRepositoryTest.cs | 63 + .../Tests/OrderRepositoryTest.cs | 130 + .../Tests/PostRepositoryTest.cs | 54 + .../Tests/ProductRepositoryTest.Queryable.cs | 390 + .../Tests/ProductRepositoryTest.cs | 745 +- .../Tests/TagRepositoryTest.cs | 41 + ...rkCore.SqlServer.Tests.Integration.csproj} | 38 +- .../appsettings.Development.json} | 0 .../appsettings.json | 11 + .../Conditions/ProductNameCondition.cs | 30 - .../Util_Data_EF_Test_SqlServer.pdb | 7789 ---------------- .../Util_Data_EF_Test_SqlServer.pdm | 7792 ----------------- .../Fakes/CustomerFakeService.cs | 33 - .../Fakes/OperationLogFakeService.cs | 27 - .../Fakes/OrderItemFakeService.cs | 29 - .../Fakes/ProductFakeService.cs | 31 - .../Infrastructure/TestBase.cs | 18 - .../Models/Customer.cs | 116 - .../Models/Order.cs | 80 - .../Models/OrderItem.cs | 71 - .../Models/Product.cs | 149 - .../Models/ProductEnum.cs | 9 - .../Repositories/ICustomerRepository.cs | 10 - .../Repositories/IProductRepository.cs | 15 - .../UnitOfWorks/ISqlServerUnitOfWork.cs | 7 - .../Filters/DeleteFilterTest.cs | 81 + .../Filters/FilterManagerTest.cs | 101 + .../Startup.cs | 53 + .../Tests/CustomerRepositoryTest.cs | 604 ++ .../Tests/EntityEventsTest.cs | 211 + .../Tests/OperationLogRepositoryTest.cs | 63 + .../Tests/OrderRepositoryTest.cs | 130 + .../Tests/PostRepositoryTest.cs | 54 + .../Tests/ProductRepositoryTest.Queryable.cs | 390 + .../Tests/ProductRepositoryTest.cs | 1408 +++ .../Tests/TagRepositoryTest.cs | 41 + ...meworkCore.Sqlite.Tests.Integration.csproj | 39 + .../appsettings.Development.json | 11 + .../appsettings.json | 11 + .../Builders/Clauses/EndClauseTest.cs | 188 + .../Builders/Clauses/FromClauseTest.cs | 187 + .../Builders/Clauses/GroupByClauseTest.cs | 267 + .../Builders/Clauses/InsertClauseTest.cs | 270 + .../Builders/Clauses/JoinClauseTest.cs | 502 ++ .../Builders/Clauses/OrderByClauseTest.cs | 183 + .../Builders/Clauses/SelectClauseTest.cs | 297 + .../Builders/Clauses/StartClauseTest.cs | 187 + .../Builders/Clauses/WhereClauseTest.cs | 595 ++ .../Builders/Conditions/AndConditionTest.cs | 103 + .../Conditions/ContainsConditionTest.cs | 64 + .../Builders/Conditions/EndsConditionTest.cs | 64 + .../Builders/Conditions/EqualConditionTest.cs | 90 + .../Conditions/ExistsConditionTest.cs | 43 + .../Conditions/GreaterConditionTest.cs | 79 + .../Conditions/GreaterEqualConditionTest.cs | 79 + .../Builders/Conditions/InConditionTest.cs | 139 + .../Conditions/IsNotNullConditionTest.cs | 37 + .../Conditions/IsNullConditionTest.cs | 37 + .../Builders/Conditions/LessConditionTest.cs | 79 + .../Conditions/LessEqualConditionTest.cs | 79 + .../Conditions/NotEqualConditionTest.cs | 89 + .../Conditions/NotExistsConditionTest.cs | 43 + .../Builders/Conditions/NotInConditionTest.cs | 139 + .../Builders/Conditions/OrConditionTest.cs | 103 + .../Conditions/SegmentConditionTest.cs | 119 + .../Conditions/StartsConditionTest.cs | 64 + .../Builders/Core/ColumnItemTest.cs | 164 + .../Builders/Core/OrderByItemTest.cs | 105 + .../Builders/Core/SplitItemTest.cs | 69 + .../Builders/Core/SqlBuilderItemTest.cs | 43 + .../Builders/Core/SqlConditionFactoryTest.cs | 186 + .../Builders/Core/TableItemTest.cs | 135 + .../Builders/Params/ParameterManagerTest.cs | 187 + .../Builders/Sets/SqlBuilderSetTest.cs | 361 + .../Builders/SqlBuilderTest.End.cs | 172 + .../Builders/SqlBuilderTest.From.cs | 118 + .../Builders/SqlBuilderTest.GroupBy.cs | 87 + .../Builders/SqlBuilderTest.Insert.cs | 123 + .../Builders/SqlBuilderTest.Join.cs | 357 + .../Builders/SqlBuilderTest.OrderBy.cs | 82 + .../Builders/SqlBuilderTest.Parameter.cs | 62 + .../Builders/SqlBuilderTest.Select.cs | 180 + .../Builders/SqlBuilderTest.Set.cs | 275 + .../Builders/SqlBuilderTest.Start.cs | 152 + .../Builders/SqlBuilderTest.Where.cs | 663 ++ .../Builders/SqlBuilderTest.cs | 27 + .../Samples/TestColumnCache.cs | 49 + .../Samples/TestDialect.cs | 41 + .../Samples/TestDialect2.cs | 29 + .../Samples/TestParameter.cs | 11 + .../Samples/TestSqlBuilder.cs | 62 + .../Util.Data.Sql.Tests.csproj | 25 + .../Conditions/DateSegmentConditionTest.cs | 23 +- .../DateTimeSegmentConditionTest.cs | 7 + .../Conditions/DoubleSegmentConditionTest.cs | 2 +- .../Conditions/IntSegmentConditionTest.cs | 2 +- test/Util.Data.Tests/Util.Data.Tests.csproj | 6 +- .../Util.Domain.Tests.csproj | 6 +- test/Util.Events.Tests/Startup.cs | 8 +- .../Util.Events.Tests.csproj | 12 +- .../Properties/AssemblyInfo.cs | 2 + .../ResourceTypes/Resource101.cs | 7 + .../ResourceTypes/Resource102.cs | 7 + .../ResourceTypes.Resource101.en-US.json | 3 + .../ResourceTypes.Resource101.zh-CN.json | 3 + .../ResourceTypes/Resource102.zh-CN.json | 3 + .../Util.Localization.Resources.csproj | 36 + .../Properties/AssemblyInfo.cs | 2 + .../Properties/launchSettings.json | 12 + .../ResourceTypes/Resource1.cs | 7 + .../ResourceTypes/Resource2.cs | 7 + .../ResourceTypes/Resource3.cs | 7 + .../ResourceTypes/Resource4.cs | 14 + .../ResourceTypes/Resource5.cs | 7 + .../ResourceTypes/Resource6.cs | 7 + .../ResourceTypes.Resource1.en-US.json | 3 + .../ResourceTypes.Resource1.zh-CN.json | 3 + .../ResourceTypes/Resource2.en-US.json | 3 + .../ResourceTypes/Resource2.zh-CN.json | 5 + .../ResourceTypes/Resource2.zh-Hans.json | 4 + .../Resources/ResourceTypes/Resource2.zh.json | 4 + .../ResourceTypes/Resource3.zh-Hans.json | 4 + .../Resource4.Resource41.zh-CN.json | 4 + .../Resources/ResourceTypes/Resource4.zh.json | 4 + .../ResourceTypes/Resource5.zh-CN.json | 4 + .../ResourceTypes/Resource5.zh-Hans.json | 4 + .../Resources/ResourceTypes/Resource5.zh.json | 4 + .../Resources/zh.json | 4 + .../Startup.cs | 54 + .../Tests/JsonStringLocalizerFactoryTest.cs | 110 + .../Tests/PathResolverTest.cs | 118 + .../Tests/StringLocalizerTest.cs | 232 + ...Util.Localization.Tests.Integration.csproj | 34 + .../LogContextAccessor.cs | 0 .../LogTest.cs | 4 +- .../Samples/Product.cs | 0 .../Startup.cs | 13 +- ...og.Exceptionless.Tests.Integration.csproj} | 17 +- .../appsettings.Production.json | 13 + .../appsettings.json | 4 +- .../LogContextAccessor.cs | 2 +- .../LogTest.cs | 0 .../Samples/Product.cs | 2 +- .../Startup.cs | 6 +- ....Logging.Serilog.Tests.Integration.csproj} | 12 +- .../appsettings.json | 0 test/Util.Logging.Tests/LogTest.Trace .cs | 3 +- .../Util.Logging.Tests.csproj | 8 +- .../Startup.cs | 8 +- ...Util.ObjectMapping.AutoMapper.Tests.csproj | 14 +- .../Startup.cs | 8 +- .../Util.Templates.Handlebars.Tests.csproj | 12 +- test/Util.Templates.Razor.Tests/Startup.cs | 8 +- .../Util.Templates.Razor.Tests.csproj | 12 +- .../CustomerConfiguration.cs | 24 +- .../OperationLogConfiguration.cs | 55 + .../OrderConfiguration.cs | 65 + .../OrderItemConfiguration.cs | 70 + .../PostConfiguration.cs | 63 + .../ProductConfiguration.cs | 42 +- .../TagConfiguration.cs | 57 + .../Repositories/CustomerRepository.cs | 8 +- .../Repositories/OperationLogRepository.cs | 9 +- .../Repositories/OrderRepository.cs | 9 +- .../Repositories/PostRepository.cs | 9 +- .../Repositories/ProductRepository.cs | 8 +- .../Repositories/TagRepository.cs | 9 +- .../UnitOfWorks/MySqlUnitOfWork.cs | 26 + .../Util.TestShare.MySql.csproj | 13 + .../CustomerConfiguration.cs | 94 + .../OperationLogConfiguration.cs | 55 + .../OrderConfiguration.cs | 65 + .../OrderItemConfiguration.cs | 70 + .../PostConfiguration.cs | 63 + .../ProductConfiguration.cs | 40 +- .../TagConfiguration.cs | 57 + .../Repositories/CustomerRepository.cs | 8 +- .../Repositories/OperationLogRepository.cs | 9 +- .../Repositories/OrderRepository.cs | 9 +- .../Repositories/PostRepository.cs | 17 + .../Repositories/ProductRepository.cs | 8 +- .../Repositories/TagRepository.cs | 17 + .../UnitOfWorks/OracleUnitOfWork.cs | 26 + .../Util.TestShare.Oracle.csproj | 13 + .../CustomerConfiguration.cs | 23 +- .../OperationLogConfiguration.cs | 4 +- .../OrderConfiguration.cs | 16 +- .../OrderItemConfiguration.cs | 7 +- .../PostConfiguration.cs | 6 +- .../ProductConfiguration.cs | 42 +- .../TagConfiguration.cs | 6 +- .../Repositories/CustomerRepository.cs | 9 +- .../Repositories/OperationLogRepository.cs | 17 + .../Repositories/OrderRepository.cs | 17 + .../Repositories/PostRepository.cs | 17 + .../Repositories/ProductRepository.cs | 9 +- .../Repositories/TagRepository.cs | 17 + .../UnitOfWorks/PgSqlUnitOfWork.cs | 5 +- .../Util.TestShare.PostgreSql.csproj | 13 + .../CustomerConfiguration.cs | 23 +- .../OperationLogConfiguration.cs | 5 +- .../OrderConfiguration.cs | 17 +- .../OrderItemConfiguration.cs | 7 +- .../PostConfiguration.cs | 63 + .../ProductConfiguration.cs | 42 +- .../TagConfiguration.cs | 57 + .../Repositories/CustomerRepository.cs | 9 +- .../Repositories/OperationLogRepository.cs | 17 + .../Repositories/OrderRepository.cs | 17 + .../Repositories/PostRepository.cs | 17 + .../Repositories/ProductRepository.cs | 9 +- .../Repositories/TagRepository.cs | 17 + .../UnitOfWorks/SqlServerUnitOfWork.cs | 5 +- .../Util.TestShare.SqlServer.csproj | 14 + .../CustomerConfiguration.cs | 21 +- .../OperationLogConfiguration.cs | 55 + .../OrderConfiguration.cs | 65 + .../OrderItemConfiguration.cs | 70 + .../PostConfiguration.cs | 63 + .../ProductConfiguration.cs | 102 + .../TagConfiguration.cs | 57 + .../Repositories/CustomerRepository.cs | 17 + .../Repositories/OperationLogRepository.cs | 17 + .../Repositories/OrderRepository.cs | 17 + .../Repositories/PostRepository.cs | 17 + .../Repositories/ProductRepository.cs | 25 + .../Repositories/TagRepository.cs | 17 + .../UnitOfWorks/SqliteUnitOfWork.cs | 26 + .../Util.TestShare.Sqlite.csproj | 13 + .../Conditions/ProductNameCondition.cs | 5 +- test/Util.TestShare/Configs/TestConfig.cs | 49 + .../Controllers/CustomerController.cs | 9 +- .../Controllers/ProductController.cs | 9 +- .../Dtos/CustomerDto.cs | 3 +- .../Dtos/ProductDto.cs | 5 +- .../OperationLogChangedEventHandler.cs | 12 +- .../OperationLogDeletedEventHandler.cs | 12 +- .../ProductChangedEventHandler.cs | 15 +- .../ProductCreatedEventHandler.cs | 12 +- .../ProductDeletedEventHandler.cs | 12 +- .../ProductUpdatedEventHandler.cs | 12 +- .../Fakes/CustomerFakeService.cs | 11 +- .../Fakes/OperationLogFakeService.cs | 5 +- .../Fakes/OrderFakeService.cs | 4 +- .../Fakes/OrderItemFakeService.cs | 5 +- .../Fakes/PostFakeService.cs | 4 +- .../Fakes/ProductFakeService.cs | 13 +- .../Fakes/TagFakeService.cs | 4 +- .../Infrastructure/ControllerTestBase.cs} | 8 +- .../Infrastructure/TestBase.cs | 2 +- .../Infrastructure/TestSession.cs | 2 +- .../Infrastructure/WebApiResult.cs | 4 +- .../Models/Customer.cs | 5 +- .../Models/OperationLog.cs | 2 +- .../Models/Order.cs | 5 +- .../Models/OrderItem.cs | 3 +- .../Models/Post.cs | 2 +- .../Models/Product.cs | 17 +- .../Models/ProductEnum.cs | 2 +- .../Models/ProductItem.cs | 2 +- .../Models/ProductItem2.cs | 2 +- .../Models/Tag.cs | 2 +- .../Queries/CustomerQuery.cs | 2 +- .../Queries/ProductQuery.cs | 2 +- .../Repositories/ICustomerRepository.cs | 4 +- .../Repositories/IOperationLogRepository.cs | 4 +- .../Repositories/IOrderRepository.cs | 4 +- .../Repositories/IPostRepository.cs | 4 +- .../Repositories/IProductRepository.cs | 4 +- .../Repositories/ITagRepository.cs | 4 +- .../Services/CustomerQueryService.cs | 11 +- .../Services/CustomerService.cs | 15 +- .../Services/ICustomerQueryService.cs | 7 +- .../Services/ICustomerService.cs | 7 +- .../Services/IProductService.cs | 7 +- .../Services/ProductService.cs | 15 +- .../UnitOfWorks/ITestUnitOfWork.cs | 9 + test/Util.TestShare/Util.TestShare.csproj | 14 + test/Util.Validation.Tests/Startup.cs | 10 +- .../Util.Validation.Tests.csproj | 12 +- 785 files changed, 47506 insertions(+), 20706 deletions(-) create mode 100644 sample/Util.WebApi.Sample/Program.cs create mode 100644 sample/Util.WebApi.Sample/Properties/AssemblyInfo.cs create mode 100644 sample/Util.WebApi.Sample/Properties/launchSettings.json create mode 100644 sample/Util.WebApi.Sample/Util.WebApi.Sample.csproj create mode 100644 sample/Util.WebApi.Sample/appsettings.Development.json create mode 100644 sample/Util.WebApi.Sample/appsettings.json create mode 100644 solutions/Util.Data.slnf create mode 100644 solutions/Util.Localization.slnf rename src/Util.Aop.AspectCore/{04-Util.Aop.AspectCore.csproj => 03-Util.Aop.AspectCore.csproj} (100%) delete mode 100644 src/Util.Aop.AspectCore/HostBuilderExtensions.cs delete mode 100644 src/Util.Aop.AspectCore/ServiceCollectionExtensions.cs create mode 100644 src/Util.Application.WebApi/IResultFactory.cs rename src/Util.AspNetCore/{02-Util.AspNetCore.csproj => 07-Util.AspNetCore.csproj} (100%) create mode 100644 src/Util.AspNetCore/Security/DataProtectionEncryptor.cs create mode 100644 src/Util.Core/Configs/OptionsExtensionBase.cs create mode 100644 src/Util.Core/Configs/PreOptions.cs create mode 100644 src/Util.Core/Dates/OptionsExtensions.cs create mode 100644 src/Util.Core/Dates/TimeOptions.cs create mode 100644 src/Util.Core/Helpers/Culture.cs create mode 100644 src/Util.Core/Helpers/Environment.cs create mode 100644 src/Util.Core/HostBuilderExtensions.cs delete mode 100644 src/Util.Core/Properties/UtilCoreResource.Designer.cs create mode 100644 src/Util.Core/Security/IEncryptor.cs create mode 100644 src/Util.Core/Security/NullEncryptor.cs create mode 100644 src/Util.Core/SystemTextJson/DateTimeJsonConverter.cs create mode 100644 src/Util.Core/SystemTextJson/NullableDateTimeJsonConverter.cs create mode 100644 src/Util.Data.Dapper.All/05-Util.Data.Dapper.All.csproj create mode 100644 src/Util.Data.Dapper.All/Infrastructure/DapperServiceRegistrar.cs create mode 100644 src/Util.Data.Dapper.All/Infrastructure/ServiceRegistrarConfigExtensions.cs create mode 100644 src/Util.Data.Dapper.All/Metadata/MetadataServiceFactory.cs create mode 100644 src/Util.Data.Dapper.All/Metadata/TypeConverterFactory.cs create mode 100644 src/Util.Data.Dapper.Core/01-Util.Data.Dapper.Core.csproj create mode 100644 src/Util.Data.Dapper.Core/Properties/UtilDataDapperResource.Designer.cs rename src/{Util.Core/Properties/UtilCoreResource.resx => Util.Data.Dapper.Core/Properties/UtilDataDapperResource.resx} (83%) create mode 100644 src/Util.Data.Dapper.Core/Sql/SqlExecutorBase.cs create mode 100644 src/Util.Data.Dapper.Core/Sql/SqlQueryBase.cs create mode 100644 src/Util.Data.Dapper.MySql/04-Util.Data.Dapper.MySql.csproj create mode 100644 src/Util.Data.Dapper.MySql/Metadata/MySqlMetadataService.cs create mode 100644 src/Util.Data.Dapper.MySql/Metadata/MySqlTypeConverter.cs create mode 100644 src/Util.Data.Dapper.MySql/Sql/Builders/MySqlBuilder.cs create mode 100644 src/Util.Data.Dapper.MySql/Sql/Builders/MySqlColumnCache.cs create mode 100644 src/Util.Data.Dapper.MySql/Sql/Builders/MySqlDialect.cs create mode 100644 src/Util.Data.Dapper.MySql/Sql/Builders/MySqlExistsSqlBuilder.cs create mode 100644 src/Util.Data.Dapper.MySql/Sql/MySqlDatabaseFactory.cs create mode 100644 src/Util.Data.Dapper.MySql/Sql/MySqlExecutor.cs create mode 100644 src/Util.Data.Dapper.MySql/Sql/MySqlExecutorBase.cs create mode 100644 src/Util.Data.Dapper.MySql/Sql/MySqlExecutorOptionsExtension.cs create mode 100644 src/Util.Data.Dapper.MySql/Sql/MySqlQuery.cs create mode 100644 src/Util.Data.Dapper.MySql/Sql/MySqlQueryBase.cs create mode 100644 src/Util.Data.Dapper.MySql/Sql/MySqlQueryOptionsExtension.cs create mode 100644 src/Util.Data.Dapper.MySql/Sql/OptionsExtensions.cs create mode 100644 src/Util.Data.Dapper.PostgreSql/03-Util.Data.Dapper.PostgreSql.csproj create mode 100644 src/Util.Data.Dapper.PostgreSql/Metadata/PostgreSqlMetadataService.cs create mode 100644 src/Util.Data.Dapper.PostgreSql/Metadata/PostgreSqlTypeConverter.cs create mode 100644 src/Util.Data.Dapper.PostgreSql/Sql/Builders/PostgreSqlBuilder.cs create mode 100644 src/Util.Data.Dapper.PostgreSql/Sql/Builders/PostgreSqlColumnCache.cs create mode 100644 src/Util.Data.Dapper.PostgreSql/Sql/Builders/PostgreSqlDialect.cs create mode 100644 src/Util.Data.Dapper.PostgreSql/Sql/Builders/PostgreSqlExistsSqlBuilder.cs create mode 100644 src/Util.Data.Dapper.PostgreSql/Sql/OptionsExtensions.cs create mode 100644 src/Util.Data.Dapper.PostgreSql/Sql/PostgreSqlDatabaseFactory.cs create mode 100644 src/Util.Data.Dapper.PostgreSql/Sql/PostgreSqlExecutor.cs create mode 100644 src/Util.Data.Dapper.PostgreSql/Sql/PostgreSqlExecutorBase.cs create mode 100644 src/Util.Data.Dapper.PostgreSql/Sql/PostgreSqlExecutorOptionsExtension.cs create mode 100644 src/Util.Data.Dapper.PostgreSql/Sql/PostgreSqlQuery.cs create mode 100644 src/Util.Data.Dapper.PostgreSql/Sql/PostgreSqlQueryBase.cs create mode 100644 src/Util.Data.Dapper.PostgreSql/Sql/PostgreSqlQueryOptionsExtension.cs create mode 100644 src/Util.Data.Dapper.SqlServer/02-Util.Data.Dapper.SqlServer.csproj create mode 100644 src/Util.Data.Dapper.SqlServer/Metadata/SqlServerMetadataService.cs create mode 100644 src/Util.Data.Dapper.SqlServer/Metadata/SqlServerTypeConverter.cs create mode 100644 src/Util.Data.Dapper.SqlServer/Sql/Builders/SqlServerBuilder.cs create mode 100644 src/Util.Data.Dapper.SqlServer/Sql/Builders/SqlServerColumnCache.cs create mode 100644 src/Util.Data.Dapper.SqlServer/Sql/Builders/SqlServerDialect.cs create mode 100644 src/Util.Data.Dapper.SqlServer/Sql/Builders/SqlServerExistsSqlBuilder.cs create mode 100644 src/Util.Data.Dapper.SqlServer/Sql/OptionsExtensions.cs create mode 100644 src/Util.Data.Dapper.SqlServer/Sql/SqlServerDatabaseFactory.cs create mode 100644 src/Util.Data.Dapper.SqlServer/Sql/SqlServerSqlExecutor.cs create mode 100644 src/Util.Data.Dapper.SqlServer/Sql/SqlServerSqlExecutorBase.cs create mode 100644 src/Util.Data.Dapper.SqlServer/Sql/SqlServerSqlExecutorOptionsExtension.cs create mode 100644 src/Util.Data.Dapper.SqlServer/Sql/SqlServerSqlQuery.cs create mode 100644 src/Util.Data.Dapper.SqlServer/Sql/SqlServerSqlQueryBase.cs create mode 100644 src/Util.Data.Dapper.SqlServer/Sql/SqlServerSqlQueryOptionsExtension.cs create mode 100644 src/Util.Data.EntityFrameworkCore.MySql/04-Util.Data.EntityFrameworkCore.MySql.csproj create mode 100644 src/Util.Data.EntityFrameworkCore.MySql/MySqlOptionsExtension.cs create mode 100644 src/Util.Data.EntityFrameworkCore.MySql/MySqlUnitOfWorkBase.cs create mode 100644 src/Util.Data.EntityFrameworkCore.MySql/OptionsExtensions.cs create mode 100644 src/Util.Data.EntityFrameworkCore.Oracle/06-Util.Data.EntityFrameworkCore.Oracle.csproj create mode 100644 src/Util.Data.EntityFrameworkCore.Oracle/OptionsExtensions.cs create mode 100644 src/Util.Data.EntityFrameworkCore.Oracle/OracleOptionsExtension.cs create mode 100644 src/Util.Data.EntityFrameworkCore.Oracle/OracleUnitOfWorkBase.cs create mode 100644 src/Util.Data.EntityFrameworkCore.Sqlite/05-Util.Data.EntityFrameworkCore.Sqlite.csproj create mode 100644 src/Util.Data.EntityFrameworkCore.Sqlite/OptionsExtensions.cs create mode 100644 src/Util.Data.EntityFrameworkCore.Sqlite/SqliteOptionsExtension.cs create mode 100644 src/Util.Data.EntityFrameworkCore.Sqlite/SqliteUnitOfWorkBase.cs create mode 100644 src/Util.Data.EntityFrameworkCore/ValueConverters/DateTimeValueConverter.cs create mode 100644 src/Util.Data.Metadata/03-Util.Data.Metadata.csproj create mode 100644 src/Util.Data.Metadata/ColumnInfo.cs create mode 100644 src/Util.Data.Metadata/DatabaseInfo.cs create mode 100644 src/Util.Data.Metadata/IMetadataService.cs create mode 100644 src/Util.Data.Metadata/IMetadataServiceFactory.cs create mode 100644 src/Util.Data.Metadata/ITypeConverter.cs create mode 100644 src/Util.Data.Metadata/ITypeConverterFactory.cs create mode 100644 src/Util.Data.Metadata/TableInfo.cs create mode 100644 src/Util.Data.Sql/02-Util.Data.Sql.csproj create mode 100644 src/Util.Data.Sql/Builders/Caches/ColumnCacheBase.cs create mode 100644 src/Util.Data.Sql/Builders/Caches/IColumnCache.cs create mode 100644 src/Util.Data.Sql/Builders/Clauses/ClauseBase.cs create mode 100644 src/Util.Data.Sql/Builders/Clauses/EndClause.cs create mode 100644 src/Util.Data.Sql/Builders/Clauses/FromClause.cs create mode 100644 src/Util.Data.Sql/Builders/Clauses/GroupByClause.cs create mode 100644 src/Util.Data.Sql/Builders/Clauses/IEndClause.cs create mode 100644 src/Util.Data.Sql/Builders/Clauses/IFromClause.cs create mode 100644 src/Util.Data.Sql/Builders/Clauses/IGroupByClause.cs create mode 100644 src/Util.Data.Sql/Builders/Clauses/IInsertClause.cs create mode 100644 src/Util.Data.Sql/Builders/Clauses/IJoinClause.cs create mode 100644 src/Util.Data.Sql/Builders/Clauses/IOrderByClause.cs create mode 100644 src/Util.Data.Sql/Builders/Clauses/ISelectClause.cs create mode 100644 src/Util.Data.Sql/Builders/Clauses/ISqlClause.cs create mode 100644 src/Util.Data.Sql/Builders/Clauses/IStartClause.cs create mode 100644 src/Util.Data.Sql/Builders/Clauses/IWhereClause.cs create mode 100644 src/Util.Data.Sql/Builders/Clauses/InsertClause.cs create mode 100644 src/Util.Data.Sql/Builders/Clauses/JoinClause.cs create mode 100644 src/Util.Data.Sql/Builders/Clauses/OrderByClause.cs create mode 100644 src/Util.Data.Sql/Builders/Clauses/SelectClause.cs create mode 100644 src/Util.Data.Sql/Builders/Clauses/StartClause.cs create mode 100644 src/Util.Data.Sql/Builders/Clauses/WhereClause.cs create mode 100644 src/Util.Data.Sql/Builders/Conditions/AndCondition.cs create mode 100644 src/Util.Data.Sql/Builders/Conditions/ContainsCondition.cs create mode 100644 src/Util.Data.Sql/Builders/Conditions/EndsCondition.cs create mode 100644 src/Util.Data.Sql/Builders/Conditions/EqualCondition.cs create mode 100644 src/Util.Data.Sql/Builders/Conditions/ExistsCondition.cs create mode 100644 src/Util.Data.Sql/Builders/Conditions/GreaterCondition.cs create mode 100644 src/Util.Data.Sql/Builders/Conditions/GreaterEqualCondition.cs create mode 100644 src/Util.Data.Sql/Builders/Conditions/InCondition.cs create mode 100644 src/Util.Data.Sql/Builders/Conditions/IsNotNullCondition.cs create mode 100644 src/Util.Data.Sql/Builders/Conditions/IsNullCondition.cs create mode 100644 src/Util.Data.Sql/Builders/Conditions/LessCondition.cs create mode 100644 src/Util.Data.Sql/Builders/Conditions/LessEqualCondition.cs create mode 100644 src/Util.Data.Sql/Builders/Conditions/NotEqualCondition.cs create mode 100644 src/Util.Data.Sql/Builders/Conditions/NotExistsCondition.cs create mode 100644 src/Util.Data.Sql/Builders/Conditions/NotInCondition.cs create mode 100644 src/Util.Data.Sql/Builders/Conditions/NullCondition.cs create mode 100644 src/Util.Data.Sql/Builders/Conditions/OrCondition.cs create mode 100644 src/Util.Data.Sql/Builders/Conditions/SegmentCondition.cs create mode 100644 src/Util.Data.Sql/Builders/Conditions/SqlCondition.cs create mode 100644 src/Util.Data.Sql/Builders/Conditions/SqlConditionBase.cs create mode 100644 src/Util.Data.Sql/Builders/Conditions/StartsCondition.cs create mode 100644 src/Util.Data.Sql/Builders/Core/ColumnItem.cs create mode 100644 src/Util.Data.Sql/Builders/Core/CteItem.cs create mode 100644 src/Util.Data.Sql/Builders/Core/DialectBase.cs create mode 100644 src/Util.Data.Sql/Builders/Core/NameItem.cs create mode 100644 src/Util.Data.Sql/Builders/Core/OrderByItem.cs create mode 100644 src/Util.Data.Sql/Builders/Core/SplitItem.cs create mode 100644 src/Util.Data.Sql/Builders/Core/SqlBuilderItem.cs create mode 100644 src/Util.Data.Sql/Builders/Core/TableItem.cs create mode 100644 src/Util.Data.Sql/Builders/IConditionFactory.cs create mode 100644 src/Util.Data.Sql/Builders/IDialect.cs create mode 100644 src/Util.Data.Sql/Builders/IExistsSqlBuilder.cs create mode 100644 src/Util.Data.Sql/Builders/ISqlContent.cs create mode 100644 src/Util.Data.Sql/Builders/ISqlPartAccessor.cs create mode 100644 src/Util.Data.Sql/Builders/Operations/IEnd.cs create mode 100644 src/Util.Data.Sql/Builders/Operations/IFrom.cs create mode 100644 src/Util.Data.Sql/Builders/Operations/IGroupBy.cs create mode 100644 src/Util.Data.Sql/Builders/Operations/IInsert.cs create mode 100644 src/Util.Data.Sql/Builders/Operations/IJoin.cs create mode 100644 src/Util.Data.Sql/Builders/Operations/IOrderBy.cs create mode 100644 src/Util.Data.Sql/Builders/Operations/ISelect.cs create mode 100644 src/Util.Data.Sql/Builders/Operations/ISet.cs create mode 100644 src/Util.Data.Sql/Builders/Operations/ISqlOperation.cs create mode 100644 src/Util.Data.Sql/Builders/Operations/ISqlParameter.cs create mode 100644 src/Util.Data.Sql/Builders/Operations/ISqlQueryOperation.cs create mode 100644 src/Util.Data.Sql/Builders/Operations/IStart.cs create mode 100644 src/Util.Data.Sql/Builders/Operations/IWhere.cs create mode 100644 src/Util.Data.Sql/Builders/Params/IClearParameters.cs create mode 100644 src/Util.Data.Sql/Builders/Params/IGetParameter.cs create mode 100644 src/Util.Data.Sql/Builders/Params/IParamLiteralsResolver.cs create mode 100644 src/Util.Data.Sql/Builders/Params/IParameterManager.cs create mode 100644 src/Util.Data.Sql/Builders/Params/ParamLiteralsResolver.cs create mode 100644 src/Util.Data.Sql/Builders/Params/ParameterManager.cs create mode 100644 src/Util.Data.Sql/Builders/Params/SqlParam.cs create mode 100644 src/Util.Data.Sql/Builders/Sets/ISqlBuilderSet.cs create mode 100644 src/Util.Data.Sql/Builders/Sets/SqlBuilderSet.cs create mode 100644 src/Util.Data.Sql/Builders/Sets/SqlBuilderSetItem.cs create mode 100644 src/Util.Data.Sql/Builders/SqlBuilderBase.cs create mode 100644 src/Util.Data.Sql/Builders/SqlBuilderResult.cs create mode 100644 src/Util.Data.Sql/Builders/SqlConditionFactory.cs create mode 100644 src/Util.Data.Sql/Configs/ISqlOptions.cs create mode 100644 src/Util.Data.Sql/Configs/ISqlOptionsAccessor.cs create mode 100644 src/Util.Data.Sql/Database/IConnectionManager.cs create mode 100644 src/Util.Data.Sql/Database/ITransactionManager.cs create mode 100644 src/Util.Data.Sql/EndClauseExtensions.cs create mode 100644 src/Util.Data.Sql/FromClauseExtensions.cs create mode 100644 src/Util.Data.Sql/GroupByClauseExtensions.cs create mode 100644 src/Util.Data.Sql/ISqlBuilder.cs create mode 100644 src/Util.Data.Sql/ISqlCondition.cs create mode 100644 src/Util.Data.Sql/ISqlExecutor.cs create mode 100644 src/Util.Data.Sql/ISqlQuery.cs create mode 100644 src/Util.Data.Sql/InsertClauseExtensions.cs create mode 100644 src/Util.Data.Sql/JoinClauseExtensions.cs create mode 100644 src/Util.Data.Sql/OrderByClauseExtensions.cs create mode 100644 src/Util.Data.Sql/ParameterExtensions.cs create mode 100644 src/Util.Data.Sql/SelectClauseExtensions.cs create mode 100644 src/Util.Data.Sql/SqlBuilderSetExtensions.cs create mode 100644 src/Util.Data.Sql/SqlExecutorExtensions.cs create mode 100644 src/Util.Data.Sql/SqlOptions.cs create mode 100644 src/Util.Data.Sql/SqlOptionsExtensions.cs create mode 100644 src/Util.Data.Sql/SqlQueryExtensions.Query.cs create mode 100644 src/Util.Data.Sql/SqlQueryExtensions.Scalar.cs create mode 100644 src/Util.Data.Sql/SqlQueryExtensions.cs create mode 100644 src/Util.Data.Sql/StartClauseExtensions.cs create mode 100644 src/Util.Data.Sql/WhereClauseExtensions.cs create mode 100644 src/Util.Localization/04-Util.Localization.csproj create mode 100644 src/Util.Localization/Json/IPathResolver.cs create mode 100644 src/Util.Localization/Json/JsonStringLocalizer.cs create mode 100644 src/Util.Localization/Json/JsonStringLocalizerFactory.cs create mode 100644 src/Util.Localization/Json/JsonStringLocalizerLoggerExtensions.cs create mode 100644 src/Util.Localization/Json/PathResolver.cs create mode 100644 src/Util.Localization/Json/StringLocalizer.cs create mode 100644 src/Util.Localization/JsonLocalizationOptionsExtension.cs create mode 100644 src/Util.Localization/OptionsExtensions.cs create mode 100644 src/Util.Logging/NullLog.cs rename src/Util.ObjectMapping.AutoMapper/{03-Util.ObjectMapping.AutoMapper.csproj => 02-Util.ObjectMapping.AutoMapper.csproj} (94%) create mode 100644 test/Util.Application.EntityFrameworkCore.MySql.Tests.Integration/Startup.cs create mode 100644 test/Util.Application.EntityFrameworkCore.MySql.Tests.Integration/Tests/CustomerQueryServiceTest.cs create mode 100644 test/Util.Application.EntityFrameworkCore.MySql.Tests.Integration/Tests/CustomerServiceTest.cs create mode 100644 test/Util.Application.EntityFrameworkCore.MySql.Tests.Integration/Tests/ProductServiceTest.cs create mode 100644 test/Util.Application.EntityFrameworkCore.MySql.Tests.Integration/Util.Application.EntityFrameworkCore.MySql.Tests.Integration.csproj create mode 100644 test/Util.Application.EntityFrameworkCore.MySql.Tests.Integration/appsettings.Development.json create mode 100644 test/Util.Application.EntityFrameworkCore.MySql.Tests.Integration/appsettings.json create mode 100644 test/Util.Application.EntityFrameworkCore.PostgreSql.Tests.Integration/Startup.cs create mode 100644 test/Util.Application.EntityFrameworkCore.PostgreSql.Tests.Integration/Tests/CustomerQueryServiceTest.cs create mode 100644 test/Util.Application.EntityFrameworkCore.PostgreSql.Tests.Integration/Tests/CustomerServiceTest.cs create mode 100644 test/Util.Application.EntityFrameworkCore.PostgreSql.Tests.Integration/Tests/ProductServiceTest.cs create mode 100644 test/Util.Application.EntityFrameworkCore.PostgreSql.Tests.Integration/Util.Application.EntityFrameworkCore.PostgreSql.Tests.Integration.csproj create mode 100644 test/Util.Application.EntityFrameworkCore.PostgreSql.Tests.Integration/appsettings.Development.json create mode 100644 test/Util.Application.EntityFrameworkCore.PostgreSql.Tests.Integration/appsettings.json delete mode 100644 test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/Models/Customer.cs delete mode 100644 test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/Models/Product.cs delete mode 100644 test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/Models/ProductItem.cs delete mode 100644 test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/Models/ProductItem2.cs delete mode 100644 test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/Repositories/ICustomerRepository.cs delete mode 100644 test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/Services/CustomerService.cs delete mode 100644 test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/Services/ICustomerService.cs delete mode 100644 test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/Services/IProductService.cs delete mode 100644 test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/UnitOfWorks/ISqlServerUnitOfWork.cs delete mode 100644 test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/UnitOfWorks/SqlServerUnitOfWork.cs create mode 100644 test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/appsettings.Development.json create mode 100644 test/Util.Application.WebApi.MySql.Tests.Integration/Properties/launchSettings.json rename test/{Util.Application.WebApi.Tests.Integration => Util.Application.WebApi.MySql.Tests.Integration}/Startup.cs (78%) rename test/{Util.Application.WebApi.Tests.Integration => Util.Application.WebApi.MySql.Tests.Integration}/Tests/CustomerControllerTest.cs (88%) rename test/{Util.Application.WebApi.Tests.Integration => Util.Application.WebApi.MySql.Tests.Integration}/Tests/ProductControllerTest.cs (95%) create mode 100644 test/Util.Application.WebApi.MySql.Tests.Integration/Util.Application.WebApi.MySql.Tests.Integration.csproj create mode 100644 test/Util.Application.WebApi.MySql.Tests.Integration/appsettings.Development.json create mode 100644 test/Util.Application.WebApi.MySql.Tests.Integration/appsettings.json create mode 100644 test/Util.Application.WebApi.PostgreSql.Tests.Integration/Properties/launchSettings.json create mode 100644 test/Util.Application.WebApi.PostgreSql.Tests.Integration/Startup.cs create mode 100644 test/Util.Application.WebApi.PostgreSql.Tests.Integration/Tests/CustomerControllerTest.cs create mode 100644 test/Util.Application.WebApi.PostgreSql.Tests.Integration/Tests/ProductControllerTest.cs create mode 100644 test/Util.Application.WebApi.PostgreSql.Tests.Integration/Util.Application.WebApi.PostgreSql.Tests.Integration.csproj create mode 100644 test/Util.Application.WebApi.PostgreSql.Tests.Integration/appsettings.Development.json create mode 100644 test/Util.Application.WebApi.PostgreSql.Tests.Integration/appsettings.json rename test/{Util.Application.WebApi.Tests.Integration => Util.Application.WebApi.SqlServer.Tests.Integration}/Properties/launchSettings.json (100%) create mode 100644 test/Util.Application.WebApi.SqlServer.Tests.Integration/Startup.cs create mode 100644 test/Util.Application.WebApi.SqlServer.Tests.Integration/Tests/CustomerControllerTest.cs create mode 100644 test/Util.Application.WebApi.SqlServer.Tests.Integration/Tests/ProductControllerTest.cs rename test/{Util.Application.WebApi.Tests.Integration/Util.Application.WebApi.Tests.Integration.csproj => Util.Application.WebApi.SqlServer.Tests.Integration/Util.Application.WebApi.SqlServer.Tests.Integration.csproj} (68%) rename test/{Util.Application.WebApi.Tests.Integration/appsettings.json => Util.Application.WebApi.SqlServer.Tests.Integration/appsettings.Development.json} (58%) create mode 100644 test/Util.Application.WebApi.SqlServer.Tests.Integration/appsettings.json delete mode 100644 test/Util.Application.WebApi.Tests.Integration/Dtos/CustomerDto.cs delete mode 100644 test/Util.Application.WebApi.Tests.Integration/Dtos/ProductDto.cs delete mode 100644 test/Util.Application.WebApi.Tests.Integration/Fakes/CustomerFakeService.cs delete mode 100644 test/Util.Application.WebApi.Tests.Integration/Fakes/ProductFakeService.cs delete mode 100644 test/Util.Application.WebApi.Tests.Integration/Models/Customer.cs delete mode 100644 test/Util.Application.WebApi.Tests.Integration/Models/Product.cs delete mode 100644 test/Util.Application.WebApi.Tests.Integration/Queries/CustomerQuery.cs delete mode 100644 test/Util.Application.WebApi.Tests.Integration/Queries/ProductQuery.cs delete mode 100644 test/Util.Application.WebApi.Tests.Integration/Repositories/IProductRepository.cs delete mode 100644 test/Util.Application.WebApi.Tests.Integration/Services/ProductService.cs delete mode 100644 test/Util.Application.WebApi.Tests.Integration/UnitOfWorks/ISqlServerUnitOfWork.cs delete mode 100644 test/Util.Application.WebApi.Tests.Integration/UnitOfWorks/SqlServerUnitOfWork.cs create mode 100644 test/Util.AspNetCore.Tests/Samples/Certificate/apiclient_cert.p12 create mode 100644 test/Util.AspNetCore.Tests/Samples/Certificate/apiclient_cert.pem create mode 100644 test/Util.AspNetCore.Tests/Samples/Certificate/apiclient_key.pem delete mode 100644 test/Util.Core.Tests.Integration/appsettings2.json create mode 100644 test/Util.Core.Tests/Helpers/CultureTest.cs create mode 100644 test/Util.Data.Dapper.MySql.Tests.Integration/Infrastructure/DatabaseScript.cs create mode 100644 test/Util.Data.Dapper.MySql.Tests.Integration/Metadata/MySqlMetadataServiceTest.cs create mode 100644 test/Util.Data.Dapper.MySql.Tests.Integration/SqlBuilders/MySqlExistsSqlBuilderTest.cs create mode 100644 test/Util.Data.Dapper.MySql.Tests.Integration/SqlExecutor/MySqlExecutorTest.Execute.cs create mode 100644 test/Util.Data.Dapper.MySql.Tests.Integration/SqlExecutor/MySqlExecutorTest.Id.cs create mode 100644 test/Util.Data.Dapper.MySql.Tests.Integration/SqlExecutor/MySqlExecutorTest.Insert.cs create mode 100644 test/Util.Data.Dapper.MySql.Tests.Integration/SqlExecutor/MySqlExecutorTest.Param.cs create mode 100644 test/Util.Data.Dapper.MySql.Tests.Integration/SqlExecutor/MySqlExecutorTest.Procedure.cs create mode 100644 test/Util.Data.Dapper.MySql.Tests.Integration/SqlExecutor/MySqlExecutorTest.Transaction.cs create mode 100644 test/Util.Data.Dapper.MySql.Tests.Integration/SqlExecutor/MySqlExecutorTest.cs create mode 100644 test/Util.Data.Dapper.MySql.Tests.Integration/SqlQuery/MySqlQueryTest.Exists.cs create mode 100644 test/Util.Data.Dapper.MySql.Tests.Integration/SqlQuery/MySqlQueryTest.Procedure.cs create mode 100644 test/Util.Data.Dapper.MySql.Tests.Integration/SqlQuery/MySqlQueryTest.Query.cs create mode 100644 test/Util.Data.Dapper.MySql.Tests.Integration/SqlQuery/MySqlQueryTest.Scalar.cs create mode 100644 test/Util.Data.Dapper.MySql.Tests.Integration/SqlQuery/MySqlQueryTest.Single.cs create mode 100644 test/Util.Data.Dapper.MySql.Tests.Integration/SqlQuery/MySqlQueryTest.cs create mode 100644 test/Util.Data.Dapper.MySql.Tests.Integration/Startup.cs create mode 100644 test/Util.Data.Dapper.MySql.Tests.Integration/Util.Data.Dapper.MySql.Tests.Integration.csproj create mode 100644 test/Util.Data.Dapper.MySql.Tests.Integration/appsettings.Development.json create mode 100644 test/Util.Data.Dapper.MySql.Tests.Integration/appsettings.json create mode 100644 test/Util.Data.Dapper.PostgreSql.Tests.Integration/Infrastructure/DatabaseScript.cs create mode 100644 test/Util.Data.Dapper.PostgreSql.Tests.Integration/Metadata/PostgreSqlMetadataServiceTest.cs create mode 100644 test/Util.Data.Dapper.PostgreSql.Tests.Integration/SqlBuilders/PostgreSqlExistsSqlBuilderTest.cs create mode 100644 test/Util.Data.Dapper.PostgreSql.Tests.Integration/SqlExecutor/PostgreSqlExecutorTest.Execute.cs create mode 100644 test/Util.Data.Dapper.PostgreSql.Tests.Integration/SqlExecutor/PostgreSqlExecutorTest.Id.cs create mode 100644 test/Util.Data.Dapper.PostgreSql.Tests.Integration/SqlExecutor/PostgreSqlExecutorTest.Insert.cs create mode 100644 test/Util.Data.Dapper.PostgreSql.Tests.Integration/SqlExecutor/PostgreSqlExecutorTest.Param.cs create mode 100644 test/Util.Data.Dapper.PostgreSql.Tests.Integration/SqlExecutor/PostgreSqlExecutorTest.Procedure.cs create mode 100644 test/Util.Data.Dapper.PostgreSql.Tests.Integration/SqlExecutor/PostgreSqlExecutorTest.cs create mode 100644 test/Util.Data.Dapper.PostgreSql.Tests.Integration/SqlExecutor/SqlServerSqlExecutorTest.Transaction.cs create mode 100644 test/Util.Data.Dapper.PostgreSql.Tests.Integration/SqlQuery/PostgreSqlQueryTest.Exists.cs create mode 100644 test/Util.Data.Dapper.PostgreSql.Tests.Integration/SqlQuery/PostgreSqlQueryTest.Procedure.cs create mode 100644 test/Util.Data.Dapper.PostgreSql.Tests.Integration/SqlQuery/PostgreSqlQueryTest.Query.cs create mode 100644 test/Util.Data.Dapper.PostgreSql.Tests.Integration/SqlQuery/PostgreSqlQueryTest.Scalar.cs create mode 100644 test/Util.Data.Dapper.PostgreSql.Tests.Integration/SqlQuery/PostgreSqlQueryTest.Single.cs create mode 100644 test/Util.Data.Dapper.PostgreSql.Tests.Integration/SqlQuery/PostgreSqlQueryTest.cs create mode 100644 test/Util.Data.Dapper.PostgreSql.Tests.Integration/Startup.cs create mode 100644 test/Util.Data.Dapper.PostgreSql.Tests.Integration/Util.Data.Dapper.PostgreSql.Tests.Integration.csproj create mode 100644 test/Util.Data.Dapper.PostgreSql.Tests.Integration/appsettings.Development.json create mode 100644 test/Util.Data.Dapper.PostgreSql.Tests.Integration/appsettings.json create mode 100644 test/Util.Data.Dapper.SqlServer.Tests.Integration/Infrastructure/DatabaseScript.cs create mode 100644 test/Util.Data.Dapper.SqlServer.Tests.Integration/Metadata/SqlServerMetadataServiceTest.cs create mode 100644 test/Util.Data.Dapper.SqlServer.Tests.Integration/SqlBuilders/SqlServerExistsSqlBuilderTest.cs create mode 100644 test/Util.Data.Dapper.SqlServer.Tests.Integration/SqlExecutor/SqlServerSqlExecutorTest.Execute.cs create mode 100644 test/Util.Data.Dapper.SqlServer.Tests.Integration/SqlExecutor/SqlServerSqlExecutorTest.Id.cs create mode 100644 test/Util.Data.Dapper.SqlServer.Tests.Integration/SqlExecutor/SqlServerSqlExecutorTest.Insert.cs create mode 100644 test/Util.Data.Dapper.SqlServer.Tests.Integration/SqlExecutor/SqlServerSqlExecutorTest.Param.cs create mode 100644 test/Util.Data.Dapper.SqlServer.Tests.Integration/SqlExecutor/SqlServerSqlExecutorTest.Procedure.cs create mode 100644 test/Util.Data.Dapper.SqlServer.Tests.Integration/SqlExecutor/SqlServerSqlExecutorTest.Transaction.cs create mode 100644 test/Util.Data.Dapper.SqlServer.Tests.Integration/SqlExecutor/SqlServerSqlExecutorTest.cs create mode 100644 test/Util.Data.Dapper.SqlServer.Tests.Integration/SqlQuery/SqlServerSqlQueryTest.Exists.cs create mode 100644 test/Util.Data.Dapper.SqlServer.Tests.Integration/SqlQuery/SqlServerSqlQueryTest.Procedure.cs create mode 100644 test/Util.Data.Dapper.SqlServer.Tests.Integration/SqlQuery/SqlServerSqlQueryTest.Query.cs create mode 100644 test/Util.Data.Dapper.SqlServer.Tests.Integration/SqlQuery/SqlServerSqlQueryTest.Scalar.cs create mode 100644 test/Util.Data.Dapper.SqlServer.Tests.Integration/SqlQuery/SqlServerSqlQueryTest.Single.cs create mode 100644 test/Util.Data.Dapper.SqlServer.Tests.Integration/SqlQuery/SqlServerSqlQueryTest.cs create mode 100644 test/Util.Data.Dapper.SqlServer.Tests.Integration/Startup.cs create mode 100644 test/Util.Data.Dapper.SqlServer.Tests.Integration/Util.Data.Dapper.SqlServer.Tests.Integration.csproj create mode 100644 test/Util.Data.Dapper.SqlServer.Tests.Integration/appsettings.Development.json create mode 100644 test/Util.Data.Dapper.SqlServer.Tests.Integration/appsettings.json rename test/{Util.Data.EntityFrameworkCore.SqlServer.Tests => Util.Data.EntityFrameworkCore.MySql.Tests.Integration}/Filters/DeleteFilterTest.cs (97%) rename test/{Util.Data.EntityFrameworkCore.SqlServer.Tests => Util.Data.EntityFrameworkCore.MySql.Tests.Integration}/Filters/FilterManagerTest.cs (97%) rename test/{Util.Data.EntityFrameworkCore.PostgreSql.Tests => Util.Data.EntityFrameworkCore.MySql.Tests.Integration}/Startup.cs (80%) rename test/{Util.Data.EntityFrameworkCore.SqlServer.Tests => Util.Data.EntityFrameworkCore.MySql.Tests.Integration}/Tests/CustomerRepositoryTest.cs (78%) rename test/{Util.Data.EntityFrameworkCore.SqlServer.Tests => Util.Data.EntityFrameworkCore.MySql.Tests.Integration}/Tests/EntityEventsTest.cs (51%) rename test/{Util.Data.EntityFrameworkCore.SqlServer.Tests => Util.Data.EntityFrameworkCore.MySql.Tests.Integration}/Tests/OperationLogRepositoryTest.cs (65%) rename test/{Util.Data.EntityFrameworkCore.SqlServer.Tests => Util.Data.EntityFrameworkCore.MySql.Tests.Integration}/Tests/OrderRepositoryTest.cs (73%) rename test/{Util.Data.EntityFrameworkCore.PostgreSql.Tests => Util.Data.EntityFrameworkCore.MySql.Tests.Integration}/Tests/PostRepositoryTest.cs (81%) rename test/{Util.Data.EntityFrameworkCore.SqlServer.Tests => Util.Data.EntityFrameworkCore.MySql.Tests.Integration}/Tests/ProductRepositoryTest.Queryable.cs (78%) create mode 100644 test/Util.Data.EntityFrameworkCore.MySql.Tests.Integration/Tests/ProductRepositoryTest.cs rename test/{Util.Data.EntityFrameworkCore.PostgreSql.Tests => Util.Data.EntityFrameworkCore.MySql.Tests.Integration}/Tests/TagRepositoryTest.cs (75%) create mode 100644 test/Util.Data.EntityFrameworkCore.MySql.Tests.Integration/Util.Data.EntityFrameworkCore.MySql.Tests.Integration.csproj create mode 100644 test/Util.Data.EntityFrameworkCore.MySql.Tests.Integration/appsettings.Development.json create mode 100644 test/Util.Data.EntityFrameworkCore.MySql.Tests.Integration/appsettings.json create mode 100644 test/Util.Data.EntityFrameworkCore.Oracle.Tests.Integration/Filters/DeleteFilterTest.cs create mode 100644 test/Util.Data.EntityFrameworkCore.Oracle.Tests.Integration/Filters/FilterManagerTest.cs rename test/{Util.Data.EntityFrameworkCore.SqlServer.Tests => Util.Data.EntityFrameworkCore.Oracle.Tests.Integration}/Startup.cs (76%) rename test/{Util.Data.EntityFrameworkCore.PostgreSql.Tests => Util.Data.EntityFrameworkCore.Oracle.Tests.Integration}/Tests/CustomerRepositoryTest.cs (77%) create mode 100644 test/Util.Data.EntityFrameworkCore.Oracle.Tests.Integration/Tests/EntityEventsTest.cs rename test/{Util.Data.EntityFrameworkCore.PostgreSql.Tests => Util.Data.EntityFrameworkCore.Oracle.Tests.Integration}/Tests/OperationLogRepositoryTest.cs (63%) rename test/{Util.Data.EntityFrameworkCore.PostgreSql.Tests => Util.Data.EntityFrameworkCore.Oracle.Tests.Integration}/Tests/OrderRepositoryTest.cs (72%) create mode 100644 test/Util.Data.EntityFrameworkCore.Oracle.Tests.Integration/Tests/PostRepositoryTest.cs rename test/{Util.Data.EntityFrameworkCore.PostgreSql.Tests => Util.Data.EntityFrameworkCore.Oracle.Tests.Integration}/Tests/ProductRepositoryTest.Queryable.cs (77%) create mode 100644 test/Util.Data.EntityFrameworkCore.Oracle.Tests.Integration/Tests/ProductRepositoryTest.cs create mode 100644 test/Util.Data.EntityFrameworkCore.Oracle.Tests.Integration/Tests/TagRepositoryTest.cs create mode 100644 test/Util.Data.EntityFrameworkCore.Oracle.Tests.Integration/Util.Data.EntityFrameworkCore.Oracle.Tests.Integration.csproj create mode 100644 test/Util.Data.EntityFrameworkCore.Oracle.Tests.Integration/appsettings.Development.json create mode 100644 test/Util.Data.EntityFrameworkCore.Oracle.Tests.Integration/appsettings.json create mode 100644 test/Util.Data.EntityFrameworkCore.PostgreSql.Tests.Integration/Filters/DeleteFilterTest.cs create mode 100644 test/Util.Data.EntityFrameworkCore.PostgreSql.Tests.Integration/Filters/FilterManagerTest.cs create mode 100644 test/Util.Data.EntityFrameworkCore.PostgreSql.Tests.Integration/Startup.cs create mode 100644 test/Util.Data.EntityFrameworkCore.PostgreSql.Tests.Integration/Tests/CustomerRepositoryTest.cs create mode 100644 test/Util.Data.EntityFrameworkCore.PostgreSql.Tests.Integration/Tests/EntityEventsTest.cs create mode 100644 test/Util.Data.EntityFrameworkCore.PostgreSql.Tests.Integration/Tests/OperationLogRepositoryTest.cs create mode 100644 test/Util.Data.EntityFrameworkCore.PostgreSql.Tests.Integration/Tests/OrderRepositoryTest.cs create mode 100644 test/Util.Data.EntityFrameworkCore.PostgreSql.Tests.Integration/Tests/PostRepositoryTest.cs create mode 100644 test/Util.Data.EntityFrameworkCore.PostgreSql.Tests.Integration/Tests/ProductRepositoryTest.Queryable.cs rename test/{Util.Data.EntityFrameworkCore.PostgreSql.Tests => Util.Data.EntityFrameworkCore.PostgreSql.Tests.Integration}/Tests/ProductRepositoryTest.cs (72%) create mode 100644 test/Util.Data.EntityFrameworkCore.PostgreSql.Tests.Integration/Tests/TagRepositoryTest.cs create mode 100644 test/Util.Data.EntityFrameworkCore.PostgreSql.Tests.Integration/Util.Data.EntityFrameworkCore.PostgreSql.Tests.Integration.csproj create mode 100644 test/Util.Data.EntityFrameworkCore.PostgreSql.Tests.Integration/appsettings.Development.json create mode 100644 test/Util.Data.EntityFrameworkCore.PostgreSql.Tests.Integration/appsettings.json delete mode 100644 test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Fakes/CustomerFakeService.cs delete mode 100644 test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Fakes/OrderFakeService.cs delete mode 100644 test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Fakes/ProductFakeService.cs delete mode 100644 test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Infrastructure/TestBase.cs delete mode 100644 test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Infrastructure/TestSession.cs delete mode 100644 test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Models/OperationLog.cs delete mode 100644 test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Models/ProductItem.cs delete mode 100644 test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Models/ProductItem2.cs delete mode 100644 test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Repositories/ICustomerRepository.cs delete mode 100644 test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Repositories/IOperationLogRepository.cs delete mode 100644 test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Repositories/IOrderRepository.cs delete mode 100644 test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Repositories/IProductRepository.cs delete mode 100644 test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/UnitOfWorks/IPgSqlUnitOfWork.cs delete mode 100644 test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Util.Data.EntityFrameworkCore.PostgreSql.Tests.csproj delete mode 100644 test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/appsettings.json create mode 100644 test/Util.Data.EntityFrameworkCore.SqlServer.Tests.Integration/Filters/DeleteFilterTest.cs create mode 100644 test/Util.Data.EntityFrameworkCore.SqlServer.Tests.Integration/Filters/FilterManagerTest.cs create mode 100644 test/Util.Data.EntityFrameworkCore.SqlServer.Tests.Integration/Startup.cs create mode 100644 test/Util.Data.EntityFrameworkCore.SqlServer.Tests.Integration/Tests/CustomerRepositoryTest.cs create mode 100644 test/Util.Data.EntityFrameworkCore.SqlServer.Tests.Integration/Tests/EntityEventsTest.cs create mode 100644 test/Util.Data.EntityFrameworkCore.SqlServer.Tests.Integration/Tests/OperationLogRepositoryTest.cs create mode 100644 test/Util.Data.EntityFrameworkCore.SqlServer.Tests.Integration/Tests/OrderRepositoryTest.cs create mode 100644 test/Util.Data.EntityFrameworkCore.SqlServer.Tests.Integration/Tests/PostRepositoryTest.cs create mode 100644 test/Util.Data.EntityFrameworkCore.SqlServer.Tests.Integration/Tests/ProductRepositoryTest.Queryable.cs rename test/{Util.Data.EntityFrameworkCore.SqlServer.Tests => Util.Data.EntityFrameworkCore.SqlServer.Tests.Integration}/Tests/ProductRepositoryTest.cs (73%) create mode 100644 test/Util.Data.EntityFrameworkCore.SqlServer.Tests.Integration/Tests/TagRepositoryTest.cs rename test/{Util.Data.EntityFrameworkCore.SqlServer.Tests/Util.Data.EntityFrameworkCore.SqlServer.Tests.csproj => Util.Data.EntityFrameworkCore.SqlServer.Tests.Integration/Util.Data.EntityFrameworkCore.SqlServer.Tests.Integration.csproj} (56%) rename test/{Util.Data.EntityFrameworkCore.SqlServer.Tests/appsettings.json => Util.Data.EntityFrameworkCore.SqlServer.Tests.Integration/appsettings.Development.json} (100%) create mode 100644 test/Util.Data.EntityFrameworkCore.SqlServer.Tests.Integration/appsettings.json delete mode 100644 test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Conditions/ProductNameCondition.cs delete mode 100644 test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Document/PowerDesigner/Util_Data_EF_Test_SqlServer.pdb delete mode 100644 test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Document/PowerDesigner/Util_Data_EF_Test_SqlServer.pdm delete mode 100644 test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Fakes/CustomerFakeService.cs delete mode 100644 test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Fakes/OperationLogFakeService.cs delete mode 100644 test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Fakes/OrderItemFakeService.cs delete mode 100644 test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Fakes/ProductFakeService.cs delete mode 100644 test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Infrastructure/TestBase.cs delete mode 100644 test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Models/Customer.cs delete mode 100644 test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Models/Order.cs delete mode 100644 test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Models/OrderItem.cs delete mode 100644 test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Models/Product.cs delete mode 100644 test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Models/ProductEnum.cs delete mode 100644 test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Repositories/ICustomerRepository.cs delete mode 100644 test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Repositories/IProductRepository.cs delete mode 100644 test/Util.Data.EntityFrameworkCore.SqlServer.Tests/UnitOfWorks/ISqlServerUnitOfWork.cs create mode 100644 test/Util.Data.EntityFrameworkCore.Sqlite.Tests.Integration/Filters/DeleteFilterTest.cs create mode 100644 test/Util.Data.EntityFrameworkCore.Sqlite.Tests.Integration/Filters/FilterManagerTest.cs create mode 100644 test/Util.Data.EntityFrameworkCore.Sqlite.Tests.Integration/Startup.cs create mode 100644 test/Util.Data.EntityFrameworkCore.Sqlite.Tests.Integration/Tests/CustomerRepositoryTest.cs create mode 100644 test/Util.Data.EntityFrameworkCore.Sqlite.Tests.Integration/Tests/EntityEventsTest.cs create mode 100644 test/Util.Data.EntityFrameworkCore.Sqlite.Tests.Integration/Tests/OperationLogRepositoryTest.cs create mode 100644 test/Util.Data.EntityFrameworkCore.Sqlite.Tests.Integration/Tests/OrderRepositoryTest.cs create mode 100644 test/Util.Data.EntityFrameworkCore.Sqlite.Tests.Integration/Tests/PostRepositoryTest.cs create mode 100644 test/Util.Data.EntityFrameworkCore.Sqlite.Tests.Integration/Tests/ProductRepositoryTest.Queryable.cs create mode 100644 test/Util.Data.EntityFrameworkCore.Sqlite.Tests.Integration/Tests/ProductRepositoryTest.cs create mode 100644 test/Util.Data.EntityFrameworkCore.Sqlite.Tests.Integration/Tests/TagRepositoryTest.cs create mode 100644 test/Util.Data.EntityFrameworkCore.Sqlite.Tests.Integration/Util.Data.EntityFrameworkCore.Sqlite.Tests.Integration.csproj create mode 100644 test/Util.Data.EntityFrameworkCore.Sqlite.Tests.Integration/appsettings.Development.json create mode 100644 test/Util.Data.EntityFrameworkCore.Sqlite.Tests.Integration/appsettings.json create mode 100644 test/Util.Data.Sql.Tests/Builders/Clauses/EndClauseTest.cs create mode 100644 test/Util.Data.Sql.Tests/Builders/Clauses/FromClauseTest.cs create mode 100644 test/Util.Data.Sql.Tests/Builders/Clauses/GroupByClauseTest.cs create mode 100644 test/Util.Data.Sql.Tests/Builders/Clauses/InsertClauseTest.cs create mode 100644 test/Util.Data.Sql.Tests/Builders/Clauses/JoinClauseTest.cs create mode 100644 test/Util.Data.Sql.Tests/Builders/Clauses/OrderByClauseTest.cs create mode 100644 test/Util.Data.Sql.Tests/Builders/Clauses/SelectClauseTest.cs create mode 100644 test/Util.Data.Sql.Tests/Builders/Clauses/StartClauseTest.cs create mode 100644 test/Util.Data.Sql.Tests/Builders/Clauses/WhereClauseTest.cs create mode 100644 test/Util.Data.Sql.Tests/Builders/Conditions/AndConditionTest.cs create mode 100644 test/Util.Data.Sql.Tests/Builders/Conditions/ContainsConditionTest.cs create mode 100644 test/Util.Data.Sql.Tests/Builders/Conditions/EndsConditionTest.cs create mode 100644 test/Util.Data.Sql.Tests/Builders/Conditions/EqualConditionTest.cs create mode 100644 test/Util.Data.Sql.Tests/Builders/Conditions/ExistsConditionTest.cs create mode 100644 test/Util.Data.Sql.Tests/Builders/Conditions/GreaterConditionTest.cs create mode 100644 test/Util.Data.Sql.Tests/Builders/Conditions/GreaterEqualConditionTest.cs create mode 100644 test/Util.Data.Sql.Tests/Builders/Conditions/InConditionTest.cs create mode 100644 test/Util.Data.Sql.Tests/Builders/Conditions/IsNotNullConditionTest.cs create mode 100644 test/Util.Data.Sql.Tests/Builders/Conditions/IsNullConditionTest.cs create mode 100644 test/Util.Data.Sql.Tests/Builders/Conditions/LessConditionTest.cs create mode 100644 test/Util.Data.Sql.Tests/Builders/Conditions/LessEqualConditionTest.cs create mode 100644 test/Util.Data.Sql.Tests/Builders/Conditions/NotEqualConditionTest.cs create mode 100644 test/Util.Data.Sql.Tests/Builders/Conditions/NotExistsConditionTest.cs create mode 100644 test/Util.Data.Sql.Tests/Builders/Conditions/NotInConditionTest.cs create mode 100644 test/Util.Data.Sql.Tests/Builders/Conditions/OrConditionTest.cs create mode 100644 test/Util.Data.Sql.Tests/Builders/Conditions/SegmentConditionTest.cs create mode 100644 test/Util.Data.Sql.Tests/Builders/Conditions/StartsConditionTest.cs create mode 100644 test/Util.Data.Sql.Tests/Builders/Core/ColumnItemTest.cs create mode 100644 test/Util.Data.Sql.Tests/Builders/Core/OrderByItemTest.cs create mode 100644 test/Util.Data.Sql.Tests/Builders/Core/SplitItemTest.cs create mode 100644 test/Util.Data.Sql.Tests/Builders/Core/SqlBuilderItemTest.cs create mode 100644 test/Util.Data.Sql.Tests/Builders/Core/SqlConditionFactoryTest.cs create mode 100644 test/Util.Data.Sql.Tests/Builders/Core/TableItemTest.cs create mode 100644 test/Util.Data.Sql.Tests/Builders/Params/ParameterManagerTest.cs create mode 100644 test/Util.Data.Sql.Tests/Builders/Sets/SqlBuilderSetTest.cs create mode 100644 test/Util.Data.Sql.Tests/Builders/SqlBuilderTest.End.cs create mode 100644 test/Util.Data.Sql.Tests/Builders/SqlBuilderTest.From.cs create mode 100644 test/Util.Data.Sql.Tests/Builders/SqlBuilderTest.GroupBy.cs create mode 100644 test/Util.Data.Sql.Tests/Builders/SqlBuilderTest.Insert.cs create mode 100644 test/Util.Data.Sql.Tests/Builders/SqlBuilderTest.Join.cs create mode 100644 test/Util.Data.Sql.Tests/Builders/SqlBuilderTest.OrderBy.cs create mode 100644 test/Util.Data.Sql.Tests/Builders/SqlBuilderTest.Parameter.cs create mode 100644 test/Util.Data.Sql.Tests/Builders/SqlBuilderTest.Select.cs create mode 100644 test/Util.Data.Sql.Tests/Builders/SqlBuilderTest.Set.cs create mode 100644 test/Util.Data.Sql.Tests/Builders/SqlBuilderTest.Start.cs create mode 100644 test/Util.Data.Sql.Tests/Builders/SqlBuilderTest.Where.cs create mode 100644 test/Util.Data.Sql.Tests/Builders/SqlBuilderTest.cs create mode 100644 test/Util.Data.Sql.Tests/Samples/TestColumnCache.cs create mode 100644 test/Util.Data.Sql.Tests/Samples/TestDialect.cs create mode 100644 test/Util.Data.Sql.Tests/Samples/TestDialect2.cs create mode 100644 test/Util.Data.Sql.Tests/Samples/TestParameter.cs create mode 100644 test/Util.Data.Sql.Tests/Samples/TestSqlBuilder.cs create mode 100644 test/Util.Data.Sql.Tests/Util.Data.Sql.Tests.csproj create mode 100644 test/Util.Localization.Resources/Properties/AssemblyInfo.cs create mode 100644 test/Util.Localization.Resources/ResourceTypes/Resource101.cs create mode 100644 test/Util.Localization.Resources/ResourceTypes/Resource102.cs create mode 100644 test/Util.Localization.Resources/Resources2/ResourceTypes.Resource101.en-US.json create mode 100644 test/Util.Localization.Resources/Resources2/ResourceTypes.Resource101.zh-CN.json create mode 100644 test/Util.Localization.Resources/Resources2/ResourceTypes/Resource102.zh-CN.json create mode 100644 test/Util.Localization.Resources/Util.Localization.Resources.csproj create mode 100644 test/Util.Localization.Tests.Integration/Properties/AssemblyInfo.cs create mode 100644 test/Util.Localization.Tests.Integration/Properties/launchSettings.json create mode 100644 test/Util.Localization.Tests.Integration/ResourceTypes/Resource1.cs create mode 100644 test/Util.Localization.Tests.Integration/ResourceTypes/Resource2.cs create mode 100644 test/Util.Localization.Tests.Integration/ResourceTypes/Resource3.cs create mode 100644 test/Util.Localization.Tests.Integration/ResourceTypes/Resource4.cs create mode 100644 test/Util.Localization.Tests.Integration/ResourceTypes/Resource5.cs create mode 100644 test/Util.Localization.Tests.Integration/ResourceTypes/Resource6.cs create mode 100644 test/Util.Localization.Tests.Integration/Resources/ResourceTypes.Resource1.en-US.json create mode 100644 test/Util.Localization.Tests.Integration/Resources/ResourceTypes.Resource1.zh-CN.json create mode 100644 test/Util.Localization.Tests.Integration/Resources/ResourceTypes/Resource2.en-US.json create mode 100644 test/Util.Localization.Tests.Integration/Resources/ResourceTypes/Resource2.zh-CN.json create mode 100644 test/Util.Localization.Tests.Integration/Resources/ResourceTypes/Resource2.zh-Hans.json create mode 100644 test/Util.Localization.Tests.Integration/Resources/ResourceTypes/Resource2.zh.json create mode 100644 test/Util.Localization.Tests.Integration/Resources/ResourceTypes/Resource3.zh-Hans.json create mode 100644 test/Util.Localization.Tests.Integration/Resources/ResourceTypes/Resource4.Resource41.zh-CN.json create mode 100644 test/Util.Localization.Tests.Integration/Resources/ResourceTypes/Resource4.zh.json create mode 100644 test/Util.Localization.Tests.Integration/Resources/ResourceTypes/Resource5.zh-CN.json create mode 100644 test/Util.Localization.Tests.Integration/Resources/ResourceTypes/Resource5.zh-Hans.json create mode 100644 test/Util.Localization.Tests.Integration/Resources/ResourceTypes/Resource5.zh.json create mode 100644 test/Util.Localization.Tests.Integration/Resources/zh.json create mode 100644 test/Util.Localization.Tests.Integration/Startup.cs create mode 100644 test/Util.Localization.Tests.Integration/Tests/JsonStringLocalizerFactoryTest.cs create mode 100644 test/Util.Localization.Tests.Integration/Tests/PathResolverTest.cs create mode 100644 test/Util.Localization.Tests.Integration/Tests/StringLocalizerTest.cs create mode 100644 test/Util.Localization.Tests.Integration/Util.Localization.Tests.Integration.csproj rename test/{Util.Logging.Serilog.Tests => Util.Logging.Serilog.Exceptionless.Tests.Integration}/LogContextAccessor.cs (100%) rename test/{Util.Logging.Serilog.Exceptionless.Tests => Util.Logging.Serilog.Exceptionless.Tests.Integration}/LogTest.cs (97%) rename test/{Util.Logging.Serilog.Tests => Util.Logging.Serilog.Exceptionless.Tests.Integration}/Samples/Product.cs (100%) rename test/{Util.Logging.Serilog.Exceptionless.Tests => Util.Logging.Serilog.Exceptionless.Tests.Integration}/Startup.cs (68%) rename test/{Util.Logging.Serilog.Exceptionless.Tests/Util.Logging.Serilog.Exceptionless.Tests.csproj => Util.Logging.Serilog.Exceptionless.Tests.Integration/Util.Logging.Serilog.Exceptionless.Tests.Integration.csproj} (79%) create mode 100644 test/Util.Logging.Serilog.Exceptionless.Tests.Integration/appsettings.Production.json rename test/{Util.Logging.Serilog.Exceptionless.Tests => Util.Logging.Serilog.Exceptionless.Tests.Integration}/appsettings.json (59%) rename test/{Util.Logging.Serilog.Exceptionless.Tests => Util.Logging.Serilog.Tests.Integration}/LogContextAccessor.cs (93%) rename test/{Util.Logging.Serilog.Tests => Util.Logging.Serilog.Tests.Integration}/LogTest.cs (100%) rename test/{Util.Logging.Serilog.Exceptionless.Tests => Util.Logging.Serilog.Tests.Integration}/Samples/Product.cs (88%) rename test/{Util.Logging.Serilog.Tests => Util.Logging.Serilog.Tests.Integration}/Startup.cs (87%) rename test/{Util.Logging.Serilog.Tests/Util.Logging.Serilog.Tests.csproj => Util.Logging.Serilog.Tests.Integration/Util.Logging.Serilog.Tests.Integration.csproj} (86%) rename test/{Util.Logging.Serilog.Tests => Util.Logging.Serilog.Tests.Integration}/appsettings.json (100%) rename test/{Util.Data.EntityFrameworkCore.PostgreSql.Tests => Util.TestShare.MySql}/EntityTypeConfigurations/CustomerConfiguration.cs (81%) create mode 100644 test/Util.TestShare.MySql/EntityTypeConfigurations/OperationLogConfiguration.cs create mode 100644 test/Util.TestShare.MySql/EntityTypeConfigurations/OrderConfiguration.cs create mode 100644 test/Util.TestShare.MySql/EntityTypeConfigurations/OrderItemConfiguration.cs create mode 100644 test/Util.TestShare.MySql/EntityTypeConfigurations/PostConfiguration.cs rename test/{Util.Data.EntityFrameworkCore.PostgreSql.Tests => Util.TestShare.MySql}/EntityTypeConfigurations/ProductConfiguration.cs (62%) create mode 100644 test/Util.TestShare.MySql/EntityTypeConfigurations/TagConfiguration.cs rename test/{Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration => Util.TestShare.MySql}/Repositories/CustomerRepository.cs (62%) rename test/{Util.Data.EntityFrameworkCore.PostgreSql.Tests => Util.TestShare.MySql}/Repositories/OperationLogRepository.cs (57%) rename test/{Util.Data.EntityFrameworkCore.PostgreSql.Tests => Util.TestShare.MySql}/Repositories/OrderRepository.cs (55%) rename test/{Util.Data.EntityFrameworkCore.PostgreSql.Tests => Util.TestShare.MySql}/Repositories/PostRepository.cs (55%) rename test/{Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration => Util.TestShare.MySql}/Repositories/ProductRepository.cs (73%) rename test/{Util.Data.EntityFrameworkCore.PostgreSql.Tests => Util.TestShare.MySql}/Repositories/TagRepository.cs (55%) create mode 100644 test/Util.TestShare.MySql/UnitOfWorks/MySqlUnitOfWork.cs create mode 100644 test/Util.TestShare.MySql/Util.TestShare.MySql.csproj create mode 100644 test/Util.TestShare.Oracle/EntityTypeConfigurations/CustomerConfiguration.cs create mode 100644 test/Util.TestShare.Oracle/EntityTypeConfigurations/OperationLogConfiguration.cs create mode 100644 test/Util.TestShare.Oracle/EntityTypeConfigurations/OrderConfiguration.cs create mode 100644 test/Util.TestShare.Oracle/EntityTypeConfigurations/OrderItemConfiguration.cs create mode 100644 test/Util.TestShare.Oracle/EntityTypeConfigurations/PostConfiguration.cs rename test/{Util.Data.EntityFrameworkCore.SqlServer.Tests => Util.TestShare.Oracle}/EntityTypeConfigurations/ProductConfiguration.cs (62%) create mode 100644 test/Util.TestShare.Oracle/EntityTypeConfigurations/TagConfiguration.cs rename test/{Util.Application.WebApi.Tests.Integration => Util.TestShare.Oracle}/Repositories/CustomerRepository.cs (62%) rename test/{Util.Data.EntityFrameworkCore.SqlServer.Tests => Util.TestShare.Oracle}/Repositories/OperationLogRepository.cs (57%) rename test/{Util.Data.EntityFrameworkCore.SqlServer.Tests => Util.TestShare.Oracle}/Repositories/OrderRepository.cs (55%) create mode 100644 test/Util.TestShare.Oracle/Repositories/PostRepository.cs rename test/{Util.Application.WebApi.Tests.Integration => Util.TestShare.Oracle}/Repositories/ProductRepository.cs (73%) create mode 100644 test/Util.TestShare.Oracle/Repositories/TagRepository.cs create mode 100644 test/Util.TestShare.Oracle/UnitOfWorks/OracleUnitOfWork.cs create mode 100644 test/Util.TestShare.Oracle/Util.TestShare.Oracle.csproj rename test/{Util.Application.WebApi.Tests.Integration => Util.TestShare.PostgreSql}/EntityTypeConfigurations/CustomerConfiguration.cs (86%) rename test/{Util.Data.EntityFrameworkCore.SqlServer.Tests => Util.TestShare.PostgreSql}/EntityTypeConfigurations/OperationLogConfiguration.cs (94%) rename test/{Util.Data.EntityFrameworkCore.SqlServer.Tests => Util.TestShare.PostgreSql}/EntityTypeConfigurations/OrderConfiguration.cs (80%) rename test/{Util.Data.EntityFrameworkCore.SqlServer.Tests => Util.TestShare.PostgreSql}/EntityTypeConfigurations/OrderItemConfiguration.cs (93%) rename test/{Util.Data.EntityFrameworkCore.PostgreSql.Tests => Util.TestShare.PostgreSql}/EntityTypeConfigurations/PostConfiguration.cs (91%) rename test/{Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration => Util.TestShare.PostgreSql}/EntityTypeConfigurations/ProductConfiguration.cs (67%) rename test/{Util.Data.EntityFrameworkCore.PostgreSql.Tests => Util.TestShare.PostgreSql}/EntityTypeConfigurations/TagConfiguration.cs (90%) rename test/{Util.Data.EntityFrameworkCore.PostgreSql.Tests => Util.TestShare.PostgreSql}/Repositories/CustomerRepository.cs (56%) create mode 100644 test/Util.TestShare.PostgreSql/Repositories/OperationLogRepository.cs create mode 100644 test/Util.TestShare.PostgreSql/Repositories/OrderRepository.cs create mode 100644 test/Util.TestShare.PostgreSql/Repositories/PostRepository.cs rename test/{Util.Data.EntityFrameworkCore.PostgreSql.Tests => Util.TestShare.PostgreSql}/Repositories/ProductRepository.cs (68%) create mode 100644 test/Util.TestShare.PostgreSql/Repositories/TagRepository.cs rename test/{Util.Data.EntityFrameworkCore.PostgreSql.Tests => Util.TestShare.PostgreSql}/UnitOfWorks/PgSqlUnitOfWork.cs (82%) create mode 100644 test/Util.TestShare.PostgreSql/Util.TestShare.PostgreSql.csproj rename test/{Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration => Util.TestShare.SqlServer}/EntityTypeConfigurations/CustomerConfiguration.cs (86%) rename test/{Util.Data.EntityFrameworkCore.PostgreSql.Tests => Util.TestShare.SqlServer}/EntityTypeConfigurations/OperationLogConfiguration.cs (92%) rename test/{Util.Data.EntityFrameworkCore.PostgreSql.Tests => Util.TestShare.SqlServer}/EntityTypeConfigurations/OrderConfiguration.cs (80%) rename test/{Util.Data.EntityFrameworkCore.PostgreSql.Tests => Util.TestShare.SqlServer}/EntityTypeConfigurations/OrderItemConfiguration.cs (93%) create mode 100644 test/Util.TestShare.SqlServer/EntityTypeConfigurations/PostConfiguration.cs rename test/{Util.Application.WebApi.Tests.Integration => Util.TestShare.SqlServer}/EntityTypeConfigurations/ProductConfiguration.cs (67%) create mode 100644 test/Util.TestShare.SqlServer/EntityTypeConfigurations/TagConfiguration.cs rename test/{Util.Data.EntityFrameworkCore.SqlServer.Tests => Util.TestShare.SqlServer}/Repositories/CustomerRepository.cs (55%) create mode 100644 test/Util.TestShare.SqlServer/Repositories/OperationLogRepository.cs create mode 100644 test/Util.TestShare.SqlServer/Repositories/OrderRepository.cs create mode 100644 test/Util.TestShare.SqlServer/Repositories/PostRepository.cs rename test/{Util.Data.EntityFrameworkCore.SqlServer.Tests => Util.TestShare.SqlServer}/Repositories/ProductRepository.cs (68%) create mode 100644 test/Util.TestShare.SqlServer/Repositories/TagRepository.cs rename test/{Util.Data.EntityFrameworkCore.SqlServer.Tests => Util.TestShare.SqlServer}/UnitOfWorks/SqlServerUnitOfWork.cs (89%) create mode 100644 test/Util.TestShare.SqlServer/Util.TestShare.SqlServer.csproj rename test/{Util.Data.EntityFrameworkCore.SqlServer.Tests => Util.TestShare.Sqlite}/EntityTypeConfigurations/CustomerConfiguration.cs (81%) create mode 100644 test/Util.TestShare.Sqlite/EntityTypeConfigurations/OperationLogConfiguration.cs create mode 100644 test/Util.TestShare.Sqlite/EntityTypeConfigurations/OrderConfiguration.cs create mode 100644 test/Util.TestShare.Sqlite/EntityTypeConfigurations/OrderItemConfiguration.cs create mode 100644 test/Util.TestShare.Sqlite/EntityTypeConfigurations/PostConfiguration.cs create mode 100644 test/Util.TestShare.Sqlite/EntityTypeConfigurations/ProductConfiguration.cs create mode 100644 test/Util.TestShare.Sqlite/EntityTypeConfigurations/TagConfiguration.cs create mode 100644 test/Util.TestShare.Sqlite/Repositories/CustomerRepository.cs create mode 100644 test/Util.TestShare.Sqlite/Repositories/OperationLogRepository.cs create mode 100644 test/Util.TestShare.Sqlite/Repositories/OrderRepository.cs create mode 100644 test/Util.TestShare.Sqlite/Repositories/PostRepository.cs create mode 100644 test/Util.TestShare.Sqlite/Repositories/ProductRepository.cs create mode 100644 test/Util.TestShare.Sqlite/Repositories/TagRepository.cs create mode 100644 test/Util.TestShare.Sqlite/UnitOfWorks/SqliteUnitOfWork.cs create mode 100644 test/Util.TestShare.Sqlite/Util.TestShare.Sqlite.csproj rename test/{Util.Data.EntityFrameworkCore.PostgreSql.Tests => Util.TestShare}/Conditions/ProductNameCondition.cs (88%) create mode 100644 test/Util.TestShare/Configs/TestConfig.cs rename test/{Util.Application.WebApi.Tests.Integration => Util.TestShare}/Controllers/CustomerController.cs (92%) rename test/{Util.Application.WebApi.Tests.Integration => Util.TestShare}/Controllers/ProductController.cs (95%) rename test/{Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration => Util.TestShare}/Dtos/CustomerDto.cs (97%) rename test/{Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration => Util.TestShare}/Dtos/ProductDto.cs (96%) rename test/{Util.Data.EntityFrameworkCore.SqlServer.Tests => Util.TestShare}/EventHandlers/OperationLogChangedEventHandler.cs (78%) rename test/{Util.Data.EntityFrameworkCore.SqlServer.Tests => Util.TestShare}/EventHandlers/OperationLogDeletedEventHandler.cs (78%) rename test/{Util.Data.EntityFrameworkCore.SqlServer.Tests => Util.TestShare}/EventHandlers/ProductChangedEventHandler.cs (83%) rename test/{Util.Data.EntityFrameworkCore.SqlServer.Tests => Util.TestShare}/EventHandlers/ProductCreatedEventHandler.cs (77%) rename test/{Util.Data.EntityFrameworkCore.SqlServer.Tests => Util.TestShare}/EventHandlers/ProductDeletedEventHandler.cs (77%) rename test/{Util.Data.EntityFrameworkCore.SqlServer.Tests => Util.TestShare}/EventHandlers/ProductUpdatedEventHandler.cs (77%) rename test/{Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration => Util.TestShare}/Fakes/CustomerFakeService.cs (75%) rename test/{Util.Data.EntityFrameworkCore.PostgreSql.Tests => Util.TestShare}/Fakes/OperationLogFakeService.cs (84%) rename test/{Util.Data.EntityFrameworkCore.SqlServer.Tests => Util.TestShare}/Fakes/OrderFakeService.cs (88%) rename test/{Util.Data.EntityFrameworkCore.PostgreSql.Tests => Util.TestShare}/Fakes/OrderItemFakeService.cs (87%) rename test/{Util.Data.EntityFrameworkCore.PostgreSql.Tests => Util.TestShare}/Fakes/PostFakeService.cs (88%) rename test/{Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration => Util.TestShare}/Fakes/ProductFakeService.cs (81%) rename test/{Util.Data.EntityFrameworkCore.PostgreSql.Tests => Util.TestShare}/Fakes/TagFakeService.cs (88%) rename test/{Util.Application.WebApi.Tests.Integration/Infrastructure/TestBase.cs => Util.TestShare/Infrastructure/ControllerTestBase.cs} (94%) rename test/{Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration => Util.TestShare}/Infrastructure/TestBase.cs (90%) rename test/{Util.Data.EntityFrameworkCore.SqlServer.Tests => Util.TestShare}/Infrastructure/TestSession.cs (91%) rename test/{Util.Application.WebApi.Tests.Integration => Util.TestShare}/Infrastructure/WebApiResult.cs (80%) rename test/{Util.Data.EntityFrameworkCore.PostgreSql.Tests => Util.TestShare}/Models/Customer.cs (96%) rename test/{Util.Data.EntityFrameworkCore.SqlServer.Tests => Util.TestShare}/Models/OperationLog.cs (97%) rename test/{Util.Data.EntityFrameworkCore.PostgreSql.Tests => Util.TestShare}/Models/Order.cs (93%) rename test/{Util.Data.EntityFrameworkCore.PostgreSql.Tests => Util.TestShare}/Models/OrderItem.cs (94%) rename test/{Util.Data.EntityFrameworkCore.PostgreSql.Tests => Util.TestShare}/Models/Post.cs (98%) rename test/{Util.Data.EntityFrameworkCore.PostgreSql.Tests => Util.TestShare}/Models/Product.cs (91%) rename test/{Util.Data.EntityFrameworkCore.PostgreSql.Tests => Util.TestShare}/Models/ProductEnum.cs (73%) rename test/{Util.Data.EntityFrameworkCore.SqlServer.Tests => Util.TestShare}/Models/ProductItem.cs (89%) rename test/{Util.Data.EntityFrameworkCore.SqlServer.Tests => Util.TestShare}/Models/ProductItem2.cs (90%) rename test/{Util.Data.EntityFrameworkCore.PostgreSql.Tests => Util.TestShare}/Models/Tag.cs (97%) rename test/{Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration => Util.TestShare}/Queries/CustomerQuery.cs (98%) rename test/{Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration => Util.TestShare}/Queries/ProductQuery.cs (98%) rename test/{Util.Application.WebApi.Tests.Integration => Util.TestShare}/Repositories/ICustomerRepository.cs (69%) rename test/{Util.Data.EntityFrameworkCore.SqlServer.Tests => Util.TestShare}/Repositories/IOperationLogRepository.cs (65%) rename test/{Util.Data.EntityFrameworkCore.SqlServer.Tests => Util.TestShare}/Repositories/IOrderRepository.cs (62%) rename test/{Util.Data.EntityFrameworkCore.PostgreSql.Tests => Util.TestShare}/Repositories/IPostRepository.cs (61%) rename test/{Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration => Util.TestShare}/Repositories/IProductRepository.cs (81%) rename test/{Util.Data.EntityFrameworkCore.PostgreSql.Tests => Util.TestShare}/Repositories/ITagRepository.cs (61%) rename test/{Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration => Util.TestShare}/Services/CustomerQueryService.cs (85%) rename test/{Util.Application.WebApi.Tests.Integration => Util.TestShare}/Services/CustomerService.cs (73%) rename test/{Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration => Util.TestShare}/Services/ICustomerQueryService.cs (60%) rename test/{Util.Application.WebApi.Tests.Integration => Util.TestShare}/Services/ICustomerService.cs (58%) rename test/{Util.Application.WebApi.Tests.Integration => Util.TestShare}/Services/IProductService.cs (57%) rename test/{Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration => Util.TestShare}/Services/ProductService.cs (61%) create mode 100644 test/Util.TestShare/UnitOfWorks/ITestUnitOfWork.cs create mode 100644 test/Util.TestShare/Util.TestShare.csproj diff --git a/.gitignore b/.gitignore index 3aa440b0..3a65f4c9 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,4 @@ BenchmarkDotNet.Artifacts /document/demo/*.pdb /document/Test/PowerDesigner/*.pdb /test/Util.Data.Dapper.SqlServer.Tests/Document/PowerDesigner/*.pdb +/documents/PowerDesigner/*.pdb diff --git a/Util.sln b/Util.sln index f7f915d8..ea46c908 100644 --- a/Util.sln +++ b/Util.sln @@ -23,19 +23,21 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{E6328DC1-C EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "benchmark", "benchmark", "{199A0EFE-EE81-4A0E-9F2E-298CDDA49D26}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "sample", "sample", "{3E5A39C2-EEF3-40E4-A997-68D4BD65E3B1}" +EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "01-Core", "01-Core", "{9BFB5DBE-8F64-45A9-BDB2-BAD91D44A4C5}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Util.Core.Tests.Integration", "test\Util.Core.Tests.Integration\Util.Core.Tests.Integration.csproj", "{21064598-1418-422E-BA37-8EC09541DFC1}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "02-Util.AspNetCore", "src\Util.AspNetCore\02-Util.AspNetCore.csproj", "{08EF3E38-E0C3-4E18-984C-3216CB6E8897}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "07-Util.AspNetCore", "src\Util.AspNetCore\07-Util.AspNetCore.csproj", "{08EF3E38-E0C3-4E18-984C-3216CB6E8897}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Util.AspNetCore.Tests", "test\Util.AspNetCore.Tests\Util.AspNetCore.Tests.csproj", "{108177E9-E113-4AE4-9B09-B25B2B4DE10E}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "03-Util.ObjectMapping.AutoMapper", "src\Util.ObjectMapping.AutoMapper\03-Util.ObjectMapping.AutoMapper.csproj", "{12C94395-09F1-42E4-8CE1-6E54D3FEBAA6}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "02-Util.ObjectMapping.AutoMapper", "src\Util.ObjectMapping.AutoMapper\02-Util.ObjectMapping.AutoMapper.csproj", "{12C94395-09F1-42E4-8CE1-6E54D3FEBAA6}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Util.ObjectMapping.AutoMapper.Tests", "test\Util.ObjectMapping.AutoMapper.Tests\Util.ObjectMapping.AutoMapper.Tests.csproj", "{955D94B8-747D-4CA4-832A-6377C9FF5B8F}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "04-Util.Aop.AspectCore", "src\Util.Aop.AspectCore\04-Util.Aop.AspectCore.csproj", "{FB337B27-C6C6-43A1-BFA5-58B3CF381BA8}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "03-Util.Aop.AspectCore", "src\Util.Aop.AspectCore\03-Util.Aop.AspectCore.csproj", "{FB337B27-C6C6-43A1-BFA5-58B3CF381BA8}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Util.Aop.AspectCore.Tests", "test\Util.Aop.AspectCore.Tests\Util.Aop.AspectCore.Tests.csproj", "{B8825802-81F7-4671-82E8-3A6E3A21F570}" EndProject @@ -57,7 +59,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Util.Events.Tests", "test\U EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "06-Data", "06-Data", "{66A85767-2877-4B99-84F1-EEABC6DC5247}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "06-Data", "06-Data", "{CC492CA2-5D86-4DB8-AB15-B118DF27C344}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "07-Data", "07-Data", "{CC492CA2-5D86-4DB8-AB15-B118DF27C344}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Util.Data.Tests", "test\Util.Data.Tests\Util.Data.Tests.csproj", "{4D40321F-2C3F-4ACB-8AE0-7A228DF0551B}" EndProject @@ -69,8 +71,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "02-EntityFrameworkCore", "0 EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "02-Util.Data.EntityFrameworkCore.SqlServer", "src\Util.Data.EntityFrameworkCore.SqlServer\02-Util.Data.EntityFrameworkCore.SqlServer.csproj", "{04E5EDDB-8440-4BAD-9531-F87A3AC826FB}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Util.Data.EntityFrameworkCore.SqlServer.Tests", "test\Util.Data.EntityFrameworkCore.SqlServer.Tests\Util.Data.EntityFrameworkCore.SqlServer.Tests.csproj", "{C752DABB-74C0-4232-80CF-CE6E7A153E67}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "02-Util.Templates.Razor", "src\Util.Templates.Razor\02-Util.Templates.Razor.csproj", "{4656C609-DBBA-4F6B-B16F-5E1A8C9D9858}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Util.Templates.Razor.Tests", "test\Util.Templates.Razor.Tests\Util.Templates.Razor.Tests.csproj", "{95751DFC-B598-46B6-84BB-1B717567B886}" @@ -81,15 +81,31 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "03-Util.Templates.Handlebar EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Util.Templates.Handlebars.Tests", "test\Util.Templates.Handlebars.Tests\Util.Templates.Handlebars.Tests.csproj", "{78C9C726-BFAB-4B31-AFCB-5A229E69DC07}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "03-Util.Data.Metadata", "src\Util.Data.Metadata\03-Util.Data.Metadata.csproj", "{257A0A17-5D13-4DA4-8E91-8A3BB2711F49}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "03-Dapper", "03-Dapper", "{4A955BB3-C1AF-45DB-9590-82C00996B608}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "02-Util.Data.Dapper.SqlServer", "src\Util.Data.Dapper.SqlServer\02-Util.Data.Dapper.SqlServer.csproj", "{9A2C7C42-086B-4482-828D-7B02D85372ED}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "02-Util.Data.Sql", "src\Util.Data.Sql\02-Util.Data.Sql.csproj", "{661B88AE-6F83-437C-9A7E-C5C1A565E650}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Util.Data.Sql.Tests", "test\Util.Data.Sql.Tests\Util.Data.Sql.Tests.csproj", "{C99E1554-5039-42BD-B1FD-93814FBEBE44}" +EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Util.Core.Benchmark", "benchmark\Util.Core.Benchmark\Util.Core.Benchmark.csproj", "{25C83DA5-BD4A-4AFA-8747-A0D16CB70500}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "01-Util.Data.Dapper.Core", "src\Util.Data.Dapper.Core\01-Util.Data.Dapper.Core.csproj", "{60424AB5-356A-4623-B1FB-7560334C0BE0}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "05-Util.Data.Dapper.All", "src\Util.Data.Dapper.All\05-Util.Data.Dapper.All.csproj", "{C2A4E6AB-16B9-4457-9445-FFBF672DFBCF}" +EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "02-Util.Domain.Biz", "src\Util.Domain.Biz\02-Util.Domain.Biz.csproj", "{AFB629C5-00C2-492C-8787-C66D810A24DB}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "04-FreeSql", "04-FreeSql", "{9E4DED9F-F404-4512-AB88-91174BD81A45}" +EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "07-Application", "07-Application", "{648CE3E3-CEC4-4F91-8696-6A3FB2F91220}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Util.Application", "src\Util.Application\Util.Application.csproj", "{9404B5FE-3431-4EC0-BCC6-42525FC5D1B8}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "07-Application", "07-Application", "{BB24822F-F104-4D8E-9CB5-0A94DEF04BAB}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "08-Application", "08-Application", "{BB24822F-F104-4D8E-9CB5-0A94DEF04BAB}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Util.Application.Tests", "test\Util.Application.Tests\Util.Application.Tests.csproj", "{EF7BDA1B-22E7-4F3D-97E0-16C9C10AA1B0}" EndProject @@ -103,12 +119,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Util.Application.EntityFram EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Util.Application.WebApi", "src\Util.Application.WebApi\Util.Application.WebApi.csproj", "{3DE7DD7A-8500-46C9-91A1-A65DB60E0235}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Util.Application.WebApi.Tests.Integration", "test\Util.Application.WebApi.Tests.Integration\Util.Application.WebApi.Tests.Integration.csproj", "{9F048957-54DF-47FA-B7A1-C98825853E46}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "03-Util.Data.EntityFrameworkCore.PostgreSql", "src\Util.Data.EntityFrameworkCore.PostgreSql\03-Util.Data.EntityFrameworkCore.PostgreSql.csproj", "{8618EE3F-F120-4AEA-8A77-F7BD5DCCB888}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Util.Data.EntityFrameworkCore.PostgreSql.Tests", "test\Util.Data.EntityFrameworkCore.PostgreSql.Tests\Util.Data.EntityFrameworkCore.PostgreSql.Tests.csproj", "{EBD7AD52-21E3-41A0-BC74-5365A58A7778}" -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "02-Logging", "02-Logging", "{D5CF25B2-1A91-4065-A647-06CDF55F4B96}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "04-Templates", "04-Templates", "{2697EEFB-06BE-4786-89C6-A566FD94A41B}" @@ -125,13 +137,71 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "01-Util.Logging", "src\Util EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Util.Logging.Tests", "test\Util.Logging.Tests\Util.Logging.Tests.csproj", "{04EA7A93-CDC7-4C68-815D-699180D99DCE}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Util.WebApi.Sample", "sample\Util.WebApi.Sample\Util.WebApi.Sample.csproj", "{6FA4820A-DEBB-49BD-BA43-204D2477B92D}" +EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "02-Util.Logging.Serilog", "src\Util.Logging.Serilog\02-Util.Logging.Serilog.csproj", "{A1186FB9-FB77-427C-9AEC-55E48A8D046A}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "03-Util.Logging.Serilog.Exceptionless", "src\Util.Logging.Serilog.Exceptionless\03-Util.Logging.Serilog.Exceptionless.csproj", "{9960FA8A-98C1-45FB-8A09-33CA183AA140}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Util.Logging.Serilog.Exceptionless.Tests", "test\Util.Logging.Serilog.Exceptionless.Tests\Util.Logging.Serilog.Exceptionless.Tests.csproj", "{F836BB0F-C5F4-4409-BDD8-C595FFD37807}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "06-Share", "06-Share", "{E3414144-C19E-40C0-A73A-2FD41AE514D1}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Util.Logging.Serilog.Tests", "test\Util.Logging.Serilog.Tests\Util.Logging.Serilog.Tests.csproj", "{ED9522AF-9F6E-42AC-8750-1B34D8CB3716}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Util.TestShare", "test\Util.TestShare\Util.TestShare.csproj", "{1855CAB7-6379-47A4-A0A4-F890C6C46403}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "04-Util.Data.EntityFrameworkCore.MySql", "src\Util.Data.EntityFrameworkCore.MySql\04-Util.Data.EntityFrameworkCore.MySql.csproj", "{C43539A5-8343-4381-B2FD-5323323F1DB6}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Util.Logging.Serilog.Tests.Integration", "test\Util.Logging.Serilog.Tests.Integration\Util.Logging.Serilog.Tests.Integration.csproj", "{D3C326CD-F1F1-4E06-962D-47F6C8090DEE}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Util.Logging.Serilog.Exceptionless.Tests.Integration", "test\Util.Logging.Serilog.Exceptionless.Tests.Integration\Util.Logging.Serilog.Exceptionless.Tests.Integration.csproj", "{13690AB8-9AA4-4936-A25F-7AF1AE3D4ED0}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Util.Data.EntityFrameworkCore.PostgreSql.Tests.Integration", "test\Util.Data.EntityFrameworkCore.PostgreSql.Tests.Integration\Util.Data.EntityFrameworkCore.PostgreSql.Tests.Integration.csproj", "{244A930D-5B84-4CBC-A3A7-7E8DE1E603D6}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Util.Data.EntityFrameworkCore.SqlServer.Tests.Integration", "test\Util.Data.EntityFrameworkCore.SqlServer.Tests.Integration\Util.Data.EntityFrameworkCore.SqlServer.Tests.Integration.csproj", "{0EDF10D7-D6D6-48E2-AC0C-BA6D814CB633}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Util.TestShare.SqlServer", "test\Util.TestShare.SqlServer\Util.TestShare.SqlServer.csproj", "{05D8A63F-B3E1-4A5E-AA66-337BCF8840C1}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Util.TestShare.PostgreSql", "test\Util.TestShare.PostgreSql\Util.TestShare.PostgreSql.csproj", "{3993A838-71C9-49C5-80B3-16CC48A5F5C9}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Util.Data.EntityFrameworkCore.MySql.Tests.Integration", "test\Util.Data.EntityFrameworkCore.MySql.Tests.Integration\Util.Data.EntityFrameworkCore.MySql.Tests.Integration.csproj", "{D785A240-1115-41C8-943E-5058161D6478}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Util.TestShare.MySql", "test\Util.TestShare.MySql\Util.TestShare.MySql.csproj", "{B1952639-773B-4C82-9D95-7CB4ED8AC59E}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Util.Data.Dapper.SqlServer.Tests.Integration", "test\Util.Data.Dapper.SqlServer.Tests.Integration\Util.Data.Dapper.SqlServer.Tests.Integration.csproj", "{29792C72-565A-46DF-B887-494AC5352818}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Util.Application.EntityFrameworkCore.PostgreSql.Tests.Integration", "test\Util.Application.EntityFrameworkCore.PostgreSql.Tests.Integration\Util.Application.EntityFrameworkCore.PostgreSql.Tests.Integration.csproj", "{C57D22E0-075B-4F27-87F1-E6CF5F203975}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Util.Application.EntityFrameworkCore.MySql.Tests.Integration", "test\Util.Application.EntityFrameworkCore.MySql.Tests.Integration\Util.Application.EntityFrameworkCore.MySql.Tests.Integration.csproj", "{B9B66159-4FC7-4F94-8C21-ADC8CCED84F4}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Util.Application.WebApi.SqlServer.Tests.Integration", "test\Util.Application.WebApi.SqlServer.Tests.Integration\Util.Application.WebApi.SqlServer.Tests.Integration.csproj", "{24FFA5F1-37CD-408B-80A9-006B5A6E11E8}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Util.Application.WebApi.PostgreSql.Tests.Integration", "test\Util.Application.WebApi.PostgreSql.Tests.Integration\Util.Application.WebApi.PostgreSql.Tests.Integration.csproj", "{6FE28297-B958-4BC5-A320-A531874D7F58}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Util.Application.WebApi.MySql.Tests.Integration", "test\Util.Application.WebApi.MySql.Tests.Integration\Util.Application.WebApi.MySql.Tests.Integration.csproj", "{838A27C6-F125-4C61-923E-7C855B598FBD}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Util.Data.Dapper.PostgreSql.Tests.Integration", "test\Util.Data.Dapper.PostgreSql.Tests.Integration\Util.Data.Dapper.PostgreSql.Tests.Integration.csproj", "{FDE43241-3C82-4005-87B3-FD1349FEF4B6}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "03-Util.Data.Dapper.PostgreSql", "src\Util.Data.Dapper.PostgreSql\03-Util.Data.Dapper.PostgreSql.csproj", "{878A2744-5122-48A7-90E6-7D8CFABC29FD}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "04-Util.Data.Dapper.MySql", "src\Util.Data.Dapper.MySql\04-Util.Data.Dapper.MySql.csproj", "{0C464725-DEDC-4894-84A3-7A155E43818B}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Util.Data.Dapper.MySql.Tests.Integration", "test\Util.Data.Dapper.MySql.Tests.Integration\Util.Data.Dapper.MySql.Tests.Integration.csproj", "{AC831843-CDE2-4B67-8BC5-8F2A0D09B273}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "05-Util.Data.EntityFrameworkCore.Sqlite", "src\Util.Data.EntityFrameworkCore.Sqlite\05-Util.Data.EntityFrameworkCore.Sqlite.csproj", "{2BE691A3-19C0-4FCF-85D2-D2371C9462C6}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Util.Data.EntityFrameworkCore.Sqlite.Tests.Integration", "test\Util.Data.EntityFrameworkCore.Sqlite.Tests.Integration\Util.Data.EntityFrameworkCore.Sqlite.Tests.Integration.csproj", "{B140F739-EC51-4265-B4B8-59467606E6EE}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Util.TestShare.Sqlite", "test\Util.TestShare.Sqlite\Util.TestShare.Sqlite.csproj", "{00E8EE51-A263-4971-9431-C4A2DEA4993A}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "06-Util.Data.EntityFrameworkCore.Oracle", "src\Util.Data.EntityFrameworkCore.Oracle\06-Util.Data.EntityFrameworkCore.Oracle.csproj", "{6B2BA282-5C97-4A71-885F-E5259274F714}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Util.TestShare.Oracle", "test\Util.TestShare.Oracle\Util.TestShare.Oracle.csproj", "{05CF624D-F42E-461A-A21D-41BEE0CCEB5C}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Util.Data.EntityFrameworkCore.Oracle.Tests.Integration", "test\Util.Data.EntityFrameworkCore.Oracle.Tests.Integration\Util.Data.EntityFrameworkCore.Oracle.Tests.Integration.csproj", "{C4A782C1-AA25-476B-B936-90433422D0A2}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "04-Util.Localization", "src\Util.Localization\04-Util.Localization.csproj", "{D9E411DD-58B1-4160-8025-068D43ADE72C}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Util.Localization.Tests.Integration", "test\Util.Localization.Tests.Integration\Util.Localization.Tests.Integration.csproj", "{B2AADB36-8433-4EDB-B247-49A3EA82FE06}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Util.Localization.Resources", "test\Util.Localization.Resources\Util.Localization.Resources.csproj", "{40F2A962-6209-42D0-9F21-CEACB411007B}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -215,10 +285,6 @@ Global {04E5EDDB-8440-4BAD-9531-F87A3AC826FB}.Debug|Any CPU.Build.0 = Debug|Any CPU {04E5EDDB-8440-4BAD-9531-F87A3AC826FB}.Release|Any CPU.ActiveCfg = Release|Any CPU {04E5EDDB-8440-4BAD-9531-F87A3AC826FB}.Release|Any CPU.Build.0 = Release|Any CPU - {C752DABB-74C0-4232-80CF-CE6E7A153E67}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {C752DABB-74C0-4232-80CF-CE6E7A153E67}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C752DABB-74C0-4232-80CF-CE6E7A153E67}.Release|Any CPU.ActiveCfg = Release|Any CPU - {C752DABB-74C0-4232-80CF-CE6E7A153E67}.Release|Any CPU.Build.0 = Release|Any CPU {4656C609-DBBA-4F6B-B16F-5E1A8C9D9858}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {4656C609-DBBA-4F6B-B16F-5E1A8C9D9858}.Debug|Any CPU.Build.0 = Debug|Any CPU {4656C609-DBBA-4F6B-B16F-5E1A8C9D9858}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -239,10 +305,34 @@ Global {78C9C726-BFAB-4B31-AFCB-5A229E69DC07}.Debug|Any CPU.Build.0 = Debug|Any CPU {78C9C726-BFAB-4B31-AFCB-5A229E69DC07}.Release|Any CPU.ActiveCfg = Release|Any CPU {78C9C726-BFAB-4B31-AFCB-5A229E69DC07}.Release|Any CPU.Build.0 = Release|Any CPU + {257A0A17-5D13-4DA4-8E91-8A3BB2711F49}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {257A0A17-5D13-4DA4-8E91-8A3BB2711F49}.Debug|Any CPU.Build.0 = Debug|Any CPU + {257A0A17-5D13-4DA4-8E91-8A3BB2711F49}.Release|Any CPU.ActiveCfg = Release|Any CPU + {257A0A17-5D13-4DA4-8E91-8A3BB2711F49}.Release|Any CPU.Build.0 = Release|Any CPU + {9A2C7C42-086B-4482-828D-7B02D85372ED}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9A2C7C42-086B-4482-828D-7B02D85372ED}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9A2C7C42-086B-4482-828D-7B02D85372ED}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9A2C7C42-086B-4482-828D-7B02D85372ED}.Release|Any CPU.Build.0 = Release|Any CPU + {661B88AE-6F83-437C-9A7E-C5C1A565E650}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {661B88AE-6F83-437C-9A7E-C5C1A565E650}.Debug|Any CPU.Build.0 = Debug|Any CPU + {661B88AE-6F83-437C-9A7E-C5C1A565E650}.Release|Any CPU.ActiveCfg = Release|Any CPU + {661B88AE-6F83-437C-9A7E-C5C1A565E650}.Release|Any CPU.Build.0 = Release|Any CPU + {C99E1554-5039-42BD-B1FD-93814FBEBE44}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C99E1554-5039-42BD-B1FD-93814FBEBE44}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C99E1554-5039-42BD-B1FD-93814FBEBE44}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C99E1554-5039-42BD-B1FD-93814FBEBE44}.Release|Any CPU.Build.0 = Release|Any CPU {25C83DA5-BD4A-4AFA-8747-A0D16CB70500}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {25C83DA5-BD4A-4AFA-8747-A0D16CB70500}.Debug|Any CPU.Build.0 = Debug|Any CPU {25C83DA5-BD4A-4AFA-8747-A0D16CB70500}.Release|Any CPU.ActiveCfg = Release|Any CPU {25C83DA5-BD4A-4AFA-8747-A0D16CB70500}.Release|Any CPU.Build.0 = Release|Any CPU + {60424AB5-356A-4623-B1FB-7560334C0BE0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {60424AB5-356A-4623-B1FB-7560334C0BE0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {60424AB5-356A-4623-B1FB-7560334C0BE0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {60424AB5-356A-4623-B1FB-7560334C0BE0}.Release|Any CPU.Build.0 = Release|Any CPU + {C2A4E6AB-16B9-4457-9445-FFBF672DFBCF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C2A4E6AB-16B9-4457-9445-FFBF672DFBCF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C2A4E6AB-16B9-4457-9445-FFBF672DFBCF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C2A4E6AB-16B9-4457-9445-FFBF672DFBCF}.Release|Any CPU.Build.0 = Release|Any CPU {AFB629C5-00C2-492C-8787-C66D810A24DB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {AFB629C5-00C2-492C-8787-C66D810A24DB}.Debug|Any CPU.Build.0 = Debug|Any CPU {AFB629C5-00C2-492C-8787-C66D810A24DB}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -275,18 +365,10 @@ Global {3DE7DD7A-8500-46C9-91A1-A65DB60E0235}.Debug|Any CPU.Build.0 = Debug|Any CPU {3DE7DD7A-8500-46C9-91A1-A65DB60E0235}.Release|Any CPU.ActiveCfg = Release|Any CPU {3DE7DD7A-8500-46C9-91A1-A65DB60E0235}.Release|Any CPU.Build.0 = Release|Any CPU - {9F048957-54DF-47FA-B7A1-C98825853E46}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {9F048957-54DF-47FA-B7A1-C98825853E46}.Debug|Any CPU.Build.0 = Debug|Any CPU - {9F048957-54DF-47FA-B7A1-C98825853E46}.Release|Any CPU.ActiveCfg = Release|Any CPU - {9F048957-54DF-47FA-B7A1-C98825853E46}.Release|Any CPU.Build.0 = Release|Any CPU {8618EE3F-F120-4AEA-8A77-F7BD5DCCB888}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {8618EE3F-F120-4AEA-8A77-F7BD5DCCB888}.Debug|Any CPU.Build.0 = Debug|Any CPU {8618EE3F-F120-4AEA-8A77-F7BD5DCCB888}.Release|Any CPU.ActiveCfg = Release|Any CPU {8618EE3F-F120-4AEA-8A77-F7BD5DCCB888}.Release|Any CPU.Build.0 = Release|Any CPU - {EBD7AD52-21E3-41A0-BC74-5365A58A7778}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {EBD7AD52-21E3-41A0-BC74-5365A58A7778}.Debug|Any CPU.Build.0 = Debug|Any CPU - {EBD7AD52-21E3-41A0-BC74-5365A58A7778}.Release|Any CPU.ActiveCfg = Release|Any CPU - {EBD7AD52-21E3-41A0-BC74-5365A58A7778}.Release|Any CPU.Build.0 = Release|Any CPU {577A7F6F-4836-4811-B715-32573127BDB3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {577A7F6F-4836-4811-B715-32573127BDB3}.Debug|Any CPU.Build.0 = Debug|Any CPU {577A7F6F-4836-4811-B715-32573127BDB3}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -295,6 +377,10 @@ Global {04EA7A93-CDC7-4C68-815D-699180D99DCE}.Debug|Any CPU.Build.0 = Debug|Any CPU {04EA7A93-CDC7-4C68-815D-699180D99DCE}.Release|Any CPU.ActiveCfg = Release|Any CPU {04EA7A93-CDC7-4C68-815D-699180D99DCE}.Release|Any CPU.Build.0 = Release|Any CPU + {6FA4820A-DEBB-49BD-BA43-204D2477B92D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6FA4820A-DEBB-49BD-BA43-204D2477B92D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6FA4820A-DEBB-49BD-BA43-204D2477B92D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6FA4820A-DEBB-49BD-BA43-204D2477B92D}.Release|Any CPU.Build.0 = Release|Any CPU {A1186FB9-FB77-427C-9AEC-55E48A8D046A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {A1186FB9-FB77-427C-9AEC-55E48A8D046A}.Debug|Any CPU.Build.0 = Debug|Any CPU {A1186FB9-FB77-427C-9AEC-55E48A8D046A}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -303,14 +389,122 @@ Global {9960FA8A-98C1-45FB-8A09-33CA183AA140}.Debug|Any CPU.Build.0 = Debug|Any CPU {9960FA8A-98C1-45FB-8A09-33CA183AA140}.Release|Any CPU.ActiveCfg = Release|Any CPU {9960FA8A-98C1-45FB-8A09-33CA183AA140}.Release|Any CPU.Build.0 = Release|Any CPU - {F836BB0F-C5F4-4409-BDD8-C595FFD37807}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {F836BB0F-C5F4-4409-BDD8-C595FFD37807}.Debug|Any CPU.Build.0 = Debug|Any CPU - {F836BB0F-C5F4-4409-BDD8-C595FFD37807}.Release|Any CPU.ActiveCfg = Release|Any CPU - {F836BB0F-C5F4-4409-BDD8-C595FFD37807}.Release|Any CPU.Build.0 = Release|Any CPU - {ED9522AF-9F6E-42AC-8750-1B34D8CB3716}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {ED9522AF-9F6E-42AC-8750-1B34D8CB3716}.Debug|Any CPU.Build.0 = Debug|Any CPU - {ED9522AF-9F6E-42AC-8750-1B34D8CB3716}.Release|Any CPU.ActiveCfg = Release|Any CPU - {ED9522AF-9F6E-42AC-8750-1B34D8CB3716}.Release|Any CPU.Build.0 = Release|Any CPU + {1855CAB7-6379-47A4-A0A4-F890C6C46403}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1855CAB7-6379-47A4-A0A4-F890C6C46403}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1855CAB7-6379-47A4-A0A4-F890C6C46403}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1855CAB7-6379-47A4-A0A4-F890C6C46403}.Release|Any CPU.Build.0 = Release|Any CPU + {C43539A5-8343-4381-B2FD-5323323F1DB6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C43539A5-8343-4381-B2FD-5323323F1DB6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C43539A5-8343-4381-B2FD-5323323F1DB6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C43539A5-8343-4381-B2FD-5323323F1DB6}.Release|Any CPU.Build.0 = Release|Any CPU + {D3C326CD-F1F1-4E06-962D-47F6C8090DEE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D3C326CD-F1F1-4E06-962D-47F6C8090DEE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D3C326CD-F1F1-4E06-962D-47F6C8090DEE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D3C326CD-F1F1-4E06-962D-47F6C8090DEE}.Release|Any CPU.Build.0 = Release|Any CPU + {13690AB8-9AA4-4936-A25F-7AF1AE3D4ED0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {13690AB8-9AA4-4936-A25F-7AF1AE3D4ED0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {13690AB8-9AA4-4936-A25F-7AF1AE3D4ED0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {13690AB8-9AA4-4936-A25F-7AF1AE3D4ED0}.Release|Any CPU.Build.0 = Release|Any CPU + {244A930D-5B84-4CBC-A3A7-7E8DE1E603D6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {244A930D-5B84-4CBC-A3A7-7E8DE1E603D6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {244A930D-5B84-4CBC-A3A7-7E8DE1E603D6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {244A930D-5B84-4CBC-A3A7-7E8DE1E603D6}.Release|Any CPU.Build.0 = Release|Any CPU + {0EDF10D7-D6D6-48E2-AC0C-BA6D814CB633}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0EDF10D7-D6D6-48E2-AC0C-BA6D814CB633}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0EDF10D7-D6D6-48E2-AC0C-BA6D814CB633}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0EDF10D7-D6D6-48E2-AC0C-BA6D814CB633}.Release|Any CPU.Build.0 = Release|Any CPU + {05D8A63F-B3E1-4A5E-AA66-337BCF8840C1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {05D8A63F-B3E1-4A5E-AA66-337BCF8840C1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {05D8A63F-B3E1-4A5E-AA66-337BCF8840C1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {05D8A63F-B3E1-4A5E-AA66-337BCF8840C1}.Release|Any CPU.Build.0 = Release|Any CPU + {3993A838-71C9-49C5-80B3-16CC48A5F5C9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3993A838-71C9-49C5-80B3-16CC48A5F5C9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3993A838-71C9-49C5-80B3-16CC48A5F5C9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3993A838-71C9-49C5-80B3-16CC48A5F5C9}.Release|Any CPU.Build.0 = Release|Any CPU + {D785A240-1115-41C8-943E-5058161D6478}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D785A240-1115-41C8-943E-5058161D6478}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D785A240-1115-41C8-943E-5058161D6478}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D785A240-1115-41C8-943E-5058161D6478}.Release|Any CPU.Build.0 = Release|Any CPU + {B1952639-773B-4C82-9D95-7CB4ED8AC59E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B1952639-773B-4C82-9D95-7CB4ED8AC59E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B1952639-773B-4C82-9D95-7CB4ED8AC59E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B1952639-773B-4C82-9D95-7CB4ED8AC59E}.Release|Any CPU.Build.0 = Release|Any CPU + {29792C72-565A-46DF-B887-494AC5352818}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {29792C72-565A-46DF-B887-494AC5352818}.Debug|Any CPU.Build.0 = Debug|Any CPU + {29792C72-565A-46DF-B887-494AC5352818}.Release|Any CPU.ActiveCfg = Release|Any CPU + {29792C72-565A-46DF-B887-494AC5352818}.Release|Any CPU.Build.0 = Release|Any CPU + {C57D22E0-075B-4F27-87F1-E6CF5F203975}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C57D22E0-075B-4F27-87F1-E6CF5F203975}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C57D22E0-075B-4F27-87F1-E6CF5F203975}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C57D22E0-075B-4F27-87F1-E6CF5F203975}.Release|Any CPU.Build.0 = Release|Any CPU + {B9B66159-4FC7-4F94-8C21-ADC8CCED84F4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B9B66159-4FC7-4F94-8C21-ADC8CCED84F4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B9B66159-4FC7-4F94-8C21-ADC8CCED84F4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B9B66159-4FC7-4F94-8C21-ADC8CCED84F4}.Release|Any CPU.Build.0 = Release|Any CPU + {24FFA5F1-37CD-408B-80A9-006B5A6E11E8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {24FFA5F1-37CD-408B-80A9-006B5A6E11E8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {24FFA5F1-37CD-408B-80A9-006B5A6E11E8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {24FFA5F1-37CD-408B-80A9-006B5A6E11E8}.Release|Any CPU.Build.0 = Release|Any CPU + {6FE28297-B958-4BC5-A320-A531874D7F58}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6FE28297-B958-4BC5-A320-A531874D7F58}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6FE28297-B958-4BC5-A320-A531874D7F58}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6FE28297-B958-4BC5-A320-A531874D7F58}.Release|Any CPU.Build.0 = Release|Any CPU + {838A27C6-F125-4C61-923E-7C855B598FBD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {838A27C6-F125-4C61-923E-7C855B598FBD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {838A27C6-F125-4C61-923E-7C855B598FBD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {838A27C6-F125-4C61-923E-7C855B598FBD}.Release|Any CPU.Build.0 = Release|Any CPU + {FDE43241-3C82-4005-87B3-FD1349FEF4B6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FDE43241-3C82-4005-87B3-FD1349FEF4B6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FDE43241-3C82-4005-87B3-FD1349FEF4B6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FDE43241-3C82-4005-87B3-FD1349FEF4B6}.Release|Any CPU.Build.0 = Release|Any CPU + {878A2744-5122-48A7-90E6-7D8CFABC29FD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {878A2744-5122-48A7-90E6-7D8CFABC29FD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {878A2744-5122-48A7-90E6-7D8CFABC29FD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {878A2744-5122-48A7-90E6-7D8CFABC29FD}.Release|Any CPU.Build.0 = Release|Any CPU + {0C464725-DEDC-4894-84A3-7A155E43818B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0C464725-DEDC-4894-84A3-7A155E43818B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0C464725-DEDC-4894-84A3-7A155E43818B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0C464725-DEDC-4894-84A3-7A155E43818B}.Release|Any CPU.Build.0 = Release|Any CPU + {AC831843-CDE2-4B67-8BC5-8F2A0D09B273}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AC831843-CDE2-4B67-8BC5-8F2A0D09B273}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AC831843-CDE2-4B67-8BC5-8F2A0D09B273}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AC831843-CDE2-4B67-8BC5-8F2A0D09B273}.Release|Any CPU.Build.0 = Release|Any CPU + {2BE691A3-19C0-4FCF-85D2-D2371C9462C6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2BE691A3-19C0-4FCF-85D2-D2371C9462C6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2BE691A3-19C0-4FCF-85D2-D2371C9462C6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2BE691A3-19C0-4FCF-85D2-D2371C9462C6}.Release|Any CPU.Build.0 = Release|Any CPU + {B140F739-EC51-4265-B4B8-59467606E6EE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B140F739-EC51-4265-B4B8-59467606E6EE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B140F739-EC51-4265-B4B8-59467606E6EE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B140F739-EC51-4265-B4B8-59467606E6EE}.Release|Any CPU.Build.0 = Release|Any CPU + {00E8EE51-A263-4971-9431-C4A2DEA4993A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {00E8EE51-A263-4971-9431-C4A2DEA4993A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {00E8EE51-A263-4971-9431-C4A2DEA4993A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {00E8EE51-A263-4971-9431-C4A2DEA4993A}.Release|Any CPU.Build.0 = Release|Any CPU + {6B2BA282-5C97-4A71-885F-E5259274F714}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6B2BA282-5C97-4A71-885F-E5259274F714}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6B2BA282-5C97-4A71-885F-E5259274F714}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6B2BA282-5C97-4A71-885F-E5259274F714}.Release|Any CPU.Build.0 = Release|Any CPU + {05CF624D-F42E-461A-A21D-41BEE0CCEB5C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {05CF624D-F42E-461A-A21D-41BEE0CCEB5C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {05CF624D-F42E-461A-A21D-41BEE0CCEB5C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {05CF624D-F42E-461A-A21D-41BEE0CCEB5C}.Release|Any CPU.Build.0 = Release|Any CPU + {C4A782C1-AA25-476B-B936-90433422D0A2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C4A782C1-AA25-476B-B936-90433422D0A2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C4A782C1-AA25-476B-B936-90433422D0A2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C4A782C1-AA25-476B-B936-90433422D0A2}.Release|Any CPU.Build.0 = Release|Any CPU + {D9E411DD-58B1-4160-8025-068D43ADE72C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D9E411DD-58B1-4160-8025-068D43ADE72C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D9E411DD-58B1-4160-8025-068D43ADE72C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D9E411DD-58B1-4160-8025-068D43ADE72C}.Release|Any CPU.Build.0 = Release|Any CPU + {B2AADB36-8433-4EDB-B247-49A3EA82FE06}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B2AADB36-8433-4EDB-B247-49A3EA82FE06}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B2AADB36-8433-4EDB-B247-49A3EA82FE06}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B2AADB36-8433-4EDB-B247-49A3EA82FE06}.Release|Any CPU.Build.0 = Release|Any CPU + {40F2A962-6209-42D0-9F21-CEACB411007B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {40F2A962-6209-42D0-9F21-CEACB411007B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {40F2A962-6209-42D0-9F21-CEACB411007B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {40F2A962-6209-42D0-9F21-CEACB411007B}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -343,14 +537,21 @@ Global {45E2ADF5-F386-44CD-A43D-A3AB47E9C39A} = {66A85767-2877-4B99-84F1-EEABC6DC5247} {4E99CBC5-1C74-44E7-9DEF-3FA44CADCCF0} = {66A85767-2877-4B99-84F1-EEABC6DC5247} {04E5EDDB-8440-4BAD-9531-F87A3AC826FB} = {4E99CBC5-1C74-44E7-9DEF-3FA44CADCCF0} - {C752DABB-74C0-4232-80CF-CE6E7A153E67} = {CC492CA2-5D86-4DB8-AB15-B118DF27C344} {4656C609-DBBA-4F6B-B16F-5E1A8C9D9858} = {2697EEFB-06BE-4786-89C6-A566FD94A41B} {95751DFC-B598-46B6-84BB-1B717567B886} = {445850B7-1A9D-4E9D-8AC1-765F3792DC19} {F7925EED-65E6-4CA2-9B8D-B7036F6DB3E8} = {2697EEFB-06BE-4786-89C6-A566FD94A41B} {D22C3F6D-434A-4F09-9EB2-B0433CC43642} = {2697EEFB-06BE-4786-89C6-A566FD94A41B} {78C9C726-BFAB-4B31-AFCB-5A229E69DC07} = {445850B7-1A9D-4E9D-8AC1-765F3792DC19} + {257A0A17-5D13-4DA4-8E91-8A3BB2711F49} = {45E2ADF5-F386-44CD-A43D-A3AB47E9C39A} + {4A955BB3-C1AF-45DB-9590-82C00996B608} = {66A85767-2877-4B99-84F1-EEABC6DC5247} + {9A2C7C42-086B-4482-828D-7B02D85372ED} = {4A955BB3-C1AF-45DB-9590-82C00996B608} + {661B88AE-6F83-437C-9A7E-C5C1A565E650} = {45E2ADF5-F386-44CD-A43D-A3AB47E9C39A} + {C99E1554-5039-42BD-B1FD-93814FBEBE44} = {CC492CA2-5D86-4DB8-AB15-B118DF27C344} {25C83DA5-BD4A-4AFA-8747-A0D16CB70500} = {199A0EFE-EE81-4A0E-9F2E-298CDDA49D26} + {60424AB5-356A-4623-B1FB-7560334C0BE0} = {4A955BB3-C1AF-45DB-9590-82C00996B608} + {C2A4E6AB-16B9-4457-9445-FFBF672DFBCF} = {4A955BB3-C1AF-45DB-9590-82C00996B608} {AFB629C5-00C2-492C-8787-C66D810A24DB} = {7AB71D86-D351-4009-A789-24097897E74A} + {9E4DED9F-F404-4512-AB88-91174BD81A45} = {66A85767-2877-4B99-84F1-EEABC6DC5247} {648CE3E3-CEC4-4F91-8696-6A3FB2F91220} = {C01B9930-D67F-41C5-90C9-C87DC53F39CB} {9404B5FE-3431-4EC0-BCC6-42525FC5D1B8} = {648CE3E3-CEC4-4F91-8696-6A3FB2F91220} {BB24822F-F104-4D8E-9CB5-0A94DEF04BAB} = {E6328DC1-C8F0-4DC6-941F-C6CAFFF783DF} @@ -360,9 +561,7 @@ Global {CA43B145-9DF2-49D3-9371-B88BFB0E846A} = {BB24822F-F104-4D8E-9CB5-0A94DEF04BAB} {95842BB6-559E-4317-B1E9-FF19D39ADA24} = {648CE3E3-CEC4-4F91-8696-6A3FB2F91220} {3DE7DD7A-8500-46C9-91A1-A65DB60E0235} = {648CE3E3-CEC4-4F91-8696-6A3FB2F91220} - {9F048957-54DF-47FA-B7A1-C98825853E46} = {BB24822F-F104-4D8E-9CB5-0A94DEF04BAB} {8618EE3F-F120-4AEA-8A77-F7BD5DCCB888} = {4E99CBC5-1C74-44E7-9DEF-3FA44CADCCF0} - {EBD7AD52-21E3-41A0-BC74-5365A58A7778} = {CC492CA2-5D86-4DB8-AB15-B118DF27C344} {D5CF25B2-1A91-4065-A647-06CDF55F4B96} = {C01B9930-D67F-41C5-90C9-C87DC53F39CB} {2697EEFB-06BE-4786-89C6-A566FD94A41B} = {C01B9930-D67F-41C5-90C9-C87DC53F39CB} {A6EB05D5-EF38-45B6-960A-0EB759373FDF} = {E6328DC1-C8F0-4DC6-941F-C6CAFFF783DF} @@ -371,10 +570,39 @@ Global {3ABD7B4B-37F9-4D49-92D9-384190177286} = {E6328DC1-C8F0-4DC6-941F-C6CAFFF783DF} {577A7F6F-4836-4811-B715-32573127BDB3} = {D5CF25B2-1A91-4065-A647-06CDF55F4B96} {04EA7A93-CDC7-4C68-815D-699180D99DCE} = {A6EB05D5-EF38-45B6-960A-0EB759373FDF} + {6FA4820A-DEBB-49BD-BA43-204D2477B92D} = {3E5A39C2-EEF3-40E4-A997-68D4BD65E3B1} {A1186FB9-FB77-427C-9AEC-55E48A8D046A} = {D5CF25B2-1A91-4065-A647-06CDF55F4B96} {9960FA8A-98C1-45FB-8A09-33CA183AA140} = {D5CF25B2-1A91-4065-A647-06CDF55F4B96} - {F836BB0F-C5F4-4409-BDD8-C595FFD37807} = {A6EB05D5-EF38-45B6-960A-0EB759373FDF} - {ED9522AF-9F6E-42AC-8750-1B34D8CB3716} = {A6EB05D5-EF38-45B6-960A-0EB759373FDF} + {E3414144-C19E-40C0-A73A-2FD41AE514D1} = {E6328DC1-C8F0-4DC6-941F-C6CAFFF783DF} + {1855CAB7-6379-47A4-A0A4-F890C6C46403} = {E3414144-C19E-40C0-A73A-2FD41AE514D1} + {C43539A5-8343-4381-B2FD-5323323F1DB6} = {4E99CBC5-1C74-44E7-9DEF-3FA44CADCCF0} + {D3C326CD-F1F1-4E06-962D-47F6C8090DEE} = {A6EB05D5-EF38-45B6-960A-0EB759373FDF} + {13690AB8-9AA4-4936-A25F-7AF1AE3D4ED0} = {A6EB05D5-EF38-45B6-960A-0EB759373FDF} + {244A930D-5B84-4CBC-A3A7-7E8DE1E603D6} = {CC492CA2-5D86-4DB8-AB15-B118DF27C344} + {0EDF10D7-D6D6-48E2-AC0C-BA6D814CB633} = {CC492CA2-5D86-4DB8-AB15-B118DF27C344} + {05D8A63F-B3E1-4A5E-AA66-337BCF8840C1} = {E3414144-C19E-40C0-A73A-2FD41AE514D1} + {3993A838-71C9-49C5-80B3-16CC48A5F5C9} = {E3414144-C19E-40C0-A73A-2FD41AE514D1} + {D785A240-1115-41C8-943E-5058161D6478} = {CC492CA2-5D86-4DB8-AB15-B118DF27C344} + {B1952639-773B-4C82-9D95-7CB4ED8AC59E} = {E3414144-C19E-40C0-A73A-2FD41AE514D1} + {29792C72-565A-46DF-B887-494AC5352818} = {CC492CA2-5D86-4DB8-AB15-B118DF27C344} + {C57D22E0-075B-4F27-87F1-E6CF5F203975} = {BB24822F-F104-4D8E-9CB5-0A94DEF04BAB} + {B9B66159-4FC7-4F94-8C21-ADC8CCED84F4} = {BB24822F-F104-4D8E-9CB5-0A94DEF04BAB} + {24FFA5F1-37CD-408B-80A9-006B5A6E11E8} = {BB24822F-F104-4D8E-9CB5-0A94DEF04BAB} + {6FE28297-B958-4BC5-A320-A531874D7F58} = {BB24822F-F104-4D8E-9CB5-0A94DEF04BAB} + {838A27C6-F125-4C61-923E-7C855B598FBD} = {BB24822F-F104-4D8E-9CB5-0A94DEF04BAB} + {FDE43241-3C82-4005-87B3-FD1349FEF4B6} = {CC492CA2-5D86-4DB8-AB15-B118DF27C344} + {878A2744-5122-48A7-90E6-7D8CFABC29FD} = {4A955BB3-C1AF-45DB-9590-82C00996B608} + {0C464725-DEDC-4894-84A3-7A155E43818B} = {4A955BB3-C1AF-45DB-9590-82C00996B608} + {AC831843-CDE2-4B67-8BC5-8F2A0D09B273} = {CC492CA2-5D86-4DB8-AB15-B118DF27C344} + {2BE691A3-19C0-4FCF-85D2-D2371C9462C6} = {4E99CBC5-1C74-44E7-9DEF-3FA44CADCCF0} + {B140F739-EC51-4265-B4B8-59467606E6EE} = {CC492CA2-5D86-4DB8-AB15-B118DF27C344} + {00E8EE51-A263-4971-9431-C4A2DEA4993A} = {E3414144-C19E-40C0-A73A-2FD41AE514D1} + {6B2BA282-5C97-4A71-885F-E5259274F714} = {4E99CBC5-1C74-44E7-9DEF-3FA44CADCCF0} + {05CF624D-F42E-461A-A21D-41BEE0CCEB5C} = {E3414144-C19E-40C0-A73A-2FD41AE514D1} + {C4A782C1-AA25-476B-B936-90433422D0A2} = {CC492CA2-5D86-4DB8-AB15-B118DF27C344} + {D9E411DD-58B1-4160-8025-068D43ADE72C} = {345739E2-E20C-4B1F-B1B2-725006FC9F72} + {B2AADB36-8433-4EDB-B247-49A3EA82FE06} = {9BFB5DBE-8F64-45A9-BDB2-BAD91D44A4C5} + {40F2A962-6209-42D0-9F21-CEACB411007B} = {9BFB5DBE-8F64-45A9-BDB2-BAD91D44A4C5} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {94347832-A36D-4C42-9C4D-B848BD4F5DA9} diff --git a/build/Build.csproj b/build/Build.csproj index 78927daa..e90b42b1 100644 --- a/build/Build.csproj +++ b/build/Build.csproj @@ -15,7 +15,7 @@ - + diff --git a/build/BuildScript.cs b/build/BuildScript.cs index c236e286..79069a06 100644 --- a/build/BuildScript.cs +++ b/build/BuildScript.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.IO; +using System.Linq; using FlubuCore.Context; using FlubuCore.Context.Attributes.BuildProperties; using FlubuCore.Context.FluentInterface.Interfaces; @@ -38,7 +39,7 @@ namespace Build { /// public FullPath SourceDir => RootDirectory.CombineWith( "../src" ); /// - /// Դ´úÂëĿ¼ + /// ²âÊÔĿ¼ /// public FullPath TestDir => RootDirectory.CombineWith( "../test" ); /// @@ -50,9 +51,24 @@ namespace Build { /// public List Projects { get; set; } /// - /// ²âÊÔÏîĿÎļþÁбí + /// µ¥Ԫ²âÊÔÏîĿÎļþÁбí /// - public List TestProjecs { get; set; } + public List UnitTestProjecs { get; set; } + /// + /// ¼¯³ɲâÊÔÏîĿÎļþÁбí + /// + public List IntegrationTestProjecs { get; set; } + /// + /// ºöÂԲâÊÔÏîĿÎļþÁбí + /// + public List IgnoreTestProjecs { get; set; } + + /// + /// »ñȡ¼¯³ɲâÊÔÏîĿÎļþÁбí + /// + protected List GetIntegrationTestProjecs() { + return IntegrationTestProjecs.Where( t => IgnoreTestProjecs.Exists( p => p.FileName == t.FileName ) == false ).ToList(); + } /// /// ¹¹½¨ǰ²Ù×÷ @@ -60,7 +76,17 @@ namespace Build { /// ¹¹½¨ÈÎÎñÉÏÏÂÎÄ protected override void BeforeBuildExecution( ITaskContext context ) { Projects = context.GetFiles( SourceDir, "*/*.csproj" ); - TestProjecs = context.GetFiles( TestDir, "*/*.csproj" ); + UnitTestProjecs = context.GetFiles( TestDir, "*/*.Tests.csproj" ); + IntegrationTestProjecs = context.GetFiles( TestDir, "*/*.Tests.Integration.csproj" ); + IgnoreTestProjecs = new List(); + AddIgnoreTestProjecs( context ); + } + + /// + /// Ìí¼ӺöÂԲâÊÔÏîĿÎļþÁбí + /// + private void AddIgnoreTestProjecs( ITaskContext context ) { + IgnoreTestProjecs.AddRange( context.GetFiles( TestDir, "*/*.Oracle.Tests.Integration.csproj" ) ); } /// @@ -71,9 +97,9 @@ namespace Build { var clean = Clean( context ); var restore = Restore( context, clean ); var build = Build( context, restore ); + var test = Test( context ); var pack = Pack( context, clean ); PublishNuGetPackage( context, pack ); - Test( context ); } /// @@ -88,30 +114,65 @@ namespace Build { /// /// »¹ԭ°ü /// - private ITarget Restore( ITaskContext context, ITarget target ) { + private ITarget Restore( ITaskContext context, params ITarget[] dependTargets ) { return context.CreateTarget( "restore" ) .SetDescription( "Restore the solution." ) - .DependsOn( target ) + .DependsOn( dependTargets ) .AddCoreTask( t => t.Restore() ); } /// /// ±àÒë½â¾ö·½°¸ /// - private ITarget Build( ITaskContext context, ITarget target ) { + private ITarget Build( ITaskContext context, params ITarget[] dependTargets ) { return context.CreateTarget( "compile" ) .SetDescription( "Compiles the solution." ) - .DependsOn( target ) + .DependsOn( dependTargets ) .AddCoreTask( t => t.Build() ); } + /// + /// ÔËÐвâÊÔ + /// + private ITarget Test( ITaskContext context, params ITarget[] dependTargets ) { + var unitTest = UnitTest( context, dependTargets ); + var integrationTest = IntegrationTest( context, dependTargets ); + return context.CreateTarget( "test" ) + .SetDescription( "Run all tests." ) + .DependsOn( unitTest, integrationTest ); + } + + /// + /// ÔËÐе¥Ԫ²âÊÔ + /// + private ITarget UnitTest( ITaskContext context, params ITarget[] dependTargets ) { + return context.CreateTarget( "unit.test" ) + .SetDescription( "Run unit tests." ) + .DependsOn( dependTargets ) + .ForEach( UnitTestProjecs, ( project, target ) => { + target.AddCoreTask( t => t.Test().Project( project ) ); + } ); + } + + /// + /// ÔËÐм¯³ɲâÊÔ + /// + private ITarget IntegrationTest( ITaskContext context, params ITarget[] dependTargets ) { + return context.CreateTarget( "integration.test" ) + .SetDescription( "Run integration tests." ) + .DependsOn( dependTargets ) + .ForEach( GetIntegrationTestProjecs(), ( project, target ) => { + target.AddCoreTask( t => t.Test().Project( project ) ); + } ); + } + /// /// ´´½¨nuget°ü /// - private ITarget Pack( ITaskContext context, ITarget dependTarget ) { + private ITarget Pack( ITaskContext context, params ITarget[] dependTargets ) { return context.CreateTarget( "pack" ) .SetDescription( "Create nuget packages." ) - .DependsOn( dependTarget ) + .DependsOn( dependTargets ) .ForEach( Projects, ( project, target ) => { target.AddCoreTask( t => t.Pack() .Project( project ) @@ -123,10 +184,10 @@ namespace Build { /// /// ·¢²¼nuget°ü /// - private void PublishNuGetPackage( ITaskContext context, ITarget dependTarget ) { + private void PublishNuGetPackage( ITaskContext context, params ITarget[] dependTargets ) { context.CreateTarget( "nuget.publish" ) .SetDescription( "Publishes nuget packages" ) - .DependsOn( dependTarget ) + .DependsOn( dependTargets ) .Do( t => { var packages = Directory.GetFiles( OutputDir, "*.nupkg" ); foreach ( var package in packages ) { @@ -140,16 +201,5 @@ namespace Build { } } ); } - - /// - /// ÔËÐвâÊÔ - /// - private void Test( ITaskContext context ) { - context.CreateTarget( "test" ) - .SetDescription( "Run all tests." ) - .ForEach( TestProjecs, ( project, target ) => { - target.AddCoreTask( t => t.Test().Project( project ) ); - } ); - } } } \ No newline at end of file diff --git a/sample/Util.WebApi.Sample/Program.cs b/sample/Util.WebApi.Sample/Program.cs new file mode 100644 index 00000000..8008de5f --- /dev/null +++ b/sample/Util.WebApi.Sample/Program.cs @@ -0,0 +1,31 @@ +using Util; +using Util.Aop; +using Util.Logging.Serilog; + +//´´½¨WebӦÓóÌÐòÉú³ÉÆ÷ +var builder = WebApplication.CreateBuilder( args ); + +//ÅäÖ÷þÎñ +builder.Services.AddControllers(); +builder.Services.AddEndpointsApiExplorer(); +builder.Services.AddSwaggerGen(); + +//ÅäÖÃUtil +builder.Host.AddUtil( options => options.UseAop() + .UseSerilog( t => t.AddExceptionless() ) +); + +//¹¹½¨WebӦÓóÌÐò +var app = builder.Build(); + +//ÅäÖÃÇëÇó¹ܵÀ +if ( app.Environment.IsDevelopment() ) { + app.UseSwagger(); + app.UseSwaggerUI(); +} +app.UseHttpLogging(); +app.UseAuthorization(); +app.MapControllers(); + +//ÔËÐÐӦÓà +app.Run(); diff --git a/sample/Util.WebApi.Sample/Properties/AssemblyInfo.cs b/sample/Util.WebApi.Sample/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..071580ef --- /dev/null +++ b/sample/Util.WebApi.Sample/Properties/AssemblyInfo.cs @@ -0,0 +1,2 @@ +using Microsoft.Extensions.Localization; +[assembly: RootNamespace( "Util.WebApi" )] \ No newline at end of file diff --git a/sample/Util.WebApi.Sample/Properties/launchSettings.json b/sample/Util.WebApi.Sample/Properties/launchSettings.json new file mode 100644 index 00000000..73b161b9 --- /dev/null +++ b/sample/Util.WebApi.Sample/Properties/launchSettings.json @@ -0,0 +1,31 @@ +{ + "$schema": "https://json.schemastore.org/launchsettings.json", + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:38416", + "sslPort": 0 + } + }, + "profiles": { + "Util.WebApi.Sample": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "launchUrl": "swagger", + "applicationUrl": "http://localhost:5173", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "launchUrl": "swagger", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/sample/Util.WebApi.Sample/Util.WebApi.Sample.csproj b/sample/Util.WebApi.Sample/Util.WebApi.Sample.csproj new file mode 100644 index 00000000..2bb6b0f1 --- /dev/null +++ b/sample/Util.WebApi.Sample/Util.WebApi.Sample.csproj @@ -0,0 +1,21 @@ + + + + $(NetTargetFramework) + Util.WebApi + enable + + + + + + + + + + + + + + + diff --git a/sample/Util.WebApi.Sample/appsettings.Development.json b/sample/Util.WebApi.Sample/appsettings.Development.json new file mode 100644 index 00000000..1b2d3baf --- /dev/null +++ b/sample/Util.WebApi.Sample/appsettings.Development.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} \ No newline at end of file diff --git a/sample/Util.WebApi.Sample/appsettings.json b/sample/Util.WebApi.Sample/appsettings.json new file mode 100644 index 00000000..a8ba5e0f --- /dev/null +++ b/sample/Util.WebApi.Sample/appsettings.json @@ -0,0 +1,10 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning", + "Microsoft.EntityFrameworkCore": "Error" + } + }, + "AllowedHosts": "*" +} \ No newline at end of file diff --git a/solutions/Util.Data.slnf b/solutions/Util.Data.slnf new file mode 100644 index 00000000..29198177 --- /dev/null +++ b/solutions/Util.Data.slnf @@ -0,0 +1,57 @@ +{ + "solution": { + "path": "..\\Util.sln", + "projects": [ + "benchmark\\Util.Data.Dapper.Benchmark\\Util.Data.Dapper.Benchmark.csproj", + "benchmark\\Util.Data.Sql.Benchmark\\Util.Data.Sql.Benchmark.csproj", + "build\\Build.csproj", + "src\\Util.Aop.AspectCore\\03-Util.Aop.AspectCore.csproj", + "src\\Util.Core\\01-Util.Core.csproj", + "src\\Util.Data.Abstractions\\05-Util.Data.Abstractions.csproj", + "src\\Util.Data.Core\\01-Util.Data.Core.csproj", + "src\\Util.Data.Dapper.All\\05-Util.Data.Dapper.All.csproj", + "src\\Util.Data.Dapper.Core\\01-Util.Data.Dapper.Core.csproj", + "src\\Util.Data.Dapper.MySql\\04-Util.Data.Dapper.MySql.csproj", + "src\\Util.Data.Dapper.PostgreSql\\03-Util.Data.Dapper.PostgreSql.csproj", + "src\\Util.Data.Dapper.SqlServer\\02-Util.Data.Dapper.SqlServer.csproj", + "src\\Util.Data.EntityFrameworkCore.MySql\\04-Util.Data.EntityFrameworkCore.MySql.csproj", + "src\\Util.Data.EntityFrameworkCore.Oracle\\06-Util.Data.EntityFrameworkCore.Oracle.csproj", + "src\\Util.Data.EntityFrameworkCore.PostgreSql\\03-Util.Data.EntityFrameworkCore.PostgreSql.csproj", + "src\\Util.Data.EntityFrameworkCore.SqlServer\\02-Util.Data.EntityFrameworkCore.SqlServer.csproj", + "src\\Util.Data.EntityFrameworkCore.Sqlite\\05-Util.Data.EntityFrameworkCore.Sqlite.csproj", + "src\\Util.Data.EntityFrameworkCore\\01-Util.Data.EntityFrameworkCore.csproj", + "src\\Util.Data.Metadata\\03-Util.Data.Metadata.csproj", + "src\\Util.Data.Sql\\02-Util.Data.Sql.csproj", + "src\\Util.Domain.Biz\\02-Util.Domain.Biz.csproj", + "src\\Util.Domain\\01-Util.Domain.csproj", + "src\\Util.Events\\01-Util.Events.csproj", + "src\\Util.Logging.Serilog.Exceptionless\\03-Util.Logging.Serilog.Exceptionless.csproj", + "src\\Util.Logging.Serilog\\02-Util.Logging.Serilog.csproj", + "src\\Util.Logging\\01-Util.Logging.csproj", + "src\\Util.ObjectMapping.AutoMapper\\02-Util.ObjectMapping.AutoMapper.csproj", + "src\\Util.Validation\\04-Util.Validation.csproj", + "test\\Util.Aop.AspectCore.Tests\\Util.Aop.AspectCore.Tests.csproj", + "test\\Util.Core.Tests.Integration\\Util.Core.Tests.Integration.csproj", + "test\\Util.Core.Tests\\Util.Core.Tests.csproj", + "test\\Util.Data.Dapper.MySql.Tests.Integration\\Util.Data.Dapper.MySql.Tests.Integration.csproj", + "test\\Util.Data.Dapper.PostgreSql.Tests.Integration\\Util.Data.Dapper.PostgreSql.Tests.Integration.csproj", + "test\\Util.Data.Dapper.SqlServer.Tests.Integration\\Util.Data.Dapper.SqlServer.Tests.Integration.csproj", + "test\\Util.Data.EntityFrameworkCore.MySql.Tests.Integration\\Util.Data.EntityFrameworkCore.MySql.Tests.Integration.csproj", + "test\\Util.Data.EntityFrameworkCore.Oracle.Tests.Integration\\Util.Data.EntityFrameworkCore.Oracle.Tests.Integration.csproj", + "test\\Util.Data.EntityFrameworkCore.PostgreSql.Tests.Integration\\Util.Data.EntityFrameworkCore.PostgreSql.Tests.Integration.csproj", + "test\\Util.Data.EntityFrameworkCore.SqlServer.Tests.Integration\\Util.Data.EntityFrameworkCore.SqlServer.Tests.Integration.csproj", + "test\\Util.Data.EntityFrameworkCore.Sqlite.Tests.Integration\\Util.Data.EntityFrameworkCore.Sqlite.Tests.Integration.csproj", + "test\\Util.Data.Sql.Tests\\Util.Data.Sql.Tests.csproj", + "test\\Util.Data.Tests\\Util.Data.Tests.csproj", + "test\\Util.Domain.Tests\\Util.Domain.Tests.csproj", + "test\\Util.ObjectMapping.AutoMapper.Tests\\Util.ObjectMapping.AutoMapper.Tests.csproj", + "test\\Util.TestShare.MySql\\Util.TestShare.MySql.csproj", + "test\\Util.TestShare.Oracle\\Util.TestShare.Oracle.csproj", + "test\\Util.TestShare.PostgreSql\\Util.TestShare.PostgreSql.csproj", + "test\\Util.TestShare.SqlServer\\Util.TestShare.SqlServer.csproj", + "test\\Util.TestShare.Sqlite\\Util.TestShare.Sqlite.csproj", + "test\\Util.TestShare\\Util.TestShare.csproj", + "test\\Util.Validation.Tests\\Util.Validation.Tests.csproj" + ] + } +} \ No newline at end of file diff --git a/solutions/Util.Localization.slnf b/solutions/Util.Localization.slnf new file mode 100644 index 00000000..eb9a9ddc --- /dev/null +++ b/solutions/Util.Localization.slnf @@ -0,0 +1,19 @@ +{ + "solution": { + "path": "..\\Util.sln", + "projects": [ + "build\\Build.csproj", + "sample\\Util.WebApi.Sample\\Util.WebApi.Sample.csproj", + "src\\Util.Application.WebApi\\Util.Application.WebApi.csproj", + "src\\Util.Application\\Util.Application.csproj", + "src\\Util.AspNetCore\\07-Util.AspNetCore.csproj", + "src\\Util.Core\\01-Util.Core.csproj", + "src\\Util.Localization\\04-Util.Localization.csproj", + "src\\Util.Validation\\05-Util.Validation.csproj", + "test\\Util.Core.Tests.Integration\\Util.Core.Tests.Integration.csproj", + "test\\Util.Core.Tests\\Util.Core.Tests.csproj", + "test\\Util.Localization.Resources\\Util.Localization.Resources.csproj", + "test\\Util.Localization.Tests.Integration\\Util.Localization.Tests.Integration.csproj" + ] + } +} \ No newline at end of file diff --git a/src/Util.Aop.AspectCore/04-Util.Aop.AspectCore.csproj b/src/Util.Aop.AspectCore/03-Util.Aop.AspectCore.csproj similarity index 100% rename from src/Util.Aop.AspectCore/04-Util.Aop.AspectCore.csproj rename to src/Util.Aop.AspectCore/03-Util.Aop.AspectCore.csproj diff --git a/src/Util.Aop.AspectCore/AopOptionsExtension.cs b/src/Util.Aop.AspectCore/AopOptionsExtension.cs index 694f7c9e..bc7fb2d5 100644 --- a/src/Util.Aop.AspectCore/AopOptionsExtension.cs +++ b/src/Util.Aop.AspectCore/AopOptionsExtension.cs @@ -1,14 +1,19 @@ using System; using AspectCore.Configuration; +using AspectCore.DynamicProxy; +using AspectCore.DynamicProxy.Parameters; +using AspectCore.Extensions.AspectScope; using AspectCore.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; using Util.Configs; +using Util.Helpers; namespace Util.Aop { /// /// Aop配置项扩展 /// - public class AopOptionsExtension : IOptionsExtension { + public class AopOptionsExtension : OptionsExtensionBase { /// /// Aop配置 /// @@ -23,11 +28,38 @@ namespace Util.Aop { } /// - /// 添加服务 + /// 配置 /// - /// 服务集合 - public void AddServices( IServiceCollection services ) { - services.ConfigureDynamicProxy( _configure ); + /// 主机生成器 + public override void Config( IHostBuilder hostBuilder ) { + hostBuilder.UseServiceProviderFactory( new DynamicProxyServiceProviderFactory() ); + } + + /// + public override void ConfigureServices( HostBuilderContext context, IServiceCollection services ) { + ConfigureDynamicProxy( services ); + RegisterAspectScoped( services ); + } + + /// + /// 配置拦截器 + /// + private void ConfigureDynamicProxy( IServiceCollection services ) { + services.ConfigureDynamicProxy( config => { + config.EnableParameterAspect(); + config.NonAspectPredicates.Add( t => Reflection.GetTopBaseType( t.DeclaringType ).SafeString() == "Microsoft.EntityFrameworkCore.DbContext" ); + config.NonAspectPredicates.Add( t => t.DeclaringType.SafeString().Contains( "Xunit.DependencyInjection.ITestOutputHelperAccessor" ) ); + _configure?.Invoke( config ); + } ); + } + + /// + /// 注册拦截作用域 + /// + private void RegisterAspectScoped( IServiceCollection services ) { + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); } } } diff --git a/src/Util.Aop.AspectCore/HostBuilderExtensions.cs b/src/Util.Aop.AspectCore/HostBuilderExtensions.cs deleted file mode 100644 index b76fec24..00000000 --- a/src/Util.Aop.AspectCore/HostBuilderExtensions.cs +++ /dev/null @@ -1,19 +0,0 @@ -using AspectCore.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; - -namespace Util.Aop { - /// - /// Aop扩展 - /// - public static class HostBuilderExtensions { - /// - /// 启用拦截器 - /// - /// 主机生成器 - public static IHostBuilder EnableAop( this IHostBuilder builder ) { - builder.UseServiceProviderFactory( new DynamicProxyServiceProviderFactory() ); - builder.ConfigureServices( ( context, services ) => services.AddAop() ); - return builder; - } - } -} diff --git a/src/Util.Aop.AspectCore/OptionsExtensions.cs b/src/Util.Aop.AspectCore/OptionsExtensions.cs index aa2f39ba..3d1cf918 100644 --- a/src/Util.Aop.AspectCore/OptionsExtensions.cs +++ b/src/Util.Aop.AspectCore/OptionsExtensions.cs @@ -8,12 +8,12 @@ namespace Util.Aop { /// public static class OptionsExtensions { /// - /// 配置拦截器 + /// 启用AspectCore拦截器 /// /// 配置项 - /// Aop配置 - public static Options UseAop( this Options options, Action configure = null ) { - options.AddExtension( new AopOptionsExtension( configure ) ); + /// AspectCore拦截器配置操作 + public static Options UseAop( this Options options, Action setupAction = null ) { + options.AddExtension( new AopOptionsExtension( setupAction ) ); return options; } } diff --git a/src/Util.Aop.AspectCore/ServiceCollectionExtensions.cs b/src/Util.Aop.AspectCore/ServiceCollectionExtensions.cs deleted file mode 100644 index 03da5f80..00000000 --- a/src/Util.Aop.AspectCore/ServiceCollectionExtensions.cs +++ /dev/null @@ -1,43 +0,0 @@ -using AspectCore.DynamicProxy; -using AspectCore.DynamicProxy.Parameters; -using AspectCore.Extensions.AspectScope; -using AspectCore.Extensions.DependencyInjection; -using Microsoft.Extensions.DependencyInjection; -using Util.Helpers; - -namespace Util.Aop { - /// - /// 服务扩展 - /// - public static class ServiceCollectionExtensions { - /// - /// 注册AspectCore Aop服务 - /// - /// 服务集合 - public static IServiceCollection AddAop( this IServiceCollection services ) { - ConfigureDynamicProxy( services ); - RegisterAspectScoped( services ); - return services; - } - - /// - /// 配置拦截器 - /// - private static void ConfigureDynamicProxy( IServiceCollection services ) { - services.ConfigureDynamicProxy( config => { - config.EnableParameterAspect(); - config.NonAspectPredicates.Add( t => Reflection.GetTopBaseType( t.DeclaringType ).SafeString() == "Microsoft.EntityFrameworkCore.DbContext" ); - config.NonAspectPredicates.Add( t => t.DeclaringType.SafeString().Contains( "Xunit.DependencyInjection.ITestOutputHelperAccessor" ) ); - } ); - } - - /// - /// 注册拦截作用域 - /// - private static void RegisterAspectScoped( IServiceCollection services ) { - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - } - } -} diff --git a/src/Util.Application.EntityFrameworkCore/CrudServiceBase.cs b/src/Util.Application.EntityFrameworkCore/CrudServiceBase.cs index 48ff36c3..9526c957 100644 --- a/src/Util.Application.EntityFrameworkCore/CrudServiceBase.cs +++ b/src/Util.Application.EntityFrameworkCore/CrudServiceBase.cs @@ -153,7 +153,7 @@ namespace Util.Applications { public virtual async Task UpdateAsync( TUpdateRequest request ) { request.CheckNull( nameof( request ) ); if( request.Id.IsEmpty() ) - throw new InvalidOperationException( UtilCoreResource.IdIsEmpty ); + throw new InvalidOperationException( R.IdIsEmpty ); var oldEntity = await FindOldEntityAsync( request.Id ); oldEntity.CheckNull( nameof( oldEntity ) ); var entity = ToEntity( oldEntity, request ); diff --git a/src/Util.Application.WebApi/Controllers/QueryControllerBase.cs b/src/Util.Application.WebApi/Controllers/QueryControllerBase.cs index 762cc84b..34471436 100644 --- a/src/Util.Application.WebApi/Controllers/QueryControllerBase.cs +++ b/src/Util.Application.WebApi/Controllers/QueryControllerBase.cs @@ -59,7 +59,7 @@ namespace Util.Applications.Controllers { /// /// 查询参数 protected async Task QueryAsync( TQuery query ) { - if( query == null ) + if ( query == null ) return Fail( WebApiResource.QueryIsEmpty ); QueryBefore( query ); var list = await _service.QueryAsync( query ); @@ -91,7 +91,7 @@ namespace Util.Applications.Controllers { /// /// 查询参数 protected async Task PageQueryAsync( TQuery query ) { - if( query == null ) + if ( query == null ) return Fail( WebApiResource.QueryIsEmpty ); PageQueryBefore( query ); var pageList = await _service.PageQueryAsync( query ); @@ -123,7 +123,7 @@ namespace Util.Applications.Controllers { /// /// 查询参数 protected async Task GetItemsAsync( TQuery query ) { - if( query == null ) + if ( query == null ) return Fail( WebApiResource.QueryIsEmpty ); var pageList = await _service.PageQueryAsync( query ); var result = pageList.Data.Select( ToItem ); diff --git a/src/Util.Application.WebApi/Controllers/WebApiControllerBase.cs b/src/Util.Application.WebApi/Controllers/WebApiControllerBase.cs index 9b0c5c8a..2f321b03 100644 --- a/src/Util.Application.WebApi/Controllers/WebApiControllerBase.cs +++ b/src/Util.Application.WebApi/Controllers/WebApiControllerBase.cs @@ -1,5 +1,5 @@ -using System.Net; -using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.DependencyInjection; using Util.Applications.Filters; using Util.Properties; @@ -18,9 +18,19 @@ namespace Util.Applications.Controllers { /// 数据 /// 消息 /// Http状态码 - protected virtual IActionResult Success( dynamic data = null, string message = null, HttpStatusCode? statusCode = HttpStatusCode.OK ) { + protected virtual IActionResult Success( dynamic data = null, string message = null, int? statusCode = 200 ) { message ??= R.Success; - return new Result( StateCode.Ok, message, data, statusCode ); + return GetResult( StateCode.Ok, message, data, statusCode ); + } + + /// + /// 获取结果 + /// + private IActionResult GetResult( string code, string message, dynamic data, int? httpStatusCode ) { + var resultFactory = HttpContext.RequestServices.GetService(); + if ( resultFactory == null ) + return new Result( code, message, data, httpStatusCode ); + return resultFactory.CreateResult( code, message, data, httpStatusCode ); } /// @@ -28,8 +38,8 @@ namespace Util.Applications.Controllers { /// /// 消息 /// Http状态码 - protected virtual IActionResult Fail( string message, HttpStatusCode? statusCode = null ) { - return new Result( StateCode.Fail, message, null, statusCode ); + protected virtual IActionResult Fail( string message, int? statusCode = 200 ) { + return GetResult( StateCode.Fail, message, null, statusCode ); } } } diff --git a/src/Util.Application.WebApi/Filters/ExceptionHandlerAttribute.cs b/src/Util.Application.WebApi/Filters/ExceptionHandlerAttribute.cs index 210cf59e..2317b5e1 100644 --- a/src/Util.Application.WebApi/Filters/ExceptionHandlerAttribute.cs +++ b/src/Util.Application.WebApi/Filters/ExceptionHandlerAttribute.cs @@ -1,5 +1,9 @@ -using Microsoft.AspNetCore.Mvc.Filters; +using System.Reflection; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Localization; using Util.Helpers; namespace Util.Applications.Filters { @@ -12,8 +16,40 @@ namespace Util.Applications.Filters { /// public override void OnException( ExceptionContext context ) { context.ExceptionHandled = true; - context.HttpContext.Response.StatusCode = 200; - context.Result = new Result( StateCode.Fail, context.Exception.GetPrompt( Web.Environment.IsProduction() ) ); + var message = context.Exception.GetPrompt( Web.Environment.IsProduction() ); + message = GetLocalizedMessages( context, message ); + var errorCode = context.Exception.GetErrorCode() ?? StateCode.Fail; + var httpStatusCode = context.Exception.GetHttpStatusCode() ?? 200; + context.Result = GetResult( context, errorCode, message, httpStatusCode ); + } + + /// + /// 获取本地化异常消息 + /// + protected virtual string GetLocalizedMessages( ExceptionContext context, string message ) { + var stringLocalizerFactory = context.HttpContext.RequestServices.GetService(); + if ( stringLocalizerFactory == null ) + return message; + var assemblyName = new AssemblyName( GetType().Assembly.FullName ); + var stringLocalizer = stringLocalizerFactory.Create( "Warning", assemblyName.Name ); + var localizedString = stringLocalizer[message]; + if ( localizedString.ResourceNotFound == false ) + return localizedString.Value; + stringLocalizer = context.HttpContext.RequestServices.GetService(); + if ( stringLocalizer == null ) + return message; + return stringLocalizer[message]; + } + + + /// + /// 获取结果 + /// + protected virtual IActionResult GetResult( ExceptionContext context, string code, string message, int? httpStatusCode ) { + var resultFactory = context.HttpContext.RequestServices.GetService(); + if ( resultFactory == null ) + return new Result( code, message, null, httpStatusCode ); + return resultFactory.CreateResult( code, message, null, httpStatusCode ); } } } diff --git a/src/Util.Application.WebApi/IResultFactory.cs b/src/Util.Application.WebApi/IResultFactory.cs new file mode 100644 index 00000000..7e346fdb --- /dev/null +++ b/src/Util.Application.WebApi/IResultFactory.cs @@ -0,0 +1,18 @@ +using Microsoft.AspNetCore.Mvc; +using Util.Dependency; + +namespace Util.Applications { + /// + /// 返回结果工厂 + /// + public interface IResultFactory : ISingletonDependency { + /// + /// 创建返回结果 + /// + /// 业务状态码 + /// 消息 + /// 数据 + /// Http状态码 + IActionResult CreateResult( string code, string message, dynamic data, int? httpStatusCode ); + } +} diff --git a/src/Util.Application.WebApi/Infrastructure/WebApiServiceRegistrar.cs b/src/Util.Application.WebApi/Infrastructure/WebApiServiceRegistrar.cs index e4fd6c76..f774cf34 100644 --- a/src/Util.Application.WebApi/Infrastructure/WebApiServiceRegistrar.cs +++ b/src/Util.Application.WebApi/Infrastructure/WebApiServiceRegistrar.cs @@ -1,7 +1,8 @@ using System; using Microsoft.AspNetCore.Hosting; -using Microsoft.Extensions.Configuration; +using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; using Util.Applications.Logging; using Util.Infrastructure; using Util.Logging; @@ -30,12 +31,14 @@ namespace Util.Applications.Infrastructure { /// /// 注册服务 /// - /// 服务集合 - /// 配置 + /// 主机生成器 /// 类型查找器 - public Action Register( IServiceCollection services, IConfiguration configuration, ITypeFinder finder ) { - services.AddSingleton(); - services.AddSingleton(); + public Action Register( IHostBuilder hostBuilder, ITypeFinder finder ) { + hostBuilder.ConfigureServices( ( context, services ) => { + services.AddSingleton(); + services.AddSingleton(); + services.Configure( options => options.SuppressModelStateInvalidFilter = true ); + } ); return null; } } diff --git a/src/Util.Application.WebApi/Result.cs b/src/Util.Application.WebApi/Result.cs index ada8ad7c..656c144b 100644 --- a/src/Util.Application.WebApi/Result.cs +++ b/src/Util.Application.WebApi/Result.cs @@ -1,6 +1,9 @@ -using System.Net; +using System.Text.Encodings.Web; +using System.Text.Json; +using System.Text.Unicode; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; +using Util.SystemTextJson; namespace Util.Applications { /// @@ -8,9 +11,9 @@ namespace Util.Applications { /// public class Result : JsonResult { /// - /// 状态码 + /// 业务状态码 /// - public StateCode Code { get; } + public string Code { get; } /// /// 消息 /// @@ -23,18 +26,23 @@ namespace Util.Applications { /// /// 初始化返回结果 /// - /// 状态码 + /// 业务状态码 /// 消息 /// 数据 /// Http状态码 - public Result( StateCode code, string message, dynamic data = null, HttpStatusCode? httpStatusCode = null ) : base( null ) { + public Result( string code, string message, dynamic data, int? httpStatusCode ) : base( null ) { Code = code; Message = message; Data = data; - var statusCode = Util.Helpers.Enum.GetValue( httpStatusCode ); - if ( statusCode == null ) - return; - StatusCode = statusCode; + SerializerSettings = new JsonSerializerOptions { + PropertyNamingPolicy = JsonNamingPolicy.CamelCase, + Encoder = JavaScriptEncoder.Create( UnicodeRanges.All ), + Converters = { + new DateTimeJsonConverter(), + new NullableDateTimeJsonConverter() + } + }; + StatusCode = httpStatusCode; } /// @@ -42,7 +50,7 @@ namespace Util.Applications { /// public override Task ExecuteResultAsync( ActionContext context ) { Value = new { - Code = Code.Value(), + Code, Message, Data }; diff --git a/src/Util.Application.WebApi/Util.Application.WebApi.csproj b/src/Util.Application.WebApi/Util.Application.WebApi.csproj index 15de3340..fd5cd34f 100644 --- a/src/Util.Application.WebApi/Util.Application.WebApi.csproj +++ b/src/Util.Application.WebApi/Util.Application.WebApi.csproj @@ -28,7 +28,7 @@ - + diff --git a/src/Util.Application/Dtos/RequestBase.cs b/src/Util.Application/Dtos/RequestBase.cs index 80eb8eda..3a5822ff 100644 --- a/src/Util.Application/Dtos/RequestBase.cs +++ b/src/Util.Application/Dtos/RequestBase.cs @@ -1,5 +1,8 @@ using System.Linq; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.ModelBinding.Validation; using Util.Exceptions; +using Util.Helpers; using Util.Validation; namespace Util.Applications.Dtos { @@ -11,10 +14,18 @@ namespace Util.Applications.Dtos { /// 验证 /// public virtual ValidationResultCollection Validate() { - var result = DataAnnotationValidation.Validate( this ); - if( result.IsValid ) + var validator = Ioc.Create(); + if ( validator == null ) { + var result = DataAnnotationValidation.Validate( this ); + if ( result.IsValid ) + return ValidationResultCollection.Success; + throw new Warning( result.First().ErrorMessage ); + } + var actionContext = new ActionContext(); + validator.Validate( actionContext, null, string.Empty, this ); + if ( actionContext.ModelState.IsValid ) return ValidationResultCollection.Success; - throw new Warning( result.First().ErrorMessage ); + throw new Warning( actionContext.ModelState.Values.First().Errors.First().ErrorMessage ); } } } diff --git a/src/Util.Application/ExceptionExtensions.cs b/src/Util.Application/ExceptionExtensions.cs index 40fb78c3..530deab6 100644 --- a/src/Util.Application/ExceptionExtensions.cs +++ b/src/Util.Application/ExceptionExtensions.cs @@ -37,5 +37,35 @@ namespace Util.Applications { return warning.GetMessage(); return isProduction ? R.SystemError : exception.Message; } + + /// + /// 获取Http状态码 + /// + /// 异常 + public static int? GetHttpStatusCode( this Exception exception ) { + if ( exception == null ) + return null; + exception = exception.GetRawException(); + if ( exception == null ) + return null; + if ( exception is Warning warning ) + return warning.HttpStatusCode; + return null; + } + + /// + /// 获取错误码 + /// + /// 异常 + public static string GetErrorCode( this Exception exception ) { + if ( exception == null ) + return null; + exception = exception.GetRawException(); + if ( exception == null ) + return null; + if ( exception is Warning warning ) + return warning.Code; + return null; + } } } diff --git a/src/Util.Application/StateCode.cs b/src/Util.Application/StateCode.cs index 0a7bce89..b3aebce8 100644 --- a/src/Util.Application/StateCode.cs +++ b/src/Util.Application/StateCode.cs @@ -1,15 +1,15 @@ namespace Util.Applications { /// - /// 状态码 + /// 业务状态码 /// - public enum StateCode { + public static class StateCode { /// /// 失败 /// - Fail = 0, + public const string Fail = "0"; /// /// 成功 /// - Ok = 1 + public const string Ok = "1"; } } diff --git a/src/Util.Application/Util.Application.csproj b/src/Util.Application/Util.Application.csproj index 95fbd9c5..2af2a266 100644 --- a/src/Util.Application/Util.Application.csproj +++ b/src/Util.Application/Util.Application.csproj @@ -27,6 +27,7 @@ + diff --git a/src/Util.AspNetCore/02-Util.AspNetCore.csproj b/src/Util.AspNetCore/07-Util.AspNetCore.csproj similarity index 100% rename from src/Util.AspNetCore/02-Util.AspNetCore.csproj rename to src/Util.AspNetCore/07-Util.AspNetCore.csproj diff --git a/src/Util.AspNetCore/Helpers/Web.cs b/src/Util.AspNetCore/Helpers/Web.cs index 1ef4ab2d..2fc4bf88 100644 --- a/src/Util.AspNetCore/Helpers/Web.cs +++ b/src/Util.AspNetCore/Helpers/Web.cs @@ -104,5 +104,17 @@ namespace Util.Helpers { public static IHttpClient Client => Ioc.Create(); #endregion + + #region GetPhysicalPath(获取物理路径) + + /// + /// 获取物理路径,基路径为IWebHostEnvironment.ContentRootPath + /// + /// 相对路径,范例:"test/a.txt" 或 "/test/a.txt" + public static string GetPhysicalPath( string relativePath ) { + return Platform.GetPhysicalPath( relativePath, Environment.ContentRootPath ); + } + + #endregion } } diff --git a/src/Util.AspNetCore/Http/HttpRequest.cs b/src/Util.AspNetCore/Http/HttpRequest.cs index b3769014..a3b1f64e 100644 --- a/src/Util.AspNetCore/Http/HttpRequest.cs +++ b/src/Util.AspNetCore/Http/HttpRequest.cs @@ -5,9 +5,11 @@ using System.Net.Http; using System.Security.Cryptography.X509Certificates; using System.Text; using System.Text.Json; +using System.Text.Json.Serialization; using System.Threading.Tasks; using Microsoft.AspNetCore.WebUtilities; using Util.Helpers; +using Util.SystemTextJson; namespace Util.Http { /// @@ -438,7 +440,7 @@ namespace Util.Http { /// 获取json内容值 /// private string GetJsonContentValue() { - var options = new JsonSerializerOptions { IgnoreNullValues = true }; + var options = new JsonSerializerOptions { DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull }; if( Param != null && Params.Count > 0 ) return Json.ToJson( GetParameters(), options ); if( Param != null ) @@ -582,7 +584,13 @@ namespace Util.Http { if( typeof( TResult ) == typeof( string ) ) return (TResult)(object)content; if( contentType.SafeString().ToLower() == "application/json" ) { - var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true }; + var options = new JsonSerializerOptions { + PropertyNameCaseInsensitive = true, + Converters = { + new DateTimeJsonConverter(), + new NullableDateTimeJsonConverter() + } + }; return Json.ToObject( content, options ); } return null; diff --git a/src/Util.AspNetCore/Infrastructure/AspNetCoreServiceRegistrar.cs b/src/Util.AspNetCore/Infrastructure/AspNetCoreServiceRegistrar.cs index 1da1bb25..b3e296a0 100644 --- a/src/Util.AspNetCore/Infrastructure/AspNetCoreServiceRegistrar.cs +++ b/src/Util.AspNetCore/Infrastructure/AspNetCoreServiceRegistrar.cs @@ -1,8 +1,8 @@ using System; using Microsoft.AspNetCore.Http; -using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; +using Microsoft.Extensions.Hosting; using Util.Helpers; using Util.Http; using Util.Reflections; @@ -30,15 +30,16 @@ namespace Util.Infrastructure { /// /// 注册服务 /// - /// 服务集合 - /// 配置 + /// 主机生成器 /// 类型查找器 - public Action Register( IServiceCollection services, IConfiguration configuration, ITypeFinder finder ) { - RegisterHttpContextAccessor( services ); - services.AddHttpClient(); - RegisterServiceLocator(); - RegisterSession( services ); - RegisterHttpClient( services ); + public Action Register( IHostBuilder hostBuilder, ITypeFinder finder ) { + hostBuilder.ConfigureServices( ( context, services ) => { + RegisterHttpContextAccessor( services ); + services.AddHttpClient(); + RegisterServiceLocator(); + RegisterSession( services ); + RegisterHttpClient( services ); + } ); return null; } diff --git a/src/Util.AspNetCore/Security/DataProtectionEncryptor.cs b/src/Util.AspNetCore/Security/DataProtectionEncryptor.cs new file mode 100644 index 00000000..485d9214 --- /dev/null +++ b/src/Util.AspNetCore/Security/DataProtectionEncryptor.cs @@ -0,0 +1,36 @@ +using System; +using Microsoft.AspNetCore.DataProtection; + +namespace Util.Security { + /// + /// 基于数据保护提供程序的加密器 + /// + public class DataProtectionEncryptor : IEncryptor { + /// + /// 数据保护器 + /// + private readonly IDataProtector _dataProtector; + + /// + /// 初始化加密器 + /// + /// 数据保护器 + public DataProtectionEncryptor( IDataProtector dataProtector ) { + _dataProtector = dataProtector ?? throw new ArgumentNullException( nameof( dataProtector ) ); + } + + /// + public string Encrypt( string data ) { + if ( data.IsEmpty() ) + return null; + return _dataProtector.Protect( data ); + } + + /// + public string Decrypt( string data ) { + if ( data.IsEmpty() ) + return null; + return _dataProtector.Unprotect( data ); + } + } +} diff --git a/src/Util.Core/01-Util.Core.csproj b/src/Util.Core/01-Util.Core.csproj index 58e74aba..e523601e 100644 --- a/src/Util.Core/01-Util.Core.csproj +++ b/src/Util.Core/01-Util.Core.csproj @@ -27,12 +27,13 @@ - + - + + @@ -43,11 +44,6 @@ True R.resx - - True - True - UtilCoreResource.resx - @@ -55,10 +51,6 @@ PublicResXFileCodeGenerator R.Designer.cs - - PublicResXFileCodeGenerator - UtilCoreResource.Designer.cs - diff --git a/src/Util.Core/Configs/IOptionsExtension.cs b/src/Util.Core/Configs/IOptionsExtension.cs index 7da31e8b..a146c00a 100644 --- a/src/Util.Core/Configs/IOptionsExtension.cs +++ b/src/Util.Core/Configs/IOptionsExtension.cs @@ -1,4 +1,6 @@ -using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; namespace Util.Configs { /// @@ -6,9 +8,21 @@ namespace Util.Configs { /// public interface IOptionsExtension { /// - /// 添加服务集合 + /// 配置服务 /// + /// 主机生成器上下文 /// 服务集合 - void AddServices( IServiceCollection services ); + void ConfigureServices( HostBuilderContext context, IServiceCollection services ); + /// + /// 配置应用 + /// + /// 主机生成器上下文 + /// 配置生成器 + void ConfigureAppConfiguration( HostBuilderContext context, IConfigurationBuilder configurationBuilder ); + /// + /// 配置 + /// + /// 主机生成器 + void Config( IHostBuilder hostBuilder ); } } diff --git a/src/Util.Core/Configs/OptionsBase.cs b/src/Util.Core/Configs/OptionsBase.cs index 9afb5dc1..ece263cf 100644 --- a/src/Util.Core/Configs/OptionsBase.cs +++ b/src/Util.Core/Configs/OptionsBase.cs @@ -1,5 +1,4 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; namespace Util.Configs { /// @@ -23,8 +22,7 @@ namespace Util.Configs { /// /// 配置项扩展 public void AddExtension( IOptionsExtension extension ) { - if( extension == null ) - throw new ArgumentNullException( nameof( extension ) ); + extension.CheckNull( nameof( extension ) ); Extensions.Add( extension ); } } diff --git a/src/Util.Core/Configs/OptionsExtensionBase.cs b/src/Util.Core/Configs/OptionsExtensionBase.cs new file mode 100644 index 00000000..d02f2f40 --- /dev/null +++ b/src/Util.Core/Configs/OptionsExtensionBase.cs @@ -0,0 +1,22 @@ +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; + +namespace Util.Configs { + /// + /// 配置项扩展 + /// + public abstract class OptionsExtensionBase : IOptionsExtension { + /// + public virtual void ConfigureServices( HostBuilderContext context, IServiceCollection services ) { + } + + /// + public virtual void ConfigureAppConfiguration( HostBuilderContext context, IConfigurationBuilder configurationBuilder ) { + } + + /// + public virtual void Config( IHostBuilder hostBuilder ) { + } + } +} diff --git a/src/Util.Core/Configs/PreOptions.cs b/src/Util.Core/Configs/PreOptions.cs new file mode 100644 index 00000000..5ef8fba4 --- /dev/null +++ b/src/Util.Core/Configs/PreOptions.cs @@ -0,0 +1,7 @@ +namespace Util.Configs { + /// + /// 前置服务配置项 + /// + public class PreOptions : OptionsBase { + } +} diff --git a/src/Util.Core/DateTimeExtensions.cs b/src/Util.Core/DateTimeExtensions.cs index 949336f8..80659af6 100644 --- a/src/Util.Core/DateTimeExtensions.cs +++ b/src/Util.Core/DateTimeExtensions.cs @@ -1,5 +1,6 @@ using System; using System.Text; +using Util.Helpers; using Util.Properties; namespace Util { @@ -13,11 +14,22 @@ namespace Util { /// 日期 /// 是否移除秒 public static string ToDateTimeString( this DateTime dateTime, bool removeSecond = false ) { - if( removeSecond ) + dateTime = GetLocalDateTime( dateTime ); + if ( removeSecond ) return dateTime.ToString( "yyyy-MM-dd HH:mm" ); return dateTime.ToString( "yyyy-MM-dd HH:mm:ss" ); } + /// + /// 获取本地日期 + /// + private static DateTime GetLocalDateTime( DateTime dateTime ) { + dateTime = Time.Normalize( dateTime ); + if ( dateTime.Kind == DateTimeKind.Utc ) + return dateTime.ToLocalTime(); + return dateTime; + } + /// /// 获取格式化字符串,带时分秒,格式:"yyyy-MM-dd HH:mm:ss" /// @@ -34,6 +46,7 @@ namespace Util { /// /// 日期 public static string ToDateString( this DateTime dateTime ) { + dateTime = GetLocalDateTime( dateTime ); return dateTime.ToString( "yyyy-MM-dd" ); } @@ -52,6 +65,7 @@ namespace Util { /// /// 日期 public static string ToTimeString( this DateTime dateTime ) { + dateTime = GetLocalDateTime( dateTime ); return dateTime.ToString( "HH:mm:ss" ); } @@ -70,6 +84,7 @@ namespace Util { /// /// 日期 public static string ToMillisecondString( this DateTime dateTime ) { + dateTime = GetLocalDateTime( dateTime ); return dateTime.ToString( "yyyy-MM-dd HH:mm:ss.fff" ); } @@ -88,6 +103,7 @@ namespace Util { /// /// 日期 public static string ToChineseDateString( this DateTime dateTime ) { + dateTime = GetLocalDateTime( dateTime ); return $"{dateTime.Year}年{dateTime.Month}月{dateTime.Day}日"; } @@ -107,6 +123,7 @@ namespace Util { /// 日期 /// 是否移除秒 public static string ToChineseDateTimeString( this DateTime dateTime, bool removeSecond = false ) { + dateTime = GetLocalDateTime( dateTime ); StringBuilder result = new StringBuilder(); result.AppendFormat( "{0}年{1}月{2}日", dateTime.Year, dateTime.Month, dateTime.Day ); result.AppendFormat( " {0}时{1}分", dateTime.Hour, dateTime.Minute ); @@ -134,27 +151,27 @@ namespace Util { StringBuilder result = new StringBuilder(); if ( timeSpan.Days > 0 ) { result.Append( timeSpan.Days ); - result.Append( UtilCoreResource.Days ); + result.Append( R.Days ); } if ( timeSpan.Hours > 0 ) { result.Append( timeSpan.Hours ); - result.Append( UtilCoreResource.Hours ); + result.Append( R.Hours ); } if ( timeSpan.Minutes > 0 ) { result.Append( timeSpan.Minutes ); - result.Append( UtilCoreResource.Minutes ); + result.Append( R.Minutes ); } if ( timeSpan.Seconds > 0 ) { result.Append( timeSpan.Seconds ); - result.Append( UtilCoreResource.Seconds ); + result.Append( R.Seconds ); } if ( timeSpan.Milliseconds > 0 ) { result.Append( timeSpan.Milliseconds ); - result.Append( UtilCoreResource.Milliseconds ); + result.Append( R.Milliseconds ); } if ( result.Length > 0 ) return result.ToString(); - return $"{timeSpan.TotalMilliseconds}{UtilCoreResource.Milliseconds}"; + return $"{timeSpan.TotalMilliseconds}{R.Milliseconds}"; } } } diff --git a/src/Util.Core/Dates/OptionsExtensions.cs b/src/Util.Core/Dates/OptionsExtensions.cs new file mode 100644 index 00000000..4d718a7f --- /dev/null +++ b/src/Util.Core/Dates/OptionsExtensions.cs @@ -0,0 +1,18 @@ +using Util.Configs; + +namespace Util.Dates { + /// + /// 日期操作扩展 + /// + public static class OptionsExtensions { + /// + /// 使用Utc日期 + /// + /// 配置项 + /// 是否使用Utc日期 + public static Options UseUtc( this Options options, bool isUseUtc = true ) { + TimeOptions.IsUseUtc = isUseUtc; + return options; + } + } +} diff --git a/src/Util.Core/Dates/TimeOptions.cs b/src/Util.Core/Dates/TimeOptions.cs new file mode 100644 index 00000000..c670eb1f --- /dev/null +++ b/src/Util.Core/Dates/TimeOptions.cs @@ -0,0 +1,11 @@ +namespace Util.Dates { + /// + /// 时间配置 + /// + public static class TimeOptions { + /// + /// 是否使用Utc日期 + /// + public static bool IsUseUtc { get; set; } = false; + } +} diff --git a/src/Util.Core/Exceptions/ConcurrencyException.cs b/src/Util.Core/Exceptions/ConcurrencyException.cs index f854e488..2011130e 100644 --- a/src/Util.Core/Exceptions/ConcurrencyException.cs +++ b/src/Util.Core/Exceptions/ConcurrencyException.cs @@ -18,14 +18,6 @@ namespace Util.Exceptions { : this( "" ) { } - /// - /// 初始化并发异常 - /// - /// 错误消息 - public ConcurrencyException( string message ) - : this( message, null ) { - } - /// /// 初始化并发异常 /// @@ -34,29 +26,21 @@ namespace Util.Exceptions { : this( "", exception ) { } - /// - /// 初始化并发异常 - /// - /// 错误消息 - /// 异常 - public ConcurrencyException( string message, Exception exception ) - : this( message, exception, "" ) { - } - /// /// 初始化并发异常 /// /// 错误消息 /// 异常 /// 错误码 - public ConcurrencyException( string message, Exception exception, string code ) - : base( message, code, exception ) { + /// Http状态码 + public ConcurrencyException( string message, Exception exception = null, string code = null, int? httpStatusCode = null ) + : base( message, exception, code, httpStatusCode ) { _message = message; } /// /// 错误消息 /// - public override string Message => $"{UtilCoreResource.ConcurrencyExceptionMessage}.{_message}"; + public override string Message => $"{R.ConcurrencyExceptionMessage}.{_message}"; } } diff --git a/src/Util.Core/Exceptions/Warning.cs b/src/Util.Core/Exceptions/Warning.cs index b5f9ad47..ed0f4995 100644 --- a/src/Util.Core/Exceptions/Warning.cs +++ b/src/Util.Core/Exceptions/Warning.cs @@ -7,29 +7,12 @@ namespace Util.Exceptions { /// 应用程序异常 /// public class Warning : Exception { - /// - /// 初始化应用程序异常 - /// - /// 错误消息 - public Warning( string message ) - : this( message, null ) { - } - /// /// 初始化应用程序异常 /// /// 异常 public Warning( Exception exception ) - : this( null, null, exception ) { - } - - /// - /// 初始化应用程序异常 - /// - /// 错误消息 - /// 错误码 - public Warning( string message, string code ) - : this( message, code, null ) { + : this( null, exception ) { } /// @@ -38,9 +21,11 @@ namespace Util.Exceptions { /// 错误消息 /// 错误码 /// 异常 - public Warning( string message, string code, Exception exception ) + /// Http状态码 + public Warning( string message, Exception exception = null, string code = null, int? httpStatusCode = null ) : base( message ?? "", exception ) { Code = code; + HttpStatusCode = httpStatusCode; } /// @@ -48,6 +33,11 @@ namespace Util.Exceptions { /// public string Code { get; set; } + /// + /// Http状态码 + /// + public int? HttpStatusCode { get; set; } + /// /// 获取错误消息 /// diff --git a/src/Util.Core/Helpers/Common.cs b/src/Util.Core/Helpers/Common.cs index b9e0cf95..74d137da 100644 --- a/src/Util.Core/Helpers/Common.cs +++ b/src/Util.Core/Helpers/Common.cs @@ -8,7 +8,7 @@ namespace Util.Helpers { /// /// 换行符 /// - public static string Line => Environment.NewLine; + public static string Line => System.Environment.NewLine; /// /// 获取类型 diff --git a/src/Util.Core/Helpers/Config.cs b/src/Util.Core/Helpers/Config.cs index 4a2834d7..7dd84601 100644 --- a/src/Util.Core/Helpers/Config.cs +++ b/src/Util.Core/Helpers/Config.cs @@ -23,44 +23,44 @@ namespace Util.Helpers { /// /// 配置选项类型 /// 配置节 - /// 配置文件名,默认值: appsettings.json - public static TOptions Get( string section,string configFileName = "appsettings.json" ) { - var configuration = GetConfiguration( configFileName ); - return Get( configuration, section ); + public static TOptions Get( string section ) { + return GetSection( section ).Get(); + } + + /// + /// 获取配置节 + /// + /// 配置节 + public static IConfigurationSection GetSection( string section ) { + return GetConfiguration().GetSection( section ); } /// /// 获取配置 /// - private static IConfiguration GetConfiguration( string configFileName ) { - if ( _configuration != null ) - return _configuration; - return CreateConfiguration( configFileName ); + private static IConfiguration GetConfiguration() { + return _configuration ??= CreateConfiguration(); } /// /// 创建配置 /// - private static IConfiguration CreateConfiguration( string configFileName ) { - var builder = new ConfigurationBuilder(); - builder.SetBasePath( Platform.ApplicationBaseDirectory ).AddJsonFile( configFileName ); + private static IConfiguration CreateConfiguration() { + var builder = new ConfigurationBuilder() + .SetBasePath( Platform.ApplicationBaseDirectory ) + .AddJsonFile( "appsettings.json", true, true ); + var environment = Environment.GetEnvironmentName(); + if ( environment.IsEmpty() == false ) + builder.AddJsonFile( $"appsettings.{environment}.json", true, true ); return builder.Build(); } - /// - /// 获取配置选项 - /// - private static TOptions Get( IConfiguration configuration, string section ) { - return configuration.GetSection( section ).Get(); - } - /// /// 获取数据库连接字符串 /// /// 数据库连接字符串键名 public static string GetConnectionString( string name ) { - var configuration = GetConfiguration( "appsettings.json" ); - return configuration.GetConnectionString( name ); + return GetConfiguration().GetConnectionString( name ); } } } diff --git a/src/Util.Core/Helpers/Convert.cs b/src/Util.Core/Helpers/Convert.cs index 52dbe3ec..8f9618d7 100644 --- a/src/Util.Core/Helpers/Convert.cs +++ b/src/Util.Core/Helpers/Convert.cs @@ -194,7 +194,14 @@ namespace Util.Helpers { /// /// 输入值 public static bool? ToBoolOrNull( object input ) { - return bool.TryParse( input.SafeString(), out var result ) ? result : null; + var value = input.SafeString(); + switch ( value ) { + case "1": + return true; + case "0": + return false; + } + return bool.TryParse( value, out var result ) ? result : null; } #endregion @@ -218,7 +225,10 @@ namespace Util.Helpers { /// /// 输入值 public static DateTime? ToDateTimeOrNull( object input ) { - return DateTime.TryParse( input.SafeString(), out var result ) ? result : null; + var success = DateTime.TryParse( input.SafeString(), out var result ); + if ( success == false ) + return null; + return Time.Normalize( result ); } #endregion @@ -311,17 +321,15 @@ namespace Util.Helpers { if( input is string && string.IsNullOrWhiteSpace( input.ToString() ) ) return default; Type type = Common.GetType(); - var typeName = type.Name.ToLower(); + var typeName = type.Name.ToUpperInvariant(); try { - if( typeName == "string" ) - return (T)(object)input.ToString(); - if( typeName == "guid" ) - return (T)(object)new Guid( input.ToString() ); - if( type.IsEnum ) + if( typeName == "STRING" || typeName == "GUID" ) + return (T)TypeDescriptor.GetConverter( typeof( T ) ).ConvertFromInvariantString( input.ToString() ); + if ( type.IsEnum ) return Enum.Parse( input ); - if( input is IConvertible ) + if ( input is IConvertible ) return (T)System.Convert.ChangeType( input, type, CultureInfo.InvariantCulture ); - if( input is JsonElement element ) { + if ( input is JsonElement element ) { var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true }; return Json.ToObject( element.GetRawText(), options ); } diff --git a/src/Util.Core/Helpers/Culture.cs b/src/Util.Core/Helpers/Culture.cs new file mode 100644 index 00000000..24da7333 --- /dev/null +++ b/src/Util.Core/Helpers/Culture.cs @@ -0,0 +1,38 @@ +using System.Collections.Generic; +using System.Globalization; + +namespace Util.Helpers { + /// + /// 区域文化 + /// + public static class Culture { + /// + /// 获取当前区域文化信息列表,包含所有父区域文化 + /// + public static List GetCurrentCultures() { + return GetCultures( CultureInfo.CurrentCulture ); + } + + /// + /// 获取当前UI区域文化信息列表,包含所有父区域文化 + /// + public static List GetCurrentUICultures() { + return GetCultures( CultureInfo.CurrentUICulture ); + } + + /// + /// 获取区域文化信息列表,包含所有父区域文化 + /// + /// 区域文化信息 + public static List GetCultures( CultureInfo culture ) { + var result = new List(); + if ( culture == null ) + return result; + while ( culture.Equals( culture.Parent ) == false ) { + result.Add( culture ); + culture = culture.Parent; + } + return result; + } + } +} diff --git a/src/Util.Core/Helpers/Enum.cs b/src/Util.Core/Helpers/Enum.cs index ca3004b7..0c728bb7 100644 --- a/src/Util.Core/Helpers/Enum.cs +++ b/src/Util.Core/Helpers/Enum.cs @@ -104,7 +104,7 @@ namespace Util.Helpers { public static List GetItems( Type type ) { type = Common.GetType( type ); if( type.IsEnum == false ) - throw new InvalidOperationException( string.Format( UtilCoreResource.TypeNotEnum,type ) ); + throw new InvalidOperationException( string.Format( R.TypeNotEnum,type ) ); var result = new List(); foreach( var field in type.GetFields() ) AddItem( type, result, field ); @@ -137,7 +137,7 @@ namespace Util.Helpers { public static List GetNames( Type type ) { type = Common.GetType( type ); if( type.IsEnum == false ) - throw new InvalidOperationException( string.Format( UtilCoreResource.TypeNotEnum, type ) ); + throw new InvalidOperationException( string.Format( R.TypeNotEnum, type ) ); var result = new List(); foreach ( var field in type.GetFields() ) { if( !field.FieldType.IsEnum ) diff --git a/src/Util.Core/Helpers/Environment.cs b/src/Util.Core/Helpers/Environment.cs new file mode 100644 index 00000000..881a42e2 --- /dev/null +++ b/src/Util.Core/Helpers/Environment.cs @@ -0,0 +1,60 @@ +namespace Util.Helpers { + /// + /// 环境操作 + /// + public static class Environment { + /// + /// DOTNET_ENVIRONMENT + /// + private const string DOTNET_ENVIRONMENT = "DOTNET_ENVIRONMENT"; + /// + /// ASPNETCORE_ENVIRONMENT + /// + private const string ASPNETCORE_ENVIRONMENT = "ASPNETCORE_ENVIRONMENT"; + /// + /// Development + /// + private const string Development = "Development"; + + /// + /// 设置环境变量 + /// + /// 环境变量名 + /// 值 + public static void SetEnvironmentVariable( string name, string value ) { + System.Environment.SetEnvironmentVariable( name, value ); + } + + /// + /// 获取环境变量 + /// + /// 环境变量名 + public static string GetEnvironmentVariable( string name ) { + return System.Environment.GetEnvironmentVariable( name ); + } + + /// + /// 获取环境名称 + /// + public static string GetEnvironmentName() { + var environment = GetEnvironmentVariable( ASPNETCORE_ENVIRONMENT ); + if ( environment.IsEmpty() == false ) + return environment; + return GetEnvironmentVariable( DOTNET_ENVIRONMENT ); + } + + /// + /// 设置开发环境变量,如果环境变量已设置则忽略 + /// + public static void SetDevelopment() { + var environment = GetEnvironmentVariable( DOTNET_ENVIRONMENT ); + if ( environment.IsEmpty() == false ) + return; + environment = GetEnvironmentVariable( ASPNETCORE_ENVIRONMENT ); + if ( environment.IsEmpty() == false ) + return; + SetEnvironmentVariable( DOTNET_ENVIRONMENT, Development ); + SetEnvironmentVariable( ASPNETCORE_ENVIRONMENT, Development ); + } + } +} diff --git a/src/Util.Core/Helpers/Id.cs b/src/Util.Core/Helpers/Id.cs index 5ae89183..5ac41888 100644 --- a/src/Util.Core/Helpers/Id.cs +++ b/src/Util.Core/Helpers/Id.cs @@ -1,4 +1,5 @@ using System; +using System.Threading; namespace Util.Helpers { /// @@ -8,35 +9,35 @@ namespace Util.Helpers { /// /// 标识 /// - private static string _id; + private static readonly AsyncLocal _id = new(); /// /// 设置标识 /// - /// Id + /// 标识 public static void SetId( string id ) { - _id = id; + _id.Value = id; } /// /// 重置标识 /// public static void Reset() { - _id = null; + _id.Value = null; } /// /// 使用去掉分隔符的Guid创建标识 /// public static string Create() { - return string.IsNullOrWhiteSpace( _id ) ? System.Guid.NewGuid().ToString( "N" ) : _id; + return string.IsNullOrEmpty( _id.Value ) ? System.Guid.NewGuid().ToString( "N" ) : _id.Value; } /// /// 创建Guid标识 /// public static Guid CreateGuid() { - return string.IsNullOrWhiteSpace( _id ) ? System.Guid.NewGuid() : _id.ToGuid(); + return string.IsNullOrEmpty( _id.Value ) ? System.Guid.NewGuid() : _id.Value.ToGuid(); } } } diff --git a/src/Util.Core/Helpers/Json.cs b/src/Util.Core/Helpers/Json.cs index 7bcf61f4..08649fab 100644 --- a/src/Util.Core/Helpers/Json.cs +++ b/src/Util.Core/Helpers/Json.cs @@ -1,8 +1,12 @@ using System.IO; using System.Text; +using System.Text.Encodings.Web; using System.Text.Json; +using System.Text.Json.Serialization; +using System.Text.Unicode; using System.Threading; using System.Threading.Tasks; +using Util.SystemTextJson; namespace Util.Helpers { /// @@ -18,12 +22,28 @@ namespace Util.Helpers { public static string ToJson( T value, JsonSerializerOptions options = null,bool removeQuotationMarks = false ) { if ( value == null ) return string.Empty; + options = GetToJsonOptions( options ); var result = JsonSerializer.Serialize( value, options ); if ( removeQuotationMarks ) result = result.Replace( "\"","" ); return result; } + /// + /// 获取对象转换为Json字符串的序列化配置 + /// + private static JsonSerializerOptions GetToJsonOptions( JsonSerializerOptions options ) { + if ( options != null ) + return options; + return new JsonSerializerOptions { + Encoder = JavaScriptEncoder.Create( UnicodeRanges.All ), + Converters = { + new DateTimeJsonConverter(), + new NullableDateTimeJsonConverter() + } + }; + } + /// /// 将对象转换为Json字符串 /// @@ -33,6 +53,7 @@ namespace Util.Helpers { public static async Task ToJsonAsyc( T value, JsonSerializerOptions options = null, CancellationToken cancellationToken = default ) { if ( value == null ) return string.Empty; + options = GetToJsonOptions( options ); await using var stream = new MemoryStream(); await JsonSerializer.SerializeAsync( stream, value, typeof( T ), options, cancellationToken ); stream.Position = 0; @@ -48,9 +69,27 @@ namespace Util.Helpers { public static T ToObject( string json, JsonSerializerOptions options = null ) { if ( string.IsNullOrWhiteSpace( json ) ) return default; + options = GetToObjectOptions( options ); return JsonSerializer.Deserialize( json, options ); } + /// + /// 获取Json字符串转换为对象的序列化配置 + /// + private static JsonSerializerOptions GetToObjectOptions( JsonSerializerOptions options ) { + if ( options != null ) + return options; + return new JsonSerializerOptions { + PropertyNameCaseInsensitive = true, + NumberHandling = JsonNumberHandling.AllowReadingFromString, + Encoder = JavaScriptEncoder.Create( UnicodeRanges.All ), + Converters = { + new DateTimeJsonConverter(), + new NullableDateTimeJsonConverter() + } + }; + } + /// /// 将Json字符串转换为对象 /// @@ -76,6 +115,7 @@ namespace Util.Helpers { public static async Task ToObjectAsync( Stream json, JsonSerializerOptions options = null, CancellationToken cancellationToken = default ) { if ( json == null ) return default; + options = GetToObjectOptions( options ); return await JsonSerializer.DeserializeAsync( json, options, cancellationToken ); } } diff --git a/src/Util.Core/Helpers/Platform.cs b/src/Util.Core/Helpers/Platform.cs index adec4b13..f188b402 100644 --- a/src/Util.Core/Helpers/Platform.cs +++ b/src/Util.Core/Helpers/Platform.cs @@ -15,14 +15,16 @@ namespace Util.Helpers { /// 获取物理路径 /// /// 相对路径,范例:"test/a.txt" 或 "/test/a.txt" - public static string GetPhysicalPath( string relativePath ) { + /// 基路径,默认为AppContext.BaseDirectory + public static string GetPhysicalPath( string relativePath,string basePath = null ) { if( relativePath.StartsWith( "~" ) ) relativePath = relativePath.TrimStart( '~' ); if( relativePath.StartsWith( "/" ) ) relativePath = relativePath.TrimStart( '/' ); if( relativePath.StartsWith( "\\" ) ) relativePath = relativePath.TrimStart( '\\' ); - return Path.Combine( ApplicationBaseDirectory, relativePath ); + basePath ??= ApplicationBaseDirectory; + return Path.Combine( basePath, relativePath ); } } } diff --git a/src/Util.Core/Helpers/Time.cs b/src/Util.Core/Helpers/Time.cs index 0ad38f6a..e5c46f63 100644 --- a/src/Util.Core/Helpers/Time.cs +++ b/src/Util.Core/Helpers/Time.cs @@ -1,5 +1,6 @@ using System; using System.Threading; +using Util.Dates; namespace Util.Helpers { /// @@ -9,7 +10,15 @@ namespace Util.Helpers { /// /// 日期 /// - private static AsyncLocal _dateTime = new AsyncLocal(); + private static readonly AsyncLocal _dateTime = new(); + /// + /// 是否使用Utc日期 + /// + private static readonly AsyncLocal _isUseUtc = new(); + /// + /// 是否使用Utc日期 + /// + private static bool IsUseUtc => _isUseUtc.Value != null ? _isUseUtc.Value.SafeValue() : TimeOptions.IsUseUtc; /// /// 设置时间 @@ -24,30 +33,61 @@ namespace Util.Helpers { /// /// 时间 public static void SetTime( string dateTime ) { - SetTime( Util.Helpers.Convert.ToDateTimeOrNull( dateTime ) ); + SetTime( Convert.ToDateTimeOrNull( dateTime ) ); } /// - /// 重置时间 + /// 设置使用Utc日期 + /// + /// 是否使用Utc日期,默认值: true + public static void UseUtc( bool? isUseUtc = true ) { + _isUseUtc.Value = isUseUtc; + } + + /// + /// 重置时间和Utc标志 /// public static void Reset() { _dateTime.Value = null; + _isUseUtc.Value = null; } /// /// 获取当前日期时间 /// - public static DateTime GetDateTime() { - if ( _dateTime.Value == null ) - return DateTime.Now; - return _dateTime.Value.Value; + public static DateTime Now { + get { + if ( _dateTime.Value != null ) + return _dateTime.Value.Value; + return IsUseUtc ? DateTime.UtcNow : DateTime.Now; + } } /// - /// 获取当前日期,不带时间 + /// 转换为标准化日期 /// - public static DateTime GetDate() { - return GetDateTime().Date; + /// 日期 + public static DateTime Normalize( DateTime date ) { + if( date == DateTime.MinValue ) + return DateTime.MinValue; + if ( IsUseUtc ) { + switch ( date.Kind ) { + case DateTimeKind.Local: + return date.ToUniversalTime(); + case DateTimeKind.Unspecified: + return DateTime.SpecifyKind( date, DateTimeKind.Utc ); + default: + return date; + } + } + switch ( date.Kind ) { + case DateTimeKind.Utc: + return date.ToLocalTime(); + case DateTimeKind.Unspecified: + return DateTime.SpecifyKind( date, DateTimeKind.Local ); + default: + return date; + } } /// diff --git a/src/Util.Core/HostBuilderExtensions.cs b/src/Util.Core/HostBuilderExtensions.cs new file mode 100644 index 00000000..e6ac78eb --- /dev/null +++ b/src/Util.Core/HostBuilderExtensions.cs @@ -0,0 +1,59 @@ +using System; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Util.Configs; +using Util.Infrastructure; + +namespace Util { + /// + /// 主机生成器服务扩展 + /// + public static class HostBuilderExtensions { + /// + /// 注册Util前置服务,用于配置具有延迟的服务 + /// + /// 主机生成器 + /// 服务配置操作 + public static IHostBuilder AddUtilBefore( this IHostBuilder hostBuilder, Action setupAction = null ) { + hostBuilder.CheckNull( nameof( hostBuilder ) ); + hostBuilder.ConfigureServices( ( context, services ) => { + Util.Helpers.Config.SetConfiguration( context.Configuration ); + } ); + hostBuilder.AddOptions( setupAction ); + return hostBuilder; + } + + /// + /// 注册Util服务 + /// + /// 主机生成器 + /// 服务配置操作 + public static IHostBuilder AddUtil( this IHostBuilder hostBuilder, Action setupAction = null ) { + hostBuilder.CheckNull( nameof( hostBuilder ) ); + var bootstrapper = new Bootstrapper( hostBuilder, setupAction ); + bootstrapper.Start(); + return hostBuilder; + } + + /// + /// 注册Util配置操作 + /// + /// 主机生成器 + /// 服务配置操作 + public static IHostBuilder AddOptions( this IHostBuilder hostBuilder, Action setupAction = null ) where TOptions : class, IOptions, new() { + hostBuilder.CheckNull( nameof( hostBuilder ) ); + var options = new TOptions(); + setupAction?.Invoke( options ); + hostBuilder.ConfigureServices( ( context, services ) => { + if ( setupAction != null ) + services.Configure( setupAction ); + } ); + foreach ( var extension in options.Extensions ) { + extension.Config( hostBuilder ); + hostBuilder.ConfigureAppConfiguration( extension.ConfigureAppConfiguration ); + hostBuilder.ConfigureServices( extension.ConfigureServices ); + } + return hostBuilder; + } + } +} diff --git a/src/Util.Core/Infrastructure/Bootstrapper.cs b/src/Util.Core/Infrastructure/Bootstrapper.cs index 81cf27ef..3e9fa843 100644 --- a/src/Util.Core/Infrastructure/Bootstrapper.cs +++ b/src/Util.Core/Infrastructure/Bootstrapper.cs @@ -1,8 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; using Util.Configs; using Util.Dependency; using Util.Helpers; @@ -14,18 +13,14 @@ namespace Util.Infrastructure { /// public class Bootstrapper { /// - /// 服务集合 + /// 主机生成器 /// - private readonly IServiceCollection _services; + private readonly IHostBuilder _hostBuilder; /// /// 服务配置 /// private readonly Action _setupAction; /// - /// 配置 - /// - private readonly IConfiguration _configuration; - /// /// 类型查找器 /// private readonly ITypeFinder _finder; @@ -37,13 +32,11 @@ namespace Util.Infrastructure { /// /// 初始化启动器 /// - /// 服务集合 + /// 主机生成器 /// 服务配置操作 - /// 配置 - public Bootstrapper( IServiceCollection services, Action setupAction = null, IConfiguration configuration = null ) { - _services = services ?? throw new ArgumentNullException( nameof( services ) ); + public Bootstrapper( IHostBuilder hostBuilder, Action setupAction = null ) { + _hostBuilder = hostBuilder ?? throw new ArgumentNullException( nameof( hostBuilder ) ); _setupAction = setupAction; - _configuration = configuration; var assemblyFinder = new AppDomainAssemblyFinder { AssemblySkipPattern = BootstrapperConfig.AssemblySkipPattern }; _finder = new AppDomainTypeFinder( assemblyFinder ); _serviceActions = new List(); @@ -52,42 +45,54 @@ namespace Util.Infrastructure { /// /// 启动 /// - public void Start() { + public virtual void Start() { + SetConfiguration(); ResolveServiceRegistrar(); ConfigOptions(); ResolveDependencyRegistrar(); ExecuteServiceActions(); } + /// + /// 设置配置实例 + /// + protected virtual void SetConfiguration() { + _hostBuilder.ConfigureServices( ( context, services ) => { + Util.Helpers.Config.SetConfiguration( context.Configuration ); + } ); + } + /// /// 解析服务注册器 /// - private void ResolveServiceRegistrar() { + protected virtual void ResolveServiceRegistrar() { var types = _finder.Find(); var instances = types.Select( type => Reflection.CreateInstance( type ) ).Where( t => t.Enabled ).OrderBy( t => t.Id ).ToList(); - instances.ForEach( t => _serviceActions.Add( t.Register( _services, _configuration, _finder ) ) ); + instances.ForEach( t => _serviceActions.Add( t.Register( _hostBuilder, _finder ) ) ); } /// /// 注册配置项 /// - private void ConfigOptions() { - _services.AddOptions( _setupAction ); + protected virtual void ConfigOptions() { + _hostBuilder.AddOptions( _setupAction ); } /// /// 解析依赖注册器 /// - private void ResolveDependencyRegistrar() { + protected virtual void ResolveDependencyRegistrar() { var types = _finder.Find(); var instances = types.Select( type => Reflection.CreateInstance( type ) ).OrderBy( t => t.Order ).ToList(); - instances.ForEach( t => t.Register( _services ) ); + _hostBuilder.ConfigureServices( ( context, services ) => { + instances.ForEach( t => t.Register( services ) ); + } ); } /// /// 执行延迟服务注册操作 /// - private void ExecuteServiceActions() { + protected virtual void ExecuteServiceActions() { _serviceActions.ForEach( action => action?.Invoke() ); } } diff --git a/src/Util.Core/Infrastructure/DependencyServiceRegistrar.cs b/src/Util.Core/Infrastructure/DependencyServiceRegistrar.cs index e3b209d5..365bacab 100644 --- a/src/Util.Core/Infrastructure/DependencyServiceRegistrar.cs +++ b/src/Util.Core/Infrastructure/DependencyServiceRegistrar.cs @@ -1,8 +1,8 @@ using System; using System.Collections.Generic; -using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; +using Microsoft.Extensions.Hosting; using Util.Dependency; using Util.Reflections; @@ -29,14 +29,15 @@ namespace Util.Infrastructure { /// /// 注册服务 /// - /// 服务集合 - /// 配置 + /// 主机生成器 /// 类型查找器 - public Action Register( IServiceCollection services, IConfiguration configuration, ITypeFinder finder ) { + public Action Register( IHostBuilder hostBuilder, ITypeFinder finder ) { return () => { - RegisterDependency( services, finder, ServiceLifetime.Singleton ); - RegisterDependency( services, finder, ServiceLifetime.Scoped ); - RegisterDependency( services, finder, ServiceLifetime.Transient ); + hostBuilder.ConfigureServices( ( context, services ) => { + RegisterDependency( services, finder, ServiceLifetime.Singleton ); + RegisterDependency( services, finder, ServiceLifetime.Scoped ); + RegisterDependency( services, finder, ServiceLifetime.Transient ); + } ); }; } diff --git a/src/Util.Core/Infrastructure/IServiceRegistrar.cs b/src/Util.Core/Infrastructure/IServiceRegistrar.cs index 75611bea..13dd3623 100644 --- a/src/Util.Core/Infrastructure/IServiceRegistrar.cs +++ b/src/Util.Core/Infrastructure/IServiceRegistrar.cs @@ -1,6 +1,5 @@ using System; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; using Util.Reflections; namespace Util.Infrastructure { @@ -11,17 +10,22 @@ namespace Util.Infrastructure { /// /// 标识 /// - int Id { get; } + int Id { + get; + } + /// /// 是否启用 /// - bool Enabled { get; } + bool Enabled { + get; + } + /// /// 注册服务,该操作在启动开始时执行,如果需要延迟执行某些操作,可在返回的Action中执行,它将在启动最后执行 /// - /// 服务集合 - /// 配置 + /// 主机生成器 /// 类型查找器 - Action Register( IServiceCollection services, IConfiguration configuration, ITypeFinder finder ); + Action Register( IHostBuilder hostBuilder, ITypeFinder finder ); } } diff --git a/src/Util.Core/Properties/R.Designer.cs b/src/Util.Core/Properties/R.Designer.cs index 9d505d02..0c83b21b 100644 --- a/src/Util.Core/Properties/R.Designer.cs +++ b/src/Util.Core/Properties/R.Designer.cs @@ -19,7 +19,7 @@ namespace Util.Properties { // 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。 // 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen // (以 /str 作为命令选项),或重新生成 VS 项目。 - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] public class R { @@ -60,6 +60,33 @@ namespace Util.Properties { } } + /// + /// 查找类似 仅允许添加一个条件,条件:{0} 的本地化字符串。 + /// + public static string CanOnlyOneCondition { + get { + return ResourceManager.GetString("CanOnlyOneCondition", resourceCulture); + } + } + + /// + /// 查找类似 当前操作的数据已被其他人修改,请刷新后重试 的本地化字符串。 + /// + public static string ConcurrencyExceptionMessage { + get { + return ResourceManager.GetString("ConcurrencyExceptionMessage", resourceCulture); + } + } + + /// + /// 查找类似 天 的本地化字符串。 + /// + public static string Days { + get { + return ResourceManager.GetString("Days", resourceCulture); + } + } + /// /// 查找类似 删除成功 的本地化字符串。 /// @@ -69,6 +96,33 @@ namespace Util.Properties { } } + /// + /// 查找类似 其他用户正在执行该操作,请稍后再试 的本地化字符串。 + /// + public static string GlobalDuplicateRequest { + get { + return ResourceManager.GetString("GlobalDuplicateRequest", resourceCulture); + } + } + + /// + /// 查找类似 小时 的本地化字符串。 + /// + public static string Hours { + get { + return ResourceManager.GetString("Hours", resourceCulture); + } + } + + /// + /// 查找类似 标识不能为空 的本地化字符串。 + /// + public static string IdIsEmpty { + get { + return ResourceManager.GetString("IdIsEmpty", resourceCulture); + } + } + /// /// 查找类似 序号 的本地化字符串。 /// @@ -78,6 +132,24 @@ namespace Util.Properties { } } + /// + /// 查找类似 毫秒 的本地化字符串。 + /// + public static string Milliseconds { + get { + return ResourceManager.GetString("Milliseconds", resourceCulture); + } + } + + /// + /// 查找类似 分 的本地化字符串。 + /// + public static string Minutes { + get { + return ResourceManager.GetString("Minutes", resourceCulture); + } + } + /// /// 查找类似 否 的本地化字符串。 /// @@ -87,6 +159,15 @@ namespace Util.Properties { } } + /// + /// 查找类似 秒 的本地化字符串。 + /// + public static string Seconds { + get { + return ResourceManager.GetString("Seconds", resourceCulture); + } + } + /// /// 查找类似 操作成功 的本地化字符串。 /// @@ -105,6 +186,15 @@ namespace Util.Properties { } } + /// + /// 查找类似 类型 {0} 不是枚举 的本地化字符串。 + /// + public static string TypeNotEnum { + get { + return ResourceManager.GetString("TypeNotEnum", resourceCulture); + } + } + /// /// 查找类似 上传 的本地化字符串。 /// @@ -114,6 +204,15 @@ namespace Util.Properties { } } + /// + /// 查找类似 请不要重复提交 的本地化字符串。 + /// + public static string UserDuplicateRequest { + get { + return ResourceManager.GetString("UserDuplicateRequest", resourceCulture); + } + } + /// /// 查找类似 是 的本地化字符串。 /// diff --git a/src/Util.Core/Properties/R.resx b/src/Util.Core/Properties/R.resx index cadf544a..95e2a065 100644 --- a/src/Util.Core/Properties/R.resx +++ b/src/Util.Core/Properties/R.resx @@ -117,15 +117,42 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + 仅允许添加一个条件,条件:{0} + + + 当前操作的数据已被其他人修改,请刷新后重试 + + + 天 + 删除成功 + + 其他用户正在执行该操作,请稍后再试 + + + 小时 + + + 标识不能为空 + 序号 + + 毫秒 + + + 分 + 否 + + 秒 + 操作成功 @@ -133,9 +160,15 @@ 系统忙,请稍后再试 抛出系统异常时显示该消息 + + 类型 {0} 不是枚举 + 上传 + + 请不要重复提交 + 是 diff --git a/src/Util.Core/Properties/UtilCoreResource.Designer.cs b/src/Util.Core/Properties/UtilCoreResource.Designer.cs deleted file mode 100644 index 57aa9930..00000000 --- a/src/Util.Core/Properties/UtilCoreResource.Designer.cs +++ /dev/null @@ -1,162 +0,0 @@ -//------------------------------------------------------------------------------ -// -// 此代码由工具生成。 -// 运行时版本:4.0.30319.42000 -// -// 对此文件的更改可能会导致不正确的行为,并且如果 -// 重新生成代码,这些更改将会丢失。 -// -//------------------------------------------------------------------------------ - -namespace Util.Properties { - using System; - - - /// - /// 一个强类型的资源类,用于查找本地化的字符串等。 - /// - // 此类是由 StronglyTypedResourceBuilder - // 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。 - // 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen - // (以 /str 作为命令选项),或重新生成 VS 项目。 - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - public class UtilCoreResource { - - private static global::System.Resources.ResourceManager resourceMan; - - private static global::System.Globalization.CultureInfo resourceCulture; - - [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - internal UtilCoreResource() { - } - - /// - /// 返回此类使用的缓存的 ResourceManager 实例。 - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - public static global::System.Resources.ResourceManager ResourceManager { - get { - if (object.ReferenceEquals(resourceMan, null)) { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Util.Properties.UtilCoreResource", typeof(UtilCoreResource).Assembly); - resourceMan = temp; - } - return resourceMan; - } - } - - /// - /// 重写当前线程的 CurrentUICulture 属性,对 - /// 使用此强类型资源类的所有资源查找执行重写。 - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - public static global::System.Globalization.CultureInfo Culture { - get { - return resourceCulture; - } - set { - resourceCulture = value; - } - } - - /// - /// 查找类似 仅允许添加一个条件,条件:{0} 的本地化字符串。 - /// - public static string CanOnlyOneCondition { - get { - return ResourceManager.GetString("CanOnlyOneCondition", resourceCulture); - } - } - - /// - /// 查找类似 当前操作的数据已被其他人修改,请刷新后重试 的本地化字符串。 - /// - public static string ConcurrencyExceptionMessage { - get { - return ResourceManager.GetString("ConcurrencyExceptionMessage", resourceCulture); - } - } - - /// - /// 查找类似 天 的本地化字符串。 - /// - public static string Days { - get { - return ResourceManager.GetString("Days", resourceCulture); - } - } - - /// - /// 查找类似 其他用户正在执行该操作,请稍后再试 的本地化字符串。 - /// - public static string GlobalDuplicateRequest { - get { - return ResourceManager.GetString("GlobalDuplicateRequest", resourceCulture); - } - } - - /// - /// 查找类似 小时 的本地化字符串。 - /// - public static string Hours { - get { - return ResourceManager.GetString("Hours", resourceCulture); - } - } - - /// - /// 查找类似 标识不能为空 的本地化字符串。 - /// - public static string IdIsEmpty { - get { - return ResourceManager.GetString("IdIsEmpty", resourceCulture); - } - } - - /// - /// 查找类似 毫秒 的本地化字符串。 - /// - public static string Milliseconds { - get { - return ResourceManager.GetString("Milliseconds", resourceCulture); - } - } - - /// - /// 查找类似 分 的本地化字符串。 - /// - public static string Minutes { - get { - return ResourceManager.GetString("Minutes", resourceCulture); - } - } - - /// - /// 查找类似 秒 的本地化字符串。 - /// - public static string Seconds { - get { - return ResourceManager.GetString("Seconds", resourceCulture); - } - } - - /// - /// 查找类似 类型 {0} 不是枚举 的本地化字符串。 - /// - public static string TypeNotEnum { - get { - return ResourceManager.GetString("TypeNotEnum", resourceCulture); - } - } - - /// - /// 查找类似 请不要重复提交 的本地化字符串。 - /// - public static string UserDuplicateRequest { - get { - return ResourceManager.GetString("UserDuplicateRequest", resourceCulture); - } - } - } -} diff --git a/src/Util.Core/Security/IEncryptor.cs b/src/Util.Core/Security/IEncryptor.cs new file mode 100644 index 00000000..0d014897 --- /dev/null +++ b/src/Util.Core/Security/IEncryptor.cs @@ -0,0 +1,17 @@ +namespace Util.Security { + /// + /// 加密器 + /// + public interface IEncryptor { + /// + /// 加密 + /// + /// 原始数据 + string Encrypt( string data ); + /// + /// 解密 + /// + /// 已加密数据 + string Decrypt( string data ); + } +} \ No newline at end of file diff --git a/src/Util.Core/Security/NullEncryptor.cs b/src/Util.Core/Security/NullEncryptor.cs new file mode 100644 index 00000000..f599fe07 --- /dev/null +++ b/src/Util.Core/Security/NullEncryptor.cs @@ -0,0 +1,27 @@ +namespace Util.Security { + /// + /// 空加密器 + /// + public class NullEncryptor : IEncryptor { + /// + /// 空加密器实例 + /// + public static readonly IEncryptor Instance = new NullEncryptor(); + + /// + /// 加密 + /// + /// 原始数据 + public string Encrypt( string data ) { + return string.Empty; + } + + /// + /// 解密 + /// + /// 已加密数据 + public string Decrypt( string data ) { + return string.Empty; + } + } +} diff --git a/src/Util.Core/ServiceCollectionExtensions.cs b/src/Util.Core/ServiceCollectionExtensions.cs index d0942702..d895176f 100644 --- a/src/Util.Core/ServiceCollectionExtensions.cs +++ b/src/Util.Core/ServiceCollectionExtensions.cs @@ -1,9 +1,6 @@ -using System; -using System.Linq; +using System.Linq; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; -using Util.Configs; -using Util.Infrastructure; namespace Util { /// @@ -32,35 +29,5 @@ namespace Util { return (T)descriptor.ImplementationFactory.Invoke( null ); return default; } - - /// - /// 添加配置 - /// - /// 服务集合 - /// 服务配置操作 - public static IServiceCollection AddOptions( this IServiceCollection services, Action setupAction ) where TOptions : class, new() { - var options = new TOptions(); - setupAction?.Invoke( options ); - if( options is IOptions conig ) { - foreach( var extension in conig.Extensions ) - extension.AddServices( services ); - } - if( setupAction != null ) - services.Configure( setupAction ); - return services; - } - - /// - /// 注册Util服务 - /// - /// 服务集合 - /// 服务配置操作 - public static IServiceCollection AddUtil( this IServiceCollection services, Action setupAction = null ) { - var configuration = services.GetConfiguration(); - Util.Helpers.Config.SetConfiguration( configuration ); - var bootstrapper = new Bootstrapper( services, setupAction, configuration ); - bootstrapper.Start(); - return services; - } } } diff --git a/src/Util.Core/SystemTextJson/DateTimeJsonConverter.cs b/src/Util.Core/SystemTextJson/DateTimeJsonConverter.cs new file mode 100644 index 00000000..1e46d238 --- /dev/null +++ b/src/Util.Core/SystemTextJson/DateTimeJsonConverter.cs @@ -0,0 +1,52 @@ +using System; +using System.Text.Json; +using System.Text.Json.Serialization; +using Util.Helpers; +using Convert = Util.Helpers.Convert; + +namespace Util.SystemTextJson { + /// + /// 日期格式Json转换器 + /// + public class DateTimeJsonConverter : JsonConverter { + /// + /// 日期格式 + /// + private readonly string _format; + + /// + /// 初始化日期格式Json转换器 + /// + public DateTimeJsonConverter() : this( "yyyy-MM-dd HH:mm:ss" ) { + } + + /// + /// 初始化日期格式Json转换器 + /// + /// 日期格式,默认值: yyyy-MM-dd HH:mm:ss + public DateTimeJsonConverter( string format ) { + _format = format; + } + + /// + /// 读取数据 + /// + public override DateTime Read( ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options ) { + if ( reader.TokenType == JsonTokenType.String ) { + return Time.Normalize( Convert.ToDateTime( reader.GetString() ) ); + } + if ( reader.TryGetDateTime( out var date ) ) { + return Time.Normalize( date ); + } + return DateTime.MinValue; + } + + /// + /// 写入数据 + /// + public override void Write( Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options ) { + var date = Time.Normalize( value ).ToString( _format ); + writer.WriteStringValue( date ); + } + } +} diff --git a/src/Util.Core/SystemTextJson/NullableDateTimeJsonConverter.cs b/src/Util.Core/SystemTextJson/NullableDateTimeJsonConverter.cs new file mode 100644 index 00000000..366a283a --- /dev/null +++ b/src/Util.Core/SystemTextJson/NullableDateTimeJsonConverter.cs @@ -0,0 +1,56 @@ +using System; +using System.Text.Json; +using System.Text.Json.Serialization; +using Util.Helpers; +using Convert = Util.Helpers.Convert; + +namespace Util.SystemTextJson { + /// + /// 可空日期格式Json转换器 + /// + public class NullableDateTimeJsonConverter : JsonConverter { + /// + /// 日期格式 + /// + private readonly string _format; + + /// + /// 初始化可空日期格式Json转换器 + /// + public NullableDateTimeJsonConverter() : this( "yyyy-MM-dd HH:mm:ss" ) { + } + + /// + /// 初始化可空日期格式Json转换器 + /// + /// 日期格式,默认值: yyyy-MM-dd HH:mm:ss + public NullableDateTimeJsonConverter( string format ) { + _format = format; + } + + /// + /// 读取数据 + /// + public override DateTime? Read( ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options ) { + if ( reader.TokenType == JsonTokenType.String ) { + return Time.Normalize( Convert.ToDateTime( reader.GetString() ) ); + } + if ( reader.TryGetDateTime( out var date ) ) { + return Time.Normalize( date ); + } + return DateTime.MinValue; + } + + /// + /// 写入数据 + /// + public override void Write( Utf8JsonWriter writer, DateTime? value, JsonSerializerOptions options ) { + if ( value == null ) { + writer.WriteNullValue(); + return; + } + var date = Time.Normalize( value.Value ).ToString( _format ); + writer.WriteStringValue( date ); + } + } +} diff --git a/src/Util.Data.Abstractions/Stores/IQueryStore.cs b/src/Util.Data.Abstractions/Stores/IQueryStore.cs index 207cdea1..d2670d44 100644 --- a/src/Util.Data.Abstractions/Stores/IQueryStore.cs +++ b/src/Util.Data.Abstractions/Stores/IQueryStore.cs @@ -21,7 +21,7 @@ namespace Util.Data.Stores { /// /// 实体类型 /// 实体标识类型 - public interface IQueryStore : IFilterOperation,IScopeDependency where TEntity : class, IKey { + public interface IQueryStore : IFilterOperation,IScopeDependency,IDisposable where TEntity : class, IKey { /// /// 获取查询对象 /// diff --git a/src/Util.Data.Abstractions/Stores/IStore.cs b/src/Util.Data.Abstractions/Stores/IStore.cs index 306b5bd4..d528e52d 100644 --- a/src/Util.Data.Abstractions/Stores/IStore.cs +++ b/src/Util.Data.Abstractions/Stores/IStore.cs @@ -20,16 +20,6 @@ namespace Util.Data.Stores { /// 对象类型 /// 对象标识类型 public interface IStore : IQueryStore where TEntity : class, IKey { - /// - /// 添加实体 - /// - /// 实体 - void Add( [Valid] TEntity entity ); - /// - /// 添加实体集合 - /// - /// 实体集合 - void Add( [Valid] IEnumerable entities ); /// /// 添加实体 /// @@ -46,42 +36,14 @@ namespace Util.Data.Stores { /// 修改实体 /// /// 实体 - void Update( [Valid] TEntity entity ); + /// 取消令牌 + Task UpdateAsync( [Valid] TEntity entity, CancellationToken cancellationToken = default ); /// /// 修改实体集合 /// /// 实体集合 - void Update( [Valid] IEnumerable entities ); - /// - /// 修改实体 - /// - /// 实体 - Task UpdateAsync( [Valid] TEntity entity ); - /// - /// 修改实体集合 - /// - /// 实体集合 - Task UpdateAsync( [Valid] IEnumerable entities ); - /// - /// 移除实体 - /// - /// 标识 - void Remove( object id ); - /// - /// 移除实体 - /// - /// 实体 - void Remove( TEntity entity ); - /// - /// 移除实体集合 - /// - /// 标识集合 - void Remove( IEnumerable ids ); - /// - /// 移除实体集合 - /// - /// 实体集合 - void Remove( IEnumerable entities ); + /// 取消令牌 + Task UpdateAsync( [Valid] IEnumerable entities, CancellationToken cancellationToken = default ); /// /// 移除实体 /// diff --git a/src/Util.Data.Core/01-Util.Data.Core.csproj b/src/Util.Data.Core/01-Util.Data.Core.csproj index d1c19965..b9d39350 100644 --- a/src/Util.Data.Core/01-Util.Data.Core.csproj +++ b/src/Util.Data.Core/01-Util.Data.Core.csproj @@ -27,14 +27,14 @@ - + - + diff --git a/src/Util.Data.Core/IUnitOfWork.cs b/src/Util.Data.Core/IUnitOfWork.cs index 7024875e..6012e623 100644 --- a/src/Util.Data.Core/IUnitOfWork.cs +++ b/src/Util.Data.Core/IUnitOfWork.cs @@ -8,10 +8,6 @@ namespace Util.Data { /// [Util.Aop.Ignore] public interface IUnitOfWork : IDisposable, IFilterOperation { - /// - /// 提交,返回影响的行数 - /// - int Commit(); /// /// 提交,返回影响的行数 /// diff --git a/src/Util.Data.Core/Queries/Conditions/WhereIfNotEmptyCondition.cs b/src/Util.Data.Core/Queries/Conditions/WhereIfNotEmptyCondition.cs index 486b62cc..4159572a 100644 --- a/src/Util.Data.Core/Queries/Conditions/WhereIfNotEmptyCondition.cs +++ b/src/Util.Data.Core/Queries/Conditions/WhereIfNotEmptyCondition.cs @@ -29,7 +29,7 @@ namespace Util.Data.Queries.Conditions { if( _condition == null ) return null; if( Lambda.GetConditionCount( _condition ) > 1 ) - throw new InvalidOperationException( string.Format( UtilCoreResource.CanOnlyOneCondition, _condition ) ); + throw new InvalidOperationException( string.Format( R.CanOnlyOneCondition, _condition ) ); return _condition.Value().SafeString().IsEmpty() ? null : _condition; } } diff --git a/src/Util.Data.Core/Trees/TreeCondition.cs b/src/Util.Data.Core/Trees/TreeCondition.cs index fa74bfcd..9691c75b 100644 --- a/src/Util.Data.Core/Trees/TreeCondition.cs +++ b/src/Util.Data.Core/Trees/TreeCondition.cs @@ -34,9 +34,6 @@ namespace Util.Data.Trees { Condition = Condition.And( t => t.Level == parameter.Level ); if( parameter.Enabled != null ) Condition = Condition.And( t => t.Enabled == parameter.Enabled ); - var parentId = Util.Helpers.Convert.To( parameter.ParentId ); - if( parameter.ParentId != null ) - Condition = Condition.And( t => t.ParentId.Equals(parentId) ); } /// diff --git a/src/Util.Data.Dapper.All/05-Util.Data.Dapper.All.csproj b/src/Util.Data.Dapper.All/05-Util.Data.Dapper.All.csproj new file mode 100644 index 00000000..a2271cfa --- /dev/null +++ b/src/Util.Data.Dapper.All/05-Util.Data.Dapper.All.csproj @@ -0,0 +1,35 @@ + + + + $(NetTargetFramework) + icon.jpg + Util.Data.Dapper.All + Util.Data + Util.Data.Dapper.All是Util应用框架基于Dapper的数据访问封装类库,包含所有支持的数据库实现 + + + + + .\obj\Debug\$(NetTargetFramework)\Util.Data.Dapper.All.xml + + + + + .\obj\Release\$(NetTargetFramework)\Util.Data.Dapper.All.xml + + + + + True + False + + + + + + + + + + + diff --git a/src/Util.Data.Dapper.All/Infrastructure/DapperServiceRegistrar.cs b/src/Util.Data.Dapper.All/Infrastructure/DapperServiceRegistrar.cs new file mode 100644 index 00000000..50e1408a --- /dev/null +++ b/src/Util.Data.Dapper.All/Infrastructure/DapperServiceRegistrar.cs @@ -0,0 +1,41 @@ +using System; +using Microsoft.Extensions.DependencyInjection.Extensions; +using Microsoft.Extensions.Hosting; +using Util.Data.Metadata; +using Util.Infrastructure; +using Util.Reflections; + +namespace Util.Data.Infrastructure { + /// + /// Dapper服务注册器 + /// + public class DapperServiceRegistrar : IServiceRegistrar { + /// + /// 获取标识 + /// + public static int GetId() => 790; + + /// + /// 标识 + /// + public int Id => GetId(); + + /// + /// 是否启用 + /// + public bool Enabled => ServiceRegistrarConfig.Instance.IsEnabled( GetId() ); + + /// + /// 注册服务 + /// + /// 主机生成器 + /// 类型查找器 + public Action Register( IHostBuilder hostBuilder, ITypeFinder finder ) { + hostBuilder.ConfigureServices( ( context, services ) => { + services.TryAddSingleton(); + services.TryAddSingleton(); + } ); + return null; + } + } +} diff --git a/src/Util.Data.Dapper.All/Infrastructure/ServiceRegistrarConfigExtensions.cs b/src/Util.Data.Dapper.All/Infrastructure/ServiceRegistrarConfigExtensions.cs new file mode 100644 index 00000000..a1650803 --- /dev/null +++ b/src/Util.Data.Dapper.All/Infrastructure/ServiceRegistrarConfigExtensions.cs @@ -0,0 +1,26 @@ +using Util.Infrastructure; + +namespace Util.Data.Infrastructure { + /// + /// Dapper服务注册器配置扩展 + /// + public static class ServiceRegistrarConfigExtensions { + /// + /// 启用Dapper服务注册器 + /// + /// 服务注册器配置 + public static ServiceRegistrarConfig EnableDapperServiceRegistrar( this ServiceRegistrarConfig config ) { + config.Enable( DapperServiceRegistrar.GetId() ); + return config; + } + + /// + ///禁用Dapper服务注册器 + /// + /// 服务注册器配置 + public static ServiceRegistrarConfig DisableDapperServiceRegistrar( this ServiceRegistrarConfig config ) { + config.Disable( DapperServiceRegistrar.GetId() ); + return config; + } + } +} diff --git a/src/Util.Data.Dapper.All/Metadata/MetadataServiceFactory.cs b/src/Util.Data.Dapper.All/Metadata/MetadataServiceFactory.cs new file mode 100644 index 00000000..ef92101e --- /dev/null +++ b/src/Util.Data.Dapper.All/Metadata/MetadataServiceFactory.cs @@ -0,0 +1,72 @@ +using System; +using Util.Data.Sql; + +namespace Util.Data.Metadata { + /// + /// 数据库元数据服务工厂 + /// + public class MetadataServiceFactory : IMetadataServiceFactory { + /// + /// 服务提供器 + /// + private readonly IServiceProvider _serviceProvider; + + /// + /// 初始化数据库元数据服务工厂 + /// + /// 服务提供器 + public MetadataServiceFactory( IServiceProvider serviceProvider ) { + _serviceProvider = serviceProvider; + } + + /// + /// 创建数据库元数据服务 + /// + /// 数据库类型 + /// 数据库连接字符串 + public IMetadataService Create( DatabaseType dbType,string connection ) { + switch ( dbType ) { + case DatabaseType.SqlServer: + return CreateSqlServerMetadataService( connection ); + case DatabaseType.PgSql: + return CreatePgSqlMetadataService( connection ); + case DatabaseType.MySql: + return CreateMySqlMetadataService( connection ); + } + throw new NotImplementedException(); + } + + /// + /// 创建Sql Server数据库元数据服务 + /// + private IMetadataService CreateSqlServerMetadataService( string connection ) { + var options = new SqlOptions { + ConnectionString = connection + }; + var sqlQuery = new SqlServerSqlQuery( _serviceProvider, options ); + return new SqlServerMetadataService( sqlQuery ); + } + + /// + /// 创建PostgreSql数据库元数据服务 + /// + private IMetadataService CreatePgSqlMetadataService( string connection ) { + var options = new SqlOptions { + ConnectionString = connection + }; + var sqlQuery = new PostgreSqlQuery( _serviceProvider, options ); + return new PostgreSqlMetadataService( sqlQuery ); + } + + /// + /// 创建MySql数据库元数据服务 + /// + private IMetadataService CreateMySqlMetadataService( string connection ) { + var options = new SqlOptions { + ConnectionString = connection + }; + var sqlQuery = new MySqlQuery( _serviceProvider, options ); + return new MySqlMetadataService( sqlQuery ); + } + } +} diff --git a/src/Util.Data.Dapper.All/Metadata/TypeConverterFactory.cs b/src/Util.Data.Dapper.All/Metadata/TypeConverterFactory.cs new file mode 100644 index 00000000..119b2fcc --- /dev/null +++ b/src/Util.Data.Dapper.All/Metadata/TypeConverterFactory.cs @@ -0,0 +1,24 @@ +using System; + +namespace Util.Data.Metadata { + /// + /// 数据类型转换器工厂 + /// + public class TypeConverterFactory : ITypeConverterFactory { + /// + /// 创建数据库元数据服务 + /// + /// 数据库类型 + public ITypeConverter Create( DatabaseType dbType ) { + switch ( dbType ) { + case DatabaseType.SqlServer: + return new SqlServerTypeConverter(); + case DatabaseType.PgSql: + return new PostgreSqlTypeConverter(); + case DatabaseType.MySql: + return new MySqlTypeConverter(); + } + throw new NotImplementedException(); + } + } +} diff --git a/src/Util.Data.Dapper.Core/01-Util.Data.Dapper.Core.csproj b/src/Util.Data.Dapper.Core/01-Util.Data.Dapper.Core.csproj new file mode 100644 index 00000000..59cf0cba --- /dev/null +++ b/src/Util.Data.Dapper.Core/01-Util.Data.Dapper.Core.csproj @@ -0,0 +1,53 @@ + + + + $(NetTargetFramework) + icon.jpg + Util.Data.Dapper.Core + Util.Data + Util.Data.Dapper.Core是Util应用框架基于Dapper的数据访问封装基础类库 + + + + + .\obj\Debug\$(NetTargetFramework)\Util.Data.Dapper.Core.xml + + + + + .\obj\Release\$(NetTargetFramework)\Util.Data.Dapper.Core.xml + + + + + True + False + + + + + + + + + + + + + + + + True + True + UtilDataDapperResource.resx + + + + + + ResXFileCodeGenerator + UtilDataDapperResource.Designer.cs + + + + diff --git a/src/Util.Data.Dapper.Core/Properties/UtilDataDapperResource.Designer.cs b/src/Util.Data.Dapper.Core/Properties/UtilDataDapperResource.Designer.cs new file mode 100644 index 00000000..159163ae --- /dev/null +++ b/src/Util.Data.Dapper.Core/Properties/UtilDataDapperResource.Designer.cs @@ -0,0 +1,81 @@ +//------------------------------------------------------------------------------ +// +// 此代码由工具生成。 +// 运行时版本:4.0.30319.42000 +// +// 对此文件的更改可能会导致不正确的行为,并且如果 +// 重新生成代码,这些更改将会丢失。 +// +//------------------------------------------------------------------------------ + +namespace Util.Data.Properties { + using System; + + + /// + /// 一个强类型的资源类,用于查找本地化的字符串等。 + /// + // 此类是由 StronglyTypedResourceBuilder + // 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。 + // 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen + // (以 /str 作为命令选项),或重新生成 VS 项目。 + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class UtilDataDapperResource { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal UtilDataDapperResource() { + } + + /// + /// 返回此类使用的缓存的 ResourceManager 实例。 + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Util.Data.Properties.UtilDataDapperResource", typeof(UtilDataDapperResource).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// 重写当前线程的 CurrentUICulture 属性,对 + /// 使用此强类型资源类的所有资源查找执行重写。 + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// 查找类似 数据库连接字符串不能为空 的本地化字符串。 + /// + internal static string ConnectionIsEmpty { + get { + return ResourceManager.GetString("ConnectionIsEmpty", resourceCulture); + } + } + + /// + /// 查找类似 数据库工厂不能为空 的本地化字符串。 + /// + internal static string DatabaseFactoryIsNull { + get { + return ResourceManager.GetString("DatabaseFactoryIsNull", resourceCulture); + } + } + } +} diff --git a/src/Util.Core/Properties/UtilCoreResource.resx b/src/Util.Data.Dapper.Core/Properties/UtilDataDapperResource.resx similarity index 83% rename from src/Util.Core/Properties/UtilCoreResource.resx rename to src/Util.Data.Dapper.Core/Properties/UtilDataDapperResource.resx index 2b4fa491..d7787e7a 100644 --- a/src/Util.Core/Properties/UtilCoreResource.resx +++ b/src/Util.Data.Dapper.Core/Properties/UtilDataDapperResource.resx @@ -117,37 +117,10 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - 仅允许添加一个条件,条件:{0} + + 数据库连接字符串不能为空 - - 当前操作的数据已被其他人修改,请刷新后重试 - - - 天 - - - 其他用户正在执行该操作,请稍后再试 - - - 小时 - - - 标识不能为空 - - - 毫秒 - - - 分 - - - 秒 - - - 类型 {0} 不是枚举 - - - 请不要重复提交 + + 数据库工厂不能为空 \ No newline at end of file diff --git a/src/Util.Data.Dapper.Core/Sql/SqlExecutorBase.cs b/src/Util.Data.Dapper.Core/Sql/SqlExecutorBase.cs new file mode 100644 index 00000000..89f9dde2 --- /dev/null +++ b/src/Util.Data.Dapper.Core/Sql/SqlExecutorBase.cs @@ -0,0 +1,78 @@ +using System; +using System.Threading.Tasks; +using Dapper; + +namespace Util.Data.Sql { + /// + /// Sql执行器 + /// + public abstract class SqlExecutorBase : SqlQueryBase, ISqlExecutor { + + #region 构造方法 + + /// + /// 初始化Sql执行器 + /// + /// 服务提供器 + /// Sql配置 + /// 数据库信息,用于接入其它数据源,比如EF DbContext + protected SqlExecutorBase( IServiceProvider serviceProvider, SqlOptions options, IDatabase database ) : base( serviceProvider,options, database ) { + } + + #endregion + + #region ExecuteAsync(执行增删改操作) + + /// + /// 执行增删改操作 + /// + /// 执行超时时间,单位:秒 + public virtual async Task ExecuteAsync( int? timeout = null ) { + int result = 0; + try { + if ( ExecuteBefore() == false ) + return 0; + var connection = GetConnection(); + result = await connection.ExecuteAsync( GetSql(), Params, GetTransaction(), timeout ); + return result; + } + catch ( Exception ) { + RollbackTransaction(); + throw; + } + finally { + ExecuteAfter( result ); + } + } + + #endregion + + #region ExecuteProcedureAsync(执行存储过程增删改操作) + + /// + /// 执行存储过程增删改操作 + /// + /// 存储过程 + /// 执行超时时间,单位:秒 + public async Task ExecuteProcedureAsync( string procedure, int? timeout = null ) { + int result = 0; + try { + if( ExecuteBefore() == false ) + return default; + SetSql( GetProcedure( procedure ) ); + var connection = GetConnection(); + result = await connection.ExecuteAsync( GetSql(), Params, GetTransaction(), timeout, GetProcedureCommandType() ); + return result; + } + catch ( Exception ) { + RollbackTransaction(); + throw; + } + finally { + ExecuteAfter( result ); + } + } + + #endregion + } +} diff --git a/src/Util.Data.Dapper.Core/Sql/SqlQueryBase.cs b/src/Util.Data.Dapper.Core/Sql/SqlQueryBase.cs new file mode 100644 index 00000000..9087099c --- /dev/null +++ b/src/Util.Data.Dapper.Core/Sql/SqlQueryBase.cs @@ -0,0 +1,1411 @@ +using System; +using System.Collections.Generic; +using System.Data; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Dapper; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; +using Util.Data.Properties; +using Util.Data.Sql.Builders; +using Util.Data.Sql.Builders.Clauses; +using Util.Data.Sql.Builders.Core; +using Util.Data.Sql.Builders.Params; +using Util.Data.Sql.Builders.Sets; +using Util.Data.Sql.Configs; +using Util.Data.Sql.Database; +using Util.Helpers; + +namespace Util.Data.Sql { + /// + /// Sql查询对象 + /// + public abstract class SqlQueryBase : ISqlQuery, ISqlPartAccessor, ISqlOptionsAccessor, IGetParameter, IClearParameters, IConnectionManager, ITransactionManager { + + #region 字段 + + /// + /// 数据库信息 + /// + private IDatabase _database; + /// + /// Sql配置 + /// + protected readonly SqlOptions Options; + /// + /// Sql生成器 + /// + private ISqlBuilder _sqlBuilder; + /// + /// 数据库连接 + /// + private IDbConnection _connection; + /// + /// 事务 + /// + private IDbTransaction _transaction; + /// + /// Sql结果字符串 + /// + private string _sql; + /// + /// 动态参数列表 + /// + private DynamicParameters _parameters; + /// + /// 参数字面值解析器 + /// + private IParamLiteralsResolver _paramLiteralsResolver; + + #endregion + + #region 构造方法 + + /// + /// 初始化Sql查询对象 + /// + /// 服务提供器 + /// Sql配置 + /// 数据库信息,用于接入其它数据源,比如EF DbContext + protected SqlQueryBase( IServiceProvider serviceProvider, SqlOptions options, IDatabase database ) { + ServiceProvider = serviceProvider ?? throw new ArgumentNullException( nameof( serviceProvider ) ); + Options = options ?? throw new ArgumentNullException( nameof( options ) ); + Logger = CreateLogger(); + _connection = options.Connection; + _database = database; + ContextId = Id.Create(); + } + + /// + /// 创建日志 + /// + private ILogger CreateLogger() { + var loggerFactory = ServiceProvider.GetService(); + if ( loggerFactory == null ) + return NullLogger.Instance; + return loggerFactory.CreateLogger( Options.LogCategory ); + } + + #endregion + + #region 属性 + + /// + /// 上下文标识 + /// + public string ContextId { get; private set; } + /// + /// 服务提供器 + /// + protected IServiceProvider ServiceProvider { get; } + /// + /// 日志操作 + /// + protected ILogger Logger { get; } + /// + /// 数据库信息 + /// + protected IDatabase Database => _database ??= CreateDatabase(); + /// + /// Sql生成器 + /// + public ISqlBuilder SqlBuilder => _sqlBuilder ??= CreateSqlBuilder(); + /// + /// Sql方言 + /// + public IDialect Dialect => ( (ISqlPartAccessor)SqlBuilder ).Dialect; + /// + /// 参数管理器 + /// + public IParameterManager ParameterManager => ( (ISqlPartAccessor)SqlBuilder ).ParameterManager; + /// + /// 参数字面值解析器 + /// + protected IParamLiteralsResolver ParamLiteralsResolver => _paramLiteralsResolver ??= CreateParamLiteralsResolver(); + /// + /// 起始子句 + /// + public IStartClause StartClause => ( (ISqlPartAccessor)SqlBuilder ).StartClause; + /// + /// Insert子句 + /// + public IFromClause FromClause => ( (ISqlPartAccessor)SqlBuilder ).FromClause; + /// + /// Join子句 + /// + public IJoinClause JoinClause => ( (ISqlPartAccessor)SqlBuilder ).JoinClause; + /// + /// Where子句 + /// + public IWhereClause WhereClause => ( (ISqlPartAccessor)SqlBuilder ).WhereClause; + /// + /// GroupBy子句 + /// + public IInsertClause InsertClause => ( (ISqlPartAccessor)SqlBuilder ).InsertClause; + /// + /// Select子句 + /// + public ISelectClause SelectClause => ( (ISqlPartAccessor)SqlBuilder ).SelectClause; + /// + /// From子句 + /// + public IGroupByClause GroupByClause => ( (ISqlPartAccessor)SqlBuilder ).GroupByClause; + /// + /// OrderBy子句 + /// + public IOrderByClause OrderByClause => ( (ISqlPartAccessor)SqlBuilder ).OrderByClause; + /// + /// 结束子句 + /// + public IEndClause EndClause => ( (ISqlPartAccessor)SqlBuilder ).EndClause; + /// + /// Sql生成器集合 + /// + public ISqlBuilderSet SqlBuilderSet => ( (ISqlPartAccessor)SqlBuilder ).SqlBuilderSet; + /// + /// 获取动态参数列表 + /// + protected DynamicParameters Params { + get { + _parameters = new DynamicParameters(); + ParameterManager.GetParams().ToList().ForEach( t => _parameters.Add( t.Name, t.Value, t.DbType, t.Direction, t.Size, t.Precision, t.Scale ) ); + ParameterManager.GetDynamicParams().ToList().ForEach( p => _parameters.AddDynamicParams( p ) ); + return _parameters; + } + } + + /// + public SqlBuilderResult PreviousSql { get; private set; } + + #endregion + + #region 工厂方法 + + /// + /// 创建Sql生成器 + /// + protected abstract ISqlBuilder CreateSqlBuilder(); + + /// + /// 创建数据库信息 + /// + protected virtual IDatabase CreateDatabase() { + if ( Options.ConnectionString.IsEmpty() ) + throw new InvalidOperationException( UtilDataDapperResource.ConnectionIsEmpty ); + var factory = CreateDatabaseFactory(); + if ( factory == null ) + throw new InvalidOperationException( UtilDataDapperResource.DatabaseFactoryIsNull ); + return factory.Create( Options.ConnectionString ); + } + + /// + /// 创建数据库工厂 + /// + protected abstract IDatabaseFactory CreateDatabaseFactory(); + + /// + /// 创建判断是否存在Sql生成器 + /// + /// Sql生成器 + protected abstract IExistsSqlBuilder CreatExistsSqlBuilder( ISqlBuilder sqlBuilder ); + + /// + /// 创建参数字面值解析器 + /// + protected virtual IParamLiteralsResolver CreateParamLiteralsResolver() { + return new ParamLiteralsResolver(); + } + + #endregion + + #region GetOptions(获取Sql配置) + + /// + /// 获取Sql配置 + /// + public SqlOptions GetOptions() { + return Options; + } + + #endregion + + #region GetParam(获取Sql参数值) + + /// + /// 获取Sql参数值 + /// + /// 参数值类型 + /// 参数名 + public virtual T GetParam( string name ) { + if ( _parameters == null && PreviousSql != null ) + return PreviousSql.GetParam( name ); + return Params.Get( name ); + } + + #endregion + + #region ClearParams(清空Sql参数) + + /// + /// 清空Sql参数 + /// + public void ClearParams() { + ParameterManager.Clear(); + _parameters = null; + } + + #endregion + + #region GetConnection(获取数据库连接) + + /// + /// 获取数据库连接 + /// + public IDbConnection GetConnection() { + if ( _connection != null ) + return _connection; + _connection = Database.GetConnection(); + if ( _connection == null ) + throw new InvalidOperationException( UtilDataDapperResource.ConnectionIsEmpty ); + return _connection; + } + + #endregion + + #region SetConnection(设置数据库连接) + + /// + /// 设置数据库连接 + /// + /// 数据库连接 + public void SetConnection( IDbConnection connection ) { + if ( connection == null ) + return; + _connection = connection; + } + + #endregion + + #region GetTransaction(获取数据库事务) + + /// + /// 获取数据库事务 + /// + public IDbTransaction GetTransaction() { + return _transaction; + } + + #endregion + + #region SetTransaction(设置数据库事务) + + /// + /// 设置数据库事务 + /// + /// 数据库事务 + public void SetTransaction( IDbTransaction transaction ) { + if ( transaction == null ) + return; + _transaction = transaction; + _connection = transaction.Connection; + } + + #endregion + + #region BeginTransaction(开始事务) + + /// + /// 开始事务 + /// + public IDbTransaction BeginTransaction() { + return BeginTransactionImpl( null ); + } + + /// + /// 开始事务 + /// + /// 隔离级别 + public IDbTransaction BeginTransaction( IsolationLevel isolationLevel ) { + return BeginTransactionImpl( isolationLevel ); + } + + /// + /// 开始事务 + /// + private IDbTransaction BeginTransactionImpl( IsolationLevel? isolationLevel ) { + try { + if ( _transaction != null ) + return _transaction; + var connection = GetConnection(); + if ( connection.State == ConnectionState.Closed ) + connection.Open(); + _transaction = isolationLevel == null ? connection.BeginTransaction() : connection.BeginTransaction( isolationLevel.SafeValue() ); + return _transaction; + } + catch { + if ( _connection?.State == ConnectionState.Open ) + _connection?.Close(); + _transaction?.Dispose(); + throw; + } + } + + #endregion + + #region CommitTransaction(提交事务) + + /// + /// 提交事务 + /// + public void CommitTransaction() { + try { + _transaction?.Commit(); + } + catch { + _transaction?.Rollback(); + throw; + } + finally { + if ( _connection?.State == ConnectionState.Open ) + _connection?.Close(); + _transaction?.Dispose(); + _transaction = null; + } + } + + #endregion + + #region RollbackTransaction(回滚事务) + + /// + /// 回滚事务 + /// + public void RollbackTransaction() { + try { + if( _connection.State != ConnectionState.Closed ) + _transaction?.Rollback(); + } + finally { + if ( _connection?.State == ConnectionState.Open ) + _connection?.Close(); + _transaction?.Dispose(); + _transaction = null; + } + } + + #endregion + + #region ExecuteExists(判断是否存在) + + /// + /// 判断是否存在 + /// + public bool ExecuteExists() { + object result = null; + try { + if ( ExecuteBefore() == false ) + return default; + _sql = CreatExistsSqlBuilder( SqlBuilder ).GetSql(); + var connection = GetConnection(); + result = connection.ExecuteScalar( GetSql(), Params, GetTransaction() ); + return Util.Helpers.Convert.ToBool( result ); + } + finally { + ExecuteAfter( result ); + } + } + + #endregion + + #region ExecuteExistsAsync(判断是否存在) + + /// + /// 判断是否存在 + /// + public async Task ExecuteExistsAsync() { + object result = null; + try { + if ( ExecuteBefore() == false ) + return default; + _sql = CreatExistsSqlBuilder( SqlBuilder ).GetSql(); + var connection = GetConnection(); + result = await connection.ExecuteScalarAsync( GetSql(), Params, GetTransaction() ); + return Util.Helpers.Convert.ToBool( result ); + } + finally { + ExecuteAfter( result ); + } + } + + #endregion + + #region ExecuteScalar(获取单值) + + /// + /// 获取单值 + /// + public virtual object ExecuteScalar( int? timeout = null ) { + object result = null; + try { + if ( ExecuteBefore() == false ) + return default; + var connection = GetConnection(); + result = connection.ExecuteScalar( GetSql(), Params, GetTransaction(), timeout ); + return result; + } + finally { + ExecuteAfter( result ); + } + } + + /// + /// 获取单值 + /// + public virtual T ExecuteScalar( int? timeout = null ) { + return Util.Helpers.Convert.To( ExecuteScalar( timeout ) ); + } + + #endregion + + #region ExecuteScalarAsync(获取单值) + + /// + /// 获取单值 + /// + public virtual async Task ExecuteScalarAsync( int? timeout = null ) { + object result = null; + try { + if ( ExecuteBefore() == false ) + return default; + var connection = GetConnection(); + result = await connection.ExecuteScalarAsync( GetSql(), Params, GetTransaction(), timeout ); + return result; + } + finally { + ExecuteAfter( result ); + } + } + + /// + /// 获取单值 + /// + public virtual async Task ExecuteScalarAsync( int? timeout = null ) { + var result = await ExecuteScalarAsync( timeout ); + return Util.Helpers.Convert.To( result ); + } + + #endregion + + #region ExecuteProcedureScalar(执行存储过程获取单值) + + /// + /// 执行存储过程获取单值 + /// + /// 存储过程 + /// 执行超时时间,单位:秒 + public virtual object ExecuteProcedureScalar( string procedure, int? timeout = null ) { + object result = null; + try { + if ( ExecuteBefore() == false ) + return default; + _sql = GetProcedure( procedure ); + var connection = GetConnection(); + result = connection.ExecuteScalar( GetSql(), Params, GetTransaction(), timeout, GetProcedureCommandType() ); + return result; + } + finally { + ExecuteAfter( result ); + } + } + + + + /// + /// 执行存储过程获取单值 + /// + /// 存储过程 + /// 执行超时时间,单位:秒 + public virtual T ExecuteProcedureScalar( string procedure, int? timeout = null ) { + return Util.Helpers.Convert.To( ExecuteProcedureScalar( procedure, timeout ) ); + } + + #endregion + + #region ExecuteProcedureScalarAsync(执行存储过程获取单值) + + /// + /// 执行存储过程获取单值 + /// + /// 存储过程 + /// 执行超时时间,单位:秒 + public virtual async Task ExecuteProcedureScalarAsync( string procedure, int? timeout = null ) { + object result = null; + try { + if ( ExecuteBefore() == false ) + return default; + _sql = GetProcedure( procedure ); + var connection = GetConnection(); + result = await connection.ExecuteScalarAsync( GetSql(), Params, GetTransaction(), timeout, GetProcedureCommandType() ); + return result; + } + finally { + ExecuteAfter( result ); + } + } + + /// + /// 执行存储过程获取单值 + /// + /// 存储过程 + /// 执行超时时间,单位:秒 + public virtual async Task ExecuteProcedureScalarAsync( string procedure, int? timeout = null ) { + var result = await ExecuteProcedureScalarAsync( procedure, timeout ); + return Util.Helpers.Convert.To( result ); + } + + #endregion + + #region ExecuteSingle(获取单个实体) + + /// + /// 获取单个实体 + /// + public virtual TEntity ExecuteSingle( int? timeout = null ) { + TEntity result = default; + try { + if ( ExecuteBefore() == false ) + return default; + var connection = GetConnection(); + result = connection.QueryFirstOrDefault( GetSql(), Params, GetTransaction(), timeout ); + return result; + } + finally { + ExecuteAfter( result ); + } + } + + #endregion + + #region ExecuteSingleAsync(获取单个实体) + + /// + /// 获取单个实体 + /// + public virtual async Task ExecuteSingleAsync( int? timeout = null ) { + TEntity result = default; + try { + if ( ExecuteBefore() == false ) + return default; + var connection = GetConnection(); + result = await connection.QueryFirstOrDefaultAsync( GetSql(), Params, GetTransaction(), timeout ); + return result; + } + finally { + ExecuteAfter( result ); + } + } + + #endregion + + #region ExecuteProcedureSingle(执行存储过程获取单个实体) + + /// + /// 执行存储过程获取单个实体 + /// + public virtual TEntity ExecuteProcedureSingle( string procedure, int? timeout = null ) { + TEntity result = default; + try { + if ( ExecuteBefore() == false ) + return default; + _sql = GetProcedure( procedure ); + var connection = GetConnection(); + result = connection.QueryFirstOrDefault( GetSql(), Params, GetTransaction(), timeout, GetProcedureCommandType() ); + return result; + } + finally { + ExecuteAfter( result ); + } + } + + #endregion + + #region ExecuteProcedureSingleAsync(执行存储过程获取单个实体) + + /// + /// 执行存储过程获取单个实体 + /// + public virtual async Task ExecuteProcedureSingleAsync( string procedure, int? timeout = null ) { + TEntity result = default; + try { + if ( ExecuteBefore() == false ) + return default; + _sql = GetProcedure( procedure ); + var connection = GetConnection(); + result = await connection.QueryFirstOrDefaultAsync( GetSql(), Params, GetTransaction(), timeout, GetProcedureCommandType() ); + return result; + } + finally { + ExecuteAfter( result ); + } + } + + #endregion + + #region ExecuteQuery(获取实体集合) + + /// + /// 获取实体集合 + /// + public virtual List ExecuteQuery( int? timeout = null, bool buffered = true ) { + List result = default; + try { + if ( ExecuteBefore() == false ) + return default; + var connection = GetConnection(); + result = connection.Query( GetSql(), Params, GetTransaction(), buffered, timeout ).ToList(); + return result; + } + finally { + ExecuteAfter( result ); + } + } + + /// + /// 获取实体集合 + /// + public virtual List ExecuteQuery( int? timeout = null, bool buffered = true ) { + List result = default; + try { + if ( ExecuteBefore() == false ) + return default; + var connection = GetConnection(); + result = connection.Query( GetSql(), Params, GetTransaction(), buffered, timeout ).ToList(); + return result; + } + finally { + ExecuteAfter( result ); + } + } + + /// + /// 获取实体集合 + /// + public virtual List ExecuteQuery( Func map, int? timeout = null, bool buffered = true ) { + List result = default; + try { + if ( ExecuteBefore() == false ) + return default; + var connection = GetConnection(); + result = connection.Query( GetSql(), map, Params, GetTransaction(), buffered, "Id", timeout ).ToList(); + return result; + } + finally { + ExecuteAfter( result ); + } + } + + /// + /// 获取实体集合 + /// + public virtual List ExecuteQuery( Func map, int? timeout = null, bool buffered = true ) { + List result = default; + try { + if ( ExecuteBefore() == false ) + return default; + var connection = GetConnection(); + result = connection.Query( GetSql(), map, Params, GetTransaction(), buffered, "Id", timeout ).ToList(); + return result; + } + finally { + ExecuteAfter( result ); + } + } + + /// + /// 获取实体集合 + /// + public virtual List ExecuteQuery( Func map, int? timeout = null, bool buffered = true ) { + List result = default; + try { + if ( ExecuteBefore() == false ) + return default; + var connection = GetConnection(); + result = connection.Query( GetSql(), map, Params, GetTransaction(), buffered, "Id", timeout ).ToList(); + return result; + } + finally { + ExecuteAfter( result ); + } + } + + /// + /// 获取实体集合 + /// + public virtual List ExecuteQuery( Func map, int? timeout = null, bool buffered = true ) { + List result = default; + try { + if ( ExecuteBefore() == false ) + return default; + var connection = GetConnection(); + result = connection.Query( GetSql(), map, Params, GetTransaction(), buffered, "Id", timeout ).ToList(); + return result; + } + finally { + ExecuteAfter( result ); + } + } + + /// + /// 获取实体集合 + /// + public virtual List ExecuteQuery( Func map, int? timeout = null, bool buffered = true ) { + List result = default; + try { + if ( ExecuteBefore() == false ) + return default; + var connection = GetConnection(); + result = connection.Query( GetSql(), map, Params, GetTransaction(), buffered, "Id", timeout ).ToList(); + return result; + } + finally { + ExecuteAfter( result ); + } + } + + /// + /// 获取实体集合 + /// + public virtual List ExecuteQuery( Func map, int? timeout = null, bool buffered = true ) { + List result = default; + try { + if ( ExecuteBefore() == false ) + return default; + var connection = GetConnection(); + result = connection.Query( GetSql(), map, Params, GetTransaction(), buffered, "Id", timeout ).ToList(); + return result; + } + finally { + ExecuteAfter( result ); + } + } + + #endregion + + #region ExecuteQueryAsync(获取实体集合) + + /// + /// 获取实体集合 + /// + public virtual async Task> ExecuteQueryAsync( int? timeout = null ) { + List result = default; + try { + if ( ExecuteBefore() == false ) + return default; + var connection = GetConnection(); + result = ( await connection.QueryAsync( GetSql(), Params, GetTransaction(), timeout ) ).ToList(); + return result; + } + finally { + ExecuteAfter( result ); + } + } + + /// + /// 获取实体集合 + /// + public virtual async Task> ExecuteQueryAsync( int? timeout = null ) { + List result = default; + try { + if ( ExecuteBefore() == false ) + return default; + var connection = GetConnection(); + result = ( await connection.QueryAsync( GetSql(), Params, GetTransaction(), timeout ) ).ToList(); + return result; + } + finally { + ExecuteAfter( result ); + } + } + + /// + /// 获取实体集合 + /// + public virtual async Task> ExecuteQueryAsync( Func map, int? timeout = null, bool buffered = true ) { + List result = default; + try { + if ( ExecuteBefore() == false ) + return default; + var connection = GetConnection(); + result = ( await connection.QueryAsync( GetSql(), map, Params, GetTransaction(), buffered, "Id", timeout ) ).ToList(); + return result; + } + finally { + ExecuteAfter( result ); + } + } + + /// + /// 获取实体集合 + /// + public virtual async Task> ExecuteQueryAsync( Func map, int? timeout = null, bool buffered = true ) { + List result = default; + try { + if ( ExecuteBefore() == false ) + return default; + var connection = GetConnection(); + result = ( await connection.QueryAsync( GetSql(), map, Params, GetTransaction(), buffered, "Id", timeout ) ).ToList(); + return result; + } + finally { + ExecuteAfter( result ); + } + } + + /// + /// 获取实体集合 + /// + public virtual async Task> ExecuteQueryAsync( Func map, int? timeout = null, bool buffered = true ) { + List result = default; + try { + if ( ExecuteBefore() == false ) + return default; + var connection = GetConnection(); + result = ( await connection.QueryAsync( GetSql(), map, Params, GetTransaction(), buffered, "Id", timeout ) ).ToList(); + return result; + } + finally { + ExecuteAfter( result ); + } + } + + /// + /// 获取实体集合 + /// + public virtual async Task> ExecuteQueryAsync( Func map, int? timeout = null, bool buffered = true ) { + List result = default; + try { + if ( ExecuteBefore() == false ) + return default; + var connection = GetConnection(); + result = ( await connection.QueryAsync( GetSql(), map, Params, GetTransaction(), buffered, "Id", timeout ) ).ToList(); + return result; + } + finally { + ExecuteAfter( result ); + } + } + + /// + /// 获取实体集合 + /// + public virtual async Task> ExecuteQueryAsync( Func map, int? timeout = null, bool buffered = true ) { + List result = default; + try { + if ( ExecuteBefore() == false ) + return default; + var connection = GetConnection(); + result = ( await connection.QueryAsync( GetSql(), map, Params, GetTransaction(), buffered, "Id", timeout ) ).ToList(); + return result; + } + finally { + ExecuteAfter( result ); + } + } + + /// + /// 获取实体集合 + /// + public virtual async Task> ExecuteQueryAsync( Func map, int? timeout = null, bool buffered = true ) { + List result = default; + try { + if ( ExecuteBefore() == false ) + return default; + var connection = GetConnection(); + result = ( await connection.QueryAsync( GetSql(), map, Params, GetTransaction(), buffered, "Id", timeout ) ).ToList(); + return result; + } + finally { + ExecuteAfter( result ); + } + } + + #endregion + + #region ExecuteProcedureQuery(执行存储过程获取实体集合) + + /// + /// 执行存储过程获取实体集合 + /// + public virtual List ExecuteProcedureQuery( string procedure, int? timeout = null, bool buffered = true ) { + List result = default; + try { + if ( ExecuteBefore() == false ) + return default; + _sql = GetProcedure( procedure ); + var connection = GetConnection(); + result = connection.Query( GetSql(), Params, GetTransaction(), buffered, timeout, GetProcedureCommandType() ).ToList(); + return result; + } + finally { + ExecuteAfter( result ); + } + } + + /// + /// 执行存储过程获取实体集合 + /// + public virtual List ExecuteProcedureQuery( string procedure, int? timeout = null, bool buffered = true ) { + List result = default; + try { + if ( ExecuteBefore() == false ) + return default; + _sql = GetProcedure( procedure ); + var connection = GetConnection(); + result = connection.Query( GetSql(), Params, GetTransaction(), buffered, timeout, GetProcedureCommandType() ).ToList(); + return result; + } + finally { + ExecuteAfter( result ); + } + } + + /// + /// 执行存储过程获取实体集合 + /// + public virtual List ExecuteProcedureQuery( string procedure, Func map, int? timeout = null, bool buffered = true ) { + List result = default; + try { + if ( ExecuteBefore() == false ) + return default; + _sql = GetProcedure( procedure ); + var connection = GetConnection(); + result = connection.Query( GetSql(), map, Params, GetTransaction(), buffered, "Id", timeout, GetProcedureCommandType() ).ToList(); + return result; + } + finally { + ExecuteAfter( result ); + } + } + + /// + /// 执行存储过程获取实体集合 + /// + public virtual List ExecuteProcedureQuery( string procedure, Func map, int? timeout = null, bool buffered = true ) { + List result = default; + try { + if ( ExecuteBefore() == false ) + return default; + _sql = GetProcedure( procedure ); + var connection = GetConnection(); + result = connection.Query( GetSql(), map, Params, GetTransaction(), buffered, "Id", timeout, GetProcedureCommandType() ).ToList(); + return result; + } + finally { + ExecuteAfter( result ); + } + } + + /// + /// 执行存储过程获取实体集合 + /// + public virtual List ExecuteProcedureQuery( string procedure, Func map, int? timeout = null, bool buffered = true ) { + List result = default; + try { + if ( ExecuteBefore() == false ) + return default; + _sql = GetProcedure( procedure ); + var connection = GetConnection(); + result = connection.Query( GetSql(), map, Params, GetTransaction(), buffered, "Id", timeout, GetProcedureCommandType() ).ToList(); + return result; + } + finally { + ExecuteAfter( result ); + } + } + + /// + /// 执行存储过程获取实体集合 + /// + public virtual List ExecuteProcedureQuery( string procedure, Func map, int? timeout = null, bool buffered = true ) { + List result = default; + try { + if ( ExecuteBefore() == false ) + return default; + _sql = GetProcedure( procedure ); + var connection = GetConnection(); + result = connection.Query( GetSql(), map, Params, GetTransaction(), buffered, "Id", timeout, GetProcedureCommandType() ).ToList(); + return result; + } + finally { + ExecuteAfter( result ); + } + } + + /// + /// 执行存储过程获取实体集合 + /// + public virtual List ExecuteProcedureQuery( string procedure, Func map, int? timeout = null, bool buffered = true ) { + List result = default; + try { + if ( ExecuteBefore() == false ) + return default; + _sql = GetProcedure( procedure ); + var connection = GetConnection(); + result = connection.Query( GetSql(), map, Params, GetTransaction(), buffered, "Id", timeout, GetProcedureCommandType() ).ToList(); + return result; + } + finally { + ExecuteAfter( result ); + } + } + + /// + /// 执行存储过程获取实体集合 + /// + public virtual List ExecuteProcedureQuery( string procedure, Func map, int? timeout = null, bool buffered = true ) { + List result = default; + try { + if ( ExecuteBefore() == false ) + return default; + _sql = GetProcedure( procedure ); + var connection = GetConnection(); + result = connection.Query( GetSql(), map, Params, GetTransaction(), buffered, "Id", timeout, GetProcedureCommandType() ).ToList(); + return result; + } + finally { + ExecuteAfter( result ); + } + } + + #endregion + + #region ExecuteProcedureQueryAsync(执行存储过程获取实体集合) + + /// + /// 执行存储过程获取实体集合 + /// + public virtual async Task> ExecuteProcedureQueryAsync( string procedure, int? timeout = null ) { + List result = default; + try { + if ( ExecuteBefore() == false ) + return default; + _sql = GetProcedure( procedure ); + var connection = GetConnection(); + result = ( await connection.QueryAsync( GetSql(), Params, GetTransaction(), timeout, GetProcedureCommandType() ) ).ToList(); + return result; + } + finally { + ExecuteAfter( result ); + } + } + + /// + /// 执行存储过程获取实体集合 + /// + public virtual async Task> ExecuteProcedureQueryAsync( string procedure, int? timeout = null ) { + List result = default; + try { + if ( ExecuteBefore() == false ) + return default; + _sql = GetProcedure( procedure ); + var connection = GetConnection(); + result = ( await connection.QueryAsync( GetSql(), Params, GetTransaction(), timeout, GetProcedureCommandType() ) ).ToList(); + return result; + } + finally { + ExecuteAfter( result ); + } + } + + /// + /// 执行存储过程获取实体集合 + /// + public virtual async Task> ExecuteProcedureQueryAsync( string procedure, Func map, int? timeout = null, bool buffered = true ) { + List result = default; + try { + if ( ExecuteBefore() == false ) + return default; + _sql = GetProcedure( procedure ); + var connection = GetConnection(); + result = ( await connection.QueryAsync( GetSql(), map, Params, GetTransaction(), buffered, "Id", timeout, GetProcedureCommandType() ) ).ToList(); + return result; + } + finally { + ExecuteAfter( result ); + } + } + + /// + /// 执行存储过程获取实体集合 + /// + public virtual async Task> ExecuteProcedureQueryAsync( string procedure, Func map, int? timeout = null, bool buffered = true ) { + List result = default; + try { + if ( ExecuteBefore() == false ) + return default; + _sql = GetProcedure( procedure ); + var connection = GetConnection(); + result = ( await connection.QueryAsync( GetSql(), map, Params, GetTransaction(), buffered, "Id", timeout, GetProcedureCommandType() ) ).ToList(); + return result; + } + finally { + ExecuteAfter( result ); + } + } + + /// + /// 执行存储过程获取实体集合 + /// + public virtual async Task> ExecuteProcedureQueryAsync( string procedure, Func map, int? timeout = null, bool buffered = true ) { + List result = default; + try { + if ( ExecuteBefore() == false ) + return default; + _sql = GetProcedure( procedure ); + var connection = GetConnection(); + result = ( await connection.QueryAsync( GetSql(), map, Params, GetTransaction(), buffered, "Id", timeout, GetProcedureCommandType() ) ).ToList(); + return result; + } + finally { + ExecuteAfter( result ); + } + } + + /// + /// 执行存储过程获取实体集合 + /// + public virtual async Task> ExecuteProcedureQueryAsync( string procedure, Func map, int? timeout = null, bool buffered = true ) { + List result = default; + try { + if ( ExecuteBefore() == false ) + return default; + _sql = GetProcedure( procedure ); + var connection = GetConnection(); + result = ( await connection.QueryAsync( GetSql(), map, Params, GetTransaction(), buffered, "Id", timeout, GetProcedureCommandType() ) ).ToList(); + return result; + } + finally { + ExecuteAfter( result ); + } + } + + /// + /// 执行存储过程获取实体集合 + /// + public virtual async Task> ExecuteProcedureQueryAsync( string procedure, Func map, int? timeout = null, bool buffered = true ) { + List result = default; + try { + if ( ExecuteBefore() == false ) + return default; + _sql = GetProcedure( procedure ); + var connection = GetConnection(); + result = ( await connection.QueryAsync( GetSql(), map, Params, GetTransaction(), buffered, "Id", timeout, GetProcedureCommandType() ) ).ToList(); + return result; + } + finally { + ExecuteAfter( result ); + } + } + + /// + /// 执行存储过程获取实体集合 + /// + public virtual async Task> ExecuteProcedureQueryAsync( string procedure, Func map, int? timeout = null, bool buffered = true ) { + List result = default; + try { + if ( ExecuteBefore() == false ) + return default; + _sql = GetProcedure( procedure ); + var connection = GetConnection(); + result = ( await connection.QueryAsync( GetSql(), map, Params, GetTransaction(), buffered, "Id", timeout, GetProcedureCommandType() ) ).ToList(); + return result; + } + finally { + ExecuteAfter( result ); + } + } + + #endregion + + #region 钩子方法 + + /// + /// 执行前操作,返回false停止执行 + /// + protected virtual bool ExecuteBefore() { + return true; + } + + /// + /// 执行后操作 + /// + /// 结果 + protected virtual void ExecuteAfter( object result ) { + SetPreviousSql(); + Clear(); + WriteLog(); + } + + #endregion + + #region GetSql(获取Sql语句) + + /// + /// 获取Sql语句 + /// + public string GetSql() { + return _sql ??= SqlBuilder.GetSql(); + } + + #endregion + + #region SetSql(设置Sql语句) + + /// + /// 设置Sql语句 + /// + /// sql语句或存储过程名 + protected void SetSql( string sql ) { + _sql = sql; + } + + #endregion + + #region GetProcedure(获取存储过程名称) + + /// + /// 获取存储过程名称 + /// + /// 存储过程 + protected virtual string GetProcedure( string procedure ) { + return new TableItem( Dialect, procedure ).ToResult(); + } + + #endregion + + #region GetProcedureCommandType(获取存储过程命令类型) + + /// + /// 获取存储过程命令类型 + /// + protected virtual CommandType GetProcedureCommandType() { + return CommandType.StoredProcedure; + } + + #endregion + + #region SetPreviousSql(设置前一次执行的Sql及参数) + + /// + /// 设置前一次执行的Sql及参数 + /// + protected virtual void SetPreviousSql() { + var sqlParams = GetSqlParams(); + PreviousSql = new SqlBuilderResult( _sql, sqlParams, ParamLiteralsResolver,ParameterManager ); + } + + #endregion + + #region GetSqlParams(获取Sql参数列表) + + /// + /// 获取Sql参数列表 + /// + protected List GetSqlParams() { + var result = new List(); + if ( _parameters == null ) + return result; + foreach ( var parameterName in _parameters.ParameterNames ) { + if ( ParameterManager.Contains( parameterName ) ) { + var param = ParameterManager.GetParam( parameterName ); + if ( param.Direction != ParameterDirection.Input ) + param = new SqlParam( param.Name, _parameters.Get( parameterName ), param.DbType, param.Direction, param.Size, param.Precision, param.Scale ); + result.Add( param ); + continue; + } + var sqlParam = new SqlParam( ParameterManager.NormalizeName( parameterName ), _parameters.Get( parameterName ) ); + result.Add( sqlParam ); + } + return result; + } + + #endregion + + #region Clear(清理) + + /// + /// 清理 + /// + protected void Clear() { + _sql = null; + SqlBuilder.Clear(); + ClearParams(); + } + + #endregion + + #region WriteLog(写日志) + + /// + /// 写日志 + /// + protected virtual void WriteLog() { + if ( Logger.IsEnabled( LogLevel.Trace ) == false ) + return; + var message = new StringBuilder(); + message.AppendLine( "标题: {Caption}" ); + message.AppendLine( "原始Sql:" ); + message.AppendLine( "{Sql}" ); + message.AppendLine( "调试Sql:" ); + message.AppendLine( "{DebugSql}" ); + message.AppendLine( "Sql参数:" ); + foreach ( var param in PreviousSql.GetParams() ) { + message.Append( "参数名: " ); + message.Append( param.Name ); + if ( param.Value != null ) { + message.Append( ",参数值: " ); + message.Append( param.Value ); + } + if ( param.DbType != null ) { + message.Append( ",参数类型: " ); + message.Append( param.DbType ); + } + if ( param.Direction != null ) { + message.Append( ",参数方向: " ); + message.Append( param.Direction ); + } + if ( param.Size != null ) { + message.Append( ",Size: " ); + message.Append( param.Size ); + } + if ( param.Precision != null ) { + message.Append( ",Precision: " ); + message.Append( param.Precision ); + } + if ( param.Scale != null ) { + message.Append( ",Scale: " ); + message.Append( param.Scale ); + } + message.AppendLine(); + } + Logger.LogTrace( message.ToString(), "Sql日志", PreviousSql.GetSql(), PreviousSql.GetDebugSql() ); + } + + #endregion + + #region Dispose(释放资源) + + /// + /// 释放资源 + /// + public void Dispose() { + if ( _connection != null ) + _connection.Dispose(); + _transaction = null; + } + + #endregion + } +} diff --git a/src/Util.Data.Dapper.MySql/04-Util.Data.Dapper.MySql.csproj b/src/Util.Data.Dapper.MySql/04-Util.Data.Dapper.MySql.csproj new file mode 100644 index 00000000..17c9b460 --- /dev/null +++ b/src/Util.Data.Dapper.MySql/04-Util.Data.Dapper.MySql.csproj @@ -0,0 +1,37 @@ + + + + $(NetTargetFramework) + icon.jpg + Util.Data.Dapper.MySql + Util.Data + Util.Data.Dapper.MySql是Util应用框架基于Dapper的数据访问封装类库,用于处理MySql数据库 + + + + + .\obj\Debug\$(NetTargetFramework)\Util.Data.Dapper.MySql.xml + + + + + .\obj\Release\$(NetTargetFramework)\Util.Data.Dapper.MySql.xml + + + + + True + False + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Util.Data.Dapper.MySql/Metadata/MySqlMetadataService.cs b/src/Util.Data.Dapper.MySql/Metadata/MySqlMetadataService.cs new file mode 100644 index 00000000..d51690bd --- /dev/null +++ b/src/Util.Data.Dapper.MySql/Metadata/MySqlMetadataService.cs @@ -0,0 +1,79 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Util.Data.Sql; + +namespace Util.Data.Metadata { + /// + /// MySql数据库元数据服务 + /// + public class MySqlMetadataService : IMetadataService { + /// + /// Sql查询对象 + /// + private readonly ISqlQuery _sqlQuery; + + /// + /// 初始化MySql数据库元数据服务 + /// + /// Sql查询对象 + public MySqlMetadataService( ISqlQuery sqlQuery ) { + _sqlQuery = sqlQuery ?? throw new ArgumentNullException( nameof( sqlQuery ) ); + } + + /// + /// 获取数据库信息 + /// + public DatabaseInfo GetDatabaseInfo() { + var result = GetDatabase(); + result.Tables.AddRange( GetTables() ); + return result; + } + + /// + /// 获取数据库信息 + /// + private DatabaseInfo GetDatabase() { + return _sqlQuery + .AppendSelect( "Database() [Id],Database() [Name]" ) + .ToEntity(); + } + + /// + /// 获取表信息 + /// + private List GetTables() { + SetGetTablesSql(); + var dic = new Dictionary(); + var tables = _sqlQuery.ToList( ( table, column ) => { + if( table == null || column == null ) + return null; + if( dic.ContainsKey( table.Id ) == false ) + dic.Add( table.Id, table ); + TableInfo result = dic[table.Id]; + result.Columns.Add( column ); + return result; + } ).Distinct().ToList(); + return tables; + } + + /// + /// 设置获取表信息Sql + /// + private void SetGetTablesSql() { + _sqlQuery + .Select( "t.Table_Name Id,t.Table_Name Name,t.Table_Comment Comment" ) + .Select( "c.Column_Name Id,c.Column_Name Name,c.Column_Comment Comment" ) + .Select( "c.Data_Type DataType,c.Numeric_Precision Precision,c.Numeric_Scale Scale" ) + .AppendSelect( ",( Case When c.Column_Key = 'PRI' Then 1 Else 0 End ) IsPrimaryKey" ) + .AppendSelect( ",( Case When c.Extra = 'auto_increment' Then 1 Else 0 End ) AS IsAutoIncrement" ) + .AppendSelect( ",( Case When c.Is_Nullable = 'NO' Then 0 Else 1 End ) AS IsNullable" ) + .AppendSelect( ",( Case When c.Column_Type = 'tinyint(1)' Then 1 " ) + .AppendSelect( "When c.Numeric_Precision Is Not Null Then c.Numeric_Precision " ) + .AppendSelect( "When c.Character_Maximum_Length Is Not Null Then c.Character_Maximum_Length Else Null End) Length" ) + .From( "Information_Schema.Tables t" ) + .Join( "Information_Schema.Columns c" ).On( "t.Table_Schema", "c.Table_Schema" ).On( "t.Table_Name", "c.Table_Name" ) + .AppendWhere( "[t].[Table_Schema] = Database()" ); + } + } +} diff --git a/src/Util.Data.Dapper.MySql/Metadata/MySqlTypeConverter.cs b/src/Util.Data.Dapper.MySql/Metadata/MySqlTypeConverter.cs new file mode 100644 index 00000000..8ca890d0 --- /dev/null +++ b/src/Util.Data.Dapper.MySql/Metadata/MySqlTypeConverter.cs @@ -0,0 +1,55 @@ +using System; +using System.Data; + +namespace Util.Data.Metadata { + /// + /// MySql数据类型转换器 + /// + public class MySqlTypeConverter : ITypeConverter { + /// + public DbType? ToType( string dataType, int? length = null ) { + if ( dataType.IsEmpty() ) + return null; + switch ( dataType.ToLower() ) { + case "char": + return length == 36 ? DbType.Guid : DbType.String; + case "varchar": + case "tinytext": + case "mediumtext": + case "longtext": + case "text": + return DbType.String; + case "tinyint": + return length == 1 ? DbType.Boolean : DbType.Byte; + case "smallint": + return DbType.Int16; + case "integer": + case "int": + case "mediumint": + return DbType.Int32; + case "bigint": + return DbType.Int64; + case "float": + return DbType.Single; + case "double": + return DbType.Double; + case "decimal": + case "numeric": + return DbType.Decimal; + case "date": + return DbType.Date; + case "time": + return DbType.Time; + case "datetime": + case "timestamp": + return DbType.DateTime; + case "tinyblob": + case "mediumblob": + case "longblob": + case "blob": + return DbType.Binary; + } + throw new NotImplementedException( dataType ); + } + } +} diff --git a/src/Util.Data.Dapper.MySql/Sql/Builders/MySqlBuilder.cs b/src/Util.Data.Dapper.MySql/Sql/Builders/MySqlBuilder.cs new file mode 100644 index 00000000..d7dbb205 --- /dev/null +++ b/src/Util.Data.Dapper.MySql/Sql/Builders/MySqlBuilder.cs @@ -0,0 +1,39 @@ +using Util.Data.Sql.Builders.Caches; +using Util.Data.Sql.Builders.Params; + +namespace Util.Data.Sql.Builders { + /// + /// MySql Sql生成器 + /// + public class MySqlBuilder : SqlBuilderBase { + /// + /// 初始化MySql Sql生成器 + /// + /// Sql参数管理器 + public MySqlBuilder( IParameterManager parameterManager = null ) + : base( parameterManager ) { + } + + /// + protected override IDialect CreateDialect() { + return MySqlDialect.Instance; + } + + /// + protected override IColumnCache CreateColumnCache() { + return MySqlColumnCache.Instance; + } + + /// + public override ISqlBuilder New() { + return new MySqlBuilder( ParameterManager ); + } + + /// + public override ISqlBuilder Clone() { + var result = new MySqlBuilder(); + result.Clone( this ); + return result; + } + } +} diff --git a/src/Util.Data.Dapper.MySql/Sql/Builders/MySqlColumnCache.cs b/src/Util.Data.Dapper.MySql/Sql/Builders/MySqlColumnCache.cs new file mode 100644 index 00000000..848c9e01 --- /dev/null +++ b/src/Util.Data.Dapper.MySql/Sql/Builders/MySqlColumnCache.cs @@ -0,0 +1,36 @@ +using System.Collections.Concurrent; +using Util.Data.Sql.Builders.Caches; + +namespace Util.Data.Sql.Builders { + /// + /// MySql列缓存 + /// + public class MySqlColumnCache : ColumnCacheBase { + /// + /// 列名缓存 + /// + private readonly ConcurrentDictionary _cache; + + /// + /// 封闭构造方法 + /// + private MySqlColumnCache() : base( MySqlDialect.Instance ) { + _cache = new ConcurrentDictionary(); + } + + /// + /// MySql列缓存实例 + /// + public static readonly IColumnCache Instance = new MySqlColumnCache(); + + /// + public override string GetSafeColumns( string columns ) { + return _cache.GetOrAdd( columns.GetHashCode(), key => NormalizeColumns( columns ) ); + } + + /// + public override string GetSafeColumn( string column ) { + return _cache.GetOrAdd( column.GetHashCode(), key => NormalizeColumn( column ) ); + } + } +} diff --git a/src/Util.Data.Dapper.MySql/Sql/Builders/MySqlDialect.cs b/src/Util.Data.Dapper.MySql/Sql/Builders/MySqlDialect.cs new file mode 100644 index 00000000..6670bffb --- /dev/null +++ b/src/Util.Data.Dapper.MySql/Sql/Builders/MySqlDialect.cs @@ -0,0 +1,34 @@ +using Util.Data.Sql.Builders.Core; + +namespace Util.Data.Sql.Builders { + /// + /// MySql方言 + /// + public class MySqlDialect : DialectBase { + /// + /// 封闭构造方法 + /// + private MySqlDialect() { + } + + /// + /// MySql方言实例 + /// + public static readonly IDialect Instance = new MySqlDialect(); + + /// + public override string GetOpeningIdentifier() { + return "`"; + } + + /// + public override string GetClosingIdentifier() { + return "`"; + } + + /// + public override string GetPrefix() { + return "@"; + } + } +} diff --git a/src/Util.Data.Dapper.MySql/Sql/Builders/MySqlExistsSqlBuilder.cs b/src/Util.Data.Dapper.MySql/Sql/Builders/MySqlExistsSqlBuilder.cs new file mode 100644 index 00000000..3e6fde4b --- /dev/null +++ b/src/Util.Data.Dapper.MySql/Sql/Builders/MySqlExistsSqlBuilder.cs @@ -0,0 +1,52 @@ +using System.Text; + +namespace Util.Data.Sql.Builders { + /// + /// 判断是否存在Sql生成器 + /// + public class MySqlExistsSqlBuilder : IExistsSqlBuilder { + /// + /// Sql生成器 + /// + private readonly ISqlBuilder _sqlBuilder; + + /// + /// 初始化判断是否存在Sql生成器 + /// + /// Sql生成器 + public MySqlExistsSqlBuilder( ISqlBuilder sqlBuilder ) { + _sqlBuilder = sqlBuilder; + } + + /// + /// 获取Sql + /// + public string GetSql() { + InitSelect(); + return GetResult(); + } + + /// + /// 将Select子句初始化为1 + /// + private void InitSelect() { + _sqlBuilder.ClearSelect(); + _sqlBuilder.AppendSelect( "1" ); + } + + /// + /// 获取结果 + /// + private string GetResult() { + var result = new StringBuilder(); + result.AppendLine( "Select Case" ); + result.AppendLine( " When Exists (" ); + _sqlBuilder.AppendTo( result ); + result.AppendLine( ")" ); + result.AppendLine( " Then true" ); + result.AppendLine( " Else false " ); + result.Append( "End" ); + return result.ToString(); + } + } +} diff --git a/src/Util.Data.Dapper.MySql/Sql/MySqlDatabaseFactory.cs b/src/Util.Data.Dapper.MySql/Sql/MySqlDatabaseFactory.cs new file mode 100644 index 00000000..9794035d --- /dev/null +++ b/src/Util.Data.Dapper.MySql/Sql/MySqlDatabaseFactory.cs @@ -0,0 +1,16 @@ +using MySqlConnector; + +namespace Util.Data.Sql { + /// + /// MySql数据库工厂 + /// + public class MySqlDatabaseFactory : IDatabaseFactory { + /// + /// 创建数据库信息 + /// + /// 数据库连接字符串 + public IDatabase Create( string connection ) { + return new DefaultDatabase( new MySqlConnection( connection ) ); + } + } +} diff --git a/src/Util.Data.Dapper.MySql/Sql/MySqlExecutor.cs b/src/Util.Data.Dapper.MySql/Sql/MySqlExecutor.cs new file mode 100644 index 00000000..b6c939c4 --- /dev/null +++ b/src/Util.Data.Dapper.MySql/Sql/MySqlExecutor.cs @@ -0,0 +1,18 @@ +using System; + +namespace Util.Data.Sql { + /// + /// MySql Sql执行器 + /// + public class MySqlExecutor : MySqlExecutorBase { + /// + /// 初始化MySql Sql执行器 + /// + /// 服务提供器 + /// Sql配置 + /// 数据库信息,用于接入其它数据源,比如EF DbContext + public MySqlExecutor( IServiceProvider serviceProvider, SqlOptions options, IDatabase database = null ) + : base( serviceProvider, options, database ) { + } + } +} diff --git a/src/Util.Data.Dapper.MySql/Sql/MySqlExecutorBase.cs b/src/Util.Data.Dapper.MySql/Sql/MySqlExecutorBase.cs new file mode 100644 index 00000000..b67b5cb5 --- /dev/null +++ b/src/Util.Data.Dapper.MySql/Sql/MySqlExecutorBase.cs @@ -0,0 +1,39 @@ +using System; +using Util.Data.Sql.Builders; + +namespace Util.Data.Sql { + /// + /// MySql Sql执行器 + /// + public abstract class MySqlExecutorBase : SqlExecutorBase { + /// + /// 初始化MySql Sql执行器 + /// + /// 服务提供器 + /// Sql配置 + /// 数据库信息,用于接入其它数据源,比如EF DbContext + protected MySqlExecutorBase( IServiceProvider serviceProvider, SqlOptions options, IDatabase database ) : base( serviceProvider, options, database ) { + } + + /// + /// 创建Sql生成器 + /// + protected override ISqlBuilder CreateSqlBuilder() { + return new MySqlBuilder(); + } + + /// + /// 创建判断是否存在Sql生成器 + /// + protected override IExistsSqlBuilder CreatExistsSqlBuilder( ISqlBuilder sqlBuilder ) { + return new MySqlExistsSqlBuilder( sqlBuilder ); + } + + /// + /// 创建数据库工厂 + /// + protected override IDatabaseFactory CreateDatabaseFactory() { + return new MySqlDatabaseFactory(); + } + } +} diff --git a/src/Util.Data.Dapper.MySql/Sql/MySqlExecutorOptionsExtension.cs b/src/Util.Data.Dapper.MySql/Sql/MySqlExecutorOptionsExtension.cs new file mode 100644 index 00000000..0d9585af --- /dev/null +++ b/src/Util.Data.Dapper.MySql/Sql/MySqlExecutorOptionsExtension.cs @@ -0,0 +1,32 @@ +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; +using Microsoft.Extensions.Hosting; +using Util.Configs; + +namespace Util.Data.Sql { + /// + /// MySql Sql执行器配置扩展 + /// + public class MySqlExecutorOptionsExtension : OptionsExtensionBase + where TService : ISqlExecutor + where TImplementation : MySqlExecutorBase, TService { + /// + /// Sql配置 + /// + private readonly SqlOptions _options; + + /// + /// 初始化MySql Sql执行器配置扩展 + /// + /// Sql配置 + public MySqlExecutorOptionsExtension( SqlOptions options ) { + _options = options; + } + + /// + public override void ConfigureServices( HostBuilderContext context, IServiceCollection services ) { + services.TryAddTransient( typeof( TService ), typeof( TImplementation ) ); + services.TryAddSingleton( typeof( SqlOptions ), ( sp ) => _options ); + } + } +} diff --git a/src/Util.Data.Dapper.MySql/Sql/MySqlQuery.cs b/src/Util.Data.Dapper.MySql/Sql/MySqlQuery.cs new file mode 100644 index 00000000..9b154c2f --- /dev/null +++ b/src/Util.Data.Dapper.MySql/Sql/MySqlQuery.cs @@ -0,0 +1,18 @@ +using System; + +namespace Util.Data.Sql { + /// + /// MySql Sql查询对象 + /// + public class MySqlQuery : MySqlQueryBase { + /// + /// 初始化MySql Sql查询对象 + /// + /// 服务提供器 + /// Sql配置 + /// 数据库信息,用于接入其它数据源,比如EF DbContext + public MySqlQuery( IServiceProvider serviceProvider, SqlOptions options, IDatabase database = null ) + : base( serviceProvider, options, database ) { + } + } +} \ No newline at end of file diff --git a/src/Util.Data.Dapper.MySql/Sql/MySqlQueryBase.cs b/src/Util.Data.Dapper.MySql/Sql/MySqlQueryBase.cs new file mode 100644 index 00000000..7f34234c --- /dev/null +++ b/src/Util.Data.Dapper.MySql/Sql/MySqlQueryBase.cs @@ -0,0 +1,33 @@ +using System; +using Util.Data.Sql.Builders; + +namespace Util.Data.Sql { + /// + /// MySql Sql查询对象 + /// + public abstract class MySqlQueryBase : SqlQueryBase { + /// + /// 初始化MySql Sql查询对象 + /// + /// 服务提供器 + /// Sql配置 + /// 数据库信息,用于接入其它数据源,比如EF DbContext + protected MySqlQueryBase( IServiceProvider serviceProvider, SqlOptions options, IDatabase database ) : base( serviceProvider, options, database ) { + } + + /// + protected override ISqlBuilder CreateSqlBuilder() { + return new MySqlBuilder(); + } + + /// + protected override IExistsSqlBuilder CreatExistsSqlBuilder( ISqlBuilder sqlBuilder ) { + return new MySqlExistsSqlBuilder( sqlBuilder ); + } + + /// + protected override IDatabaseFactory CreateDatabaseFactory() { + return new MySqlDatabaseFactory(); + } + } +} diff --git a/src/Util.Data.Dapper.MySql/Sql/MySqlQueryOptionsExtension.cs b/src/Util.Data.Dapper.MySql/Sql/MySqlQueryOptionsExtension.cs new file mode 100644 index 00000000..99f8a04d --- /dev/null +++ b/src/Util.Data.Dapper.MySql/Sql/MySqlQueryOptionsExtension.cs @@ -0,0 +1,32 @@ +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; +using Microsoft.Extensions.Hosting; +using Util.Configs; + +namespace Util.Data.Sql { + /// + /// MySql Sql查询对象配置扩展 + /// + public class MySqlQueryOptionsExtension : OptionsExtensionBase + where TService : ISqlQuery + where TImplementation : MySqlQueryBase, TService { + /// + /// Sql配置 + /// + private readonly SqlOptions _options; + + /// + /// 初始化MySql Sql查询对象配置扩展 + /// + /// Sql配置 + public MySqlQueryOptionsExtension( SqlOptions options ) { + _options = options; + } + + /// + public override void ConfigureServices( HostBuilderContext context, IServiceCollection services ) { + services.TryAddTransient( typeof( TService ), typeof( TImplementation ) ); + services.TryAddSingleton( typeof( SqlOptions ), ( sp ) => _options ); + } + } +} diff --git a/src/Util.Data.Dapper.MySql/Sql/OptionsExtensions.cs b/src/Util.Data.Dapper.MySql/Sql/OptionsExtensions.cs new file mode 100644 index 00000000..c07af869 --- /dev/null +++ b/src/Util.Data.Dapper.MySql/Sql/OptionsExtensions.cs @@ -0,0 +1,120 @@ +using System; +using Util.Configs; + +namespace Util.Data.Sql { + /// + /// MySql数据库操作扩展 + /// + public static class OptionsExtensions { + + #region UseMySqlQuery(配置MySql Sql查询对象) + + /// + /// 配置MySql Sql查询对象 + /// + /// 配置项 + public static Options UseMySqlQuery( this Options options ) { + return options.UseMySqlQuery( "" ); + } + + /// + /// 配置MySql Sql查询对象 + /// + /// 配置项 + /// 数据库连接字符串 + public static Options UseMySqlQuery( this Options options, string connection ) { + return options.UseMySqlQuery( connection ); + } + + /// + /// 配置MySql Sql查询对象 + /// + /// 配置项 + /// 配置操作 + public static Options UseMySqlQuery( this Options options, Action setupAction ) { + return options.UseMySqlQuery( setupAction ); + } + + /// + /// 配置MySql Sql查询对象 + /// + /// 配置项 + /// 数据库连接字符串 + public static Options UseMySqlQuery( this Options options, string connection ) + where TService : ISqlQuery + where TImplementation : MySqlQueryBase, TService { + return options.UseMySqlQuery( t => t.ConnectionString( connection ) ); + } + + /// + /// 配置MySql Sql查询对象 + /// + /// 配置项 + /// 配置操作 + public static Options UseMySqlQuery( this Options options, Action setupAction ) + where TService : ISqlQuery + where TImplementation : MySqlQueryBase, TService { + var sqlOptions = new SqlOptions(); + setupAction?.Invoke( sqlOptions ); + options.AddExtension( new MySqlQueryOptionsExtension( sqlOptions ) ); + return options; + } + + #endregion + + #region UseMySqlExecutor(配置MySql Sql执行器) + + /// + /// 配置MySql Sql执行器 + /// + /// 配置项 + public static Options UseMySqlExecutor( this Options options ) { + return options.UseMySqlExecutor( "" ); + } + + /// + /// 配置MySql Sql执行器 + /// + /// 配置项 + /// 数据库连接字符串 + public static Options UseMySqlExecutor( this Options options, string connection ) { + return options.UseMySqlExecutor( connection ); + } + + /// + /// 配置MySql Sql执行器 + /// + /// 配置项 + /// 配置操作 + public static Options UseMySqlExecutor( this Options options, Action setupAction ) { + return options.UseMySqlExecutor( setupAction ); + } + + /// + /// 配置MySql Sql执行器 + /// + /// 配置项 + /// 数据库连接字符串 + public static Options UseMySqlExecutor( this Options options, string connection ) + where TService : ISqlExecutor + where TImplementation : MySqlExecutorBase, TService { + return options.UseMySqlExecutor( t => t.ConnectionString( connection ) ); + } + + /// + /// 配置MySql Sql执行器 + /// + /// 配置项 + /// 配置操作 + public static Options UseMySqlExecutor( this Options options, Action setupAction ) + where TService : ISqlExecutor + where TImplementation : MySqlExecutorBase, TService { + var sqlOptions = new SqlOptions(); + setupAction?.Invoke( sqlOptions ); + options.AddExtension( new MySqlExecutorOptionsExtension( sqlOptions ) ); + return options; + } + + #endregion + } +} diff --git a/src/Util.Data.Dapper.PostgreSql/03-Util.Data.Dapper.PostgreSql.csproj b/src/Util.Data.Dapper.PostgreSql/03-Util.Data.Dapper.PostgreSql.csproj new file mode 100644 index 00000000..9fd4d295 --- /dev/null +++ b/src/Util.Data.Dapper.PostgreSql/03-Util.Data.Dapper.PostgreSql.csproj @@ -0,0 +1,37 @@ + + + + $(NetTargetFramework) + icon.jpg + Util.Data.Dapper.PostgreSql + Util.Data + Util.Data.Dapper.PostgreSql是Util应用框架基于Dapper的数据访问封装类库,用于处理PostgreSql数据库 + + + + + .\obj\Debug\$(NetTargetFramework)\Util.Data.Dapper.PostgreSql.xml + + + + + .\obj\Release\$(NetTargetFramework)\Util.Data.Dapper.PostgreSql.xml + + + + + True + False + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Util.Data.Dapper.PostgreSql/Metadata/PostgreSqlMetadataService.cs b/src/Util.Data.Dapper.PostgreSql/Metadata/PostgreSqlMetadataService.cs new file mode 100644 index 00000000..1b28e80c --- /dev/null +++ b/src/Util.Data.Dapper.PostgreSql/Metadata/PostgreSqlMetadataService.cs @@ -0,0 +1,101 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Util.Data.Sql; + +namespace Util.Data.Metadata { + /// + /// PostgreSql数据库元数据服务 + /// + public class PostgreSqlMetadataService : IMetadataService { + /// + /// Sql查询对象 + /// + private readonly ISqlQuery _sqlQuery; + + /// + /// 初始化PostgreSql数据库元数据服务 + /// + /// Sql查询对象 + public PostgreSqlMetadataService( ISqlQuery sqlQuery ) { + _sqlQuery = sqlQuery ?? throw new ArgumentNullException( nameof( sqlQuery ) ); + } + + /// + /// 获取数据库信息 + /// + public DatabaseInfo GetDatabaseInfo() { + var result = GetDatabase(); + result.Tables.AddRange( GetTables() ); + return result; + } + + /// + /// 获取数据库信息 + /// + private DatabaseInfo GetDatabase() { + return _sqlQuery + .Select( "oid Id,datname Name" ) + .From( "pg_database" ) + .AppendWhere( "datname=current_database()" ) + .ToEntity(); + } + + /// + /// 获取表信息 + /// + private List GetTables() { + SetGetTablesSql(); + var dic = new Dictionary(); + var tables = _sqlQuery.ToList( ( table, column ) => { + if( table == null || column == null ) + return null; + if( dic.ContainsKey( table.Id ) == false ) + dic.Add( table.Id, table ); + TableInfo result = dic[table.Id]; + result.Columns.Add( column ); + return result; + } ).Distinct().ToList(); + return tables; + } + + /// + /// 设置获取表信息Sql + /// + private void SetGetTablesSql() { + _sqlQuery + .Select( "c1.oid Id,t.tablename Name,t.schemaname Schema" ) + .AppendSelect( ",obj_description(c1.oid) [Comment]" ) + .Select( "c.*" ) + .From( "pg_tables t" ) + .Join( "pg_class c1" ).On( "t.tablename", "c1.relname" ) + .Join( GetColumnsSql(), "c" ).On( "c.table_id", "c1.oid" ) + .In( "t.schemaname", t => t + .Select( "schema_name" ) + .From( "information_schema.schemata" ) + .AppendWhere( "catalog_name=current_database()" ) + .AppendWhere( "schema_name != 'information_schema'" ) + .AppendWhere( "schema_name not like 'pg_%'" ) + ); + } + + /// + /// 获取列信息子查询 + /// + private ISqlBuilder GetColumnsSql() { + return _sqlQuery.NewSqlBuilder() + .Select( "a.attrelid table_id,a.attname Id,a.attname Name,col.udt_name DataType" ) + .Select( "col.numeric_precision Precision,col.numeric_scale Scale" ) + .AppendSelect( ",Coalesce(col.character_maximum_length, col.numeric_precision, -1) [Length]" ) + .AppendSelect( ",( Case a.attnotnull When 't' Then 0 Else 1 End ) [IsNullable]" ) + .AppendSelect( ",( Case a.attnum When con.conkey[[1]] Then 1 Else 0 End ) [IsPrimaryKey]" ) + .AppendSelect( ",( Case When col.is_identity='YES' Then 1 Else 0 End ) [IsAutoIncrement]" ) + .AppendSelect( ",col_description( a.attrelid, a.attnum ) [Comment]" ) + .From( "pg_attribute a" ) + .Join( "pg_class c2" ).On( "a.attrelid", "c2.oid" ) + .Join( "pg_constraint con" ).On( "con.conrelid", "c2.oid" ).AppendOn( "con.contype = 'p'" ) + .Join( "pg_namespace n" ).On( "n.oid", "c2.relnamespace" ) + .Join( "information_schema.columns col" ).On( "col.table_schema", "n.nspname" ).On( "col.table_name", "c2.relname" ).On( "col.column_name", "a.attname" ); + } + } +} diff --git a/src/Util.Data.Dapper.PostgreSql/Metadata/PostgreSqlTypeConverter.cs b/src/Util.Data.Dapper.PostgreSql/Metadata/PostgreSqlTypeConverter.cs new file mode 100644 index 00000000..624d1082 --- /dev/null +++ b/src/Util.Data.Dapper.PostgreSql/Metadata/PostgreSqlTypeConverter.cs @@ -0,0 +1,53 @@ +using System; +using System.Data; + +namespace Util.Data.Metadata { + /// + /// PostgreSql数据类型转换器 + /// + public class PostgreSqlTypeConverter : ITypeConverter { + /// + public DbType? ToType( string dataType, int? length = null ) { + if ( dataType.IsEmpty() ) + return null; + switch ( dataType.ToLower() ) { + case "uuid": + return DbType.Guid; + case "varchar": + case "text": + case "json": + case "jsonb": + case "xml": + return DbType.String; + case "bool": + return DbType.Boolean; + case "char": + return DbType.Byte; + case "int2": + return DbType.Int16; + case "int4": + return DbType.Int32; + case "int8": + return DbType.Int64; + case "float4": + return DbType.Single; + case "float8": + return DbType.Double; + case "numeric": + case "decimal": + return DbType.Decimal; + case "date": + return DbType.Date; + case "time": + case "timetz": + return DbType.Time; + case "timestamp": + case "timestamptz": + return DbType.DateTime; + case "bytea": + return DbType.Binary; + } + throw new NotImplementedException( dataType ); + } + } +} diff --git a/src/Util.Data.Dapper.PostgreSql/Sql/Builders/PostgreSqlBuilder.cs b/src/Util.Data.Dapper.PostgreSql/Sql/Builders/PostgreSqlBuilder.cs new file mode 100644 index 00000000..e3811074 --- /dev/null +++ b/src/Util.Data.Dapper.PostgreSql/Sql/Builders/PostgreSqlBuilder.cs @@ -0,0 +1,39 @@ +using Util.Data.Sql.Builders.Caches; +using Util.Data.Sql.Builders.Params; + +namespace Util.Data.Sql.Builders { + /// + /// PostgreSql Sql生成器 + /// + public class PostgreSqlBuilder : SqlBuilderBase { + /// + /// 初始化PostgreSql Sql生成器 + /// + /// Sql参数管理器 + public PostgreSqlBuilder( IParameterManager parameterManager = null ) + : base( parameterManager ) { + } + + /// + protected override IDialect CreateDialect() { + return PostgreSqlDialect.Instance; + } + + /// + protected override IColumnCache CreateColumnCache() { + return PostgreSqlColumnCache.Instance; + } + + /// + public override ISqlBuilder New() { + return new PostgreSqlBuilder( ParameterManager ); + } + + /// + public override ISqlBuilder Clone() { + var result = new PostgreSqlBuilder(); + result.Clone( this ); + return result; + } + } +} diff --git a/src/Util.Data.Dapper.PostgreSql/Sql/Builders/PostgreSqlColumnCache.cs b/src/Util.Data.Dapper.PostgreSql/Sql/Builders/PostgreSqlColumnCache.cs new file mode 100644 index 00000000..60ccc8f6 --- /dev/null +++ b/src/Util.Data.Dapper.PostgreSql/Sql/Builders/PostgreSqlColumnCache.cs @@ -0,0 +1,36 @@ +using System.Collections.Concurrent; +using Util.Data.Sql.Builders.Caches; + +namespace Util.Data.Sql.Builders { + /// + /// PostgreSql列缓存 + /// + public class PostgreSqlColumnCache : ColumnCacheBase { + /// + /// 列名缓存 + /// + private readonly ConcurrentDictionary _cache; + + /// + /// 封闭构造方法 + /// + private PostgreSqlColumnCache() : base( PostgreSqlDialect.Instance ) { + _cache = new ConcurrentDictionary(); + } + + /// + /// PostgreSql列缓存实例 + /// + public static readonly IColumnCache Instance = new PostgreSqlColumnCache(); + + /// + public override string GetSafeColumns( string columns ) { + return _cache.GetOrAdd( columns.GetHashCode(), key => NormalizeColumns( columns ) ); + } + + /// + public override string GetSafeColumn( string column ) { + return _cache.GetOrAdd( column.GetHashCode(), key => NormalizeColumn( column ) ); + } + } +} diff --git a/src/Util.Data.Dapper.PostgreSql/Sql/Builders/PostgreSqlDialect.cs b/src/Util.Data.Dapper.PostgreSql/Sql/Builders/PostgreSqlDialect.cs new file mode 100644 index 00000000..adeeb19d --- /dev/null +++ b/src/Util.Data.Dapper.PostgreSql/Sql/Builders/PostgreSqlDialect.cs @@ -0,0 +1,34 @@ +using Util.Data.Sql.Builders.Core; + +namespace Util.Data.Sql.Builders { + /// + /// PostgreSql方言 + /// + public class PostgreSqlDialect : DialectBase { + /// + /// 封闭构造方法 + /// + private PostgreSqlDialect() { + } + + /// + /// PostgreSql方言实例 + /// + public static readonly IDialect Instance = new PostgreSqlDialect(); + + /// + public override string GetOpeningIdentifier() { + return "\""; + } + + /// + public override string GetClosingIdentifier() { + return "\""; + } + + /// + public override string GetPrefix() { + return "@"; + } + } +} diff --git a/src/Util.Data.Dapper.PostgreSql/Sql/Builders/PostgreSqlExistsSqlBuilder.cs b/src/Util.Data.Dapper.PostgreSql/Sql/Builders/PostgreSqlExistsSqlBuilder.cs new file mode 100644 index 00000000..e49216f3 --- /dev/null +++ b/src/Util.Data.Dapper.PostgreSql/Sql/Builders/PostgreSqlExistsSqlBuilder.cs @@ -0,0 +1,52 @@ +using System.Text; + +namespace Util.Data.Sql.Builders { + /// + /// 判断是否存在Sql生成器 + /// + public class PostgreSqlExistsSqlBuilder : IExistsSqlBuilder { + /// + /// Sql生成器 + /// + private readonly ISqlBuilder _sqlBuilder; + + /// + /// 初始化判断是否存在Sql生成器 + /// + /// Sql生成器 + public PostgreSqlExistsSqlBuilder( ISqlBuilder sqlBuilder ) { + _sqlBuilder = sqlBuilder; + } + + /// + /// 获取Sql + /// + public string GetSql() { + InitSelect(); + return GetResult(); + } + + /// + /// 将Select子句初始化为1 + /// + private void InitSelect() { + _sqlBuilder.ClearSelect(); + _sqlBuilder.AppendSelect( "1" ); + } + + /// + /// 获取结果 + /// + private string GetResult() { + var result = new StringBuilder(); + result.AppendLine( "Select Case" ); + result.AppendLine( " When Exists (" ); + _sqlBuilder.AppendTo( result ); + result.AppendLine( ")" ); + result.AppendLine( " Then Cast(1 As Bit)" ); + result.AppendLine( " Else Cast(0 As Bit) " ); + result.Append( "End" ); + return result.ToString(); + } + } +} diff --git a/src/Util.Data.Dapper.PostgreSql/Sql/OptionsExtensions.cs b/src/Util.Data.Dapper.PostgreSql/Sql/OptionsExtensions.cs new file mode 100644 index 00000000..2aced74a --- /dev/null +++ b/src/Util.Data.Dapper.PostgreSql/Sql/OptionsExtensions.cs @@ -0,0 +1,120 @@ +using System; +using Util.Configs; + +namespace Util.Data.Sql { + /// + /// PostgreSql数据库操作扩展 + /// + public static class OptionsExtensions { + + #region UsePgSqlQuery(配置PostgreSql Sql查询对象) + + /// + /// 配置PostgreSql Sql查询对象 + /// + /// 配置项 + public static Options UsePgSqlQuery( this Options options ) { + return options.UsePgSqlQuery( "" ); + } + + /// + /// 配置PostgreSql Sql查询对象 + /// + /// 配置项 + /// 数据库连接字符串 + public static Options UsePgSqlQuery( this Options options, string connection ) { + return options.UsePgSqlQuery( connection ); + } + + /// + /// 配置PostgreSql Sql查询对象 + /// + /// 配置项 + /// 配置操作 + public static Options UsePgSqlQuery( this Options options, Action setupAction ) { + return options.UsePgSqlQuery( setupAction ); + } + + /// + /// 配置PostgreSql Sql查询对象 + /// + /// 配置项 + /// 数据库连接字符串 + public static Options UsePgSqlQuery( this Options options, string connection ) + where TService : ISqlQuery + where TImplementation : PostgreSqlQueryBase, TService { + return options.UsePgSqlQuery( t => t.ConnectionString( connection ) ); + } + + /// + /// 配置PostgreSql Sql查询对象 + /// + /// 配置项 + /// 配置操作 + public static Options UsePgSqlQuery( this Options options, Action setupAction ) + where TService : ISqlQuery + where TImplementation : PostgreSqlQueryBase, TService { + var sqlOptions = new SqlOptions(); + setupAction?.Invoke( sqlOptions ); + options.AddExtension( new PostgreSqlQueryOptionsExtension( sqlOptions ) ); + return options; + } + + #endregion + + #region UsePgSqlExecutor(配置PostgreSql Sql执行器) + + /// + /// 配置PostgreSql Sql执行器 + /// + /// 配置项 + public static Options UsePgSqlExecutor( this Options options ) { + return options.UsePgSqlExecutor( "" ); + } + + /// + /// 配置PostgreSql Sql执行器 + /// + /// 配置项 + /// 数据库连接字符串 + public static Options UsePgSqlExecutor( this Options options, string connection ) { + return options.UsePgSqlExecutor( connection ); + } + + /// + /// 配置PostgreSql Sql执行器 + /// + /// 配置项 + /// 配置操作 + public static Options UsePgSqlExecutor( this Options options, Action setupAction ) { + return options.UsePgSqlExecutor( setupAction ); + } + + /// + /// 配置PostgreSql Sql执行器 + /// + /// 配置项 + /// 数据库连接字符串 + public static Options UsePgSqlExecutor( this Options options, string connection ) + where TService : ISqlExecutor + where TImplementation : PostgreSqlExecutorBase, TService { + return options.UsePgSqlExecutor( t => t.ConnectionString( connection ) ); + } + + /// + /// 配置PostgreSql Sql执行器 + /// + /// 配置项 + /// 配置操作 + public static Options UsePgSqlExecutor( this Options options, Action setupAction ) + where TService : ISqlExecutor + where TImplementation : PostgreSqlExecutorBase, TService { + var sqlOptions = new SqlOptions(); + setupAction?.Invoke( sqlOptions ); + options.AddExtension( new PostgreSqlExecutorOptionsExtension( sqlOptions ) ); + return options; + } + + #endregion + } +} diff --git a/src/Util.Data.Dapper.PostgreSql/Sql/PostgreSqlDatabaseFactory.cs b/src/Util.Data.Dapper.PostgreSql/Sql/PostgreSqlDatabaseFactory.cs new file mode 100644 index 00000000..f402d2a8 --- /dev/null +++ b/src/Util.Data.Dapper.PostgreSql/Sql/PostgreSqlDatabaseFactory.cs @@ -0,0 +1,16 @@ +using Npgsql; + +namespace Util.Data.Sql { + /// + /// PostgreSql数据库工厂 + /// + public class PostgreSqlDatabaseFactory : IDatabaseFactory { + /// + /// 创建数据库信息 + /// + /// 数据库连接字符串 + public IDatabase Create( string connection ) { + return new DefaultDatabase( new NpgsqlConnection( connection ) ); + } + } +} diff --git a/src/Util.Data.Dapper.PostgreSql/Sql/PostgreSqlExecutor.cs b/src/Util.Data.Dapper.PostgreSql/Sql/PostgreSqlExecutor.cs new file mode 100644 index 00000000..2c814301 --- /dev/null +++ b/src/Util.Data.Dapper.PostgreSql/Sql/PostgreSqlExecutor.cs @@ -0,0 +1,18 @@ +using System; + +namespace Util.Data.Sql { + /// + /// PostgreSql Sql执行器 + /// + public class PostgreSqlExecutor : PostgreSqlExecutorBase { + /// + /// 初始化PostgreSql Sql执行器 + /// + /// 服务提供器 + /// Sql配置 + /// 数据库信息,用于接入其它数据源,比如EF DbContext + public PostgreSqlExecutor( IServiceProvider serviceProvider, SqlOptions options, IDatabase database = null ) + : base( serviceProvider, options, database ) { + } + } +} diff --git a/src/Util.Data.Dapper.PostgreSql/Sql/PostgreSqlExecutorBase.cs b/src/Util.Data.Dapper.PostgreSql/Sql/PostgreSqlExecutorBase.cs new file mode 100644 index 00000000..780c98a8 --- /dev/null +++ b/src/Util.Data.Dapper.PostgreSql/Sql/PostgreSqlExecutorBase.cs @@ -0,0 +1,67 @@ +using System; +using System.Data; +using Util.Data.Sql.Builders; +using Util.Data.Sql.Builders.Core; + +namespace Util.Data.Sql { + /// + /// PostgreSql Sql执行器 + /// + public abstract class PostgreSqlExecutorBase : SqlExecutorBase { + /// + /// 初始化PostgreSql Sql执行器 + /// + /// 服务提供器 + /// Sql配置 + /// 数据库信息,用于接入其它数据源,比如EF DbContext + protected PostgreSqlExecutorBase( IServiceProvider serviceProvider, SqlOptions options, IDatabase database ) : base( serviceProvider, options, database ) { + } + + /// + /// 创建Sql生成器 + /// + protected override ISqlBuilder CreateSqlBuilder() { + return new PostgreSqlBuilder(); + } + + /// + /// 创建判断是否存在Sql生成器 + /// + protected override IExistsSqlBuilder CreatExistsSqlBuilder( ISqlBuilder sqlBuilder ) { + return new PostgreSqlExistsSqlBuilder( sqlBuilder ); + } + + /// + /// 创建数据库工厂 + /// + protected override IDatabaseFactory CreateDatabaseFactory() { + return new PostgreSqlDatabaseFactory(); + } + + /// + /// 获取存储过程名称 + /// + /// 存储过程 + protected override string GetProcedure( string procedure ) { + if ( IsProcedure( procedure ) ) + return Dialect.ReplaceSql( procedure ); + return new TableItem( Dialect, procedure ).ToResult(); + } + + /// + /// 是否存储过程 + /// + protected virtual bool IsProcedure( string procedure ) { + return procedure.Trim().StartsWith( "call ", StringComparison.OrdinalIgnoreCase ); + } + + /// + /// 获取存储过程命令类型 + /// + protected override CommandType GetProcedureCommandType() { + if ( IsProcedure( GetSql() ) ) + return CommandType.Text; + return CommandType.StoredProcedure; + } + } +} diff --git a/src/Util.Data.Dapper.PostgreSql/Sql/PostgreSqlExecutorOptionsExtension.cs b/src/Util.Data.Dapper.PostgreSql/Sql/PostgreSqlExecutorOptionsExtension.cs new file mode 100644 index 00000000..66d3e3ef --- /dev/null +++ b/src/Util.Data.Dapper.PostgreSql/Sql/PostgreSqlExecutorOptionsExtension.cs @@ -0,0 +1,32 @@ +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; +using Microsoft.Extensions.Hosting; +using Util.Configs; + +namespace Util.Data.Sql { + /// + /// PostgreSql Sql执行器配置扩展 + /// + public class PostgreSqlExecutorOptionsExtension : OptionsExtensionBase + where TService : ISqlExecutor + where TImplementation : PostgreSqlExecutorBase, TService { + /// + /// Sql配置 + /// + private readonly SqlOptions _options; + + /// + /// 初始化PostgreSql Sql执行器配置扩展 + /// + /// Sql配置 + public PostgreSqlExecutorOptionsExtension( SqlOptions options ) { + _options = options; + } + + /// + public override void ConfigureServices( HostBuilderContext context, IServiceCollection services ) { + services.TryAddTransient( typeof( TService ), typeof( TImplementation ) ); + services.TryAddSingleton( typeof( SqlOptions ), ( sp ) => _options ); + } + } +} diff --git a/src/Util.Data.Dapper.PostgreSql/Sql/PostgreSqlQuery.cs b/src/Util.Data.Dapper.PostgreSql/Sql/PostgreSqlQuery.cs new file mode 100644 index 00000000..53943f43 --- /dev/null +++ b/src/Util.Data.Dapper.PostgreSql/Sql/PostgreSqlQuery.cs @@ -0,0 +1,18 @@ +using System; + +namespace Util.Data.Sql { + /// + /// PostgreSql Sql查询对象 + /// + public class PostgreSqlQuery : PostgreSqlQueryBase { + /// + /// 初始化PostgreSql Sql查询对象 + /// + /// 服务提供器 + /// Sql配置 + /// 数据库信息,用于接入其它数据源,比如EF DbContext + public PostgreSqlQuery( IServiceProvider serviceProvider, SqlOptions options, IDatabase database = null ) + : base( serviceProvider, options, database ) { + } + } +} \ No newline at end of file diff --git a/src/Util.Data.Dapper.PostgreSql/Sql/PostgreSqlQueryBase.cs b/src/Util.Data.Dapper.PostgreSql/Sql/PostgreSqlQueryBase.cs new file mode 100644 index 00000000..63f5d316 --- /dev/null +++ b/src/Util.Data.Dapper.PostgreSql/Sql/PostgreSqlQueryBase.cs @@ -0,0 +1,56 @@ +using System; +using System.Data; +using Util.Data.Sql.Builders; +using Util.Data.Sql.Builders.Core; + +namespace Util.Data.Sql { + /// + /// PostgreSql Sql查询对象 + /// + public abstract class PostgreSqlQueryBase : SqlQueryBase { + /// + /// 初始化PostgreSql Sql查询对象 + /// + /// 服务提供器 + /// Sql配置 + /// 数据库信息,用于接入其它数据源,比如EF DbContext + protected PostgreSqlQueryBase( IServiceProvider serviceProvider, SqlOptions options, IDatabase database ) : base( serviceProvider, options, database ) { + } + + /// + protected override ISqlBuilder CreateSqlBuilder() { + return new PostgreSqlBuilder(); + } + + /// + protected override IExistsSqlBuilder CreatExistsSqlBuilder( ISqlBuilder sqlBuilder ) { + return new PostgreSqlExistsSqlBuilder( sqlBuilder ); + } + + /// + protected override IDatabaseFactory CreateDatabaseFactory() { + return new PostgreSqlDatabaseFactory(); + } + + /// + protected override string GetProcedure( string procedure ) { + if ( IsProcedure( procedure ) ) + return Dialect.ReplaceSql( procedure ); + return new TableItem( Dialect, procedure ).ToResult(); + } + + /// + /// 是否存储过程 + /// + protected virtual bool IsProcedure( string procedure ) { + return procedure.Trim().StartsWith( "call ", StringComparison.OrdinalIgnoreCase ); + } + + /// + protected override CommandType GetProcedureCommandType() { + if ( IsProcedure( GetSql() ) ) + return CommandType.Text; + return CommandType.StoredProcedure; + } + } +} diff --git a/src/Util.Data.Dapper.PostgreSql/Sql/PostgreSqlQueryOptionsExtension.cs b/src/Util.Data.Dapper.PostgreSql/Sql/PostgreSqlQueryOptionsExtension.cs new file mode 100644 index 00000000..e278c15d --- /dev/null +++ b/src/Util.Data.Dapper.PostgreSql/Sql/PostgreSqlQueryOptionsExtension.cs @@ -0,0 +1,32 @@ +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; +using Microsoft.Extensions.Hosting; +using Util.Configs; + +namespace Util.Data.Sql { + /// + /// PostgreSql Sql查询对象配置扩展 + /// + public class PostgreSqlQueryOptionsExtension : OptionsExtensionBase + where TService : ISqlQuery + where TImplementation : PostgreSqlQueryBase, TService { + /// + /// Sql配置 + /// + private readonly SqlOptions _options; + + /// + /// 初始化PostgreSql Sql查询对象配置扩展 + /// + /// Sql配置 + public PostgreSqlQueryOptionsExtension( SqlOptions options ) { + _options = options; + } + + /// + public override void ConfigureServices( HostBuilderContext context, IServiceCollection services ) { + services.TryAddTransient( typeof( TService ), typeof( TImplementation ) ); + services.TryAddSingleton( typeof( SqlOptions ), ( sp ) => _options ); + } + } +} diff --git a/src/Util.Data.Dapper.SqlServer/02-Util.Data.Dapper.SqlServer.csproj b/src/Util.Data.Dapper.SqlServer/02-Util.Data.Dapper.SqlServer.csproj new file mode 100644 index 00000000..98932f97 --- /dev/null +++ b/src/Util.Data.Dapper.SqlServer/02-Util.Data.Dapper.SqlServer.csproj @@ -0,0 +1,37 @@ + + + + $(NetTargetFramework) + icon.jpg + Util.Data.Dapper.SqlServer + Util.Data + Util.Data.Dapper.SqlServer是Util应用框架基于Dapper的数据访问封装类库,用于处理SqlServer数据库 + + + + + .\obj\Debug\$(NetTargetFramework)\Util.Data.Dapper.SqlServer.xml + + + + + .\obj\Release\$(NetTargetFramework)\Util.Data.Dapper.SqlServer.xml + + + + + True + False + + + + + + + + + + + + + diff --git a/src/Util.Data.Dapper.SqlServer/Metadata/SqlServerMetadataService.cs b/src/Util.Data.Dapper.SqlServer/Metadata/SqlServerMetadataService.cs new file mode 100644 index 00000000..b4c89ee6 --- /dev/null +++ b/src/Util.Data.Dapper.SqlServer/Metadata/SqlServerMetadataService.cs @@ -0,0 +1,110 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Util.Data.Sql; + +namespace Util.Data.Metadata { + /// + /// Sql Server数据库元数据服务 + /// + public class SqlServerMetadataService : IMetadataService { + /// + /// Sql查询对象 + /// + private readonly ISqlQuery _sqlQuery; + + /// + /// 初始化Sql Server数据库元数据服务 + /// + /// Sql查询对象 + public SqlServerMetadataService( ISqlQuery sqlQuery ) { + _sqlQuery = sqlQuery ?? throw new ArgumentNullException( nameof( sqlQuery ) ); + } + + /// + /// 获取数据库信息 + /// + public DatabaseInfo GetDatabaseInfo() { + var result = GetDatabase(); + result.Tables.AddRange( GetTables() ); + return result; + } + + /// + /// 获取数据库信息 + /// + private DatabaseInfo GetDatabase() { + return _sqlQuery + .Select( "Dbid Id,Name" ) + .From( "sys.SysDataBases" ) + .Where( "DbId", t => t.Select( "Dbid" ).From( "sys.SysProcesses" ).AppendWhere( "Spid = @@spid" ) ) + .ToEntity(); + } + + /// + /// 获取表信息 + /// + private List GetTables() { + SetGetTablesSql(); + var dic = new Dictionary(); + var tables = _sqlQuery.ToList( ( table, column ) => { + if( table == null || column == null ) + return null; + if( dic.ContainsKey( table.Id ) == false ) + dic.Add( table.Id, table ); + TableInfo result = dic[table.Id]; + result.Columns.Add( column ); + return result; + } ).Distinct().ToList(); + return tables; + } + + /// + /// 设置获取表信息Sql + /// + private void SetGetTablesSql() { + _sqlQuery + .Select( "o.object_id Id,o.name,s.name Schema,ep.value Comment" ) + .Select( "c.Id,c.name,c.Comment" ) + .AppendSelect( ",(Case When Exists(" ) + .AppendSelect( GetIsPrimaryKeySql() ) + .AppendSelect( ") Then Cast(1 As Bit) Else Cast(0 As Bit) End) As IsPrimaryKey" ) + .Select( "c.is_identity IsAutoIncrement,c.is_nullable IsNullable" ) + .Select( "c.DataType,c.max_length Length,c.precision,c.scale" ) + .From( "sys.Objects o" ) + .LeftJoin( "sys.Schemas s" ).On( "o.schema_id", "s.schema_id" ) + .LeftJoin( "sys.Extended_Properties ep" ).On( "o.object_id", "ep.major_id" ).On( "ep.minor_id", 0 ) + .Join( GetColumnsSql(), "c" ).On( "c.object_id", "o.object_id" ) + .In( "o.type", new[] { 'U', 'V' } ); + } + + /// + /// 获取是否主键子查询 + /// + private ISqlBuilder GetIsPrimaryKeySql() { + return _sqlQuery.NewSqlBuilder() + .Select() + .From( "Information_Schema.Key_Column_Usage k" ) + .Join( "Information_Schema.Table_Constraints tc" ) + .On( "k.table_name", "tc.table_name" ) + .On( "k.Constraint_Name", "tc.Constraint_Name" ) + .AppendOn( "tc.Constraint_Type='PRIMARY KEY'" ) + .AppendWhere( "o.name=k.table_name" ) + .AppendWhere( "c.name=k.column_name" ); + } + + /// + /// 获取列信息子查询 + /// + private ISqlBuilder GetColumnsSql() { + return _sqlQuery.NewSqlBuilder() + .Select( "c.object_id,c.column_id Id,c.name,ep.value Comment" ) + .Select( "c.is_identity,c.is_nullable,t.name DataType,c.max_length" ) + .Select( "c.precision,c.scale" ) + .From( "sys.Columns c" ) + .LeftJoin( "sys.Extended_Properties ep" ).On( "c.object_id", "ep.major_id" ).On( "c.column_id", "ep.minor_id" ) + .LeftJoin( "sys.Types t" ).On( "c.system_type_id", "t.system_type_id" ) + .AppendWhere( "t.name!='sysname'" ); + } + } +} diff --git a/src/Util.Data.Dapper.SqlServer/Metadata/SqlServerTypeConverter.cs b/src/Util.Data.Dapper.SqlServer/Metadata/SqlServerTypeConverter.cs new file mode 100644 index 00000000..f837084e --- /dev/null +++ b/src/Util.Data.Dapper.SqlServer/Metadata/SqlServerTypeConverter.cs @@ -0,0 +1,71 @@ +using System; +using System.Data; + +namespace Util.Data.Metadata { + /// + /// Sql Server数据类型转换器 + /// + public class SqlServerTypeConverter : ITypeConverter { + /// + public DbType? ToType( string dataType, int? length = null ) { + if ( dataType.IsEmpty() ) + return null; + switch ( dataType.ToLower() ) { + case "uniqueidentifier": + return DbType.Guid; + case "char": + return DbType.AnsiStringFixedLength; + case "nchar": + return DbType.StringFixedLength; + case "varchar": + return DbType.AnsiString; + case "nvarchar": + case "text": + case "ntext": + return DbType.String; + case "bit": + return DbType.Boolean; + case "tinyint": + return DbType.Byte; + case "smallint": + return DbType.Int16; + case "int": + return DbType.Int32; + case "bigint": + return DbType.Int64; + case "real": + return DbType.Single; + case "float": + return DbType.Double; + case "decimal": + case "numeric": + case "money": + case "smallmoney": + return DbType.Decimal; + case "date": + return DbType.Date; + case "time": + return DbType.Time; + case "datetime": + case "smalldatetime": + return DbType.DateTime; + case "datetime2": + return DbType.DateTime2; + case "datetimeoffset": + return DbType.DateTimeOffset; + case "binary": + case "varbinary": + case "varbinary(max)": + case "image": + case "rowversion": + case "timestamp": + return DbType.Binary; + case "xml": + return DbType.Xml; + case "sql_variant": + return DbType.Object; + } + throw new NotImplementedException( dataType ); + } + } +} diff --git a/src/Util.Data.Dapper.SqlServer/Sql/Builders/SqlServerBuilder.cs b/src/Util.Data.Dapper.SqlServer/Sql/Builders/SqlServerBuilder.cs new file mode 100644 index 00000000..3c0f81f8 --- /dev/null +++ b/src/Util.Data.Dapper.SqlServer/Sql/Builders/SqlServerBuilder.cs @@ -0,0 +1,39 @@ +using Util.Data.Sql.Builders.Caches; +using Util.Data.Sql.Builders.Params; + +namespace Util.Data.Sql.Builders { + /// + /// Sql Server Sql生成器 + /// + public class SqlServerBuilder : SqlBuilderBase { + /// + /// 初始化Sql Server Sql生成器 + /// + /// Sql参数管理器 + public SqlServerBuilder( IParameterManager parameterManager = null ) + : base( parameterManager ) { + } + + /// + protected override IDialect CreateDialect() { + return SqlServerDialect.Instance; + } + + /// + protected override IColumnCache CreateColumnCache() { + return SqlServerColumnCache.Instance; + } + + /// + public override ISqlBuilder New() { + return new SqlServerBuilder( ParameterManager ); + } + + /// + public override ISqlBuilder Clone() { + var result = new SqlServerBuilder(); + result.Clone( this ); + return result; + } + } +} diff --git a/src/Util.Data.Dapper.SqlServer/Sql/Builders/SqlServerColumnCache.cs b/src/Util.Data.Dapper.SqlServer/Sql/Builders/SqlServerColumnCache.cs new file mode 100644 index 00000000..c321d317 --- /dev/null +++ b/src/Util.Data.Dapper.SqlServer/Sql/Builders/SqlServerColumnCache.cs @@ -0,0 +1,36 @@ +using System.Collections.Concurrent; +using Util.Data.Sql.Builders.Caches; + +namespace Util.Data.Sql.Builders { + /// + /// Sql Server列缓存 + /// + public class SqlServerColumnCache : ColumnCacheBase { + /// + /// 列名缓存 + /// + private readonly ConcurrentDictionary _cache; + + /// + /// 封闭构造方法 + /// + private SqlServerColumnCache() : base( SqlServerDialect.Instance ) { + _cache = new ConcurrentDictionary(); + } + + /// + /// Sql Server列缓存实例 + /// + public static readonly IColumnCache Instance = new SqlServerColumnCache(); + + /// + public override string GetSafeColumns( string columns ) { + return _cache.GetOrAdd( columns.GetHashCode(), key => NormalizeColumns( columns ) ); + } + + /// + public override string GetSafeColumn( string column ) { + return _cache.GetOrAdd( column.GetHashCode(), key => NormalizeColumn( column ) ); + } + } +} diff --git a/src/Util.Data.Dapper.SqlServer/Sql/Builders/SqlServerDialect.cs b/src/Util.Data.Dapper.SqlServer/Sql/Builders/SqlServerDialect.cs new file mode 100644 index 00000000..fe24744d --- /dev/null +++ b/src/Util.Data.Dapper.SqlServer/Sql/Builders/SqlServerDialect.cs @@ -0,0 +1,34 @@ +using Util.Data.Sql.Builders.Core; + +namespace Util.Data.Sql.Builders { + /// + /// Sql Server方言 + /// + public class SqlServerDialect : DialectBase { + /// + /// 封闭构造方法 + /// + private SqlServerDialect() { + } + + /// + /// Sql Server方言实例 + /// + public static readonly IDialect Instance = new SqlServerDialect(); + + /// + public override string GetOpeningIdentifier() { + return "["; + } + + /// + public override string GetClosingIdentifier() { + return "]"; + } + + /// + public override string GetPrefix() { + return "@"; + } + } +} diff --git a/src/Util.Data.Dapper.SqlServer/Sql/Builders/SqlServerExistsSqlBuilder.cs b/src/Util.Data.Dapper.SqlServer/Sql/Builders/SqlServerExistsSqlBuilder.cs new file mode 100644 index 00000000..3390e767 --- /dev/null +++ b/src/Util.Data.Dapper.SqlServer/Sql/Builders/SqlServerExistsSqlBuilder.cs @@ -0,0 +1,52 @@ +using System.Text; + +namespace Util.Data.Sql.Builders { + /// + /// 判断是否存在Sql生成器 + /// + public class SqlServerExistsSqlBuilder : IExistsSqlBuilder { + /// + /// Sql生成器 + /// + private readonly ISqlBuilder _sqlBuilder; + + /// + /// 初始化判断是否存在Sql生成器 + /// + /// Sql生成器 + public SqlServerExistsSqlBuilder( ISqlBuilder sqlBuilder ) { + _sqlBuilder = sqlBuilder; + } + + /// + /// 获取Sql + /// + public string GetSql() { + InitSelect(); + return GetResult(); + } + + /// + /// 将Select子句初始化为1 + /// + private void InitSelect() { + _sqlBuilder.ClearSelect(); + _sqlBuilder.AppendSelect( "1" ); + } + + /// + /// 获取结果 + /// + private string GetResult() { + var result = new StringBuilder(); + result.AppendLine( "Select Case" ); + result.AppendLine( " When Exists (" ); + _sqlBuilder.AppendTo( result ); + result.AppendLine( ")" ); + result.AppendLine( " Then Cast(1 As Bit)" ); + result.AppendLine( " Else Cast(0 As Bit) " ); + result.Append( "End" ); + return result.ToString(); + } + } +} diff --git a/src/Util.Data.Dapper.SqlServer/Sql/OptionsExtensions.cs b/src/Util.Data.Dapper.SqlServer/Sql/OptionsExtensions.cs new file mode 100644 index 00000000..3b474f2b --- /dev/null +++ b/src/Util.Data.Dapper.SqlServer/Sql/OptionsExtensions.cs @@ -0,0 +1,120 @@ +using System; +using Util.Configs; + +namespace Util.Data.Sql { + /// + /// Sql Server数据库操作扩展 + /// + public static class OptionsExtensions { + + #region UseSqlServerSqlQuery(配置Sql Server Sql查询对象) + + /// + /// 配置Sql Server Sql查询对象 + /// + /// 配置项 + public static Options UseSqlServerSqlQuery( this Options options ) { + return options.UseSqlServerSqlQuery( "" ); + } + + /// + /// 配置Sql Server Sql查询对象 + /// + /// 配置项 + /// 数据库连接字符串 + public static Options UseSqlServerSqlQuery( this Options options, string connection ) { + return options.UseSqlServerSqlQuery( connection ); + } + + /// + /// 配置Sql Server Sql查询对象 + /// + /// 配置项 + /// 配置操作 + public static Options UseSqlServerSqlQuery( this Options options, Action setupAction ) { + return options.UseSqlServerSqlQuery( setupAction ); + } + + /// + /// 配置Sql Server Sql查询对象 + /// + /// 配置项 + /// 数据库连接字符串 + public static Options UseSqlServerSqlQuery( this Options options, string connection ) + where TService : ISqlQuery + where TImplementation : SqlServerSqlQueryBase, TService { + return options.UseSqlServerSqlQuery( t => t.ConnectionString( connection ) ); + } + + /// + /// 配置Sql Server Sql查询对象 + /// + /// 配置项 + /// 配置操作 + public static Options UseSqlServerSqlQuery( this Options options, Action setupAction ) + where TService : ISqlQuery + where TImplementation : SqlServerSqlQueryBase, TService { + var sqlOptions = new SqlOptions(); + setupAction?.Invoke( sqlOptions ); + options.AddExtension( new SqlServerSqlQueryOptionsExtension( sqlOptions ) ); + return options; + } + + #endregion + + #region UseSqlServerSqlExecutor(配置Sql Server Sql执行器) + + /// + /// 配置Sql Server Sql执行器 + /// + /// 配置项 + public static Options UseSqlServerSqlExecutor( this Options options ) { + return options.UseSqlServerSqlExecutor( "" ); + } + + /// + /// 配置Sql Server Sql执行器 + /// + /// 配置项 + /// 数据库连接字符串 + public static Options UseSqlServerSqlExecutor( this Options options, string connection ) { + return options.UseSqlServerSqlExecutor( connection ); + } + + /// + /// 配置Sql Server Sql执行器 + /// + /// 配置项 + /// 配置操作 + public static Options UseSqlServerSqlExecutor( this Options options, Action setupAction ) { + return options.UseSqlServerSqlExecutor( setupAction ); + } + + /// + /// 配置Sql Server Sql执行器 + /// + /// 配置项 + /// 数据库连接字符串 + public static Options UseSqlServerSqlExecutor( this Options options, string connection ) + where TService : ISqlExecutor + where TImplementation : SqlServerSqlExecutorBase, TService { + return options.UseSqlServerSqlExecutor( t => t.ConnectionString( connection ) ); + } + + /// + /// 配置Sql Server Sql执行器 + /// + /// 配置项 + /// 配置操作 + public static Options UseSqlServerSqlExecutor( this Options options, Action setupAction ) + where TService : ISqlExecutor + where TImplementation : SqlServerSqlExecutorBase, TService { + var sqlOptions = new SqlOptions(); + setupAction?.Invoke( sqlOptions ); + options.AddExtension( new SqlServerSqlExecutorOptionsExtension( sqlOptions ) ); + return options; + } + + #endregion + } +} diff --git a/src/Util.Data.Dapper.SqlServer/Sql/SqlServerDatabaseFactory.cs b/src/Util.Data.Dapper.SqlServer/Sql/SqlServerDatabaseFactory.cs new file mode 100644 index 00000000..d347407b --- /dev/null +++ b/src/Util.Data.Dapper.SqlServer/Sql/SqlServerDatabaseFactory.cs @@ -0,0 +1,16 @@ +using System.Data.SqlClient; + +namespace Util.Data.Sql { + /// + /// Sql Server数据库工厂 + /// + public class SqlServerDatabaseFactory : IDatabaseFactory { + /// + /// 创建数据库信息 + /// + /// 数据库连接字符串 + public IDatabase Create( string connection ) { + return new DefaultDatabase( new SqlConnection( connection ) ); + } + } +} diff --git a/src/Util.Data.Dapper.SqlServer/Sql/SqlServerSqlExecutor.cs b/src/Util.Data.Dapper.SqlServer/Sql/SqlServerSqlExecutor.cs new file mode 100644 index 00000000..740f4c94 --- /dev/null +++ b/src/Util.Data.Dapper.SqlServer/Sql/SqlServerSqlExecutor.cs @@ -0,0 +1,18 @@ +using System; + +namespace Util.Data.Sql { + /// + /// Sql Server Sql执行器 + /// + public class SqlServerSqlExecutor : SqlServerSqlExecutorBase { + /// + /// 初始化Sql Server Sql执行器 + /// + /// 服务提供器 + /// Sql配置 + /// 数据库信息,用于接入其它数据源,比如EF DbContext + public SqlServerSqlExecutor( IServiceProvider serviceProvider, SqlOptions options, IDatabase database = null ) + : base( serviceProvider, options, database ) { + } + } +} diff --git a/src/Util.Data.Dapper.SqlServer/Sql/SqlServerSqlExecutorBase.cs b/src/Util.Data.Dapper.SqlServer/Sql/SqlServerSqlExecutorBase.cs new file mode 100644 index 00000000..fd554345 --- /dev/null +++ b/src/Util.Data.Dapper.SqlServer/Sql/SqlServerSqlExecutorBase.cs @@ -0,0 +1,39 @@ +using System; +using Util.Data.Sql.Builders; + +namespace Util.Data.Sql { + /// + /// Sql Server Sql执行器 + /// + public abstract class SqlServerSqlExecutorBase : SqlExecutorBase { + /// + /// 初始化Sql Server Sql执行器 + /// + /// 服务提供器 + /// Sql配置 + /// 数据库信息,用于接入其它数据源,比如EF DbContext + protected SqlServerSqlExecutorBase( IServiceProvider serviceProvider, SqlOptions options, IDatabase database ) : base( serviceProvider, options, database ) { + } + + /// + /// 创建Sql生成器 + /// + protected override ISqlBuilder CreateSqlBuilder() { + return new SqlServerBuilder(); + } + + /// + /// 创建判断是否存在Sql生成器 + /// + protected override IExistsSqlBuilder CreatExistsSqlBuilder( ISqlBuilder sqlBuilder ) { + return new SqlServerExistsSqlBuilder( sqlBuilder ); + } + + /// + /// 创建数据库工厂 + /// + protected override IDatabaseFactory CreateDatabaseFactory() { + return new SqlServerDatabaseFactory(); + } + } +} diff --git a/src/Util.Data.Dapper.SqlServer/Sql/SqlServerSqlExecutorOptionsExtension.cs b/src/Util.Data.Dapper.SqlServer/Sql/SqlServerSqlExecutorOptionsExtension.cs new file mode 100644 index 00000000..7e5e84c8 --- /dev/null +++ b/src/Util.Data.Dapper.SqlServer/Sql/SqlServerSqlExecutorOptionsExtension.cs @@ -0,0 +1,32 @@ +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; +using Microsoft.Extensions.Hosting; +using Util.Configs; + +namespace Util.Data.Sql { + /// + /// Sql Server Sql执行器配置扩展 + /// + public class SqlServerSqlExecutorOptionsExtension : OptionsExtensionBase + where TService : ISqlExecutor + where TImplementation : SqlServerSqlExecutorBase, TService { + /// + /// Sql配置 + /// + private readonly SqlOptions _options; + + /// + /// 初始化Sql Server Sql执行器配置扩展 + /// + /// Sql配置 + public SqlServerSqlExecutorOptionsExtension( SqlOptions options ) { + _options = options; + } + + /// + public override void ConfigureServices( HostBuilderContext context, IServiceCollection services ) { + services.TryAddTransient( typeof( TService ), typeof( TImplementation ) ); + services.TryAddSingleton( typeof( SqlOptions ), ( sp ) => _options ); + } + } +} diff --git a/src/Util.Data.Dapper.SqlServer/Sql/SqlServerSqlQuery.cs b/src/Util.Data.Dapper.SqlServer/Sql/SqlServerSqlQuery.cs new file mode 100644 index 00000000..48556d5b --- /dev/null +++ b/src/Util.Data.Dapper.SqlServer/Sql/SqlServerSqlQuery.cs @@ -0,0 +1,18 @@ +using System; + +namespace Util.Data.Sql { + /// + /// Sql Server Sql查询对象 + /// + public class SqlServerSqlQuery : SqlServerSqlQueryBase { + /// + /// 初始化Sql Server Sql查询对象 + /// + /// 服务提供器 + /// Sql配置 + /// 数据库信息,用于接入其它数据源,比如EF DbContext + public SqlServerSqlQuery( IServiceProvider serviceProvider, SqlOptions options, IDatabase database = null ) + : base( serviceProvider, options, database ) { + } + } +} \ No newline at end of file diff --git a/src/Util.Data.Dapper.SqlServer/Sql/SqlServerSqlQueryBase.cs b/src/Util.Data.Dapper.SqlServer/Sql/SqlServerSqlQueryBase.cs new file mode 100644 index 00000000..a2bef027 --- /dev/null +++ b/src/Util.Data.Dapper.SqlServer/Sql/SqlServerSqlQueryBase.cs @@ -0,0 +1,33 @@ +using System; +using Util.Data.Sql.Builders; + +namespace Util.Data.Sql { + /// + /// Sql Server Sql查询对象 + /// + public abstract class SqlServerSqlQueryBase : SqlQueryBase { + /// + /// 初始化Sql Server Sql查询对象 + /// + /// 服务提供器 + /// Sql配置 + /// 数据库信息,用于接入其它数据源,比如EF DbContext + protected SqlServerSqlQueryBase( IServiceProvider serviceProvider, SqlOptions options, IDatabase database ) : base( serviceProvider, options, database ) { + } + + /// + protected override ISqlBuilder CreateSqlBuilder() { + return new SqlServerBuilder(); + } + + /// + protected override IExistsSqlBuilder CreatExistsSqlBuilder( ISqlBuilder sqlBuilder ) { + return new SqlServerExistsSqlBuilder( sqlBuilder ); + } + + /// + protected override IDatabaseFactory CreateDatabaseFactory() { + return new SqlServerDatabaseFactory(); + } + } +} diff --git a/src/Util.Data.Dapper.SqlServer/Sql/SqlServerSqlQueryOptionsExtension.cs b/src/Util.Data.Dapper.SqlServer/Sql/SqlServerSqlQueryOptionsExtension.cs new file mode 100644 index 00000000..dd6e7fd8 --- /dev/null +++ b/src/Util.Data.Dapper.SqlServer/Sql/SqlServerSqlQueryOptionsExtension.cs @@ -0,0 +1,32 @@ +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; +using Microsoft.Extensions.Hosting; +using Util.Configs; + +namespace Util.Data.Sql { + /// + /// Sql Server Sql查询对象配置扩展 + /// + public class SqlServerSqlQueryOptionsExtension : OptionsExtensionBase + where TService : ISqlQuery + where TImplementation : SqlServerSqlQueryBase, TService { + /// + /// Sql配置 + /// + private readonly SqlOptions _options; + + /// + /// 初始化Sql Server Sql查询对象配置扩展 + /// + /// Sql配置 + public SqlServerSqlQueryOptionsExtension( SqlOptions options ) { + _options = options; + } + + /// + public override void ConfigureServices( HostBuilderContext context, IServiceCollection services ) { + services.TryAddTransient( typeof( TService ), typeof( TImplementation ) ); + services.TryAddSingleton( typeof( SqlOptions ), ( sp ) => _options ); + } + } +} diff --git a/src/Util.Data.EntityFrameworkCore.MySql/04-Util.Data.EntityFrameworkCore.MySql.csproj b/src/Util.Data.EntityFrameworkCore.MySql/04-Util.Data.EntityFrameworkCore.MySql.csproj new file mode 100644 index 00000000..668a2159 --- /dev/null +++ b/src/Util.Data.EntityFrameworkCore.MySql/04-Util.Data.EntityFrameworkCore.MySql.csproj @@ -0,0 +1,37 @@ + + + + $(NetTargetFramework) + icon.jpg + Util.Data.EntityFrameworkCore.MySql + Util.Data.EntityFrameworkCore + Util.Data.EntityFrameworkCore.MySql是Util应用框架基于EntityFrameworkCore的数据访问封装类库,用于处理MySql数据库 + + + + + .\obj\Debug\$(NetTargetFramework)\Util.Data.EntityFrameworkCore.MySql.xml + + + + + .\obj\Release\$(NetTargetFramework)\Util.Data.EntityFrameworkCore.MySql.xml + + + + + True + False + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Util.Data.EntityFrameworkCore.MySql/MySqlOptionsExtension.cs b/src/Util.Data.EntityFrameworkCore.MySql/MySqlOptionsExtension.cs new file mode 100644 index 00000000..257924e9 --- /dev/null +++ b/src/Util.Data.EntityFrameworkCore.MySql/MySqlOptionsExtension.cs @@ -0,0 +1,62 @@ +using System; +using System.Data.Common; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using MySqlConnector; +using Util.Configs; + +namespace Util.Data.EntityFrameworkCore { + /// + /// MySql工作单元配置扩展 + /// + public class MySqlOptionsExtension : OptionsExtensionBase + where TService : class, IUnitOfWork + where TImplementation : UnitOfWorkBase, TService { + /// + /// 数据库连接字符串 + /// + private readonly string _connectionString; + /// + /// 数据库连接 + /// + private readonly DbConnection _connection; + /// + /// 工作单元配置操作 + /// + private readonly Action _setupAction; + /// + /// MySql配置操作 + /// + private readonly Action _mySqlSetupAction; + + /// + /// 初始化PostgreSql工作单元配置扩展 + /// + /// 数据库连接字符串 + /// 数据库连接 + /// 工作单元配置操作 + /// MySql配置操作 + public MySqlOptionsExtension( string connectionString, DbConnection connection, Action setupAction, Action mySqlSetupAction ) { + _connectionString = connectionString; + _connection = connection; + _setupAction = setupAction; + _mySqlSetupAction = mySqlSetupAction; + } + + /// + public override void ConfigureServices( HostBuilderContext context, IServiceCollection services ) { + services.AddDbContext( options => { + _setupAction?.Invoke( options ); + if ( _connectionString.IsEmpty() == false ) { + options.UseMySql( _connectionString, ServerVersion.AutoDetect( _connectionString ), _mySqlSetupAction ); + return; + } + if ( _connection != null ) { + options.UseMySql( _connection, ServerVersion.AutoDetect( (MySqlConnection)_connection ), _mySqlSetupAction ); + } + } ); + } + } +} diff --git a/src/Util.Data.EntityFrameworkCore.MySql/MySqlUnitOfWorkBase.cs b/src/Util.Data.EntityFrameworkCore.MySql/MySqlUnitOfWorkBase.cs new file mode 100644 index 00000000..b01ad4a8 --- /dev/null +++ b/src/Util.Data.EntityFrameworkCore.MySql/MySqlUnitOfWorkBase.cs @@ -0,0 +1,18 @@ +using System; +using Microsoft.EntityFrameworkCore; + +namespace Util.Data.EntityFrameworkCore { + /// + /// MySql工作单元基类 + /// + public abstract class MySqlUnitOfWorkBase : UnitOfWorkBase { + /// + /// 初始化MySql工作单元 + /// + /// 服务提供器 + /// 配置 + protected MySqlUnitOfWorkBase( IServiceProvider serviceProvider, DbContextOptions options ) + : base( serviceProvider, options ) { + } + } +} diff --git a/src/Util.Data.EntityFrameworkCore.MySql/OptionsExtensions.cs b/src/Util.Data.EntityFrameworkCore.MySql/OptionsExtensions.cs new file mode 100644 index 00000000..4c359a53 --- /dev/null +++ b/src/Util.Data.EntityFrameworkCore.MySql/OptionsExtensions.cs @@ -0,0 +1,51 @@ +using System; +using System.Data.Common; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Util.Configs; + +namespace Util.Data.EntityFrameworkCore { + /// + /// MySql工作单元操作扩展 + /// + public static class OptionsExtensions { + /// + /// 配置MySql工作单元 + /// + /// 配置项 + /// 数据库连接字符串 + /// 工作单元配置操作 + /// MySql配置操作 + public static Options UseMySqlUnitOfWork( this Options options, string connection, Action setupAction = null, + Action mySqlSetupAction = null ) + where TService : class, IUnitOfWork + where TImplementation : UnitOfWorkBase, TService { + return options.UseMySqlUnitOfWork( connection, null, setupAction, mySqlSetupAction ); + } + + /// + /// 配置MySql工作单元 + /// + /// 配置项 + /// 数据库连接 + /// 工作单元配置操作 + /// MySql配置操作 + public static Options UseMySqlUnitOfWork( this Options options, DbConnection connection, Action setupAction = null, + Action mySqlSetupAction = null ) + where TService : class, IUnitOfWork + where TImplementation : UnitOfWorkBase, TService { + return options.UseMySqlUnitOfWork( null, connection, setupAction, mySqlSetupAction ); + } + + /// + /// 配置MySql工作单元 + /// + private static Options UseMySqlUnitOfWork( this Options options, string connectionString, DbConnection connection, Action setupAction, + Action mySqlSetupAction ) + where TService : class, IUnitOfWork + where TImplementation : UnitOfWorkBase, TService { + options.AddExtension( new MySqlOptionsExtension( connectionString, connection, setupAction, mySqlSetupAction ) ); + return options; + } + } +} diff --git a/src/Util.Data.EntityFrameworkCore.Oracle/06-Util.Data.EntityFrameworkCore.Oracle.csproj b/src/Util.Data.EntityFrameworkCore.Oracle/06-Util.Data.EntityFrameworkCore.Oracle.csproj new file mode 100644 index 00000000..59d3bb30 --- /dev/null +++ b/src/Util.Data.EntityFrameworkCore.Oracle/06-Util.Data.EntityFrameworkCore.Oracle.csproj @@ -0,0 +1,37 @@ + + + + $(NetTargetFramework) + icon.jpg + Util.Data.EntityFrameworkCore.Oracle + Util.Data.EntityFrameworkCore + Util.Data.EntityFrameworkCore.Oracle是Util应用框架基于EntityFrameworkCore的数据访问封装类库,用于处理Oracle数据库 + + + + + .\obj\Debug\$(NetTargetFramework)\Util.Data.EntityFrameworkCore.Oracle.xml + + + + + .\obj\Release\$(NetTargetFramework)\Util.Data.EntityFrameworkCore.Oracle.xml + + + + + True + False + + + + + + + + + + + + + diff --git a/src/Util.Data.EntityFrameworkCore.Oracle/OptionsExtensions.cs b/src/Util.Data.EntityFrameworkCore.Oracle/OptionsExtensions.cs new file mode 100644 index 00000000..47628de5 --- /dev/null +++ b/src/Util.Data.EntityFrameworkCore.Oracle/OptionsExtensions.cs @@ -0,0 +1,51 @@ +using System; +using System.Data.Common; +using Microsoft.EntityFrameworkCore; +using Oracle.EntityFrameworkCore.Infrastructure; +using Util.Configs; + +namespace Util.Data.EntityFrameworkCore { + /// + /// Oracle工作单元操作扩展 + /// + public static class OptionsExtensions { + /// + /// 配置Oracle工作单元 + /// + /// 配置项 + /// 数据库连接字符串 + /// 工作单元配置操作 + /// Oracle配置操作 + public static Options UseOracleUnitOfWork( this Options options, string connection, Action setupAction = null, + Action oracleSetupAction = null ) + where TService : class, IUnitOfWork + where TImplementation : UnitOfWorkBase, TService { + return options.UseOracleUnitOfWork( connection, null, setupAction, oracleSetupAction ); + } + + /// + /// 配置Oracle工作单元 + /// + /// 配置项 + /// 数据库连接 + /// 工作单元配置操作 + /// Oracle配置操作 + public static Options UseOracleUnitOfWork( this Options options, DbConnection connection, Action setupAction = null, + Action oracleSetupAction = null ) + where TService : class, IUnitOfWork + where TImplementation : UnitOfWorkBase, TService { + return options.UseOracleUnitOfWork( null, connection, setupAction, oracleSetupAction ); + } + + /// + /// 配置Oracle工作单元 + /// + private static Options UseOracleUnitOfWork( this Options options, string connectionString, DbConnection connection, Action setupAction, + Action oracleSetupAction ) + where TService : class, IUnitOfWork + where TImplementation : UnitOfWorkBase, TService { + options.AddExtension( new OracleOptionsExtension( connectionString, connection, setupAction, oracleSetupAction ) ); + return options; + } + } +} diff --git a/src/Util.Data.EntityFrameworkCore.Oracle/OracleOptionsExtension.cs b/src/Util.Data.EntityFrameworkCore.Oracle/OracleOptionsExtension.cs new file mode 100644 index 00000000..185620c1 --- /dev/null +++ b/src/Util.Data.EntityFrameworkCore.Oracle/OracleOptionsExtension.cs @@ -0,0 +1,61 @@ +using System; +using System.Data.Common; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Oracle.EntityFrameworkCore.Infrastructure; +using Util.Configs; + +namespace Util.Data.EntityFrameworkCore { + /// + /// Oracle工作单元配置扩展 + /// + public class OracleOptionsExtension : OptionsExtensionBase + where TService : class, IUnitOfWork + where TImplementation : UnitOfWorkBase, TService { + /// + /// 数据库连接字符串 + /// + private readonly string _connectionString; + /// + /// 数据库连接 + /// + private readonly DbConnection _connection; + /// + /// 工作单元配置操作 + /// + private readonly Action _setupAction; + /// + /// Oracle配置操作 + /// + private readonly Action _oracleSetupAction; + + /// + /// 初始化Oracle工作单元配置扩展 + /// + /// 数据库连接字符串 + /// 数据库连接 + /// 工作单元配置操作 + /// Oracle配置操作 + public OracleOptionsExtension( string connectionString, DbConnection connection, Action setupAction, Action oracleSetupAction ) { + _connectionString = connectionString; + _connection = connection; + _setupAction = setupAction; + _oracleSetupAction = oracleSetupAction; + } + + /// + public override void ConfigureServices( HostBuilderContext context, IServiceCollection services ) { + services.AddDbContext( options => { + _setupAction?.Invoke( options ); + if ( _connectionString.IsEmpty() == false ) { + options.UseOracle( _connectionString, _oracleSetupAction ); + return; + } + if ( _connection != null ) { + options.UseOracle( _connection, _oracleSetupAction ); + } + } ); + } + } +} diff --git a/src/Util.Data.EntityFrameworkCore.Oracle/OracleUnitOfWorkBase.cs b/src/Util.Data.EntityFrameworkCore.Oracle/OracleUnitOfWorkBase.cs new file mode 100644 index 00000000..9c1d0c0d --- /dev/null +++ b/src/Util.Data.EntityFrameworkCore.Oracle/OracleUnitOfWorkBase.cs @@ -0,0 +1,18 @@ +using System; +using Microsoft.EntityFrameworkCore; + +namespace Util.Data.EntityFrameworkCore { + /// + /// Oracle工作单元基类 + /// + public abstract class OracleUnitOfWorkBase : UnitOfWorkBase { + /// + /// 初始化Oracle工作单元 + /// + /// 服务提供器 + /// 配置 + protected OracleUnitOfWorkBase( IServiceProvider serviceProvider, DbContextOptions options ) + : base( serviceProvider, options ) { + } + } +} diff --git a/src/Util.Data.EntityFrameworkCore.PostgreSql/03-Util.Data.EntityFrameworkCore.PostgreSql.csproj b/src/Util.Data.EntityFrameworkCore.PostgreSql/03-Util.Data.EntityFrameworkCore.PostgreSql.csproj index 0363498e..fc65c55b 100644 --- a/src/Util.Data.EntityFrameworkCore.PostgreSql/03-Util.Data.EntityFrameworkCore.PostgreSql.csproj +++ b/src/Util.Data.EntityFrameworkCore.PostgreSql/03-Util.Data.EntityFrameworkCore.PostgreSql.csproj @@ -5,17 +5,17 @@ icon.jpg Util.Data.EntityFrameworkCore.PostgreSql Util.Data.EntityFrameworkCore - Util.Data.EntityFrameworkCore.PostgreSql是Util应用框架针对PostgreSql数据库的EntityFrameworkCore封装类库 + Util.Data.EntityFrameworkCore.PostgreSql是Util应用框架基于EntityFrameworkCore的数据访问封装类库,用于处理PostgreSql数据库 - .\obj\Debug\$(NetTargetFramework)\Util.Data.EntityFrameworkCore.SqlServer.xml + .\obj\Debug\$(NetTargetFramework)\Util.Data.EntityFrameworkCore.PostgreSql.xml - .\obj\Release\$(NetTargetFramework)\Util.Data.EntityFrameworkCore.SqlServer.xml + .\obj\Release\$(NetTargetFramework)\Util.Data.EntityFrameworkCore.PostgreSql.xml @@ -27,7 +27,7 @@ - + diff --git a/src/Util.Data.EntityFrameworkCore.PostgreSql/PgSqlOptionsExtension.cs b/src/Util.Data.EntityFrameworkCore.PostgreSql/PgSqlOptionsExtension.cs index 3a74da98..0344fc66 100644 --- a/src/Util.Data.EntityFrameworkCore.PostgreSql/PgSqlOptionsExtension.cs +++ b/src/Util.Data.EntityFrameworkCore.PostgreSql/PgSqlOptionsExtension.cs @@ -2,6 +2,7 @@ using System.Data.Common; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; using Npgsql.EntityFrameworkCore.PostgreSQL.Infrastructure; using Util.Configs; @@ -9,7 +10,7 @@ namespace Util.Data.EntityFrameworkCore { /// /// PostgreSql工作单元配置扩展 /// - public class PgSqlOptionsExtension : IOptionsExtension + public class PgSqlOptionsExtension : OptionsExtensionBase where TService : class, IUnitOfWork where TImplementation : UnitOfWorkBase, TService { /// @@ -43,18 +44,15 @@ namespace Util.Data.EntityFrameworkCore { _pgSqlSetupAction = pgSqlSetupAction; } - /// - /// 添加服务 - /// - /// 服务集合 - public void AddServices( IServiceCollection services ) { + /// + public override void ConfigureServices( HostBuilderContext context, IServiceCollection services ) { services.AddDbContext( options => { _setupAction?.Invoke( options ); if ( _connectionString.IsEmpty() == false ) { options.UseNpgsql( _connectionString, _pgSqlSetupAction ); return; } - if( _connection != null ) { + if ( _connection != null ) { options.UseNpgsql( _connection, _pgSqlSetupAction ); } } ); diff --git a/src/Util.Data.EntityFrameworkCore.SqlServer/02-Util.Data.EntityFrameworkCore.SqlServer.csproj b/src/Util.Data.EntityFrameworkCore.SqlServer/02-Util.Data.EntityFrameworkCore.SqlServer.csproj index 175a4ff8..00e8660c 100644 --- a/src/Util.Data.EntityFrameworkCore.SqlServer/02-Util.Data.EntityFrameworkCore.SqlServer.csproj +++ b/src/Util.Data.EntityFrameworkCore.SqlServer/02-Util.Data.EntityFrameworkCore.SqlServer.csproj @@ -5,7 +5,7 @@ icon.jpg Util.Data.EntityFrameworkCore.SqlServer Util.Data.EntityFrameworkCore - Util.Data.EntityFrameworkCore.SqlServer是Util应用框架针对SqlServer数据库的EntityFrameworkCore封装类库 + Util.Data.EntityFrameworkCore.SqlServer是Util应用框架基于EntityFrameworkCore的数据访问封装类库,用于处理SqlServer数据库 @@ -27,7 +27,7 @@ - + diff --git a/src/Util.Data.EntityFrameworkCore.SqlServer/SqlServerOptionsExtension.cs b/src/Util.Data.EntityFrameworkCore.SqlServer/SqlServerOptionsExtension.cs index 3d283ad4..64eb813e 100644 --- a/src/Util.Data.EntityFrameworkCore.SqlServer/SqlServerOptionsExtension.cs +++ b/src/Util.Data.EntityFrameworkCore.SqlServer/SqlServerOptionsExtension.cs @@ -3,13 +3,14 @@ using System.Data.Common; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; using Util.Configs; namespace Util.Data.EntityFrameworkCore { /// /// Sql Server 工作单元配置扩展 /// - public class SqlServerOptionsExtension : IOptionsExtension + public class SqlServerOptionsExtension : OptionsExtensionBase where TService : class, IUnitOfWork where TImplementation : UnitOfWorkBase, TService { /// @@ -43,18 +44,15 @@ namespace Util.Data.EntityFrameworkCore { _sqlServerSetupAction = sqlServerSetupAction; } - /// - /// 添加服务 - /// - /// 服务集合 - public void AddServices( IServiceCollection services ) { + /// + public override void ConfigureServices( HostBuilderContext context, IServiceCollection services ) { services.AddDbContext( options => { _setupAction?.Invoke( options ); if ( _connectionString.IsEmpty() == false ) { options.UseSqlServer( _connectionString, _sqlServerSetupAction ); return; } - if( _connection != null ) { + if ( _connection != null ) { options.UseSqlServer( _connection, _sqlServerSetupAction ); } } ); diff --git a/src/Util.Data.EntityFrameworkCore.Sqlite/05-Util.Data.EntityFrameworkCore.Sqlite.csproj b/src/Util.Data.EntityFrameworkCore.Sqlite/05-Util.Data.EntityFrameworkCore.Sqlite.csproj new file mode 100644 index 00000000..81b65773 --- /dev/null +++ b/src/Util.Data.EntityFrameworkCore.Sqlite/05-Util.Data.EntityFrameworkCore.Sqlite.csproj @@ -0,0 +1,37 @@ + + + + $(NetTargetFramework) + icon.jpg + Util.Data.EntityFrameworkCore.Sqlite + Util.Data.EntityFrameworkCore + Util.Data.EntityFrameworkCore.Sqlite是Util应用框架基于EntityFrameworkCore的数据访问封装类库,用于处理Sqlite数据库 + + + + + .\obj\Debug\$(NetTargetFramework)\Util.Data.EntityFrameworkCore.Sqlite.xml + + + + + .\obj\Release\$(NetTargetFramework)\Util.Data.EntityFrameworkCore.Sqlite.xml + + + + + True + False + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Util.Data.EntityFrameworkCore.Sqlite/OptionsExtensions.cs b/src/Util.Data.EntityFrameworkCore.Sqlite/OptionsExtensions.cs new file mode 100644 index 00000000..f1393793 --- /dev/null +++ b/src/Util.Data.EntityFrameworkCore.Sqlite/OptionsExtensions.cs @@ -0,0 +1,51 @@ +using System; +using System.Data.Common; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Util.Configs; + +namespace Util.Data.EntityFrameworkCore { + /// + /// Sqlite工作单元操作扩展 + /// + public static class OptionsExtensions { + /// + /// 配置Sqlite工作单元 + /// + /// 配置项 + /// 数据库连接字符串 + /// 工作单元配置操作 + /// Sqlite配置操作 + public static Options UseSqliteUnitOfWork( this Options options, string connection, Action setupAction = null, + Action sqliteSetupAction = null ) + where TService : class, IUnitOfWork + where TImplementation : UnitOfWorkBase, TService { + return options.UseSqliteUnitOfWork( connection, null, setupAction, sqliteSetupAction ); + } + + /// + /// 配置Sqlite工作单元 + /// + /// 配置项 + /// 数据库连接 + /// 工作单元配置操作 + /// Sqlite配置操作 + public static Options UseSqliteUnitOfWork( this Options options, DbConnection connection, Action setupAction = null, + Action sqliteSetupAction = null ) + where TService : class, IUnitOfWork + where TImplementation : UnitOfWorkBase, TService { + return options.UseSqliteUnitOfWork( null, connection, setupAction, sqliteSetupAction ); + } + + /// + /// 配置Sqlite工作单元 + /// + private static Options UseSqliteUnitOfWork( this Options options, string connectionString, DbConnection connection, Action setupAction, + Action sqliteSetupAction ) + where TService : class, IUnitOfWork + where TImplementation : UnitOfWorkBase, TService { + options.AddExtension( new SqliteOptionsExtension( connectionString, connection, setupAction, sqliteSetupAction ) ); + return options; + } + } +} diff --git a/src/Util.Data.EntityFrameworkCore.Sqlite/SqliteOptionsExtension.cs b/src/Util.Data.EntityFrameworkCore.Sqlite/SqliteOptionsExtension.cs new file mode 100644 index 00000000..b6a0d203 --- /dev/null +++ b/src/Util.Data.EntityFrameworkCore.Sqlite/SqliteOptionsExtension.cs @@ -0,0 +1,61 @@ +using System; +using System.Data.Common; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Util.Configs; + +namespace Util.Data.EntityFrameworkCore { + /// + /// Sqlite工作单元配置扩展 + /// + public class SqliteOptionsExtension : OptionsExtensionBase + where TService : class, IUnitOfWork + where TImplementation : UnitOfWorkBase, TService { + /// + /// 数据库连接字符串 + /// + private readonly string _connectionString; + /// + /// 数据库连接 + /// + private readonly DbConnection _connection; + /// + /// 工作单元配置操作 + /// + private readonly Action _setupAction; + /// + /// Sqlite配置操作 + /// + private readonly Action _sqliteSetupAction; + + /// + /// 初始化Sqlite工作单元配置扩展 + /// + /// 数据库连接字符串 + /// 数据库连接 + /// 工作单元配置操作 + /// Sqlite配置操作 + public SqliteOptionsExtension( string connectionString, DbConnection connection, Action setupAction, Action sqliteSetupAction ) { + _connectionString = connectionString; + _connection = connection; + _setupAction = setupAction; + _sqliteSetupAction = sqliteSetupAction; + } + + /// + public override void ConfigureServices( HostBuilderContext context, IServiceCollection services ) { + services.AddDbContext( options => { + _setupAction?.Invoke( options ); + if ( _connectionString.IsEmpty() == false ) { + options.UseSqlite( _connectionString, _sqliteSetupAction ); + return; + } + if ( _connection != null ) { + options.UseSqlite( _connection, _sqliteSetupAction ); + } + } ); + } + } +} diff --git a/src/Util.Data.EntityFrameworkCore.Sqlite/SqliteUnitOfWorkBase.cs b/src/Util.Data.EntityFrameworkCore.Sqlite/SqliteUnitOfWorkBase.cs new file mode 100644 index 00000000..975c39cd --- /dev/null +++ b/src/Util.Data.EntityFrameworkCore.Sqlite/SqliteUnitOfWorkBase.cs @@ -0,0 +1,18 @@ +using System; +using Microsoft.EntityFrameworkCore; + +namespace Util.Data.EntityFrameworkCore { + /// + /// Sqlite工作单元基类 + /// + public abstract class SqliteUnitOfWorkBase : UnitOfWorkBase { + /// + /// 初始化Sqlite工作单元 + /// + /// 服务提供器 + /// 配置 + protected SqliteUnitOfWorkBase( IServiceProvider serviceProvider, DbContextOptions options ) + : base( serviceProvider, options ) { + } + } +} diff --git a/src/Util.Data.EntityFrameworkCore/01-Util.Data.EntityFrameworkCore.csproj b/src/Util.Data.EntityFrameworkCore/01-Util.Data.EntityFrameworkCore.csproj index c11746d8..85d07c53 100644 --- a/src/Util.Data.EntityFrameworkCore/01-Util.Data.EntityFrameworkCore.csproj +++ b/src/Util.Data.EntityFrameworkCore/01-Util.Data.EntityFrameworkCore.csproj @@ -5,7 +5,7 @@ icon.jpg Util.Data.EntityFrameworkCore Util.Data.EntityFrameworkCore - Util.Data.EntityFrameworkCore是Util应用框架EntityFrameworkCore数据访问封装基础类库 + Util.Data.EntityFrameworkCore是Util应用框架基于EntityFrameworkCore的数据访问封装基础类库 @@ -27,8 +27,8 @@ - - + + diff --git a/src/Util.Data.EntityFrameworkCore/Infrastructure/EntityFrameworkServiceRegistrar.cs b/src/Util.Data.EntityFrameworkCore/Infrastructure/EntityFrameworkServiceRegistrar.cs index dc31eb0d..2931b669 100644 --- a/src/Util.Data.EntityFrameworkCore/Infrastructure/EntityFrameworkServiceRegistrar.cs +++ b/src/Util.Data.EntityFrameworkCore/Infrastructure/EntityFrameworkServiceRegistrar.cs @@ -1,6 +1,5 @@ using System; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; using Util.Data.EntityFrameworkCore.Filters; using Util.Domain; using Util.Infrastructure; @@ -29,10 +28,9 @@ namespace Util.Data.EntityFrameworkCore.Infrastructure { /// /// 注册服务 /// - /// 服务集合 - /// 配置 + /// 主机生成器 /// 类型查找器 - public Action Register( IServiceCollection services, IConfiguration configuration, ITypeFinder finder ) { + public Action Register( IHostBuilder hostBuilder, ITypeFinder finder ) { FilterManager.AddFilterType(); return null; } diff --git a/src/Util.Data.EntityFrameworkCore/StoreBase.cs b/src/Util.Data.EntityFrameworkCore/StoreBase.cs index ae8be9ff..cac71dca 100644 --- a/src/Util.Data.EntityFrameworkCore/StoreBase.cs +++ b/src/Util.Data.EntityFrameworkCore/StoreBase.cs @@ -11,7 +11,6 @@ using Util.Data.Queries; using Util.Data.Stores; using Util.Domain; using Util.Exceptions; -using Convert = Util.Helpers.Convert; namespace Util.Data.EntityFrameworkCore { /// @@ -35,6 +34,15 @@ namespace Util.Data.EntityFrameworkCore { /// 实体标识类型 public abstract class StoreBase : IStore, IFilterSwitch, ITrack where TEntity : class, IKey { + #region 字段 + + /// + /// 是否已释放 + /// + private bool _disposed; + + #endregion + #region 构造方法 /// @@ -105,7 +113,8 @@ namespace Util.Data.EntityFrameworkCore { /// public IQueryable Find() { - if( IsTracking ) + ThrowIfDisposed(); + if ( IsTracking ) return Set; var result = Set.AsNoTracking(); IsTracking = true; @@ -128,7 +137,8 @@ namespace Util.Data.EntityFrameworkCore { /// public TEntity FindById( object id ) { - if( id.SafeString().IsEmpty() ) + ThrowIfDisposed(); + if ( id.SafeString().IsEmpty() ) return null; var key = GetKey( id ); if( IsTracking ) @@ -142,7 +152,7 @@ namespace Util.Data.EntityFrameworkCore { protected object GetKey( object id ) { if( id is TKey ) return id; - return Convert.To( id ); + return Util.Helpers.Convert.To( id ); } #endregion @@ -151,7 +161,9 @@ namespace Util.Data.EntityFrameworkCore { /// public async Task FindByIdAsync( object id, CancellationToken cancellationToken = default ) { - if( id.SafeString().IsEmpty() ) + cancellationToken.ThrowIfCancellationRequested(); + ThrowIfDisposed(); + if ( id.SafeString().IsEmpty() ) return null; var key = GetKey( id ); if( IsTracking ) @@ -175,7 +187,7 @@ namespace Util.Data.EntityFrameworkCore { /// public virtual List FindByIds( string ids ) { - return FindByIds( Convert.ToList( ids ) ); + return FindByIds( Util.Helpers.Convert.ToList( ids ) ); } #endregion @@ -189,12 +201,13 @@ namespace Util.Data.EntityFrameworkCore { /// public virtual async Task> FindByIdsAsync( IEnumerable ids, CancellationToken cancellationToken = default ) { + cancellationToken.ThrowIfCancellationRequested(); return ids == null ? null : await Find( t => ids.Contains( t.Id ) ).ToListAsync( cancellationToken ); } /// public virtual async Task> FindByIdsAsync( string ids, CancellationToken cancellationToken = default ) { - return await FindByIdsAsync( Convert.ToList( ids ), cancellationToken ); + return await FindByIdsAsync( Util.Helpers.Convert.ToList( ids ), cancellationToken ); } #endregion @@ -219,12 +232,14 @@ namespace Util.Data.EntityFrameworkCore { /// public virtual async Task SingleAsync( Expression> condition, CancellationToken cancellationToken = default ) { + cancellationToken.ThrowIfCancellationRequested(); return await Find().FirstOrDefaultAsync( condition, cancellationToken ); } /// public virtual async Task SingleAsync( Expression> condition, Func, IQueryable> action, CancellationToken cancellationToken = default ) { - if( action == null ) + cancellationToken.ThrowIfCancellationRequested(); + if ( action == null ) return await SingleAsync( condition, cancellationToken ); return await action( Find() ).FirstOrDefaultAsync( condition, cancellationToken ); } @@ -244,7 +259,8 @@ namespace Util.Data.EntityFrameworkCore { /// public virtual async Task> FindAllAsync( Expression> condition = null, CancellationToken cancellationToken = default ) { - if( condition == null ) + cancellationToken.ThrowIfCancellationRequested(); + if ( condition == null ) return await Find().ToListAsync( cancellationToken ); return await Find( condition ).ToListAsync( cancellationToken ); } @@ -274,6 +290,7 @@ namespace Util.Data.EntityFrameworkCore { /// public virtual async Task ExistsAsync( Expression> condition, CancellationToken cancellationToken = default ) { + cancellationToken.ThrowIfCancellationRequested(); return condition != null && await Find().AnyAsync( condition, cancellationToken ); } @@ -292,6 +309,7 @@ namespace Util.Data.EntityFrameworkCore { /// public virtual async Task CountAsync( Expression> condition = null, CancellationToken cancellationToken = default ) { + cancellationToken.ThrowIfCancellationRequested(); return condition == null ? await Find().CountAsync( cancellationToken ) : await Find().CountAsync( condition, cancellationToken ); @@ -299,28 +317,6 @@ namespace Util.Data.EntityFrameworkCore { #endregion - #region Add(添加实体) - - /// - /// 添加实体 - /// - /// 实体 - public virtual void Add( TEntity entity ) { - entity.CheckNull( nameof( entity ) ); - Set.Add( entity ); - } - - /// - /// 添加实体集合 - /// - /// 实体集合 - public virtual void Add( IEnumerable entities ) { - entities.CheckNull( nameof( entities ) ); - Set.AddRange( entities ); - } - - #endregion - #region AddAsync(添加实体) /// @@ -329,6 +325,8 @@ namespace Util.Data.EntityFrameworkCore { /// 实体 /// 取消令牌 public virtual async Task AddAsync( TEntity entity, CancellationToken cancellationToken = default ) { + cancellationToken.ThrowIfCancellationRequested(); + ThrowIfDisposed(); entity.CheckNull( nameof( entity ) ); await Set.AddAsync( entity, cancellationToken ); } @@ -339,16 +337,28 @@ namespace Util.Data.EntityFrameworkCore { /// 实体集合 /// 取消令牌 public virtual async Task AddAsync( IEnumerable entities, CancellationToken cancellationToken = default ) { + cancellationToken.ThrowIfCancellationRequested(); + ThrowIfDisposed(); entities.CheckNull( nameof( entities ) ); await Set.AddRangeAsync( entities, cancellationToken ); } #endregion - #region Update(修改实体) + #region UpdateAsync(修改实体) /// - public virtual void Update( TEntity entity ) { + public virtual Task UpdateAsync( TEntity entity, CancellationToken cancellationToken = default ) { + cancellationToken.ThrowIfCancellationRequested(); + Update( entity ); + return Task.CompletedTask; + } + + /// + /// 更新 + /// + protected void Update( TEntity entity ) { + ThrowIfDisposed(); entity.CheckNull( nameof( entity ) ); var entry = UnitOfWork.Entry( entity ); ValidateVersion( entry, entity ); @@ -359,15 +369,15 @@ namespace Util.Data.EntityFrameworkCore { /// 验证版本号 /// protected void ValidateVersion( EntityEntry entry, TEntity entity ) { - if( entry.State == EntityState.Detached ) + if ( entry.State == EntityState.Detached ) return; - if( entity is not IVersion current ) + if ( entity is not IVersion current ) return; - if( current.Version == null ) + if ( current.Version == null ) return; var oldVersion = entry.OriginalValues.GetValue( "Version" ); - for( int i = 0; i < oldVersion.Length; i++ ) { - if( current.Version[i] != oldVersion[i] ) + for ( int i = 0; i < oldVersion.Length; i++ ) { + if ( current.Version[i] != oldVersion[i] ) throw new ConcurrencyException( new Exception( $"Type:{typeof( TEntity )},Id:{entity.Id}" ) ); } } @@ -377,93 +387,30 @@ namespace Util.Data.EntityFrameworkCore { /// protected void UpdateEntity( EntityEntry entry, TEntity entity ) { var oldEntry = UnitOfWork.ChangeTracker.Entries().FirstOrDefault( t => t.Entity.Equals( entity ) ); - if( oldEntry != null ) { + if ( oldEntry != null ) { oldEntry.CurrentValues.SetValues( entity ); return; } - if( entry.State == EntityState.Detached ) + if ( entry.State == EntityState.Detached ) UnitOfWork.Update( entity ); } /// - public void Update( IEnumerable entities ) { - entities.CheckNull( nameof( entities ) ); - foreach( var entity in entities ) - Update( entity ); - } - - #endregion - - #region UpdateAsync(修改实体) - - /// - public virtual Task UpdateAsync( TEntity entity ) { - Update( entity ); - return Task.CompletedTask; - } - - /// - public virtual Task UpdateAsync( IEnumerable entities ) { + public virtual Task UpdateAsync( IEnumerable entities, CancellationToken cancellationToken = default ) { + cancellationToken.ThrowIfCancellationRequested(); entities.CheckNull( nameof( entities ) ); Update( entities ); return Task.CompletedTask; } - #endregion - - #region Remove(移除实体) - - /// - public void Remove( object id ) { - var entity = FindById( id ); - Delete( entity ); - } - /// - /// 删除 + /// 更新实体集合 /// - private void Delete( TEntity entity ) { - if( entity == null ) - return; - if( entity is IDelete model ) { - model.IsDeleted = true; - return; - } - Set.Remove( entity ); - } - - /// - public void Remove( TEntity entity ) { - if( entity == null ) - return; - Remove( entity.Id ); - } - - /// - public void Remove( IEnumerable ids ) { - if( ids == null ) - return; - var list = FindByIds( ids ); - Delete( list ); - } - - /// - /// 删除实体集合 - /// - private void Delete( List list ) { - if( list == null ) - return; - if( !list.Any() ) - return; - foreach( var entity in list ) - Delete( entity ); - } - - /// - public void Remove( IEnumerable entities ) { - if( entities == null ) - return; - Remove( entities.Select( t => t.Id ) ); + protected void Update( IEnumerable entities ) { + ThrowIfDisposed(); + entities.CheckNull( nameof( entities ) ); + foreach ( var entity in entities ) + Update( entity ); } #endregion @@ -472,32 +419,85 @@ namespace Util.Data.EntityFrameworkCore { /// public virtual async Task RemoveAsync( object id, CancellationToken cancellationToken = default ) { + cancellationToken.ThrowIfCancellationRequested(); + ThrowIfDisposed(); var entity = await FindByIdAsync( id, cancellationToken ); Delete( entity ); } + /// + /// 删除 + /// + private void Delete( TEntity entity ) { + if ( entity == null ) + return; + if ( entity is IDelete model ) { + model.IsDeleted = true; + return; + } + Set.Remove( entity ); + } + /// public virtual async Task RemoveAsync( TEntity entity, CancellationToken cancellationToken = default ) { - if( entity == null ) + if ( entity == null ) return; await RemoveAsync( entity.Id, cancellationToken ); } /// public virtual async Task RemoveAsync( IEnumerable ids, CancellationToken cancellationToken = default ) { - if( ids == null ) + cancellationToken.ThrowIfCancellationRequested(); + ThrowIfDisposed(); + if ( ids == null ) return; var entities = await FindByIdsAsync( ids, cancellationToken ); Delete( entities ); } + /// + /// 删除实体集合 + /// + private void Delete( List list ) { + if ( list == null ) + return; + if ( !list.Any() ) + return; + foreach ( var entity in list ) + Delete( entity ); + } + /// public virtual async Task RemoveAsync( IEnumerable entities, CancellationToken cancellationToken = default ) { - if( entities == null ) + if ( entities == null ) return; await RemoveAsync( entities.Select( t => t.Id ), cancellationToken ); } #endregion + + #region ThrowIfDisposed(已释放则抛出异常) + + /// + /// 已释放则抛出异常 + /// + protected void ThrowIfDisposed() { + if ( _disposed ) { + throw new ObjectDisposedException( GetType().Name ); + } + } + + #endregion + + #region Dispose(释放) + + /// + /// 释放 + /// + public void Dispose() { + _disposed = true; + } + + #endregion } } diff --git a/src/Util.Data.EntityFrameworkCore/UnitOfWorkBase.cs b/src/Util.Data.EntityFrameworkCore/UnitOfWorkBase.cs index dedf21a8..b6864e9f 100644 --- a/src/Util.Data.EntityFrameworkCore/UnitOfWorkBase.cs +++ b/src/Util.Data.EntityFrameworkCore/UnitOfWorkBase.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Linq.Expressions; using System.Reflection; using System.Text; @@ -13,6 +14,7 @@ using Microsoft.Extensions.Hosting; using Util.Data.EntityFrameworkCore.ValueComparers; using Util.Data.EntityFrameworkCore.ValueConverters; using Util.Data.Filters; +using Util.Dates; using Util.Domain; using Util.Domain.Auditing; using Util.Domain.Events; @@ -53,11 +55,11 @@ namespace Util.Data.EntityFrameworkCore { /// /// 服务提供器 /// - public IServiceProvider ServiceProvider { get; } + protected IServiceProvider ServiceProvider { get; } /// /// 执行环境 /// - public IHostEnvironment Environment { get; } + protected IHostEnvironment Environment { get; } /// /// 用户会话 /// @@ -111,7 +113,7 @@ namespace Util.Data.EntityFrameworkCore { /// /// 过滤器类型 public IDisposable DisableFilter() where TFilterType : class { - if( FilterManager == null ) + if ( FilterManager == null ) return DisposeAction.Null; return FilterManager.DisableFilter(); } @@ -152,11 +154,12 @@ namespace Util.Data.EntityFrameworkCore { /// 模型生成器 protected override void OnModelCreating( ModelBuilder modelBuilder ) { ApplyConfigurations( modelBuilder ); - foreach( var entityType in modelBuilder.Model.GetEntityTypes() ) { + foreach ( var entityType in modelBuilder.Model.GetEntityTypes() ) { ApplyFilters( modelBuilder, entityType ); ApplyExtraProperties( modelBuilder, entityType ); ApplyVersion( modelBuilder, entityType ); ApplyIsDeleted( modelBuilder, entityType ); + ApplyUtc( modelBuilder, entityType ); } } @@ -191,9 +194,9 @@ namespace Util.Data.EntityFrameworkCore { /// /// 模型生成器 protected virtual void ApplyFiltersImp( ModelBuilder modelBuilder ) where TEntity : class { - if( FilterManager == null ) + if ( FilterManager == null ) return; - if( FilterManager.IsEntityEnabled() == false ) + if ( FilterManager.IsEntityEnabled() == false ) return; modelBuilder.Entity().HasQueryFilter( GetFilterExpression() ); } @@ -212,7 +215,7 @@ namespace Util.Data.EntityFrameworkCore { /// 实体类型 protected virtual Expression> GetDeleteFilterExpression() where TEntity : class { var filter = FilterManager.GetFilter(); - if( filter.IsEntityEnabled() == false ) + if ( filter.IsEntityEnabled() == false ) return null; var expression = filter.GetExpression(); Expression> result = entity => !IsDeleteFilterEnabled; @@ -229,7 +232,7 @@ namespace Util.Data.EntityFrameworkCore { /// 模型生成器 /// 实体类型 protected virtual void ApplyExtraProperties( ModelBuilder modelBuilder, IMutableEntityType entityType ) { - if( typeof( IExtraProperties ).IsAssignableFrom( entityType.ClrType ) == false ) + if ( typeof( IExtraProperties ).IsAssignableFrom( entityType.ClrType ) == false ) return; modelBuilder.Entity( entityType.ClrType ) .Property( "ExtraProperties" ) @@ -248,7 +251,7 @@ namespace Util.Data.EntityFrameworkCore { /// 模型生成器 /// 实体类型 protected virtual void ApplyVersion( ModelBuilder modelBuilder, IMutableEntityType entityType ) { - if( typeof( IVersion ).IsAssignableFrom( entityType.ClrType ) == false ) + if ( typeof( IVersion ).IsAssignableFrom( entityType.ClrType ) == false ) return; modelBuilder.Entity( entityType.ClrType ) .Property( "Version" ) @@ -266,7 +269,7 @@ namespace Util.Data.EntityFrameworkCore { /// 模型生成器 /// 实体类型 protected virtual void ApplyIsDeleted( ModelBuilder modelBuilder, IMutableEntityType entityType ) { - if( typeof( IDelete ).IsAssignableFrom( entityType.ClrType ) == false ) + if ( typeof( IDelete ).IsAssignableFrom( entityType.ClrType ) == false ) return; modelBuilder.Entity( entityType.ClrType ) .Property( "IsDeleted" ) @@ -275,6 +278,28 @@ namespace Util.Data.EntityFrameworkCore { #endregion + #region ApplyUtc(配置Utc日期) + + /// + /// 配置Utc日期 + /// + /// 模型生成器 + /// 实体类型 + protected virtual void ApplyUtc( ModelBuilder modelBuilder, IMutableEntityType entityType ) { + if ( TimeOptions.IsUseUtc == false ) + return; + var properties = entityType.ClrType.GetProperties() + .Where( property => ( property.PropertyType == typeof( DateTime ) || property.PropertyType == typeof( DateTime? ) ) && property.CanWrite ) + .ToList(); + properties.ForEach( property => { + modelBuilder.Entity( entityType.ClrType ) + .Property( property.Name ) + .HasConversion( new DateTimeValueConverter() ); + } ); + } + + #endregion + #region Commit(提交) /// @@ -284,18 +309,11 @@ namespace Util.Data.EntityFrameworkCore { try { return SaveChanges(); } - catch( DbUpdateConcurrencyException ex ) { + catch ( DbUpdateConcurrencyException ex ) { throw new ConcurrencyException( ex ); } } - /// - /// 保存更改 - /// - public override int SaveChanges() { - return SaveChangesAsync().GetAwaiter().GetResult(); - } - #endregion #region CommitAsync(提交) @@ -307,7 +325,7 @@ namespace Util.Data.EntityFrameworkCore { try { return await SaveChangesAsync(); } - catch( DbUpdateConcurrencyException ex ) { + catch ( DbUpdateConcurrencyException ex ) { throw new ConcurrencyException( ex ); } } @@ -334,8 +352,8 @@ namespace Util.Data.EntityFrameworkCore { /// 保存前操作 /// protected virtual void SaveChangesBefore() { - foreach( var entry in ChangeTracker.Entries() ) { - switch( entry.State ) { + foreach ( var entry in ChangeTracker.Entries() ) { + switch ( entry.State ) { case EntityState.Added: AddBefore( entry ); break; @@ -418,10 +436,10 @@ namespace Util.Data.EntityFrameworkCore { /// 设置版本号 /// protected virtual void SetVersion( object obj ) { - if( !( obj is IVersion entity ) ) + if ( !( obj is IVersion entity ) ) return; var version = GetVersion(); - if( version == null ) + if ( version == null ) return; entity.Version = version; } @@ -458,7 +476,7 @@ namespace Util.Data.EntityFrameworkCore { /// 添加实体创建事件 /// protected virtual void AddEntityCreatedEvent( object entity ) { - var @event = CreateEntityEvent( typeof(EntityCreatedEvent<>), entity ); + var @event = CreateEntityEvent( typeof( EntityCreatedEvent<> ), entity ); Events.Add( @event ); AddEntityChangedEvent( entity, EntityChangeType.Created ); } @@ -479,7 +497,7 @@ namespace Util.Data.EntityFrameworkCore { /// 添加实体修改事件 /// protected virtual void AddEntityUpdatedEvent( object entity ) { - if ( entity is IDelete {IsDeleted: true} ) { + if ( entity is IDelete { IsDeleted: true } ) { AddEntityDeletedEvent( entity ); return; } diff --git a/src/Util.Data.EntityFrameworkCore/ValueConverters/DateTimeValueConverter.cs b/src/Util.Data.EntityFrameworkCore/ValueConverters/DateTimeValueConverter.cs new file mode 100644 index 00000000..0f1c3fe1 --- /dev/null +++ b/src/Util.Data.EntityFrameworkCore/ValueConverters/DateTimeValueConverter.cs @@ -0,0 +1,20 @@ +using System; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Util.Helpers; + +namespace Util.Data.EntityFrameworkCore.ValueConverters { + /// + /// 日期值转换器,用于处理Utc日期 + /// + public class DateTimeValueConverter : ValueConverter { + /// + /// 初始化日期值转换器 + /// + public DateTimeValueConverter( ConverterMappingHints mappingHints = null ) + : base( + date => date.HasValue ? Time.Normalize( date.Value ) : date, + date => date.HasValue ? Time.Normalize( date.Value ) : date, mappingHints + ) { + } + } +} \ No newline at end of file diff --git a/src/Util.Data.EntityFrameworkCore/ValueConverters/ExtraPropertiesValueConverter.cs b/src/Util.Data.EntityFrameworkCore/ValueConverters/ExtraPropertiesValueConverter.cs index e2be1f58..d69c3ded 100644 --- a/src/Util.Data.EntityFrameworkCore/ValueConverters/ExtraPropertiesValueConverter.cs +++ b/src/Util.Data.EntityFrameworkCore/ValueConverters/ExtraPropertiesValueConverter.cs @@ -1,4 +1,5 @@ using System.Text.Json; +using System.Text.Json.Serialization; using Microsoft.EntityFrameworkCore.Storage.ValueConversion; using Util.Domain.Extending; @@ -18,7 +19,7 @@ namespace Util.Data.EntityFrameworkCore.ValueConverters { /// 扩展属性转换为json /// private static string PropertiesToJson( ExtraPropertyDictionary extraProperties ) { - var options = new JsonSerializerOptions { IgnoreNullValues = true }; + var options = new JsonSerializerOptions { DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull }; return Util.Helpers.Json.ToJson( extraProperties, options ); } diff --git a/src/Util.Data.Metadata/03-Util.Data.Metadata.csproj b/src/Util.Data.Metadata/03-Util.Data.Metadata.csproj new file mode 100644 index 00000000..fdc9b0f7 --- /dev/null +++ b/src/Util.Data.Metadata/03-Util.Data.Metadata.csproj @@ -0,0 +1,32 @@ + + + + $(NetTargetFramework) + icon.jpg + Util.Data.Metadata + Util.Data.Metadata + Util.Data.Metadata是Util应用框架数据库元数据操作类库 + + + + + .\obj\Debug\$(NetTargetFramework)\Util.Data.Metadata.xml + + + + + .\obj\Release\$(NetTargetFramework)\Util.Data.Metadata.xml + + + + + True + False + + + + + + + + diff --git a/src/Util.Data.Metadata/ColumnInfo.cs b/src/Util.Data.Metadata/ColumnInfo.cs new file mode 100644 index 00000000..dc74df05 --- /dev/null +++ b/src/Util.Data.Metadata/ColumnInfo.cs @@ -0,0 +1,47 @@ +namespace Util.Data.Metadata { + /// + /// 列信息 + /// + public class ColumnInfo { + /// + /// 列标识 + /// + public string Id { get; set; } + /// + /// 列名 + /// + public string Name { get; set; } + /// + /// 注释 + /// + public string Comment { get; set; } + /// + /// 是否主键 + /// + public bool IsPrimaryKey { get; set; } + /// + /// 是否自增 + /// + public bool IsAutoIncrement { get; set; } + /// + /// 是否可空 + /// + public bool? IsNullable { get; set; } + /// + /// 数据类型 + /// + public string DataType { get; set; } + /// + /// 长度 + /// + public long Length { get; set; } + /// + /// 精度,即数值位数 + /// + public int? Precision { get; set; } + /// + /// 小数位数 + /// + public int? Scale { get; set; } + } +} diff --git a/src/Util.Data.Metadata/DatabaseInfo.cs b/src/Util.Data.Metadata/DatabaseInfo.cs new file mode 100644 index 00000000..589d2c7b --- /dev/null +++ b/src/Util.Data.Metadata/DatabaseInfo.cs @@ -0,0 +1,28 @@ +using System.Collections.Generic; + +namespace Util.Data.Metadata { + /// + /// 数据库信息 + /// + public class DatabaseInfo { + /// + /// 初始化数据库信息 + /// + public DatabaseInfo() { + Tables = new List(); + } + + /// + /// 数据库标识 + /// + public string Id { get; set; } + /// + /// 数据库名 + /// + public string Name { get; set; } + /// + /// 表信息集合 + /// + public List Tables { get; } + } +} diff --git a/src/Util.Data.Metadata/IMetadataService.cs b/src/Util.Data.Metadata/IMetadataService.cs new file mode 100644 index 00000000..a0e20baf --- /dev/null +++ b/src/Util.Data.Metadata/IMetadataService.cs @@ -0,0 +1,11 @@ +namespace Util.Data.Metadata { + /// + /// 数据库元数据服务 + /// + public interface IMetadataService { + /// + /// 获取数据库信息 + /// + DatabaseInfo GetDatabaseInfo(); + } +} diff --git a/src/Util.Data.Metadata/IMetadataServiceFactory.cs b/src/Util.Data.Metadata/IMetadataServiceFactory.cs new file mode 100644 index 00000000..c11fd0ea --- /dev/null +++ b/src/Util.Data.Metadata/IMetadataServiceFactory.cs @@ -0,0 +1,13 @@ +namespace Util.Data.Metadata { + /// + /// 数据库元数据服务工厂 + /// + public interface IMetadataServiceFactory { + /// + /// 创建数据库元数据服务 + /// + /// 数据库类型 + /// 数据库连接字符串 + IMetadataService Create( DatabaseType dbType, string connection ); + } +} diff --git a/src/Util.Data.Metadata/ITypeConverter.cs b/src/Util.Data.Metadata/ITypeConverter.cs new file mode 100644 index 00000000..fe59b31c --- /dev/null +++ b/src/Util.Data.Metadata/ITypeConverter.cs @@ -0,0 +1,15 @@ +using System.Data; + +namespace Util.Data.Metadata { + /// + /// 数据类型转换器 + /// + public interface ITypeConverter { + /// + /// 将数据类型转换为DbType + /// + /// 数据类型 + /// 数据长度 + DbType? ToType( string dataType, int? length = null ); + } +} diff --git a/src/Util.Data.Metadata/ITypeConverterFactory.cs b/src/Util.Data.Metadata/ITypeConverterFactory.cs new file mode 100644 index 00000000..972a7a3d --- /dev/null +++ b/src/Util.Data.Metadata/ITypeConverterFactory.cs @@ -0,0 +1,12 @@ +namespace Util.Data.Metadata { + /// + /// 数据类型转换器工厂 + /// + public interface ITypeConverterFactory { + /// + /// 创建数据库元数据服务 + /// + /// 数据库类型 + ITypeConverter Create( DatabaseType dbType ); + } +} diff --git a/src/Util.Data.Metadata/TableInfo.cs b/src/Util.Data.Metadata/TableInfo.cs new file mode 100644 index 00000000..9d58363b --- /dev/null +++ b/src/Util.Data.Metadata/TableInfo.cs @@ -0,0 +1,36 @@ +using System.Collections.Generic; + +namespace Util.Data.Metadata { + /// + /// 表信息 + /// + public class TableInfo { + /// + /// 初始化表信息 + /// + public TableInfo() { + Columns = new List(); + } + + /// + /// 表标识 + /// + public string Id { get; set; } + /// + /// 架构 + /// + public string Schema { get; set; } + /// + /// 表名 + /// + public string Name { get; set; } + /// + /// 注释 + /// + public string Comment { get; set; } + /// + /// 列信息集合 + /// + public List Columns { get; } + } +} diff --git a/src/Util.Data.Sql/02-Util.Data.Sql.csproj b/src/Util.Data.Sql/02-Util.Data.Sql.csproj new file mode 100644 index 00000000..0a6cccf3 --- /dev/null +++ b/src/Util.Data.Sql/02-Util.Data.Sql.csproj @@ -0,0 +1,34 @@ + + + + $(NetTargetFramework) + icon.jpg + Util.Data.Sql + Util.Data.Sql + Util.Data.Sql是Util应用框架处理和构造Sql相关的数据访问基础类库 + + + + + .\obj\Debug\$(NetTargetFramework)\Util.Data.Sql.xml + + + + + .\obj\Release\$(NetTargetFramework)\Util.Data.Sql.xml + + + + + True + False + + + + + + + + + + diff --git a/src/Util.Data.Sql/Builders/Caches/ColumnCacheBase.cs b/src/Util.Data.Sql/Builders/Caches/ColumnCacheBase.cs new file mode 100644 index 00000000..fa525cb1 --- /dev/null +++ b/src/Util.Data.Sql/Builders/Caches/ColumnCacheBase.cs @@ -0,0 +1,63 @@ +using System.Linq; +using System.Text; +using Util.Data.Sql.Builders.Core; + +namespace Util.Data.Sql.Builders.Caches { + /// + /// 列缓存基类 + /// + public abstract class ColumnCacheBase : IColumnCache { + /// + /// Sql方言 + /// + protected readonly IDialect Dialect; + + /// + /// 初始化列缓存 + /// + /// Sql方言 + protected ColumnCacheBase( IDialect dialect ) { + Dialect = dialect; + } + + /// + /// 从缓存中获取处理后的列集合 + /// + /// 列集合 + public abstract string GetSafeColumns( string columns ); + + /// + /// 规范化列集合 + /// + /// 列集合 + protected string NormalizeColumns( string columns ) { + if( columns.IsEmpty() ) + return null; + var result = new StringBuilder(); + var items = columns.Split( ',' ).Where( column => column.IsEmpty() == false ).Select( column => new ColumnItem( Dialect, column ) ); + foreach( var item in items ) { + item.AppendTo( result ); + result.Append( "," ); + } + result.RemoveEnd( "," ); + return result.ToString(); + } + + /// + /// 从缓存中获取处理后的列 + /// + /// 列 + public abstract string GetSafeColumn( string column ); + + /// + /// 规范化列 + /// + /// 列 + protected string NormalizeColumn( string column ) { + if( column.IsEmpty() ) + return null; + var item = new ColumnItem( Dialect, column ); + return item.ToResult(); + } + } +} diff --git a/src/Util.Data.Sql/Builders/Caches/IColumnCache.cs b/src/Util.Data.Sql/Builders/Caches/IColumnCache.cs new file mode 100644 index 00000000..ff686950 --- /dev/null +++ b/src/Util.Data.Sql/Builders/Caches/IColumnCache.cs @@ -0,0 +1,17 @@ +namespace Util.Data.Sql.Builders.Caches { + /// + /// 列缓存 + /// + public interface IColumnCache { + /// + /// 从缓存中获取处理后的列集合 + /// + /// 列集合 + string GetSafeColumns( string columns ); + /// + /// 从缓存中获取处理后的列 + /// + /// 列 + string GetSafeColumn( string column ); + } +} diff --git a/src/Util.Data.Sql/Builders/Clauses/ClauseBase.cs b/src/Util.Data.Sql/Builders/Clauses/ClauseBase.cs new file mode 100644 index 00000000..64db9d87 --- /dev/null +++ b/src/Util.Data.Sql/Builders/Clauses/ClauseBase.cs @@ -0,0 +1,34 @@ +using System; + +namespace Util.Data.Sql.Builders.Clauses { + /// + /// Sql子句基类 + /// + public abstract class ClauseBase { + /// + /// Sql生成器 + /// + protected readonly SqlBuilderBase SqlBuilder; + /// + /// Sql方言 + /// + protected readonly IDialect Dialect; + + /// + /// 初始化Sql子句 + /// + /// Sql生成器 + protected ClauseBase( SqlBuilderBase sqlBuilder ) { + SqlBuilder = sqlBuilder ?? throw new ArgumentNullException( nameof( sqlBuilder ) ); + Dialect = SqlBuilder.Dialect; + } + + /// + /// 替换原始Sql,将[]替换为特定Sql转义符 + /// + /// 原始Sql + protected string ReplaceRawSql( string sql ) { + return Dialect.ReplaceSql( sql ); + } + } +} diff --git a/src/Util.Data.Sql/Builders/Clauses/EndClause.cs b/src/Util.Data.Sql/Builders/Clauses/EndClause.cs new file mode 100644 index 00000000..0b9b2aac --- /dev/null +++ b/src/Util.Data.Sql/Builders/Clauses/EndClause.cs @@ -0,0 +1,209 @@ +using System.Text; +using Util.Data.Queries; +using Util.Data.Sql.Builders.Params; + +namespace Util.Data.Sql.Builders.Clauses { + /// + /// 结束子句 + /// + public class EndClause : ClauseBase, IEndClause { + + #region 字段 + + /// + /// 结束子句结果 + /// + protected readonly StringBuilder Result; + /// + /// 跳过行数参数名 + /// + protected string OffsetParam; + /// + /// 限制行数参数名 + /// + protected string LimitParam; + /// + /// 参数管理器 + /// + protected IParameterManager ParameterManager; + /// + /// 分页 + /// + protected IPage Pager; + + #endregion + + #region 构造方法 + + /// + /// 初始化结束子句 + /// + /// Sql生成器 + /// 结束子句结果 + /// 跳过行数参数名 + /// 限制行数参数名 + /// 分页 + public EndClause( SqlBuilderBase sqlBuilder, StringBuilder result = null, string offsetParam = null, string limitParam = null, IPage pager = null ) : base( sqlBuilder ) { + Result = result ?? new StringBuilder(); + OffsetParam = offsetParam; + LimitParam = limitParam; + Pager = pager; + ParameterManager = sqlBuilder.ParameterManager; + } + + #endregion + + #region Page(设置分页) + + /// + public void Page( IPage page ) { + if( page == null ) + return; + Pager = page; + Skip( page.GetSkipCount() ); + Take( page.PageSize ); + } + + #endregion + + #region Skip(设置跳过行数) + + /// + public void Skip( int count ) { + var param = GetOffsetParam(); + ParameterManager.Add( param, count ); + } + + /// + /// 获取跳过行数参数名 + /// + protected string GetOffsetParam() { + if( OffsetParam.IsEmpty() == false ) + return OffsetParam; + OffsetParam = CreateOffsetParam(); + return OffsetParam; + } + + /// + /// 创建跳过行数参数名 + /// + private string CreateOffsetParam() { + var result = ParameterManager.GenerateName(); + ParameterManager.Add( result, 0 ); + return result; + } + + #endregion + + #region Take(设置获取行数) + + /// + public void Take( int count ) { + var param = GetLimitParam(); + ParameterManager.Add( param, count ); + } + + /// + /// 获取限制行数的参数名 + /// + protected string GetLimitParam() { + if( LimitParam.IsEmpty() == false ) + return LimitParam; + LimitParam = ParameterManager.GenerateName(); + return LimitParam; + } + + #endregion + + #region AppendSql(添加到结束位置) + + /// + /// 添加到结束位置 + /// + /// Sql语句 + /// 是否原样添加 + public void AppendSql( string sql, bool raw ) { + if( string.IsNullOrWhiteSpace( sql ) ) + return; + if( raw ) { + Result.Append( sql ); + return; + } + Result.Append( ReplaceRawSql( sql ) ); + } + + #endregion + + #region Validate(验证) + + /// + public bool Validate() { + if ( Result.Length > 0 ) + return true; + if ( LimitParam.IsEmpty() == false ) + return true; + return false; + } + + #endregion + + #region AppendTo(添加到字符串生成器) + + /// + public void AppendTo( StringBuilder builder ) { + builder.CheckNull( nameof( builder ) ); + if( Validate() == false ) + return; + AppendLimit( builder ); + builder.Append( Result ); + } + + #endregion + + #region AppendLimit(添加行限制) + + /// + /// 添加行限制 + /// + /// 字符串生成器 + protected virtual void AppendLimit( StringBuilder builder ) { + if( LimitParam.IsEmpty() ) + return; + builder.AppendFormat( "Limit {0} OFFSET {1}", GetLimitParam(), GetOffsetParam() ); + } + + #endregion + + #region ClearPage(清理分页) + + /// + public void ClearPage() { + OffsetParam = null; + LimitParam = null; + Pager = null; + } + + #endregion + + #region Clear(清理) + + /// + public void Clear() { + Result.Clear(); + ClearPage(); + } + + #endregion + + #region Clone(复制结束子句) + + /// + public virtual IEndClause Clone( SqlBuilderBase builder ) { + var result = new StringBuilder(); + result.Append( Result ); + return new EndClause( builder, result, OffsetParam, LimitParam, Pager ); + } + + #endregion + } +} diff --git a/src/Util.Data.Sql/Builders/Clauses/FromClause.cs b/src/Util.Data.Sql/Builders/Clauses/FromClause.cs new file mode 100644 index 00000000..9aca447b --- /dev/null +++ b/src/Util.Data.Sql/Builders/Clauses/FromClause.cs @@ -0,0 +1,127 @@ +using System; +using System.Text; +using Util.Data.Sql.Builders.Core; + +namespace Util.Data.Sql.Builders.Clauses { + /// + /// From子句 + /// + public class FromClause : ClauseBase, IFromClause { + + #region 字段 + + /// + /// From子句结果 + /// + protected readonly StringBuilder Result; + + #endregion + + #region 构造方法 + + /// + /// 初始化From子句 + /// + /// Sql生成器 + /// From子句结果 + public FromClause( SqlBuilderBase sqlBuilder, StringBuilder result = null ) : base( sqlBuilder ) { + Result = result ?? new StringBuilder(); + } + + #endregion + + #region From(设置表) + + /// + public void From( string table ) { + if ( table.IsEmpty() ) + return; + var item = CreateTableItem( table ); + item.AppendTo( Result ); + } + + /// + /// 创建表项 + /// + /// 表名 + protected virtual TableItem CreateTableItem( string table ) { + return new( Dialect, table ); + } + + /// + public void From( ISqlBuilder builder, string alias ) { + if( builder == null ) + return; + var item = new SqlBuilderItem( Dialect, builder, alias ); + item.AppendTo( Result ); + } + + /// + public void From( Action action, string alias ) { + if( action == null ) + return; + var builder = SqlBuilder.New(); + action( builder ); + From( builder, alias ); + } + + #endregion + + #region AppendSql(添加到From子句) + + /// + public void AppendSql( string sql, bool raw ) { + if( string.IsNullOrWhiteSpace( sql ) ) + return; + if( raw ) { + Result.Append( sql ); + return; + } + Result.Append( ReplaceRawSql( sql ) ); + } + + #endregion + + #region Validate(验证) + + /// + public bool Validate() { + return Result.Length > 0; + } + + #endregion + + #region AppendTo(添加到字符串生成器) + + /// + public void AppendTo( StringBuilder builder ) { + builder.CheckNull( nameof( builder ) ); + if( Validate() == false ) + return; + builder.Append( "From " ); + builder.Append( Result ); + } + + #endregion + + #region Clear(清理) + + /// + public void Clear() { + Result.Clear(); + } + + #endregion + + #region Clone(复制From子句) + + /// + public virtual IFromClause Clone( SqlBuilderBase builder ) { + var result = new StringBuilder(); + result.Append( Result ); + return new FromClause( builder, result ); + } + + #endregion + } +} diff --git a/src/Util.Data.Sql/Builders/Clauses/GroupByClause.cs b/src/Util.Data.Sql/Builders/Clauses/GroupByClause.cs new file mode 100644 index 00000000..c2cbba67 --- /dev/null +++ b/src/Util.Data.Sql/Builders/Clauses/GroupByClause.cs @@ -0,0 +1,157 @@ +using System.Text; +using Util.Data.Sql.Builders.Caches; +using Util.Data.Sql.Builders.Conditions; + +namespace Util.Data.Sql.Builders.Clauses { + /// + /// Group By子句 + /// + public class GroupByClause : ClauseBase, IGroupByClause { + + #region 字段 + + /// + /// 子句结果 + /// + protected readonly StringBuilder Result; + /// + /// 分组条件 + /// + protected StringBuilder Condition; + /// + /// 列缓存 + /// + protected readonly IColumnCache ColumnCache; + /// + /// Sql条件工厂 + /// + protected readonly IConditionFactory ConditionFactory; + + #endregion + + #region 构造方法 + + /// + /// 初始化Group By子句 + /// + /// Sql生成器 + /// Group By子句结果 + /// 分组条件 + public GroupByClause( SqlBuilderBase sqlBuilder, StringBuilder result = null, StringBuilder condition = null ) : base( sqlBuilder ) { + Result = result ?? new StringBuilder(); + Condition = condition ?? new StringBuilder(); + ColumnCache = sqlBuilder.ColumnCache; + ConditionFactory = sqlBuilder.ConditionFactory; + } + + #endregion + + #region GroupBy(添加分组列) + + /// + public void GroupBy( string columns ) { + if( string.IsNullOrWhiteSpace( columns ) ) + return; + if( Result.Length > 0 ) + Result.Append( "," ); + Result.Append( ColumnCache.GetSafeColumns( columns ) ); + } + + #endregion + + #region Having(添加分组条件) + + /// + public void Having( string expression, object value, Operator @operator = Operator.Equal, bool isParameterization = true ) { + And( ConditionFactory.Create( expression, value, @operator, isParameterization ) ); + } + + /// + /// And连接条件 + /// + private void And( ISqlCondition condition ) { + new AndCondition( condition ).AppendTo( Condition ); + } + + #endregion + + #region AppendGroupBy(添加到Group By子句) + + /// + public void AppendGroupBy( string sql, bool raw ) { + if( string.IsNullOrWhiteSpace( sql ) ) + return; + if( raw ) { + Result.Append( sql ); + return; + } + Result.Append( ReplaceRawSql( sql ) ); + } + + #endregion + + #region AppendHaving(添加到Having子句) + + /// + public void AppendHaving( string sql, bool raw ) { + if( string.IsNullOrWhiteSpace( sql ) ) + return; + if( raw ) { + And( new SqlCondition( sql ) ); + return; + } + And( new SqlCondition( ReplaceRawSql( sql ) ) ); + } + + #endregion + + #region Validate(验证) + + /// + public bool Validate() { + return Result.Length > 0; + } + + #endregion + + #region AppendTo(添加到字符串生成器) + + /// + public void AppendTo( StringBuilder builder ) { + builder.CheckNull( nameof( builder ) ); + if( Validate() == false ) + return; + builder.Append( "Group By " ); + builder.Append( Result ); + if( Condition.Length == 0 ) + return; + builder.Append( " Having " ); + builder.Append( Condition ); + } + + #endregion + + #region Clear(清理) + + /// + public void Clear() { + Result.Clear(); + Condition.Clear(); + } + + #endregion + + #region Clone(复制Group By子句) + + /// + public virtual IGroupByClause Clone( SqlBuilderBase builder ) { + var result = new StringBuilder(); + result.Append( Result ); + var condition = new StringBuilder(); + condition.Append( Condition ); + return new GroupByClause( builder, result, condition ); + } + + #endregion + } +} diff --git a/src/Util.Data.Sql/Builders/Clauses/IEndClause.cs b/src/Util.Data.Sql/Builders/Clauses/IEndClause.cs new file mode 100644 index 00000000..7f3ccd34 --- /dev/null +++ b/src/Util.Data.Sql/Builders/Clauses/IEndClause.cs @@ -0,0 +1,43 @@ +using Util.Data.Queries; + +namespace Util.Data.Sql.Builders.Clauses { + /// + /// 结束子句 + /// + public interface IEndClause : ISqlClause { + /// + /// 设置跳过行数 + /// + /// 跳过的行数 + void Skip( int count ); + /// + /// 设置获取行数 + /// + /// 获取的行数 + void Take( int count ); + /// + /// 设置分页 + /// + /// 分页参数 + void Page( IPage page ); + /// + /// 添加到结束位置 + /// + /// Sql语句 + /// 是否原样添加 + void AppendSql( string sql, bool raw ); + /// + /// 清理分页 + /// + void ClearPage(); + /// + /// 清理 + /// + void Clear(); + /// + /// 复制结束子句 + /// + /// Sql生成器 + IEndClause Clone( SqlBuilderBase builder ); + } +} diff --git a/src/Util.Data.Sql/Builders/Clauses/IFromClause.cs b/src/Util.Data.Sql/Builders/Clauses/IFromClause.cs new file mode 100644 index 00000000..847bab39 --- /dev/null +++ b/src/Util.Data.Sql/Builders/Clauses/IFromClause.cs @@ -0,0 +1,41 @@ +using System; + +namespace Util.Data.Sql.Builders.Clauses { + /// + /// From子句 + /// + public interface IFromClause : ISqlClause { + /// + /// 设置表名 + /// + /// 表名 + void From( string table ); + /// + /// 设置子查询表 + /// + /// Sql生成器 + /// 表别名 + void From( ISqlBuilder builder, string alias ); + /// + /// 设置子查询表 + /// + /// 子查询操作 + /// 表别名 + void From( Action action, string alias ); + /// + /// 添加到From子句 + /// + /// Sql语句 + /// 是否原样添加 + void AppendSql( string sql, bool raw ); + /// + /// 清理 + /// + void Clear(); + /// + /// 复制From子句 + /// + /// Sql生成器 + IFromClause Clone( SqlBuilderBase builder ); + } +} diff --git a/src/Util.Data.Sql/Builders/Clauses/IGroupByClause.cs b/src/Util.Data.Sql/Builders/Clauses/IGroupByClause.cs new file mode 100644 index 00000000..46626015 --- /dev/null +++ b/src/Util.Data.Sql/Builders/Clauses/IGroupByClause.cs @@ -0,0 +1,41 @@ +namespace Util.Data.Sql.Builders.Clauses { + /// + /// Group By子句 + /// + public interface IGroupByClause : ISqlClause { + /// + /// 添加分组列 + /// + /// 分组字段 + void GroupBy( string columns ); + /// + /// 添加分组条件 + /// + /// 聚合表达式 + /// 值 + /// 运算符 + /// 是否参数化 + void Having( string expression, object value, Operator @operator = Operator.Equal,bool isParameterization = true ); + /// + /// 添加到Group By子句 + /// + /// Sql语句 + /// 是否原样添加 + void AppendGroupBy( string sql, bool raw ); + /// + /// 添加到Having子句 + /// + /// Sql语句 + /// 是否原样添加 + void AppendHaving( string sql, bool raw ); + /// + /// 清理 + /// + void Clear(); + /// + /// 复制Group By子句 + /// + /// Sql生成器 + IGroupByClause Clone( SqlBuilderBase builder ); + } +} diff --git a/src/Util.Data.Sql/Builders/Clauses/IInsertClause.cs b/src/Util.Data.Sql/Builders/Clauses/IInsertClause.cs new file mode 100644 index 00000000..b233baac --- /dev/null +++ b/src/Util.Data.Sql/Builders/Clauses/IInsertClause.cs @@ -0,0 +1,39 @@ +namespace Util.Data.Sql.Builders.Clauses { + /// + /// Insert子句 + /// + public interface IInsertClause : ISqlClause { + /// + /// 设置插入的表和列名集合 + /// + /// 列名集合 + /// 表名 + void Insert( string columns, string table = null ); + /// + /// 设置Insert语句插入的值集合 + /// + /// 值集合 + void Values( params object[] values ); + /// + /// 添加到Insert子句 + /// + /// Sql语句 + /// 是否原样添加 + void AppendInsert( string sql, bool raw ); + /// + /// 添加到Values子句 + /// + /// Sql语句 + /// 是否原样添加 + void AppendValues( string sql, bool raw ); + /// + /// 清理 + /// + void Clear(); + /// + /// 复制Insert子句 + /// + /// Sql生成器 + IInsertClause Clone( SqlBuilderBase builder ); + } +} diff --git a/src/Util.Data.Sql/Builders/Clauses/IJoinClause.cs b/src/Util.Data.Sql/Builders/Clauses/IJoinClause.cs new file mode 100644 index 00000000..1fd1d84f --- /dev/null +++ b/src/Util.Data.Sql/Builders/Clauses/IJoinClause.cs @@ -0,0 +1,101 @@ +using System; + +namespace Util.Data.Sql.Builders.Clauses { + /// + /// Join子句 + /// + public interface IJoinClause : ISqlClause { + /// + /// 内连接 + /// + /// 表名 + void Join( string table ); + /// + /// 内连接子查询 + /// + /// Sql生成器 + /// 表别名 + void Join( ISqlBuilder builder, string alias ); + /// + /// 内连接子查询 + /// + /// 子查询操作 + /// 表别名 + void Join( Action action, string alias ); + /// + /// 左外连接 + /// + /// 表名 + void LeftJoin( string table ); + /// + /// 左外连接子查询 + /// + /// Sql生成器 + /// 表别名 + void LeftJoin( ISqlBuilder builder, string alias ); + /// + /// 左外连接子查询 + /// + /// 子查询操作 + /// 表别名 + void LeftJoin( Action action, string alias ); + /// + /// 右外连接 + /// + /// 表名 + void RightJoin( string table ); + /// + /// 右外连接子查询 + /// + /// Sql生成器 + /// 表别名 + void RightJoin( ISqlBuilder builder, string alias ); + /// + /// 右外连接子查询 + /// + /// 子查询操作 + /// 表别名 + void RightJoin( Action action, string alias ); + /// + /// 设置连接条件 + /// + /// 列名 + /// 值 + /// 运算符 + /// 是否参数化 + void On( string column, object value, Operator @operator = Operator.Equal, bool isParameterization = false ); + /// + /// 添加到内连接子句 + /// + /// Sql语句 + /// 是否原样添加 + void AppendJoin( string sql, bool raw ); + /// + /// 添加到左外连接子句 + /// + /// Sql语句 + /// 是否原样添加 + void AppendLeftJoin( string sql, bool raw ); + /// + /// 添加到右外连接子句 + /// + /// Sql语句 + /// 是否原样添加 + void AppendRightJoin( string sql, bool raw ); + /// + /// 添加到On子句 + /// + /// Sql语句 + /// 是否原样添加 + void AppendOn( string sql, bool raw ); + /// + /// 清理 + /// + void Clear(); + /// + /// 复制Join子句 + /// + /// Sql生成器 + IJoinClause Clone( SqlBuilderBase builder ); + } +} diff --git a/src/Util.Data.Sql/Builders/Clauses/IOrderByClause.cs b/src/Util.Data.Sql/Builders/Clauses/IOrderByClause.cs new file mode 100644 index 00000000..8ef52475 --- /dev/null +++ b/src/Util.Data.Sql/Builders/Clauses/IOrderByClause.cs @@ -0,0 +1,27 @@ +namespace Util.Data.Sql.Builders.Clauses { + /// + /// Order By子句 + /// + public interface IOrderByClause : ISqlClause { + /// + /// 排序 + /// + /// 排序列表 + void OrderBy( string order ); + /// + /// 添加到Order By子句 + /// + /// Sql语句 + /// 是否原样添加 + void AppendSql( string sql, bool raw ); + /// + /// 清理 + /// + void Clear(); + /// + /// 复制Order By子句 + /// + /// Sql生成器 + IOrderByClause Clone( SqlBuilderBase builder ); + } +} diff --git a/src/Util.Data.Sql/Builders/Clauses/ISelectClause.cs b/src/Util.Data.Sql/Builders/Clauses/ISelectClause.cs new file mode 100644 index 00000000..cf4e5e8b --- /dev/null +++ b/src/Util.Data.Sql/Builders/Clauses/ISelectClause.cs @@ -0,0 +1,55 @@ +using System; + +namespace Util.Data.Sql.Builders.Clauses { + /// + /// Select子句 + /// + public interface ISelectClause : ISqlClause { + /// + /// 设置星号*列 + /// + void Select(); + /// + /// 设置列名 + /// + /// 列名 + void Select( string columns ); + /// + /// 设置子查询列 + /// + /// Sql生成器 + /// 列别名 + void Select( ISqlBuilder builder, string alias ); + /// + /// 设置子查询列 + /// + /// 子查询操作 + /// 列别名 + void Select( Action action, string alias ); + /// + /// 添加到Select子句 + /// + /// Sql语句 + /// 是否原样添加 + void AppendSql( string sql, bool raw ); + /// + /// 添加子查询到Select子句 + /// + /// Sql生成器 + void AppendSql( ISqlBuilder builder ); + /// + /// 添加子查询到Select子句 + /// + /// 子查询操作 + void AppendSql( Action action ); + /// + /// 清理 + /// + void Clear(); + /// + /// 复制Select子句 + /// + /// Sql生成器 + ISelectClause Clone( SqlBuilderBase builder ); + } +} diff --git a/src/Util.Data.Sql/Builders/Clauses/ISqlClause.cs b/src/Util.Data.Sql/Builders/Clauses/ISqlClause.cs new file mode 100644 index 00000000..f4bc7bbd --- /dev/null +++ b/src/Util.Data.Sql/Builders/Clauses/ISqlClause.cs @@ -0,0 +1,11 @@ +namespace Util.Data.Sql.Builders.Clauses { + /// + /// Sql子句 + /// + public interface ISqlClause : ISqlContent { + /// + /// 验证 + /// + bool Validate(); + } +} diff --git a/src/Util.Data.Sql/Builders/Clauses/IStartClause.cs b/src/Util.Data.Sql/Builders/Clauses/IStartClause.cs new file mode 100644 index 00000000..f46b2330 --- /dev/null +++ b/src/Util.Data.Sql/Builders/Clauses/IStartClause.cs @@ -0,0 +1,38 @@ +namespace Util.Data.Sql.Builders.Clauses { + /// + /// 起始子句 + /// + public interface IStartClause : ISqlClause { + /// + /// 公用表表达式CTE + /// + /// 公用表表达式名称 + /// Sql生成器 + void Cte( string name, ISqlBuilder builder ); + /// + /// 添加到起始位置 + /// + /// Sql语句 + /// 是否原样添加 + void Append( string sql, bool raw ); + /// + /// 添加到起始位置并换行 + /// + /// Sql语句 + /// 是否原样添加 + void AppendLine( string sql, bool raw ); + /// + /// 清理公用表表达式CTE + /// + void ClearCte(); + /// + /// 清理 + /// + void Clear(); + /// + /// 复制起始子句 + /// + /// Sql生成器 + IStartClause Clone( SqlBuilderBase builder ); + } +} diff --git a/src/Util.Data.Sql/Builders/Clauses/IWhereClause.cs b/src/Util.Data.Sql/Builders/Clauses/IWhereClause.cs new file mode 100644 index 00000000..9aa571aa --- /dev/null +++ b/src/Util.Data.Sql/Builders/Clauses/IWhereClause.cs @@ -0,0 +1,129 @@ +using System; +using Util.Data.Queries; + +namespace Util.Data.Sql.Builders.Clauses { + /// + /// Where子句 + /// + public interface IWhereClause : ISqlClause { + /// + /// 与连接条件 + /// + /// 查询条件 + void And( ISqlCondition condition ); + /// + /// 或连接条件 + /// + /// 查询条件 + void Or( ISqlCondition condition ); + /// + /// 设置查询条件 + /// + /// 列名 + /// 值 + /// 运算符 + void Where( string column, object value, Operator @operator ); + /// + /// 设置子查询条件 + /// + /// 列名 + /// 子查询Sql生成器 + /// 运算符 + void Where( string column, ISqlBuilder builder, Operator @operator ); + /// + /// 设置子查询条件 + /// + /// 列名 + /// 子查询操作 + /// 运算符 + void Where( string column, Action action, Operator @operator ); + /// + /// 设置Is Null查询条件 + /// + /// 列名 + void IsNull( string column ); + /// + /// 设置Is Not Null条件 + /// + /// 列名 + void IsNotNull( string column ); + /// + /// 设置空条件 + /// + /// 列名 + void IsEmpty( string column ); + /// + /// 设置非空条件 + /// + /// 列名 + void IsNotEmpty( string column ); + /// + /// 设置范围查询条件 + /// + /// 列名 + /// 最小值 + /// 最大值 + /// 包含边界 + void Between( string column, int? min, int? max, Boundary boundary ); + /// + /// 设置范围查询条件 + /// + /// 列名 + /// 最小值 + /// 最大值 + /// 包含边界 + void Between( string column, double? min, double? max, Boundary boundary ); + /// + /// 设置范围查询条件 + /// + /// 列名 + /// 最小值 + /// 最大值 + /// 包含边界 + void Between( string column, decimal? min, decimal? max, Boundary boundary ); + /// + /// 设置范围查询条件 + /// + /// 列名 + /// 最小值 + /// 最大值 + /// 是否包含时间 + /// 包含边界 + void Between( string column, DateTime? min, DateTime? max, bool includeTime, Boundary? boundary ); + /// + /// 设置Exists查询条件 + /// + /// 子查询Sql生成器 + void Exists( ISqlBuilder builder ); + /// + /// 设置Exists查询条件 + /// + /// 子查询操作 + void Exists( Action action ); + /// + /// 设置Not Exists查询条件 + /// + /// 子查询Sql生成器 + void NotExists( ISqlBuilder builder ); + /// + /// 设置Not Exists查询条件 + /// + /// 子查询操作 + void NotExists( Action action ); + /// + /// 添加到Where子句 + /// + /// Sql语句 + /// 是否原样添加 + void AppendSql( string sql, bool raw ); + /// + /// 清理 + /// + void Clear(); + /// + /// 复制Where子句 + /// + /// Sql生成器 + IWhereClause Clone( SqlBuilderBase builder ); + } +} diff --git a/src/Util.Data.Sql/Builders/Clauses/InsertClause.cs b/src/Util.Data.Sql/Builders/Clauses/InsertClause.cs new file mode 100644 index 00000000..e412593f --- /dev/null +++ b/src/Util.Data.Sql/Builders/Clauses/InsertClause.cs @@ -0,0 +1,181 @@ +using System.Text; +using Util.Data.Sql.Builders.Caches; +using Util.Data.Sql.Builders.Core; +using Util.Data.Sql.Builders.Params; +using Util.Helpers; + +namespace Util.Data.Sql.Builders.Clauses { + /// + /// Insert子句 + /// + public class InsertClause : ClauseBase, IInsertClause { + + #region 字段 + + /// + /// Insert结果 + /// + protected readonly StringBuilder InsertResult; + /// + /// Values结果 + /// + protected readonly StringBuilder ValuesResult; + /// + /// 列缓存 + /// + protected readonly IColumnCache ColumnCache; + /// + /// 参数管理器 + /// + protected readonly IParameterManager ParameterManager; + + #endregion + + #region 构造方法 + + /// + /// 初始化Insert子句 + /// + /// Sql生成器 + /// Insert结果 + /// Values结果 + public InsertClause( SqlBuilderBase sqlBuilder, StringBuilder insertResult = null, StringBuilder valuesResult = null ) : base( sqlBuilder ) { + InsertResult = insertResult ?? new StringBuilder(); + ValuesResult = valuesResult ?? new StringBuilder(); + ColumnCache = sqlBuilder.ColumnCache; + ParameterManager = sqlBuilder.ParameterManager; + } + + #endregion + + #region Insert(设置插入的表和列名集合) + + /// + public void Insert( string columns, string table = null ) { + if ( InsertResult.Length == 0 ) { + if ( table.IsEmpty() ) + return; + var tableItem = new TableItem( Dialect, table ); + tableItem.AppendTo( InsertResult ); + InsertResult.Append( "(" ); + InsertResult.Append( ColumnCache.GetSafeColumns( columns ) ); + InsertResult.Append( ")" ); + return; + } + AppendColumns( ColumnCache.GetSafeColumns( columns ) ); + } + + /// + /// 添加列 + /// + protected void AppendColumns( string columns ) { + InsertResult.RemoveEnd( ")" ); + InsertResult.Append( "," ); + InsertResult.Append( columns ); + InsertResult.Append( ")" ); + } + + #endregion + + #region Values(设置插入的值集合) + + /// + public void Values( params object[] values ) { + if ( values == null ) + return; + if ( ValuesResult.Length > 0 ) + ValuesResult.Append( "," ); + ValuesResult.Append( "(" ); + foreach ( var value in values ) { + var paramName = ParameterManager.GenerateName(); + ValuesResult.AppendFormat( "{0},", paramName ); + ParameterManager.Add( paramName, value ); + } + ValuesResult.RemoveEnd( "," ).Append( ")" ); + } + + #endregion + + #region AppendInsert(添加到Insert子句) + + /// + public void AppendInsert( string sql, bool raw ) { + if ( string.IsNullOrWhiteSpace( sql ) ) + return; + if ( raw ) { + InsertResult.Append( sql ); + return; + } + InsertResult.Append( ReplaceRawSql( sql ) ); + } + + #endregion + + #region AppendValues(添加到Values子句) + + /// + public void AppendValues( string sql, bool raw ) { + if ( string.IsNullOrWhiteSpace( sql ) ) + return; + if ( raw ) { + ValuesResult.Append( sql ); + return; + } + ValuesResult.Append( ReplaceRawSql( sql ) ); + } + + #endregion + + #region Validate(验证) + + /// + public bool Validate() { + return InsertResult.Length != 0; + } + + #endregion + + #region AppendTo(添加到字符串生成器) + + /// + public void AppendTo( StringBuilder builder ) { + builder.CheckNull( nameof( builder ) ); + if ( Validate() == false ) + return; + builder.Append( "Insert Into " ); + builder.Append( InsertResult ); + builder.AppendLine( " " ); + if ( ValuesResult.Length == 0 ) { + builder.RemoveEnd( Common.Line ); + return; + } + builder.Append( "Values" ); + builder.Append( ValuesResult ); + } + + #endregion + + #region Clear(清理) + + /// + public void Clear() { + InsertResult.Clear(); + ValuesResult.Clear(); + } + + #endregion + + #region Clone(复制Insert子句) + + /// + public virtual IInsertClause Clone( SqlBuilderBase builder ) { + var insertResult = new StringBuilder(); + insertResult.Append( InsertResult ); + var valuesResult = new StringBuilder(); + valuesResult.Append( ValuesResult ); + return new InsertClause( builder, insertResult, valuesResult ); + } + + #endregion + } +} diff --git a/src/Util.Data.Sql/Builders/Clauses/JoinClause.cs b/src/Util.Data.Sql/Builders/Clauses/JoinClause.cs new file mode 100644 index 00000000..7348142e --- /dev/null +++ b/src/Util.Data.Sql/Builders/Clauses/JoinClause.cs @@ -0,0 +1,323 @@ +using System; +using System.Text; +using Util.Data.Sql.Builders.Caches; +using Util.Data.Sql.Builders.Conditions; +using Util.Data.Sql.Builders.Core; +using Util.Helpers; + +namespace Util.Data.Sql.Builders.Clauses { + /// + /// Join子句 + /// + public class JoinClause : ClauseBase, IJoinClause { + + #region 常量 + + /// + /// Join关键字 + /// + private const string JoinKey = "Join"; + /// + /// Left Join关键字 + /// + private const string LeftJoinKey = "Left Join"; + /// + /// Right Join关键字 + /// + private const string RightJoinKey = "Right Join"; + + #endregion + + #region 字段 + + /// + /// Join子句结果 + /// + protected readonly StringBuilder Result; + /// + /// 连接条件 + /// + protected StringBuilder Condition; + /// + /// 列缓存 + /// + protected readonly IColumnCache ColumnCache; + /// + /// Sql条件工厂 + /// + protected readonly IConditionFactory ConditionFactory; + + #endregion + + #region 构造方法 + + /// + /// 初始化Join子句 + /// + /// Sql生成器 + /// Join子句结果 + /// 连接条件 + public JoinClause( SqlBuilderBase sqlBuilder, StringBuilder result = null, StringBuilder condition = null ) : base( sqlBuilder ) { + Result = result ?? new StringBuilder(); + Condition = condition ?? new StringBuilder(); + ColumnCache = sqlBuilder.ColumnCache; + ConditionFactory = sqlBuilder.ConditionFactory; + } + + #endregion + + #region Join(内连接) + + /// + public void Join( string table ) { + Join( JoinKey, table ); + } + + /// + /// 表连接 + /// + private void Join( string joinType, string table ) { + AppendOn(); + AppendJoin( joinType, table ); + } + + /// + /// 添加On条件 + /// + private void AppendOn() { + if( Condition.Length == 0 ) + return; + Result.Append( " On " ); + Result.Append( Condition ); + Result.AppendLine( " " ); + Condition.Clear(); + } + + /// + /// 添加Join + /// + private void AppendJoin( string joinType, string table ) { + Result.AppendFormat( "{0} ", joinType ); + var item = CreateTableItem( table ); + item.AppendTo( Result ); + } + + /// + /// 创建表项 + /// + /// 表名 + protected virtual TableItem CreateTableItem( string table ) { + return new( Dialect, table ); + } + + /// + public void Join( ISqlBuilder builder, string alias ) { + Join( JoinKey, builder, alias ); + } + + /// + /// 表连接 + /// + private void Join( string joinType, ISqlBuilder builder, string alias ) { + if( builder == null ) + return; + AppendOn(); + Result.AppendFormat( "{0} ", joinType ); + var item = new SqlBuilderItem( Dialect, builder, alias ); + item.AppendTo( Result ); + } + + /// + public void Join( Action action, string alias ) { + if( action == null ) + return; + var builder = SqlBuilder.New(); + action( builder ); + Join( builder, alias ); + } + + #endregion + + #region LeftJoin(左外连接) + + /// + public void LeftJoin( string table ) { + Join( LeftJoinKey, table ); + } + + /// + public void LeftJoin( ISqlBuilder builder, string alias ) { + Join( LeftJoinKey, builder, alias ); + } + + /// + public void LeftJoin( Action action, string alias ) { + if( action == null ) + return; + var builder = SqlBuilder.New(); + action( builder ); + LeftJoin( builder, alias ); + } + + #endregion + + #region RightJoin(右外连接) + + /// + public void RightJoin( string table ) { + Join( RightJoinKey, table ); + } + + /// + public void RightJoin( ISqlBuilder builder, string alias ) { + Join( RightJoinKey, builder, alias ); + } + + /// + public void RightJoin( Action action, string alias ) { + if( action == null ) + return; + var builder = SqlBuilder.New(); + action( builder ); + RightJoin( builder, alias ); + } + + #endregion + + #region On(设置连接条件) + + /// + public void On( string column, object value, Operator @operator = Operator.Equal, bool isParameterization = false ) { + column = ColumnCache.GetSafeColumn( column ); + value = GetValue( value, isParameterization ); + var condition = ConditionFactory.Create( column, value, @operator, isParameterization ); + On( condition ); + } + + /// + /// 获取值,非参数化字符串值被认为是列名,将进行规范化处理 + /// + private object GetValue( object value, bool isParameterization ) { + if( value == null ) + return null; + if( isParameterization ) + return value; + if( value.GetType() != typeof( string ) ) + return value; + return ColumnCache.GetSafeColumn( value.ToString() ); + } + + /// + /// 设置连接条件 + /// + /// 连接条件 + public void On( ISqlCondition condition ) { + if( condition == null ) + return; + new AndCondition( condition ).AppendTo( Condition ); + } + + #endregion + + #region AppendJoin(添加到内连接子句) + + /// + public void AppendJoin( string sql, bool raw ) { + AppendSql( JoinKey, sql, raw ); + } + + /// + /// 添加到连接子句 + /// + private void AppendSql( string joinType, string sql, bool raw ) { + if( string.IsNullOrWhiteSpace( sql ) ) + return; + AppendOn(); + Result.AppendFormat( "{0} ", joinType ); + if( raw ) { + Result.Append( sql ); + return; + } + Result.Append( ReplaceRawSql( sql ) ); + } + + #endregion + + #region AppendLeftJoin(添加到左外连接子句) + + /// + public void AppendLeftJoin( string sql, bool raw ) { + AppendSql( LeftJoinKey, sql, raw ); + } + + #endregion + + #region AppendRightJoin(添加到右外连接子句) + + /// + public void AppendRightJoin( string sql, bool raw ) { + AppendSql( RightJoinKey, sql, raw ); + } + + #endregion + + #region AppendOn(添加到On子句) + + /// + public void AppendOn( string sql, bool raw ) { + if( raw ) { + On( new SqlCondition( sql ) ); + return; + } + On( new SqlCondition( ReplaceRawSql( sql ) ) ); + } + + #endregion + + #region Validate(验证) + + /// + public bool Validate() { + return Result.Length > 0; + } + + #endregion + + #region AppendTo(添加到字符串生成器) + + /// + public void AppendTo( StringBuilder builder ) { + builder.CheckNull( nameof( builder ) ); + if( Validate() == false ) + return; + AppendOn(); + builder.Append( Result ); + builder.RemoveEnd( $" {Common.Line}" ); + } + + #endregion + + #region Clear(清理) + + /// + public void Clear() { + Result.Clear(); + Condition.Clear(); + } + + #endregion + + #region Clone(复制Join子句) + + /// + public virtual IJoinClause Clone( SqlBuilderBase builder ) { + var result = new StringBuilder(); + result.Append( Result ); + var condition = new StringBuilder(); + condition.Append( Condition ); + return new JoinClause( builder, result, condition ); + } + + #endregion + } +} diff --git a/src/Util.Data.Sql/Builders/Clauses/OrderByClause.cs b/src/Util.Data.Sql/Builders/Clauses/OrderByClause.cs new file mode 100644 index 00000000..48f31ee0 --- /dev/null +++ b/src/Util.Data.Sql/Builders/Clauses/OrderByClause.cs @@ -0,0 +1,115 @@ +using System.Linq; +using System.Text; +using Util.Data.Sql.Builders.Caches; +using Util.Data.Sql.Builders.Core; + +namespace Util.Data.Sql.Builders.Clauses { + /// + /// Order By子句 + /// + public class OrderByClause : ClauseBase, IOrderByClause { + + #region 字段 + + /// + /// 子句结果 + /// + protected readonly StringBuilder Result; + /// + /// 列缓存 + /// + protected readonly IColumnCache ColumnCache; + + #endregion + + #region 构造方法 + + /// + /// 初始化排序子句 + /// + /// Sql生成器 + /// Order By子句结果 + public OrderByClause( SqlBuilderBase sqlBuilder, StringBuilder result = null ) : base( sqlBuilder ) { + Result = result ?? new StringBuilder(); + ColumnCache = sqlBuilder.ColumnCache; + } + + #endregion + + #region OrderBy(排序) + + /// + public void OrderBy( string order ) { + if( string.IsNullOrWhiteSpace( order ) ) + return; + var items = order.Split( ',' ).Where( t => t.IsEmpty() == false ); + foreach( var item in items ) { + var orderItem = new OrderByItem( item ); + Result.Append( ColumnCache.GetSafeColumn( orderItem.Column ) ); + if( orderItem.Desc ) + Result.Append( " Desc" ); + Result.Append( "," ); + } + } + + #endregion + + #region AppendSql(添加到排序子句) + + /// + public void AppendSql( string sql, bool raw ) { + if( string.IsNullOrWhiteSpace( sql ) ) + return; + if( raw ) { + Result.Append( sql ); + return; + } + Result.Append( ReplaceRawSql( sql ) ); + } + + #endregion + + #region Validate(验证) + + /// + public bool Validate() { + return Result.Length > 0; + } + + #endregion + + #region AppendTo(添加到字符串生成器) + + /// + public void AppendTo( StringBuilder builder ) { + builder.CheckNull( nameof( builder ) ); + if( Validate() == false ) + return; + builder.Append( "Order By " ); + builder.Append( Result ); + builder.RemoveEnd( "," ); + } + + #endregion + + #region Clear(清理) + + /// + public void Clear() { + Result.Clear(); + } + + #endregion + + #region Clone(复制Order By子句) + + /// + public virtual IOrderByClause Clone( SqlBuilderBase builder ) { + var result = new StringBuilder(); + result.Append( Result ); + return new OrderByClause( builder, result ); + } + + #endregion + } +} diff --git a/src/Util.Data.Sql/Builders/Clauses/SelectClause.cs b/src/Util.Data.Sql/Builders/Clauses/SelectClause.cs new file mode 100644 index 00000000..2116994a --- /dev/null +++ b/src/Util.Data.Sql/Builders/Clauses/SelectClause.cs @@ -0,0 +1,161 @@ +using System; +using System.Text; +using Util.Data.Sql.Builders.Caches; +using Util.Data.Sql.Builders.Core; + +namespace Util.Data.Sql.Builders.Clauses { + /// + /// Select子句 + /// + public class SelectClause : ClauseBase, ISelectClause { + + #region 字段 + + /// + /// Select子句结果 + /// + protected readonly StringBuilder Result; + /// + /// 列缓存 + /// + protected readonly IColumnCache ColumnCache; + + #endregion + + #region 构造方法 + + /// + /// 初始化Select子句 + /// + /// Sql生成器 + /// Select子句结果 + public SelectClause( SqlBuilderBase sqlBuilder, StringBuilder result = null ) : base( sqlBuilder ) { + Result = result ?? new StringBuilder(); + ColumnCache = sqlBuilder.ColumnCache; + } + + #endregion + + #region Select(设置列名) + + /// + public void Select() { + Result.Clear(); + Result.Append( "*" ); + } + + /// + public void Select( string columns ) { + if ( columns.IsEmpty() ) + return; + if ( columns == "*" ) { + Select(); + return; + } + AppendColumns( ColumnCache.GetSafeColumns( columns ) ); + } + + /// + /// 添加列 + /// + protected void AppendColumns( string columns ) { + if( Result.Length > 0 ) + Result.RemoveEnd( "," ).Append( "," ); + Result.Append( columns ); + } + + /// + public void Select( ISqlBuilder builder, string alias ) { + if( builder == null ) + return; + if( Result.Length > 0 ) + Result.Append( "," ); + var item = new SqlBuilderItem( Dialect, builder, alias ); + item.AppendTo( Result ); + } + + /// + public void Select( Action action, string alias ) { + if( action == null ) + return; + var builder = SqlBuilder.New(); + action( builder ); + Select( builder, alias ); + } + + #endregion + + #region AppendSql(添加到Select子句) + + /// + public void AppendSql( string sql, bool raw ) { + if( string.IsNullOrWhiteSpace( sql ) ) + return; + if( raw ) { + Result.Append( sql ); + return; + } + Result.Append( ReplaceRawSql( sql ) ); + } + + /// + public void AppendSql( ISqlBuilder builder ) { + if( builder == null ) + return; + builder.AppendTo( Result ); + } + + /// + public void AppendSql( Action action ) { + if( action == null ) + return; + var builder = SqlBuilder.New(); + action( builder ); + AppendSql( builder ); + } + + #endregion + + #region Validate(验证) + + /// + public bool Validate() { + return Result.Length > 0; + } + + #endregion + + #region AppendTo(添加到字符串生成器) + + /// + public void AppendTo( StringBuilder builder ) { + builder.CheckNull( nameof( builder ) ); + if ( Validate() == false ) + return; + builder.Append( "Select " ); + builder.Append( Result ); + } + + #endregion + + #region Clear(清理) + + /// + public void Clear() { + Result.Clear(); + } + + #endregion + + #region Clone(复制Select子句) + + /// + public virtual ISelectClause Clone( SqlBuilderBase builder ) { + var result = new StringBuilder(); + result.Append( Result ); + return new SelectClause( builder, result ); + } + + #endregion + } +} diff --git a/src/Util.Data.Sql/Builders/Clauses/StartClause.cs b/src/Util.Data.Sql/Builders/Clauses/StartClause.cs new file mode 100644 index 00000000..5ab76e11 --- /dev/null +++ b/src/Util.Data.Sql/Builders/Clauses/StartClause.cs @@ -0,0 +1,198 @@ +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Util.Data.Sql.Builders.Caches; +using Util.Data.Sql.Builders.Core; +using Util.Helpers; + +namespace Util.Data.Sql.Builders.Clauses { + /// + /// 起始子句 + /// + public class StartClause : ClauseBase, IStartClause { + + #region 字段 + + /// + /// 起始子句结果 + /// + protected readonly StringBuilder Result; + /// + /// 公用表表达式CTE项集合 + /// + protected List CteItems; + /// + /// 列缓存 + /// + protected readonly IColumnCache ColumnCache; + + #endregion + + #region 构造方法 + + /// + /// 初始化起始子句 + /// + /// Sql生成器 + /// 起始子句结果 + /// 公用表表达式CTE项集合 + public StartClause( SqlBuilderBase sqlBuilder, StringBuilder result = null, List cteItems = null ) : base( sqlBuilder ) { + Result = result ?? new StringBuilder(); + CteItems = cteItems ?? new List(); + ColumnCache = sqlBuilder.ColumnCache; + } + + #endregion + + #region Cte(公用表表达式CTE) + + /// + /// 公用表表达式CTE + /// + /// 公用表表达式名称 + /// Sql生成器 + public void Cte( string name, ISqlBuilder builder ) { + if( name.IsEmpty() || builder == null ) + return; + name = ColumnCache.GetSafeColumn( name ); + CteItems.Add( new CteItem( name, builder ) ); + } + + #endregion + + #region Append(添加到起始位置) + + /// + /// 添加到起始位置 + /// + /// Sql语句 + /// 是否原样添加 + public void Append( string sql, bool raw ) { + if( string.IsNullOrWhiteSpace( sql ) ) + return; + if( raw ) { + Result.Append( sql ); + return; + } + Result.Append( ReplaceRawSql( sql ) ); + } + + #endregion + + #region AppendLine(添加到起始位置并换行) + + /// + /// 添加到起始位置并换行 + /// + /// Sql语句 + /// 是否原样添加 + public void AppendLine( string sql, bool raw ) { + if( string.IsNullOrWhiteSpace( sql ) ) + return; + if( raw ) { + Result.AppendLine( sql ); + return; + } + Result.AppendLine( ReplaceRawSql( sql ) ); + } + + #endregion + + #region Validate(验证) + + /// + /// 验证 + /// + public bool Validate() { + if( Result.Length > 0 ) + return true; + if( CteItems.Count > 0 ) + return true; + return false; + } + + #endregion + + #region AppendTo(添加到字符串生成器) + + /// + /// 添加到字符串生成器 + /// + /// 字符串生成器 + public void AppendTo( StringBuilder builder ) { + builder.CheckNull( nameof( builder ) ); + if( Validate() == false ) + return; + AppendCte( builder ); + builder.Append( Result ); + } + + #endregion + + #region AppendCte(添加公用表表达式CTE) + + /// + /// 添加公用表表达式CTE + /// + /// 字符串生成器 + protected virtual void AppendCte( StringBuilder builder ) { + if( CteItems.Count == 0 ) + return; + builder.AppendFormat( "{0} ", GetCteKeyWord() ); + foreach( var item in CteItems ) { + builder.Append( item.Name ); + builder.AppendLine( " " ); + builder.Append( "As (" ); + item.Builder.AppendTo( builder ); + builder.AppendLine( ")," ); + } + builder.RemoveEnd( $",{Common.Line}" ); + } + + /// + /// 获取CTE关键字 + /// + protected virtual string GetCteKeyWord() { + return "With"; + } + + #endregion + + #region ClearCte(清理公用表表达式CTE) + + /// + /// 清理公用表表达式CTE + /// + public void ClearCte() { + CteItems.Clear(); + } + + #endregion + + #region Clear(清理) + + /// + /// 清理 + /// + public void Clear() { + Result.Clear(); + CteItems.Clear(); + } + + #endregion + + #region Clone(复制起始子句) + + /// + /// 复制起始子句 + /// + /// Sql生成器 + public virtual IStartClause Clone( SqlBuilderBase builder ) { + var result = new StringBuilder(); + result.Append( Result ); + return new StartClause( builder, result, CteItems.Select( t => t.Clone() ).ToList() ); + } + + #endregion + } +} diff --git a/src/Util.Data.Sql/Builders/Clauses/WhereClause.cs b/src/Util.Data.Sql/Builders/Clauses/WhereClause.cs new file mode 100644 index 00000000..dbf6d38b --- /dev/null +++ b/src/Util.Data.Sql/Builders/Clauses/WhereClause.cs @@ -0,0 +1,308 @@ +using System; +using System.Text; +using Util.Data.Queries; +using Util.Data.Sql.Builders.Caches; +using Util.Data.Sql.Builders.Conditions; + +namespace Util.Data.Sql.Builders.Clauses { + /// + /// Where子句 + /// + public class WhereClause : ClauseBase,IWhereClause { + + #region 字段 + + /// + /// Where子句结果 + /// + protected readonly StringBuilder Result; + /// + /// 列缓存 + /// + protected readonly IColumnCache ColumnCache; + /// + /// Sql条件工厂 + /// + protected readonly IConditionFactory ConditionFactory; + + #endregion + + #region 构造方法 + + /// + /// 初始化Where子句 + /// + /// Sql生成器 + /// Where子句结果 + public WhereClause( SqlBuilderBase sqlBuilder, StringBuilder result = null ) : base( sqlBuilder ) { + Result = result ?? new StringBuilder(); + ColumnCache = sqlBuilder.ColumnCache; + ConditionFactory = sqlBuilder.ConditionFactory; + } + + #endregion + + #region And + + /// + public void And( ISqlCondition condition ) { + new AndCondition( condition ).AppendTo( Result ); + } + + #endregion + + #region Or + + /// + public void Or( ISqlCondition condition ) { + new OrCondition( condition ).AppendTo( Result ); + } + + #endregion + + #region Where + + /// + public void Where( string column, object value, Operator @operator ) { + column = ColumnCache.GetSafeColumn( column ); + And( ConditionFactory.Create( column, value, @operator ) ); + } + + /// + public void Where( string column, ISqlBuilder builder, Operator @operator ) { + if( builder == null ) + return; + Where( column, (object)builder, @operator ); + } + + /// + public void Where( string column, Action action, Operator @operator ) { + if( action == null ) + return; + var builder = SqlBuilder.New(); + action( builder ); + Where( column, builder, @operator ); + } + + #endregion + + #region IsNull + + /// + public void IsNull( string column ) { + Where( column, (object)null, Operator.Equal ); + } + + #endregion + + #region IsNotNull + + /// + public void IsNotNull( string column ) { + Where( column, (object)null, Operator.NotEqual ); + } + + #endregion + + #region IsEmpty + + /// + public void IsEmpty( string column ) { + column = ColumnCache.GetSafeColumn( column ); + var nullCondition = ConditionFactory.Create( column, null, Operator.Equal ); + var emptyCondition = ConditionFactory.Create( column, "''", Operator.Equal, false ); + And( new OrCondition( nullCondition, emptyCondition ) ); + } + + #endregion + + #region IsNotEmpty + + /// + public void IsNotEmpty( string column ) { + column = ColumnCache.GetSafeColumn( column ); + var notNullCondition = ConditionFactory.Create( column, null, Operator.NotEqual ); + var notEmptyCondition = ConditionFactory.Create( column, "''", Operator.NotEqual, false ); + And( new AndCondition( notNullCondition, notEmptyCondition ) ); + } + + #endregion + + #region Between + + /// + public void Between( string column, int? min, int? max, Boundary boundary ) { + column = ColumnCache.GetSafeColumn( column ); + if( min > max ) { + And( ConditionFactory.Create( column, max, min, boundary ) ); + return; + } + And( ConditionFactory.Create( column, min, max, boundary ) ); + } + + /// + public void Between( string column, double? min, double? max, Boundary boundary ) { + column = ColumnCache.GetSafeColumn( column ); + if( min > max ) { + And( ConditionFactory.Create( column, max, min, boundary ) ); + return; + } + And( ConditionFactory.Create( column, min, max, boundary ) ); + } + + /// + public void Between( string column, decimal? min, decimal? max, Boundary boundary ) { + column = ColumnCache.GetSafeColumn( column ); + if( min > max ) { + And( ConditionFactory.Create( column, max, min, boundary ) ); + return; + } + And( ConditionFactory.Create( column, min, max, boundary ) ); + } + + /// + public void Between( string column, DateTime? min, DateTime? max, bool includeTime, Boundary? boundary ) { + column = ColumnCache.GetSafeColumn( column ); + And( ConditionFactory.Create( column, GetMin( min, max, includeTime ), GetMax( min, max, includeTime ), GetBoundary( boundary, includeTime ) ) ); + } + + /// + /// 获取最小日期 + /// + private DateTime? GetMin( DateTime? min, DateTime? max, bool includeTime ) { + if( min == null ) + return null; + DateTime? result = min; + if( min > max ) + result = max; + if( includeTime ) + return result; + return result.SafeValue().Date; + } + + /// + /// 获取最大日期 + /// + private DateTime? GetMax( DateTime? min, DateTime? max, bool includeTime ) { + if( max == null ) + return null; + DateTime? result = max; + if( min > max ) + result = min; + if( includeTime ) + return result; + return result.SafeValue().Date.AddDays( 1 ); + } + + /// + /// 获取日期范围查询条件边界 + /// + private Boundary GetBoundary( Boundary? boundary, bool includeTime ) { + if( boundary != null ) + return boundary.SafeValue(); + if( includeTime ) + return Boundary.Both; + return Boundary.Left; + } + + #endregion + + #region Exists + + /// + public void Exists( ISqlBuilder builder ) { + if ( builder == null ) + return; + And( new ExistsCondition( builder ) ); + } + + /// + public void Exists( Action action ) { + if ( action == null ) + return; + var builder = SqlBuilder.New(); + action( builder ); + Exists( builder ); + } + + #endregion + + #region NotExists + + /// + public void NotExists( ISqlBuilder builder ) { + if ( builder == null ) + return; + And( new NotExistsCondition( builder ) ); + } + + /// + public void NotExists( Action action ) { + if ( action == null ) + return; + var builder = SqlBuilder.New(); + action( builder ); + NotExists( builder ); + } + + #endregion + + #region AppendSql + + /// + public void AppendSql( string sql, bool raw ) { + if( string.IsNullOrWhiteSpace( sql ) ) + return; + if( raw ) { + And( new SqlCondition( sql ) ); + return; + } + And( new SqlCondition( ReplaceRawSql( sql ) ) ); + } + + #endregion + + #region Validate + + /// + public bool Validate() { + return Result.Length > 0; + } + + #endregion + + #region AppendTo + + /// + public void AppendTo( StringBuilder builder ) { + builder.CheckNull( nameof(builder) ); + if( Validate() == false ) + return; + builder.Append( "Where " ); + builder.Append( Result ); + } + + #endregion + + #region Clear + + /// + public void Clear() { + Result.Clear(); + } + + #endregion + + #region Clone + + /// + public virtual IWhereClause Clone( SqlBuilderBase builder ) { + var result = new StringBuilder(); + result.Append( Result ); + return new WhereClause( builder, result ); + } + + #endregion + } +} + diff --git a/src/Util.Data.Sql/Builders/Conditions/AndCondition.cs b/src/Util.Data.Sql/Builders/Conditions/AndCondition.cs new file mode 100644 index 00000000..37f447c5 --- /dev/null +++ b/src/Util.Data.Sql/Builders/Conditions/AndCondition.cs @@ -0,0 +1,52 @@ +using System.Text; + +namespace Util.Data.Sql.Builders.Conditions { + /// + /// And连接条件 + /// + public class AndCondition : ISqlCondition { + /// + /// Sql条件1 + /// + private readonly ISqlCondition _condition1; + /// + /// Sql条件2 + /// + private readonly ISqlCondition _condition2; + + /// + /// 初始化And连接条件 + /// + /// Sql条件1 + /// Sql条件2 + public AndCondition( ISqlCondition condition1, ISqlCondition condition2 = null ) { + _condition1 = condition1; + _condition2 = condition2; + } + + /// + /// 添加到字符串生成器 + /// + /// 字符串生成器 + public void AppendTo( StringBuilder builder ) { + if( _condition1 == null && _condition2 == null ) + return; + And( builder, _condition1 ); + And( builder, _condition2 ); + } + + /// + /// 与连接 + /// + private void And( StringBuilder builder,ISqlCondition condition ) { + if ( condition == null || condition == NullCondition.Instance ) + return; + if ( builder.Length == 0 ) { + condition.AppendTo( builder ); + return; + } + builder.Append( " And " ); + condition.AppendTo( builder ); + } + } +} diff --git a/src/Util.Data.Sql/Builders/Conditions/ContainsCondition.cs b/src/Util.Data.Sql/Builders/Conditions/ContainsCondition.cs new file mode 100644 index 00000000..d41c5d55 --- /dev/null +++ b/src/Util.Data.Sql/Builders/Conditions/ContainsCondition.cs @@ -0,0 +1,41 @@ +using System.Text; +using Util.Data.Sql.Builders.Params; + +namespace Util.Data.Sql.Builders.Conditions { + /// + /// Sql模糊匹配查询条件 + /// + public class ContainsCondition : SqlConditionBase { + /// + /// 初始化Sql模糊匹配查询条件 + /// + public ContainsCondition( IParameterManager parameterManager, string column, object value, bool isParameterization ) + : base( parameterManager, column, value, isParameterization ) { + } + + /// + /// 获取参数值 + /// + protected override object GetValue() { + return $"%{Value}%"; + } + + /// + /// 添加Sql条件 + /// + /// 字符串生成器 + /// 列名 + /// 值 + protected override void AppendCondition( StringBuilder builder, string column, object value ) { + builder.AppendFormat( "{0} Like {1}", column, value ); + } + + /// + /// 添加非参数化条件 + /// + /// 字符串生成器 + protected override void AppendNonParameterizedCondition( StringBuilder builder ) { + AppendCondition( builder, Column, $"'{GetValue()}'" ); + } + } +} diff --git a/src/Util.Data.Sql/Builders/Conditions/EndsCondition.cs b/src/Util.Data.Sql/Builders/Conditions/EndsCondition.cs new file mode 100644 index 00000000..8ae7ef98 --- /dev/null +++ b/src/Util.Data.Sql/Builders/Conditions/EndsCondition.cs @@ -0,0 +1,41 @@ +using System.Text; +using Util.Data.Sql.Builders.Params; + +namespace Util.Data.Sql.Builders.Conditions { + /// + /// Sql尾匹配查询条件 + /// + public class EndsCondition : SqlConditionBase { + /// + /// 初始化Sql尾匹配查询条件 + /// + public EndsCondition( IParameterManager parameterManager, string column, object value, bool isParameterization ) + : base( parameterManager, column, value, isParameterization ) { + } + + /// + /// 获取参数值 + /// + protected override object GetValue() { + return $"%{Value}"; + } + + /// + /// 添加Sql条件 + /// + /// 字符串生成器 + /// 列名 + /// 值 + protected override void AppendCondition( StringBuilder builder, string column, object value ) { + builder.AppendFormat( "{0} Like {1}", column, value ); + } + + /// + /// 添加非参数化条件 + /// + /// 字符串生成器 + protected override void AppendNonParameterizedCondition( StringBuilder builder ) { + AppendCondition( builder, Column, $"'{GetValue()}'" ); + } + } +} diff --git a/src/Util.Data.Sql/Builders/Conditions/EqualCondition.cs b/src/Util.Data.Sql/Builders/Conditions/EqualCondition.cs new file mode 100644 index 00000000..03127fb3 --- /dev/null +++ b/src/Util.Data.Sql/Builders/Conditions/EqualCondition.cs @@ -0,0 +1,51 @@ +using System.Text; +using Util.Data.Sql.Builders.Params; + +namespace Util.Data.Sql.Builders.Conditions { + /// + /// Sql相等查询条件 + /// + public class EqualCondition : SqlConditionBase { + /// + /// 初始化Sql相等查询条件 + /// + public EqualCondition( IParameterManager parameterManager, string column, object value, bool isParameterization ) + : base( parameterManager, column, value, isParameterization ) { + } + + /// + /// 添加到字符串生成器 + /// + /// 字符串生成器 + public override void AppendTo( StringBuilder builder ) { + if ( Value == null ) { + new IsNullCondition( Column ).AppendTo( builder ); + return; + } + base.AppendTo( builder ); + } + + /// + /// 添加Sql条件 + /// + /// 字符串生成器 + /// 列名 + /// 值 + protected override void AppendCondition( StringBuilder builder, string column, object value ) { + builder.AppendFormat( "{0}={1}", column, value ); + } + + /// + /// 添加Sql生成器 + /// + /// 字符串生成器 + /// 列名 + /// Sql生成器 + protected override void AppendSqlBuilder( StringBuilder builder, string column, ISqlBuilder sqlBuilder ) { + builder.AppendFormat( "{0}=", column ); + builder.Append( "(" ); + sqlBuilder.AppendTo( builder ); + builder.Append( ")" ); + } + } +} diff --git a/src/Util.Data.Sql/Builders/Conditions/ExistsCondition.cs b/src/Util.Data.Sql/Builders/Conditions/ExistsCondition.cs new file mode 100644 index 00000000..7829bab5 --- /dev/null +++ b/src/Util.Data.Sql/Builders/Conditions/ExistsCondition.cs @@ -0,0 +1,35 @@ +using System; +using System.Text; + +namespace Util.Data.Sql.Builders.Conditions { + /// + /// Exists查询条件 + /// + public class ExistsCondition : ISqlCondition { + /// + /// 子查询Sql生成器 + /// + private readonly ISqlBuilder _sqlBuilder; + + /// + /// 初始化Exists查询条件 + /// + /// 子查询Sql生成器 + public ExistsCondition( ISqlBuilder builder ) { + _sqlBuilder = builder; + } + + /// + /// 添加到字符串生成器 + /// + /// 字符串生成器 + /// + public void AppendTo( StringBuilder builder ) { + if ( _sqlBuilder == null ) + return; + builder.Append( "Exists (" ); + _sqlBuilder.AppendTo( builder ); + builder.Append( ")" ); + } + } +} diff --git a/src/Util.Data.Sql/Builders/Conditions/GreaterCondition.cs b/src/Util.Data.Sql/Builders/Conditions/GreaterCondition.cs new file mode 100644 index 00000000..2dca05c9 --- /dev/null +++ b/src/Util.Data.Sql/Builders/Conditions/GreaterCondition.cs @@ -0,0 +1,39 @@ +using System.Text; +using Util.Data.Sql.Builders.Params; + +namespace Util.Data.Sql.Builders.Conditions { + /// + /// Sql大于查询条件 + /// + public class GreaterCondition : SqlConditionBase { + /// + /// 初始化Sql大于查询条件 + /// + public GreaterCondition( IParameterManager parameterManager, string column, object value, bool isParameterization ) + : base( parameterManager, column, value, isParameterization ) { + } + + /// + /// 添加Sql条件 + /// + /// 字符串生成器 + /// 列名 + /// 值 + protected override void AppendCondition( StringBuilder builder, string column, object value ) { + builder.AppendFormat( "{0}>{1}", column, value ); + } + + /// + /// 添加Sql生成器 + /// + /// 字符串生成器 + /// 列名 + /// Sql生成器 + protected override void AppendSqlBuilder( StringBuilder builder, string column, ISqlBuilder sqlBuilder ) { + builder.AppendFormat( "{0}>", column ); + builder.Append( "(" ); + sqlBuilder.AppendTo( builder ); + builder.Append( ")" ); + } + } +} \ No newline at end of file diff --git a/src/Util.Data.Sql/Builders/Conditions/GreaterEqualCondition.cs b/src/Util.Data.Sql/Builders/Conditions/GreaterEqualCondition.cs new file mode 100644 index 00000000..791ff964 --- /dev/null +++ b/src/Util.Data.Sql/Builders/Conditions/GreaterEqualCondition.cs @@ -0,0 +1,39 @@ +using System.Text; +using Util.Data.Sql.Builders.Params; + +namespace Util.Data.Sql.Builders.Conditions { + /// + /// Sql大于等于查询条件 + /// + public class GreaterEqualCondition : SqlConditionBase { + /// + /// 初始化Sql大于等于查询条件 + /// + public GreaterEqualCondition( IParameterManager parameterManager, string column, object value, bool isParameterization ) + : base( parameterManager, column, value, isParameterization ) { + } + + /// + /// 添加Sql条件 + /// + /// 字符串生成器 + /// 列名 + /// 值 + protected override void AppendCondition( StringBuilder builder, string column, object value ) { + builder.AppendFormat( "{0}>={1}", column, value ); + } + + /// + /// 添加Sql生成器 + /// + /// 字符串生成器 + /// 列名 + /// Sql生成器 + protected override void AppendSqlBuilder( StringBuilder builder, string column, ISqlBuilder sqlBuilder ) { + builder.AppendFormat( "{0}>=", column ); + builder.Append( "(" ); + sqlBuilder.AppendTo( builder ); + builder.Append( ")" ); + } + } +} \ No newline at end of file diff --git a/src/Util.Data.Sql/Builders/Conditions/InCondition.cs b/src/Util.Data.Sql/Builders/Conditions/InCondition.cs new file mode 100644 index 00000000..9b761d3f --- /dev/null +++ b/src/Util.Data.Sql/Builders/Conditions/InCondition.cs @@ -0,0 +1,136 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Text; +using Util.Data.Sql.Builders.Params; + +namespace Util.Data.Sql.Builders.Conditions { + /// + /// In查询条件 + /// + public class InCondition : ISqlCondition { + /// + /// Sql参数管理器 + /// + protected readonly IParameterManager ParameterManager; + /// + /// 列名 + /// + protected readonly string Column; + /// + /// 列名 + /// + protected readonly object Value; + /// + /// 是否参数化 + /// + protected readonly bool IsParameterization; + + /// + /// 初始化In查询条件 + /// + /// Sql参数管理器 + /// 列名 + /// 值 + /// 是否参数化 + public InCondition( IParameterManager parameterManager, string column, object value, bool isParameterization ) { + ParameterManager = parameterManager ?? throw new ArgumentNullException( nameof( parameterManager ) ); + if( string.IsNullOrWhiteSpace( column ) ) + throw new ArgumentNullException( nameof( column ) ); + Column = column; + Value = value; + IsParameterization = isParameterization; + } + + /// + /// 添加到字符串生成器 + /// + /// 字符串生成器 + public void AppendTo( StringBuilder builder ) { + if( Value is ISqlBuilder sqlBuilder ) { + AppendSqlBuilder( builder, Column, sqlBuilder ); + return; + } + var values = GetValues(); + if( values.Count == 0 ) + return; + if ( IsParameterization ) { + AppendParameterizedCondition( builder,values ); + return; + } + AppendNonParameterizedCondition( builder,values ); + } + + /// + /// 添加Sql生成器 + /// + /// 字符串生成器 + /// 列名 + /// Sql生成器 + protected virtual void AppendSqlBuilder( StringBuilder builder, string column, ISqlBuilder sqlBuilder ) { + builder.AppendFormat( "{0} {1} ", column, GetOperator() ); + builder.Append( "(" ); + sqlBuilder.AppendTo( builder ); + builder.Append( ")" ); + } + + /// + /// 获取操作符关键字 + /// + protected virtual string GetOperator() { + return "In"; + } + + /// + /// 获取值 + /// + private List GetValues() { + var values = Value as IEnumerable; + if( values == null ) + return null; + var result = new List(); + foreach ( var value in values ) { + if ( value == null ) + continue; + result.Add( value ); + } + return result; + } + + /// + /// 添加参数化条件 + /// + protected virtual void AppendParameterizedCondition( StringBuilder builder, List values ) { + builder.AppendFormat( "{0} {1} (", Column, GetOperator() ); + foreach( var value in values ) { + var paramName = ParameterManager.GenerateName(); + builder.AppendFormat( "{0},", paramName ); + ParameterManager.Add( paramName, value ); + } + builder.RemoveEnd( "," ).Append( ")" ); + } + + /// + /// 添加非参数化条件 + /// + protected virtual void AppendNonParameterizedCondition( StringBuilder builder, List values ) { + builder.AppendFormat( "{0} {1} (", Column, GetOperator() ); + foreach( var value in values ) { + builder.AppendFormat( "{0},", GetFormattedValue( value ) ); + } + builder.RemoveEnd( "," ).Append( ")" ); + } + + /// + /// 获取格式化后的值 + /// + private string GetFormattedValue( object value ) { + switch ( value.GetType().ToString() ) { + case "System.String": + return $"'{value}'"; + default: + return value.ToString(); + } + } + } +} \ No newline at end of file diff --git a/src/Util.Data.Sql/Builders/Conditions/IsNotNullCondition.cs b/src/Util.Data.Sql/Builders/Conditions/IsNotNullCondition.cs new file mode 100644 index 00000000..9131cc28 --- /dev/null +++ b/src/Util.Data.Sql/Builders/Conditions/IsNotNullCondition.cs @@ -0,0 +1,31 @@ +using System.Text; + +namespace Util.Data.Sql.Builders.Conditions { + /// + /// Is Not Null查询条件 + /// + public class IsNotNullCondition : ISqlCondition { + /// + /// 列名 + /// + private readonly string _name; + + /// + /// 初始化Is Not Null查询条件 + /// + /// 列名 + public IsNotNullCondition( string name ) { + _name = name; + } + + /// + /// 添加到字符串生成器 + /// + /// 字符串生成器 + public void AppendTo( StringBuilder builder ) { + if( _name.IsEmpty() ) + return; + builder.AppendFormat( "{0} Is Not Null", _name ); + } + } +} \ No newline at end of file diff --git a/src/Util.Data.Sql/Builders/Conditions/IsNullCondition.cs b/src/Util.Data.Sql/Builders/Conditions/IsNullCondition.cs new file mode 100644 index 00000000..3a032de2 --- /dev/null +++ b/src/Util.Data.Sql/Builders/Conditions/IsNullCondition.cs @@ -0,0 +1,31 @@ +using System.Text; + +namespace Util.Data.Sql.Builders.Conditions { + /// + /// Is Null查询条件 + /// + public class IsNullCondition : ISqlCondition { + /// + /// 列名 + /// + private readonly string _name; + + /// + /// 初始化Is Null查询条件 + /// + /// 列名 + public IsNullCondition( string name ) { + _name = name; + } + + /// + /// 添加到字符串生成器 + /// + /// 字符串生成器 + public void AppendTo( StringBuilder builder ) { + if ( _name.IsEmpty() ) + return; + builder.AppendFormat( "{0} Is Null", _name ); + } + } +} \ No newline at end of file diff --git a/src/Util.Data.Sql/Builders/Conditions/LessCondition.cs b/src/Util.Data.Sql/Builders/Conditions/LessCondition.cs new file mode 100644 index 00000000..58303a8d --- /dev/null +++ b/src/Util.Data.Sql/Builders/Conditions/LessCondition.cs @@ -0,0 +1,39 @@ +using System.Text; +using Util.Data.Sql.Builders.Params; + +namespace Util.Data.Sql.Builders.Conditions { + /// + /// Sql小于查询条件 + /// + public class LessCondition : SqlConditionBase { + /// + /// 初始化Sql小于查询条件 + /// + public LessCondition( IParameterManager parameterManager, string column, object value, bool isParameterization ) + : base( parameterManager, column, value, isParameterization ) { + } + + /// + /// 添加Sql条件 + /// + /// 字符串生成器 + /// 列名 + /// 值 + protected override void AppendCondition( StringBuilder builder, string column, object value ) { + builder.AppendFormat( "{0}<{1}", column, value ); + } + + /// + /// 添加Sql生成器 + /// + /// 字符串生成器 + /// 列名 + /// Sql生成器 + protected override void AppendSqlBuilder( StringBuilder builder, string column, ISqlBuilder sqlBuilder ) { + builder.AppendFormat( "{0}<", column ); + builder.Append( "(" ); + sqlBuilder.AppendTo( builder ); + builder.Append( ")" ); + } + } +} \ No newline at end of file diff --git a/src/Util.Data.Sql/Builders/Conditions/LessEqualCondition.cs b/src/Util.Data.Sql/Builders/Conditions/LessEqualCondition.cs new file mode 100644 index 00000000..48119c50 --- /dev/null +++ b/src/Util.Data.Sql/Builders/Conditions/LessEqualCondition.cs @@ -0,0 +1,39 @@ +using System.Text; +using Util.Data.Sql.Builders.Params; + +namespace Util.Data.Sql.Builders.Conditions { + /// + /// Sql小于等于查询条件 + /// + public class LessEqualCondition : SqlConditionBase { + /// + /// 初始化Sql小于等于查询条件 + /// + public LessEqualCondition( IParameterManager parameterManager, string column, object value, bool isParameterization ) + : base( parameterManager, column, value, isParameterization ) { + } + + /// + /// 添加Sql条件 + /// + /// 字符串生成器 + /// 列名 + /// 值 + protected override void AppendCondition( StringBuilder builder, string column, object value ) { + builder.AppendFormat( "{0}<={1}", column, value ); + } + + /// + /// 添加Sql生成器 + /// + /// 字符串生成器 + /// 列名 + /// Sql生成器 + protected override void AppendSqlBuilder( StringBuilder builder, string column, ISqlBuilder sqlBuilder ) { + builder.AppendFormat( "{0}<=", column ); + builder.Append( "(" ); + sqlBuilder.AppendTo( builder ); + builder.Append( ")" ); + } + } +} \ No newline at end of file diff --git a/src/Util.Data.Sql/Builders/Conditions/NotEqualCondition.cs b/src/Util.Data.Sql/Builders/Conditions/NotEqualCondition.cs new file mode 100644 index 00000000..dbc86536 --- /dev/null +++ b/src/Util.Data.Sql/Builders/Conditions/NotEqualCondition.cs @@ -0,0 +1,51 @@ +using System.Text; +using Util.Data.Sql.Builders.Params; + +namespace Util.Data.Sql.Builders.Conditions { + /// + /// Sql不相等查询条件 + /// + public class NotEqualCondition : SqlConditionBase { + /// + /// 初始化Sql不相等查询条件 + /// + public NotEqualCondition( IParameterManager parameterManager, string column, object value, bool isParameterization ) + : base( parameterManager, column, value, isParameterization ) { + } + + /// + /// 添加到字符串生成器 + /// + /// 字符串生成器 + public override void AppendTo( StringBuilder builder ) { + if( Value == null ) { + new IsNotNullCondition( Column ).AppendTo( builder ); + return; + } + base.AppendTo( builder ); + } + + /// + /// 添加Sql条件 + /// + /// 字符串生成器 + /// 列名 + /// 值 + protected override void AppendCondition( StringBuilder builder, string column, object value ) { + builder.AppendFormat( "{0}<>{1}", column, value ); + } + + /// + /// 添加Sql生成器 + /// + /// 字符串生成器 + /// 列名 + /// Sql生成器 + protected override void AppendSqlBuilder( StringBuilder builder, string column, ISqlBuilder sqlBuilder ) { + builder.AppendFormat( "{0}<>", column ); + builder.Append( "(" ); + sqlBuilder.AppendTo( builder ); + builder.Append( ")" ); + } + } +} \ No newline at end of file diff --git a/src/Util.Data.Sql/Builders/Conditions/NotExistsCondition.cs b/src/Util.Data.Sql/Builders/Conditions/NotExistsCondition.cs new file mode 100644 index 00000000..e145a6d1 --- /dev/null +++ b/src/Util.Data.Sql/Builders/Conditions/NotExistsCondition.cs @@ -0,0 +1,35 @@ +using System; +using System.Text; + +namespace Util.Data.Sql.Builders.Conditions { + /// + /// Not Exists查询条件 + /// + public class NotExistsCondition : ISqlCondition { + /// + /// 子查询Sql生成器 + /// + private readonly ISqlBuilder _sqlBuilder; + + /// + /// 初始化Not Exists查询条件 + /// + /// 子查询Sql生成器 + public NotExistsCondition( ISqlBuilder builder ) { + _sqlBuilder = builder; + } + + /// + /// 添加到字符串生成器 + /// + /// 字符串生成器 + /// + public void AppendTo( StringBuilder builder ) { + if ( _sqlBuilder == null ) + return; + builder.Append( "Not Exists (" ); + _sqlBuilder.AppendTo( builder ); + builder.Append( ")" ); + } + } +} diff --git a/src/Util.Data.Sql/Builders/Conditions/NotInCondition.cs b/src/Util.Data.Sql/Builders/Conditions/NotInCondition.cs new file mode 100644 index 00000000..d1dd1e5b --- /dev/null +++ b/src/Util.Data.Sql/Builders/Conditions/NotInCondition.cs @@ -0,0 +1,26 @@ +using Util.Data.Sql.Builders.Params; + +namespace Util.Data.Sql.Builders.Conditions { + /// + /// Not In查询条件 + /// + public class NotInCondition : InCondition { + /// + /// 初始化Not In查询条件 + /// + /// Sql参数管理器 + /// 列名 + /// 值 + /// 是否参数化 + public NotInCondition( IParameterManager parameterManager, string column, object value, bool isParameterization ) + :base( parameterManager, column, value, isParameterization ) { + } + + /// + /// 获取操作符关键字 + /// + protected override string GetOperator() { + return "Not In"; + } + } +} \ No newline at end of file diff --git a/src/Util.Data.Sql/Builders/Conditions/NullCondition.cs b/src/Util.Data.Sql/Builders/Conditions/NullCondition.cs new file mode 100644 index 00000000..67d4b23d --- /dev/null +++ b/src/Util.Data.Sql/Builders/Conditions/NullCondition.cs @@ -0,0 +1,26 @@ +using System.Text; + +namespace Util.Data.Sql.Builders.Conditions { + /// + /// 空查询条件 + /// + public class NullCondition : ISqlCondition { + /// + /// 封闭构造方法 + /// + private NullCondition() { + } + + /// + /// 空查询条件实例 + /// + public static readonly NullCondition Instance = new NullCondition(); + + /// + /// 添加到字符串生成器 + /// + /// 字符串生成器 + public void AppendTo( StringBuilder builder ) { + } + } +} \ No newline at end of file diff --git a/src/Util.Data.Sql/Builders/Conditions/OrCondition.cs b/src/Util.Data.Sql/Builders/Conditions/OrCondition.cs new file mode 100644 index 00000000..5aa292a6 --- /dev/null +++ b/src/Util.Data.Sql/Builders/Conditions/OrCondition.cs @@ -0,0 +1,85 @@ +using System.Text; + +namespace Util.Data.Sql.Builders.Conditions { + /// + /// Or连接条件 + /// + public class OrCondition : ISqlCondition { + /// + /// Sql条件1 + /// + private readonly ISqlCondition _condition1; + /// + /// Sql条件2 + /// + private readonly ISqlCondition _condition2; + + /// + /// 初始化Or连接条件 + /// + /// Sql条件1 + /// Sql条件2 + public OrCondition( ISqlCondition condition1, ISqlCondition condition2 = null ) { + _condition1 = condition1; + _condition2 = condition2; + if ( condition1 != null && condition1 == NullCondition.Instance ) + _condition1 = null; + if( condition2 != null && condition2 == NullCondition.Instance ) + _condition2 = null; + } + + /// + /// 添加到字符串生成器 + /// + /// 字符串生成器 + public void AppendTo( StringBuilder builder ) { + if( _condition1 == null && _condition2 == null ) + return; + if ( _condition1 != null && _condition2 != null ) { + AppendAllCondition( builder ); + return; + } + AppendCondition( builder, _condition1 ); + AppendCondition( builder, _condition2 ); + } + + /// + /// 连接两个条件 + /// + private void AppendAllCondition( StringBuilder builder ) { + if( builder.Length == 0 ) { + Or( builder ); + return; + } + builder.Append( " And " ); + Or( builder ); + } + + /// + /// 或操作 + /// + private void Or( StringBuilder builder ) { + builder.Append( "(" ); + _condition1.AppendTo( builder ); + builder.Append( " Or " ); + _condition2.AppendTo( builder ); + builder.Append( ")" ); + } + + /// + /// 连接1个条件 + /// + private void AppendCondition( StringBuilder builder,ISqlCondition condition ) { + if ( condition == null ) + return; + if( builder.Length == 0 ) { + condition.AppendTo( builder ); + return; + } + builder.Insert( 0, '(' ); + builder.Append( " Or " ); + condition.AppendTo( builder ); + builder.Append( ")" ); + } + } +} \ No newline at end of file diff --git a/src/Util.Data.Sql/Builders/Conditions/SegmentCondition.cs b/src/Util.Data.Sql/Builders/Conditions/SegmentCondition.cs new file mode 100644 index 00000000..c6b1c310 --- /dev/null +++ b/src/Util.Data.Sql/Builders/Conditions/SegmentCondition.cs @@ -0,0 +1,96 @@ +using System; +using System.Text; +using Util.Data.Queries; +using Util.Data.Sql.Builders.Params; + +namespace Util.Data.Sql.Builders.Conditions { + /// + /// 范围过滤条件 + /// + public class SegmentCondition : ISqlCondition { + /// + /// Sql参数管理器 + /// + protected readonly IParameterManager ParameterManager; + /// + /// 列名 + /// + protected readonly string Column; + /// + /// 最小值 + /// + protected readonly object MinValue; + /// + /// 最大值 + /// + protected readonly object MaxValue; + /// + /// 包含边界 + /// + protected Boundary Boundary; + /// + /// 是否参数化 + /// + protected readonly bool IsParameterization; + + /// + /// 初始化范围过滤条件 + /// + /// Sql参数管理器 + /// 列名 + /// 最小值 + /// 最大值 + /// 包含边界 + /// 是否参数化 + public SegmentCondition( IParameterManager parameterManager, string column, object minValue, object maxValue, Boundary boundary, bool isParameterization ) { + ParameterManager = parameterManager ?? throw new ArgumentNullException( nameof( parameterManager ) ); + if( string.IsNullOrWhiteSpace( column ) ) + throw new ArgumentNullException( nameof( column ) ); + Column = column; + MinValue = minValue; + MaxValue = maxValue; + Boundary = boundary; + IsParameterization = isParameterization; + } + + /// + /// 添加到字符串生成器 + /// + /// 字符串生成器 + public void AppendTo( StringBuilder builder ) { + new AndCondition( CreateLeftCondition(), CreateRightCondition() ).AppendTo( builder ); + } + + /// + /// 创建左条件 + /// + private ISqlCondition CreateLeftCondition() { + if( string.IsNullOrWhiteSpace( MinValue.SafeString() ) ) + return NullCondition.Instance; + switch( Boundary ) { + case Boundary.Left: + return new GreaterEqualCondition( ParameterManager, Column, MinValue, IsParameterization ); + case Boundary.Both: + return new GreaterEqualCondition( ParameterManager, Column, MinValue, IsParameterization ); + default: + return new GreaterCondition( ParameterManager, Column, MinValue, IsParameterization ); + } + } + + /// + /// 创建右条件 + /// + private ISqlCondition CreateRightCondition() { + if( string.IsNullOrWhiteSpace( MaxValue.SafeString() ) ) + return NullCondition.Instance; + switch( Boundary ) { + case Boundary.Right: + return new LessEqualCondition( ParameterManager, Column, MaxValue, IsParameterization ); + case Boundary.Both: + return new LessEqualCondition( ParameterManager, Column, MaxValue, IsParameterization ); + default: + return new LessCondition( ParameterManager, Column, MaxValue, IsParameterization ); + } + } + } +} diff --git a/src/Util.Data.Sql/Builders/Conditions/SqlCondition.cs b/src/Util.Data.Sql/Builders/Conditions/SqlCondition.cs new file mode 100644 index 00000000..0af94419 --- /dev/null +++ b/src/Util.Data.Sql/Builders/Conditions/SqlCondition.cs @@ -0,0 +1,29 @@ +using System.Text; + +namespace Util.Data.Sql.Builders.Conditions { + /// + /// Sql查询条件 + /// + public class SqlCondition : ISqlCondition { + /// + /// Sql查询条件 + /// + private readonly string _condition; + + /// + /// 初始化Sql查询条件 + /// + /// 查询条件 + public SqlCondition( string condition ) { + _condition = condition; + } + + /// + /// 添加到字符串生成器 + /// + /// 字符串生成器 + public void AppendTo( StringBuilder builder ) { + builder.Append( _condition ); + } + } +} diff --git a/src/Util.Data.Sql/Builders/Conditions/SqlConditionBase.cs b/src/Util.Data.Sql/Builders/Conditions/SqlConditionBase.cs new file mode 100644 index 00000000..8e211bfe --- /dev/null +++ b/src/Util.Data.Sql/Builders/Conditions/SqlConditionBase.cs @@ -0,0 +1,110 @@ +using System; +using System.Text; +using Util.Data.Sql.Builders.Params; + +namespace Util.Data.Sql.Builders.Conditions { + /// + /// Sql查询条件 + /// + public abstract class SqlConditionBase : ISqlCondition { + /// + /// Sql参数管理器 + /// + protected readonly IParameterManager ParameterManager; + /// + /// 列名 + /// + protected readonly string Column; + /// + /// 值 + /// + protected readonly object Value; + /// + /// 是否参数化 + /// + protected readonly bool IsParameterization; + + /// + /// 初始化Sql查询条件 + /// + /// Sql参数管理器 + /// 列名 + /// 值 + /// 是否参数化 + protected SqlConditionBase( IParameterManager parameterManager, string column, object value, bool isParameterization ) { + ParameterManager = parameterManager ?? throw new ArgumentNullException( nameof( parameterManager ) ); + if( string.IsNullOrWhiteSpace( column ) ) + throw new ArgumentNullException( nameof( column ) ); + Column = column; + Value = value; + IsParameterization = isParameterization; + } + + /// + /// 添加到字符串生成器 + /// + /// 字符串生成器 + public virtual void AppendTo( StringBuilder builder ) { + if ( Value is ISqlBuilder sqlBuilder ) { + AppendSqlBuilder( builder,Column, sqlBuilder ); + return; + } + if ( IsParameterization ) { + AppendParameterizedCondition( builder ); + return; + } + AppendNonParameterizedCondition( builder ); + } + + /// + /// 添加Sql生成器 + /// + /// 字符串生成器 + /// 列名 + /// Sql生成器 + protected virtual void AppendSqlBuilder( StringBuilder builder, string column, ISqlBuilder sqlBuilder ) { + throw new NotImplementedException(); + } + + /// + /// 添加参数化条件 + /// + /// 字符串生成器 + protected virtual void AppendParameterizedCondition( StringBuilder builder ) { + var paramName = GenerateParamName(); + var value = GetValue(); + ParameterManager.Add( paramName, value ); + AppendCondition( builder, Column, paramName ); + } + + /// + /// 创建参数名 + /// + protected virtual string GenerateParamName() { + return ParameterManager.GenerateName(); + } + + /// + /// 获取参数值 + /// + protected virtual object GetValue() { + return Value; + } + + /// + /// 添加Sql条件 + /// + /// 字符串生成器 + /// 列名 + /// 值 + protected abstract void AppendCondition( StringBuilder builder,string column, object value ); + + /// + /// 添加非参数化条件 + /// + /// 字符串生成器 + protected virtual void AppendNonParameterizedCondition( StringBuilder builder ) { + AppendCondition( builder, Column, GetValue() ); + } + } +} diff --git a/src/Util.Data.Sql/Builders/Conditions/StartsCondition.cs b/src/Util.Data.Sql/Builders/Conditions/StartsCondition.cs new file mode 100644 index 00000000..c7652cfa --- /dev/null +++ b/src/Util.Data.Sql/Builders/Conditions/StartsCondition.cs @@ -0,0 +1,41 @@ +using System.Text; +using Util.Data.Sql.Builders.Params; + +namespace Util.Data.Sql.Builders.Conditions { + /// + /// Sql头匹配查询条件 + /// + public class StartsCondition : SqlConditionBase { + /// + /// 初始化Sql头匹配查询条件 + /// + public StartsCondition( IParameterManager parameterManager, string column, object value, bool isParameterization ) + : base( parameterManager, column, value, isParameterization ) { + } + + /// + /// 获取参数值 + /// + protected override object GetValue() { + return $"{Value}%"; + } + + /// + /// 添加Sql条件 + /// + /// 字符串生成器 + /// 列名 + /// 值 + protected override void AppendCondition( StringBuilder builder, string column, object value ) { + builder.AppendFormat( "{0} Like {1}", column, value ); + } + + /// + /// 添加非参数化条件 + /// + /// 字符串生成器 + protected override void AppendNonParameterizedCondition( StringBuilder builder ) { + AppendCondition( builder, Column, $"'{GetValue()}'" ); + } + } +} diff --git a/src/Util.Data.Sql/Builders/Core/ColumnItem.cs b/src/Util.Data.Sql/Builders/Core/ColumnItem.cs new file mode 100644 index 00000000..552f4f77 --- /dev/null +++ b/src/Util.Data.Sql/Builders/Core/ColumnItem.cs @@ -0,0 +1,94 @@ +using System.Text; + +namespace Util.Data.Sql.Builders.Core { + /// + /// 列项 + /// + public class ColumnItem { + /// + /// Sql方言 + /// + private readonly IDialect _dialect; + + /// + /// 初始化列项 + /// + /// Sql方言 + /// 列名 + public ColumnItem( IDialect dialect, string name ) { + _dialect = dialect; + Resolve( name ); + } + + /// + /// 解析 + /// + private void Resolve( string name ) { + var item = new NameItem( name ); + TableAlias = item.Prefix; + Name = item.Name; + ColumnAlias = item.Alias; + } + + /// + /// 表别名 + /// + public string TableAlias { get; set; } + + /// + /// 列名 + /// + public string Name { get; set; } + + /// + /// 列别名 + /// + public string ColumnAlias { get; set; } + + /// + /// 获取结果 + /// + public string ToResult() { + var builder = new StringBuilder(); + AppendTo( builder ); + return builder.ToString(); + } + + /// + /// 添加到字符串生成器 + /// + /// 字符串生成器 + public void AppendTo( StringBuilder builder ) { + AppendTableAlias( builder ); + AppendColumn( builder ); + AppendColumnAlias( builder ); + } + + /// + /// 添加表别名 + /// + private void AppendTableAlias( StringBuilder builder ) { + if ( TableAlias.IsEmpty() ) + return; + builder.AppendFormat( "{0}.", _dialect.GetSafeName( TableAlias ) ); + } + + /// + /// 添加列名 + /// + private void AppendColumn( StringBuilder builder ) { + if( Name.IsEmpty() ) + return; + builder.AppendFormat( _dialect.GetSafeName( Name ) ); + } + + /// + /// 添加列别名 + /// + private void AppendColumnAlias( StringBuilder builder ) { + if( ColumnAlias.IsEmpty() ) + return; + builder.AppendFormat( " As {0}", _dialect.GetSafeName( ColumnAlias ) ); + } + } +} diff --git a/src/Util.Data.Sql/Builders/Core/CteItem.cs b/src/Util.Data.Sql/Builders/Core/CteItem.cs new file mode 100644 index 00000000..efdcfb4b --- /dev/null +++ b/src/Util.Data.Sql/Builders/Core/CteItem.cs @@ -0,0 +1,33 @@ +namespace Util.Data.Sql.Builders.Core { + /// + /// 公用表表达式CTE项 + /// + public class CteItem { + /// + /// 初始化公用表表达式CTE项 + /// + /// 公用表表达式名称 + /// Sql生成器 + public CteItem( string name, ISqlBuilder builder ) { + Name = name; + Builder = builder; + } + + /// + /// 公用表表达式名称 + /// + public string Name { get; } + + /// + /// Sql生成器 + /// + public ISqlBuilder Builder { get; } + + /// + /// 复制公用表表达式CTE项 + /// + public CteItem Clone() { + return new CteItem( Name, Builder.Clone() ); + } + } +} diff --git a/src/Util.Data.Sql/Builders/Core/DialectBase.cs b/src/Util.Data.Sql/Builders/Core/DialectBase.cs new file mode 100644 index 00000000..620ed0cf --- /dev/null +++ b/src/Util.Data.Sql/Builders/Core/DialectBase.cs @@ -0,0 +1,62 @@ +using System; + +namespace Util.Data.Sql.Builders.Core { + /// + /// Sql方言 + /// + public abstract class DialectBase : IDialect { + /// + /// 获取起始转义标识符 + /// + public abstract string GetOpeningIdentifier(); + + /// + /// 获取结束转义标识符 + /// + public abstract string GetClosingIdentifier(); + + /// + /// 获取安全名称 + /// + public virtual string GetSafeName( string name ) { + if( string.IsNullOrWhiteSpace( name ) ) + return string.Empty; + if( name == "*" ) + return name; + return $"{GetOpeningIdentifier()}{FilterName( name )}{GetClosingIdentifier()}"; + } + + /// + /// 过滤名称 + /// + private string FilterName( string name ) { + return name.Trim().RemoveStart( GetOpeningIdentifier() ).RemoveEnd( GetClosingIdentifier() ); + } + + /// + /// 获取参数前缀 + /// + public abstract string GetPrefix(); + + /// + /// Select子句是否支持As关键字 + /// + public virtual bool SupportSelectAs() { + return true; + } + + /// + /// 替换Sql,将[]替换为特定Sql转义符 + /// + /// 原始Sql + public virtual string ReplaceSql( string sql ) { + return sql? + .Replace( "[[", "|&<&|", StringComparison.Ordinal ) + .Replace( "]]", "|&>&|", StringComparison.Ordinal ) + .Replace( "[", GetOpeningIdentifier(), StringComparison.Ordinal ) + .Replace( "]", GetClosingIdentifier(), StringComparison.Ordinal ) + .Replace( "|&<&|", "[", StringComparison.Ordinal ) + .Replace( "|&>&|", "]", StringComparison.Ordinal ); + } + } +} diff --git a/src/Util.Data.Sql/Builders/Core/NameItem.cs b/src/Util.Data.Sql/Builders/Core/NameItem.cs new file mode 100644 index 00000000..3856a7f9 --- /dev/null +++ b/src/Util.Data.Sql/Builders/Core/NameItem.cs @@ -0,0 +1,69 @@ +using System; + +namespace Util.Data.Sql.Builders.Core { + /// + /// 名称项,用于拆分列名或表名 + /// + public class NameItem { + /// + /// 初始化名称项 + /// + /// 名称 + public NameItem( string name ) { + Resolve( name ); + } + + /// + /// 解析 + /// + private void Resolve( string name ) { + name = Filter( name ); + var asItem = new SplitItem( name ); + Alias = asItem.Right; + var dotItem = new SplitItem( asItem.Left, "." ); + if( dotItem.Right.IsEmpty() ) { + Name = dotItem.Left; + return; + } + Prefix = dotItem.Left; + Name = dotItem.Right; + } + + /// + /// 过滤 + /// + private string Filter( string name ) { + name = FilterAs( name ); + return FilterDotSpace( name ); + } + + /// + /// 过滤as关键字,替换为空格 + /// + private string FilterAs( string name ) { + return name.Replace( " as ", " ",StringComparison.OrdinalIgnoreCase ); + } + + /// + /// 过滤.前后空格 + /// + private string FilterDotSpace( string name ) { + return name.Replace( @" .", "." ).Replace( @". ", "." ); + } + + /// + /// 前缀,范例:a.b As c,值为 a + /// + public string Prefix { get; private set; } + + /// + /// 名称,范例:a.b As c,值为 b + /// + public string Name { get; private set; } + + /// + /// 别名,范例:a.b As c,值为 c + /// + public string Alias { get; private set; } + } +} diff --git a/src/Util.Data.Sql/Builders/Core/OrderByItem.cs b/src/Util.Data.Sql/Builders/Core/OrderByItem.cs new file mode 100644 index 00000000..d1cb2fc5 --- /dev/null +++ b/src/Util.Data.Sql/Builders/Core/OrderByItem.cs @@ -0,0 +1,34 @@ +using System; + +namespace Util.Data.Sql.Builders.Core { + /// + /// 排序项 + /// + public class OrderByItem { + /// + /// 初始化排序项 + /// + /// 排序表达式 + public OrderByItem( string order ) { + Column = order.SafeString().Trim(); + if ( Column.EndsWith( " Asc",StringComparison.OrdinalIgnoreCase ) ) { + Column = Column.Substring( 0, Column.Length - 3 ).Trim(); + return; + } + if( Column.EndsWith( " Desc", StringComparison.OrdinalIgnoreCase ) ) { + Desc = true; + Column = Column.Substring( 0, Column.Length - 4 ).Trim(); + } + } + + /// + /// 排序列 + /// + public string Column { get; } + + /// + /// 是否倒排 + /// + public bool Desc { get; } + } +} diff --git a/src/Util.Data.Sql/Builders/Core/SplitItem.cs b/src/Util.Data.Sql/Builders/Core/SplitItem.cs new file mode 100644 index 00000000..09aaa26f --- /dev/null +++ b/src/Util.Data.Sql/Builders/Core/SplitItem.cs @@ -0,0 +1,37 @@ +using System.Linq; + +namespace Util.Data.Sql.Builders.Core { + /// + /// 拆分项 + /// + public class SplitItem { + /// + /// 初始化拆分项 + /// + /// 值 + /// 拆分字符 + public SplitItem( string value,string separator = " " ) { + if ( string.IsNullOrEmpty( value ) ) + return; + var list = value.Trim().Split( separator ).Where( item => item.IsEmpty() == false ).ToList(); + if( list.Count == 1 ) { + Left = list[0]; + return; + } + if ( list.Count == 2 ) { + Left = list[0]; + Right = list[1]; + } + } + + /// + /// 左拆分值 + /// + public string Left { get; set; } + + /// + /// 右拆分值 + /// + public string Right { get; set; } + } +} diff --git a/src/Util.Data.Sql/Builders/Core/SqlBuilderItem.cs b/src/Util.Data.Sql/Builders/Core/SqlBuilderItem.cs new file mode 100644 index 00000000..8f81cc48 --- /dev/null +++ b/src/Util.Data.Sql/Builders/Core/SqlBuilderItem.cs @@ -0,0 +1,46 @@ +using System.Text; + +namespace Util.Data.Sql.Builders.Core { + /// + /// Sql生成器项 - 用于子查询 + /// + public class SqlBuilderItem { + /// + /// Sql方言 + /// + private readonly IDialect _dialect; + /// + /// Sql生成器实例 + /// + private readonly ISqlBuilder _builder; + /// + /// 别名 + /// + private readonly string _alias; + + /// + /// 初始化Sql生成器列项 + /// + /// Sql方言 + /// Sql生成器实例 + /// 别名 + public SqlBuilderItem( IDialect dialect, ISqlBuilder builder, string alias = null ) { + _dialect = dialect; + _builder = builder; + _alias = alias; + } + + /// + /// 添加到字符串生成器 + /// + /// 字符串生成器 + public void AppendTo( StringBuilder builder ) { + builder.Append( "(" ); + _builder.AppendTo( builder ); + builder.Append( ")" ); + if ( _alias.IsEmpty() ) + return; + builder.AppendFormat( " As {0}", _dialect.GetSafeName( _alias ) ); + } + } +} diff --git a/src/Util.Data.Sql/Builders/Core/TableItem.cs b/src/Util.Data.Sql/Builders/Core/TableItem.cs new file mode 100644 index 00000000..65c953f1 --- /dev/null +++ b/src/Util.Data.Sql/Builders/Core/TableItem.cs @@ -0,0 +1,101 @@ +using System.Text; + +namespace Util.Data.Sql.Builders.Core { + /// + /// 表项 + /// + public class TableItem { + /// + /// Sql方言 + /// + private readonly IDialect _dialect; + + /// + /// 初始化表项 + /// + /// Sql方言 + /// 列名 + public TableItem( IDialect dialect, string name ) { + _dialect = dialect; + Resolve( name ); + } + + /// + /// 解析 + /// + private void Resolve( string name ) { + var item = new NameItem( name ); + Schema = item.Prefix; + Name = item.Name; + TableAlias = item.Alias; + } + + /// + /// 架构名 + /// + public string Schema { get; set; } + + /// + /// 表名 + /// + public string Name { get; set; } + + /// + /// 表别名 + /// + public string TableAlias { get; set; } + + /// + /// 验证是否有效 + /// + public bool Validate() { + return !string.IsNullOrWhiteSpace( Name ); + } + + /// + /// 获取结果 + /// + public string ToResult() { + var builder = new StringBuilder(); + AppendTo( builder ); + return builder.ToString(); + } + + /// + /// 添加到字符串生成器 + /// + /// 字符串生成器 + public virtual void AppendTo( StringBuilder builder ) { + AppendSchema( builder ); + AppendTable( builder ); + AppendTableAlias( builder ); + } + + /// + /// 添加架构名 + /// + private void AppendSchema( StringBuilder builder ) { + if ( Schema.IsEmpty() ) + return; + builder.AppendFormat( "{0}.", _dialect.GetSafeName( Schema ) ); + } + + /// + /// 添加表名 + /// + private void AppendTable( StringBuilder builder ) { + if( Name.IsEmpty() ) + return; + builder.AppendFormat( _dialect.GetSafeName( Name ) ); + } + + /// + /// 添加表别名 + /// + private void AppendTableAlias( StringBuilder builder ) { + if( TableAlias.IsEmpty() ) + return; + builder.AppendFormat( " As {0}", _dialect.GetSafeName( TableAlias ) ); + } + } +} diff --git a/src/Util.Data.Sql/Builders/IConditionFactory.cs b/src/Util.Data.Sql/Builders/IConditionFactory.cs new file mode 100644 index 00000000..33041dd9 --- /dev/null +++ b/src/Util.Data.Sql/Builders/IConditionFactory.cs @@ -0,0 +1,26 @@ +using Util.Data.Queries; + +namespace Util.Data.Sql.Builders { + /// + /// Sql条件工厂 + /// + public interface IConditionFactory { + /// + /// 创建Sql条件 + /// + /// 列名 + /// 值 + /// 操作 + /// 是否参数化 + ISqlCondition Create( string column, object value, Operator @operator, bool isParameterization = true ); + /// + /// 创建Sql范围条件 + /// + /// 列名 + /// 最小值 + /// 最大值 + /// 包含边界 + /// 是否参数化 + ISqlCondition Create( string column, object minValue,object maxValue, Boundary boundary, bool isParameterization = true ); + } +} diff --git a/src/Util.Data.Sql/Builders/IDialect.cs b/src/Util.Data.Sql/Builders/IDialect.cs new file mode 100644 index 00000000..4ff419c8 --- /dev/null +++ b/src/Util.Data.Sql/Builders/IDialect.cs @@ -0,0 +1,29 @@ +namespace Util.Data.Sql.Builders { + /// + /// Sql方言 + /// + public interface IDialect { + /// + /// 获取起始转义标识符 + /// + string GetOpeningIdentifier(); + /// + /// 获取结束转义标识符 + /// + string GetClosingIdentifier(); + /// + /// 获取安全名称 + /// + /// 名称 + string GetSafeName( string name ); + /// + /// 获取参数前缀 + /// + string GetPrefix(); + /// + /// 替换Sql,将[]替换为特定Sql转义符 + /// + /// 原始Sql + string ReplaceSql( string sql ); + } +} diff --git a/src/Util.Data.Sql/Builders/IExistsSqlBuilder.cs b/src/Util.Data.Sql/Builders/IExistsSqlBuilder.cs new file mode 100644 index 00000000..e3ce7384 --- /dev/null +++ b/src/Util.Data.Sql/Builders/IExistsSqlBuilder.cs @@ -0,0 +1,11 @@ +namespace Util.Data.Sql.Builders { + /// + /// 判断是否存在Sql生成器 + /// + public interface IExistsSqlBuilder { + /// + /// 获取Sql语句 + /// + string GetSql(); + } +} diff --git a/src/Util.Data.Sql/Builders/ISqlContent.cs b/src/Util.Data.Sql/Builders/ISqlContent.cs new file mode 100644 index 00000000..c2abfb85 --- /dev/null +++ b/src/Util.Data.Sql/Builders/ISqlContent.cs @@ -0,0 +1,14 @@ +using System.Text; + +namespace Util.Data.Sql.Builders { + /// + /// Sql内容 + /// + public interface ISqlContent { + /// + /// 添加到字符串生成器 + /// + /// 字符串生成器 + void AppendTo( StringBuilder builder ); + } +} diff --git a/src/Util.Data.Sql/Builders/ISqlPartAccessor.cs b/src/Util.Data.Sql/Builders/ISqlPartAccessor.cs new file mode 100644 index 00000000..56fdef04 --- /dev/null +++ b/src/Util.Data.Sql/Builders/ISqlPartAccessor.cs @@ -0,0 +1,59 @@ +using Util.Data.Sql.Builders.Clauses; +using Util.Data.Sql.Builders.Params; +using Util.Data.Sql.Builders.Sets; + +namespace Util.Data.Sql.Builders { + /// + /// Sql组件访问器 + /// + public interface ISqlPartAccessor { + /// + /// Sql方言 + /// + IDialect Dialect { get; } + /// + /// 参数管理器 + /// + IParameterManager ParameterManager { get; } + /// + /// 起始子句 + /// + IStartClause StartClause { get; } + /// + /// Select子句 + /// + ISelectClause SelectClause { get; } + /// + /// From子句 + /// + IFromClause FromClause { get; } + /// + /// Join子句 + /// + IJoinClause JoinClause { get; } + /// + /// Where子句 + /// + IWhereClause WhereClause { get; } + /// + /// GroupBy子句 + /// + IGroupByClause GroupByClause { get; } + /// + /// OrderBy子句 + /// + IOrderByClause OrderByClause { get; } + /// + /// Insert子句 + /// + IInsertClause InsertClause { get; } + /// + /// 结束子句 + /// + IEndClause EndClause { get; } + /// + /// Sql生成器集合 + /// + ISqlBuilderSet SqlBuilderSet { get; } + } +} diff --git a/src/Util.Data.Sql/Builders/Operations/IEnd.cs b/src/Util.Data.Sql/Builders/Operations/IEnd.cs new file mode 100644 index 00000000..19ffd9af --- /dev/null +++ b/src/Util.Data.Sql/Builders/Operations/IEnd.cs @@ -0,0 +1,7 @@ +namespace Util.Data.Sql.Builders.Operations { + /// + /// 结束子句操作 + /// + public interface IEnd { + } +} diff --git a/src/Util.Data.Sql/Builders/Operations/IFrom.cs b/src/Util.Data.Sql/Builders/Operations/IFrom.cs new file mode 100644 index 00000000..4be56776 --- /dev/null +++ b/src/Util.Data.Sql/Builders/Operations/IFrom.cs @@ -0,0 +1,7 @@ +namespace Util.Data.Sql.Builders.Operations { + /// + /// From子句操作 + /// + public interface IFrom { + } +} \ No newline at end of file diff --git a/src/Util.Data.Sql/Builders/Operations/IGroupBy.cs b/src/Util.Data.Sql/Builders/Operations/IGroupBy.cs new file mode 100644 index 00000000..06602563 --- /dev/null +++ b/src/Util.Data.Sql/Builders/Operations/IGroupBy.cs @@ -0,0 +1,7 @@ +namespace Util.Data.Sql.Builders.Operations { + /// + /// GroupBy子句操作 + /// + public interface IGroupBy { + } +} \ No newline at end of file diff --git a/src/Util.Data.Sql/Builders/Operations/IInsert.cs b/src/Util.Data.Sql/Builders/Operations/IInsert.cs new file mode 100644 index 00000000..fee40742 --- /dev/null +++ b/src/Util.Data.Sql/Builders/Operations/IInsert.cs @@ -0,0 +1,7 @@ +namespace Util.Data.Sql.Builders.Operations { + /// + /// 插入子句操作 + /// + public interface IInsert { + } +} diff --git a/src/Util.Data.Sql/Builders/Operations/IJoin.cs b/src/Util.Data.Sql/Builders/Operations/IJoin.cs new file mode 100644 index 00000000..9805421f --- /dev/null +++ b/src/Util.Data.Sql/Builders/Operations/IJoin.cs @@ -0,0 +1,7 @@ +namespace Util.Data.Sql.Builders.Operations { + /// + /// Join子句操作 + /// + public interface IJoin { + } +} \ No newline at end of file diff --git a/src/Util.Data.Sql/Builders/Operations/IOrderBy.cs b/src/Util.Data.Sql/Builders/Operations/IOrderBy.cs new file mode 100644 index 00000000..388cf777 --- /dev/null +++ b/src/Util.Data.Sql/Builders/Operations/IOrderBy.cs @@ -0,0 +1,7 @@ +namespace Util.Data.Sql.Builders.Operations { + /// + /// OrderBy子句操作 + /// + public interface IOrderBy { + } +} \ No newline at end of file diff --git a/src/Util.Data.Sql/Builders/Operations/ISelect.cs b/src/Util.Data.Sql/Builders/Operations/ISelect.cs new file mode 100644 index 00000000..661ae9b9 --- /dev/null +++ b/src/Util.Data.Sql/Builders/Operations/ISelect.cs @@ -0,0 +1,7 @@ +namespace Util.Data.Sql.Builders.Operations { + /// + /// Select子句操作 + /// + public interface ISelect { + } +} diff --git a/src/Util.Data.Sql/Builders/Operations/ISet.cs b/src/Util.Data.Sql/Builders/Operations/ISet.cs new file mode 100644 index 00000000..7480e408 --- /dev/null +++ b/src/Util.Data.Sql/Builders/Operations/ISet.cs @@ -0,0 +1,7 @@ +namespace Util.Data.Sql.Builders.Operations { + /// + /// Sql集合操作 + /// + public interface ISet { + } +} diff --git a/src/Util.Data.Sql/Builders/Operations/ISqlOperation.cs b/src/Util.Data.Sql/Builders/Operations/ISqlOperation.cs new file mode 100644 index 00000000..48ea78d0 --- /dev/null +++ b/src/Util.Data.Sql/Builders/Operations/ISqlOperation.cs @@ -0,0 +1,7 @@ +namespace Util.Data.Sql.Builders.Operations { + /// + /// Sql操作 + /// + public interface ISqlOperation : ISqlQueryOperation, IInsert { + } +} diff --git a/src/Util.Data.Sql/Builders/Operations/ISqlParameter.cs b/src/Util.Data.Sql/Builders/Operations/ISqlParameter.cs new file mode 100644 index 00000000..6bcdccf6 --- /dev/null +++ b/src/Util.Data.Sql/Builders/Operations/ISqlParameter.cs @@ -0,0 +1,7 @@ +namespace Util.Data.Sql.Builders.Operations { + /// + /// Sql参数操作 + /// + public interface ISqlParameter { + } +} diff --git a/src/Util.Data.Sql/Builders/Operations/ISqlQueryOperation.cs b/src/Util.Data.Sql/Builders/Operations/ISqlQueryOperation.cs new file mode 100644 index 00000000..b9693233 --- /dev/null +++ b/src/Util.Data.Sql/Builders/Operations/ISqlQueryOperation.cs @@ -0,0 +1,7 @@ +namespace Util.Data.Sql.Builders.Operations { + /// + /// Sql查询操作 + /// + public interface ISqlQueryOperation : IStart, ISelect, IFrom, IJoin, IWhere, IGroupBy, IOrderBy, IEnd, ISqlParameter, ISet { + } +} diff --git a/src/Util.Data.Sql/Builders/Operations/IStart.cs b/src/Util.Data.Sql/Builders/Operations/IStart.cs new file mode 100644 index 00000000..704dff07 --- /dev/null +++ b/src/Util.Data.Sql/Builders/Operations/IStart.cs @@ -0,0 +1,7 @@ +namespace Util.Data.Sql.Builders.Operations { + /// + /// 起始子句操作 + /// + public interface IStart { + } +} diff --git a/src/Util.Data.Sql/Builders/Operations/IWhere.cs b/src/Util.Data.Sql/Builders/Operations/IWhere.cs new file mode 100644 index 00000000..276fdaad --- /dev/null +++ b/src/Util.Data.Sql/Builders/Operations/IWhere.cs @@ -0,0 +1,7 @@ +namespace Util.Data.Sql.Builders.Operations { + /// + /// Where子句操作 + /// + public interface IWhere { + } +} \ No newline at end of file diff --git a/src/Util.Data.Sql/Builders/Params/IClearParameters.cs b/src/Util.Data.Sql/Builders/Params/IClearParameters.cs new file mode 100644 index 00000000..a866c23f --- /dev/null +++ b/src/Util.Data.Sql/Builders/Params/IClearParameters.cs @@ -0,0 +1,11 @@ +namespace Util.Data.Sql.Builders.Params { + /// + /// 清空Sql参数 + /// + public interface IClearParameters { + /// + /// 清空Sql参数 + /// + void ClearParams(); + } +} diff --git a/src/Util.Data.Sql/Builders/Params/IGetParameter.cs b/src/Util.Data.Sql/Builders/Params/IGetParameter.cs new file mode 100644 index 00000000..5a777fd4 --- /dev/null +++ b/src/Util.Data.Sql/Builders/Params/IGetParameter.cs @@ -0,0 +1,13 @@ +namespace Util.Data.Sql.Builders.Params { + /// + /// 获取Sql参数 + /// + public interface IGetParameter { + /// + /// 获取Sql参数值 + /// + /// 参数值类型 + /// 参数名 + T GetParam( string name ); + } +} diff --git a/src/Util.Data.Sql/Builders/Params/IParamLiteralsResolver.cs b/src/Util.Data.Sql/Builders/Params/IParamLiteralsResolver.cs new file mode 100644 index 00000000..3ddae052 --- /dev/null +++ b/src/Util.Data.Sql/Builders/Params/IParamLiteralsResolver.cs @@ -0,0 +1,12 @@ +namespace Util.Data.Sql.Builders.Params { + /// + /// 参数字面值解析器 + /// + public interface IParamLiteralsResolver { + /// + /// 获取参数字面值 + /// + /// 参数值 + string GetParamLiterals( object value ); + } +} diff --git a/src/Util.Data.Sql/Builders/Params/IParameterManager.cs b/src/Util.Data.Sql/Builders/Params/IParameterManager.cs new file mode 100644 index 00000000..93a3f8c8 --- /dev/null +++ b/src/Util.Data.Sql/Builders/Params/IParameterManager.cs @@ -0,0 +1,66 @@ +using System.Collections.Generic; +using System.Data; + +namespace Util.Data.Sql.Builders.Params { + /// + /// Sql参数管理器 + /// + public interface IParameterManager { + /// + /// 创建参数名 + /// + string GenerateName(); + /// + /// 标准化参数名 + /// + /// 参数名 + string NormalizeName( string name ); + /// + /// 添加动态参数 + /// + /// 动态参数 + void AddDynamicParams( object param ); + /// + /// 添加参数,如果参数已存在则替换 + /// + /// 参数名 + /// 参数值 + /// 参数类型 + /// 参数方向 + /// 字段长度 + /// 数值有效位数 + /// 数值小数位数 + void Add( string name, object value = null, DbType? dbType = null, ParameterDirection? direction = null, int? size = null, byte? precision = null, byte? scale = null ); + /// + /// 获取动态参数列表 + /// + IReadOnlyList GetDynamicParams(); + /// + /// 获取参数列表 + /// + IReadOnlyList GetParams(); + /// + /// 是否包含参数 + /// + /// 参数名 + bool Contains( string name ); + /// + /// 获取参数 + /// + /// 参数名 + SqlParam GetParam( string name ); + /// + /// 获取参数值 + /// + /// 参数名 + object GetValue( string name ); + /// + /// 清空参数 + /// + void Clear(); + /// + /// 复制Sql参数管理器副本 + /// + IParameterManager Clone(); + } +} diff --git a/src/Util.Data.Sql/Builders/Params/ParamLiteralsResolver.cs b/src/Util.Data.Sql/Builders/Params/ParamLiteralsResolver.cs new file mode 100644 index 00000000..fb54323b --- /dev/null +++ b/src/Util.Data.Sql/Builders/Params/ParamLiteralsResolver.cs @@ -0,0 +1,28 @@ +namespace Util.Data.Sql.Builders.Params { + /// + /// 参数字面值解析器 + /// + public class ParamLiteralsResolver : IParamLiteralsResolver { + /// + /// 获取参数字面值 + /// + /// 参数值 + public string GetParamLiterals( object value ) { + if( value == null ) + return "''"; + switch( value.GetType().Name.ToLower() ) { + case "boolean": + return Helpers.Convert.ToBool( value ) ? "1" : "0"; + case "int16": + case "int32": + case "int64": + case "single": + case "double": + case "decimal": + return value.SafeString(); + default: + return $"'{value}'"; + } + } + } +} diff --git a/src/Util.Data.Sql/Builders/Params/ParameterManager.cs b/src/Util.Data.Sql/Builders/Params/ParameterManager.cs new file mode 100644 index 00000000..07b57c5d --- /dev/null +++ b/src/Util.Data.Sql/Builders/Params/ParameterManager.cs @@ -0,0 +1,157 @@ +using System.Collections.Generic; +using System.Data; +using System.Linq; + +namespace Util.Data.Sql.Builders.Params { + /// + /// Sql参数管理器 + /// + public class ParameterManager : IParameterManager { + /// + /// Sql方言 + /// + protected readonly IDialect Dialect; + /// + /// 参数集合 + /// + private readonly IDictionary _params; + /// + /// 动态参数集合 + /// + private readonly List _dynamicParams; + /// + /// 参数索引 + /// + private int _paramIndex; + + /// + /// 初始化Sql参数管理器 + /// + /// Sql方言 + public ParameterManager( IDialect dialect ) { + Dialect = dialect; + _paramIndex = 0; + _params = new Dictionary(); + _dynamicParams = new List(); + } + + /// + /// 初始化Sql参数管理器 + /// + /// Sql方言 + public ParameterManager( ParameterManager manager ) { + Dialect = manager.Dialect; + _paramIndex = manager._paramIndex; + _params = new Dictionary( manager._params ); + _dynamicParams = new List( manager._dynamicParams ); + } + + /// + /// 创建参数名 + /// + public virtual string GenerateName() { + var result = $"{Dialect.GetPrefix()}_p_{_paramIndex}"; + _paramIndex++; + return result; + } + + /// + /// 标准化参数名 + /// + /// 参数名 + public virtual string NormalizeName( string name ) { + if ( name.IsEmpty() ) + return name; + name = name.Trim(); + if ( name.StartsWith( Dialect.GetPrefix() ) ) + return name; + return $"{Dialect.GetPrefix()}{name}"; + } + + /// + /// 添加动态参数 + /// + /// 动态参数 + public virtual void AddDynamicParams( object param ) { + if ( param == null ) + return; + _dynamicParams.Add( param ); + } + + /// + /// 添加参数,如果参数已存在则替换 + /// + /// 参数名 + /// 参数值 + /// 参数类型 + /// 参数方向 + /// 字段长度 + /// 数值有效位数 + /// 数值小数位数 + public virtual void Add( string name, object value = null, DbType? dbType = null, ParameterDirection? direction = null, int? size = null, byte? precision = null, byte? scale = null ) { + if ( name.IsEmpty() ) + return; + name = NormalizeName( name ); + if ( _params.ContainsKey( name ) ) + _params.Remove( name ); + var param = new SqlParam( name, value, dbType, direction, size, precision, scale ); + _params.Add( name, param ); + } + + /// + /// 获取动态参数列表 + /// + public IReadOnlyList GetDynamicParams() { + return _dynamicParams; + } + + /// + /// 获取参数列表 + /// + public IReadOnlyList GetParams() { + return _params.Values.ToList(); + } + + /// + /// 是否包含参数 + /// + /// 参数名 + public virtual bool Contains( string name ) { + name = NormalizeName( name ); + return _params.ContainsKey( name ); + } + + /// + /// 获取参数 + /// + /// 参数名 + public virtual SqlParam GetParam( string name ) { + name = NormalizeName( name ); + return _params.ContainsKey( name ) ? _params[name] : null; + } + + /// + /// 获取参数值 + /// + /// 参数名 + public virtual object GetValue( string name ) { + name = NormalizeName( name ); + return _params.ContainsKey( name ) ? _params[name].Value : null; + } + + /// + /// 清空参数 + /// + public virtual void Clear() { + _paramIndex = 0; + _params.Clear(); + } + + /// + /// 复制副本 + /// + public IParameterManager Clone() { + return new ParameterManager( this ); + } + } +} diff --git a/src/Util.Data.Sql/Builders/Params/SqlParam.cs b/src/Util.Data.Sql/Builders/Params/SqlParam.cs new file mode 100644 index 00000000..26989763 --- /dev/null +++ b/src/Util.Data.Sql/Builders/Params/SqlParam.cs @@ -0,0 +1,57 @@ +using System.Data; + +namespace Util.Data.Sql.Builders.Params { + /// + /// Sql参数 + /// + public class SqlParam { + /// + /// 初始化Sql参数 + /// + /// 参数名 + /// 参数值 + /// 参数类型 + /// 参数方向 + /// 字段长度 + /// 数值有效位数 + /// 数值小数位数 + public SqlParam( string name, object value, DbType? dbType = null, ParameterDirection? direction = null, int? size = null, byte? precision = null, byte? scale = null ) { + Name = name; + Value = value; + Direction = direction; + DbType = dbType; + Size = size; + Precision = precision; + Scale = scale; + } + + /// + /// 参数名 + /// + public string Name { get; } + /// + /// 参数值 + /// + public object Value { get; } + /// + /// 参数方向 + /// + public ParameterDirection? Direction { get; } + /// + /// 参数类型 + /// + public DbType? DbType { get; } + /// + /// 字段长度 + /// + public int? Size { get; } + /// + /// 数值有效位数 + /// + public byte? Precision { get; } + /// + /// 数值小数位数 + /// + public byte? Scale { get; } + } +} diff --git a/src/Util.Data.Sql/Builders/Sets/ISqlBuilderSet.cs b/src/Util.Data.Sql/Builders/Sets/ISqlBuilderSet.cs new file mode 100644 index 00000000..b22d72dc --- /dev/null +++ b/src/Util.Data.Sql/Builders/Sets/ISqlBuilderSet.cs @@ -0,0 +1,62 @@ +using System.Collections.Generic; + +namespace Util.Data.Sql.Builders.Sets { + /// + /// Sql生成器集合 + /// + public interface ISqlBuilderSet { + /// + /// 合并结果集 + /// + /// Sql生成器集合 + void Union( params ISqlBuilder[] builders ); + /// + /// 合并结果集 + /// + /// Sql生成器集合 + void Union( IEnumerable builders ); + /// + /// 合并结果集 + /// + /// Sql生成器集合 + void UnionAll( params ISqlBuilder[] builders ); + /// + /// 合并结果集 + /// + /// Sql生成器集合 + void UnionAll( IEnumerable builders ); + /// + /// 交集 + /// + /// Sql生成器集合 + void Intersect( params ISqlBuilder[] builders ); + /// + /// 交集 + /// + /// Sql生成器集合 + void Intersect( IEnumerable builders ); + /// + /// 差集 + /// + /// Sql生成器集合 + void Except( params ISqlBuilder[] builders ); + /// + /// 差集 + /// + /// Sql生成器集合 + void Except( IEnumerable builders ); + /// + /// 清理 + /// + void Clear(); + /// + /// 获取结果 + /// + string ToResult(); + /// + /// 复制Sql生成器集合 + /// + /// Sql生成器 + ISqlBuilderSet Clone( SqlBuilderBase builder ); + } +} diff --git a/src/Util.Data.Sql/Builders/Sets/SqlBuilderSet.cs b/src/Util.Data.Sql/Builders/Sets/SqlBuilderSet.cs new file mode 100644 index 00000000..27704e34 --- /dev/null +++ b/src/Util.Data.Sql/Builders/Sets/SqlBuilderSet.cs @@ -0,0 +1,254 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Util.Data.Sql.Builders.Clauses; +using Util.Helpers; + +namespace Util.Data.Sql.Builders.Sets { + /// + /// Sql生成器集合 + /// + public class SqlBuilderSet : ISqlBuilderSet { + + #region 字段 + + /// + /// 主Sql生成器 + /// + protected ISqlBuilder MasterBuilder; + /// + /// Sql生成器集合 + /// + protected List SetItems; + + #endregion + + #region 构造方法 + + /// + /// 初始化Sql生成器集合 + /// + /// 主Sql生成器 + /// Sql生成器集合 + public SqlBuilderSet( ISqlBuilder builder, List setItems = null ) { + MasterBuilder = builder ?? throw new ArgumentNullException( nameof( builder ) ); + SetItems = setItems ?? new List(); + } + + #endregion + + #region Set(集合操作) + + /// + /// 集合操作 + /// + /// 操作符 + /// Sql生成器集合 + protected void Set( string @operator, IEnumerable builders ) { + if( builders == null ) + return; + foreach( var builder in builders ) { + SetItems.Add( new SqlBuilderSetItem( @operator, builder ) ); + } + } + + #endregion + + #region Union(合并结果集) + + /// + /// 合并结果集 + /// + /// Sql生成器集合 + public virtual void Union( params ISqlBuilder[] builders ) { + Set( "Union", builders ); + } + + /// + /// 合并结果集 + /// + /// Sql生成器集合 + public virtual void Union( IEnumerable builders ) { + Set( "Union", builders ); + } + + #endregion + + #region UnionAll(合并结果集) + + /// + /// 合并结果集 + /// + /// Sql生成器集合 + public virtual void UnionAll( params ISqlBuilder[] builders ) { + Set( "Union All", builders ); + } + + /// + /// 合并结果集 + /// + /// Sql生成器集合 + public virtual void UnionAll( IEnumerable builders ) { + Set( "Union All", builders ); + } + + #endregion + + #region Intersect(交集) + + /// + /// 交集 + /// + /// Sql生成器集合 + public virtual void Intersect( params ISqlBuilder[] builders ) { + Set( "Intersect", builders ); + } + + /// + /// 交集 + /// + /// Sql生成器集合 + public virtual void Intersect( IEnumerable builders ) { + Set( "Intersect", builders ); + } + + #endregion + + #region Except(差集) + + /// + /// 差集 + /// + /// Sql生成器集合 + public virtual void Except( params ISqlBuilder[] builders ) { + Set( "Except", builders ); + } + + /// + /// 差集 + /// + /// Sql生成器集合 + public virtual void Except( IEnumerable builders ) { + Set( "Except", builders ); + } + + #endregion + + #region ToResult(获取结果) + + /// + /// 获取结果 + /// + public string ToResult() { + if( SetItems.Count == 0 ) + return GetMasterResult(); + return GetSetResult(); + } + + /// + /// 获取主查询结果 + /// + protected virtual string GetMasterResult() { + var builder = new StringBuilder(); + MasterBuilder.AppendTo( builder ); + return builder.ToString(); + } + + /// + /// 获取集合操作结果 + /// + protected virtual string GetSetResult() { + var builder = new StringBuilder(); + AppendMasterSql( builder ); + AppendSetSql( builder ); + AppendEndSql( builder ); + return builder.ToString(); + } + + /// + /// 添加主查询结果 + /// + protected virtual void AppendMasterSql( StringBuilder result ) { + var accessor = ToSqlPartAccessor( MasterBuilder ); + AppendSql( result, accessor.StartClause ); + result.AppendLine( "(" ); + AppendSql( result, accessor.SelectClause ); + AppendSql( result, accessor.FromClause ); + AppendSql( result, accessor.JoinClause ); + AppendSql( result, accessor.WhereClause ); + AppendSql( result, accessor.GroupByClause ); + result.AppendLine( ")" ); + } + + /// + /// 添加集合Sql + /// + protected virtual void AppendSetSql( StringBuilder result ) { + foreach ( var item in SetItems ) { + var accessor = ToSqlPartAccessor( item.Builder ); + result.AppendFormat( "{0} ", item.Operator ); + result.AppendLine(); + result.AppendLine( "(" ); + AppendSql( result, accessor.SelectClause ); + AppendSql( result, accessor.FromClause ); + AppendSql( result, accessor.JoinClause ); + AppendSql( result, accessor.WhereClause ); + AppendSql( result, accessor.GroupByClause ); + result.AppendLine( ")" ); + } + } + + /// + /// 添加结束Sql + /// + protected virtual void AppendEndSql( StringBuilder result ) { + var accessor = ToSqlPartAccessor( MasterBuilder ); + AppendSql( result, accessor.OrderByClause ); + AppendSql( result, accessor.EndClause ); + result.RemoveEnd( $" {Common.Line}" ); + } + + /// + /// 转换为Sql组件访问器 + /// + protected ISqlPartAccessor ToSqlPartAccessor( ISqlBuilder builder ) { + var accessor = builder as ISqlPartAccessor; + if( accessor == null ) + throw new NotImplementedException( nameof( ISqlPartAccessor ) ); + return accessor; + } + + /// + /// 添加Sql + /// + protected void AppendSql( StringBuilder builder, ISqlClause content ) { + if( content.Validate() == false ) + return; + content.AppendTo( builder ); + builder.AppendLine( " " ); + } + + #endregion + + #region Clear(清理) + + /// + /// 清理 + /// + public void Clear() { + SetItems.Clear(); + } + + #endregion + + #region Clone(复制Sql生成器集合) + + /// + public virtual ISqlBuilderSet Clone( SqlBuilderBase builder ) { + return new SqlBuilderSet( builder, SetItems.Select( t => t.Clone() ).ToList() ); + } + + #endregion + } +} diff --git a/src/Util.Data.Sql/Builders/Sets/SqlBuilderSetItem.cs b/src/Util.Data.Sql/Builders/Sets/SqlBuilderSetItem.cs new file mode 100644 index 00000000..f952af42 --- /dev/null +++ b/src/Util.Data.Sql/Builders/Sets/SqlBuilderSetItem.cs @@ -0,0 +1,33 @@ +namespace Util.Data.Sql.Builders.Sets { + /// + /// Sql生成器集合项 + /// + public class SqlBuilderSetItem { + /// + /// 初始化Sql生成器集合项 + /// + /// 操作 + /// Sql生成器实例 + public SqlBuilderSetItem( string @operator, ISqlBuilder builder ) { + Operator = @operator; + Builder = builder; + } + + /// + /// 操作 + /// + public string Operator { get; } + + /// + /// Sql生成器 + /// + public ISqlBuilder Builder { get; } + + /// + /// 复制Sql生成器集合项 + /// + public SqlBuilderSetItem Clone() { + return new SqlBuilderSetItem( Operator, Builder.Clone() ); + } + } +} diff --git a/src/Util.Data.Sql/Builders/SqlBuilderBase.cs b/src/Util.Data.Sql/Builders/SqlBuilderBase.cs new file mode 100644 index 00000000..18de6b3f --- /dev/null +++ b/src/Util.Data.Sql/Builders/SqlBuilderBase.cs @@ -0,0 +1,349 @@ +using System.Text; +using Util.Data.Sql.Builders.Caches; +using Util.Data.Sql.Builders.Clauses; +using Util.Data.Sql.Builders.Params; +using Util.Data.Sql.Builders.Sets; +using Util.Helpers; + +namespace Util.Data.Sql.Builders { + /// + /// Sql生成器 + /// + public abstract class SqlBuilderBase : ISqlBuilder, ISqlPartAccessor { + + #region 字段 + + /// + /// Sql方言 + /// + private IDialect _dialect; + /// + /// 列缓存 + /// + private IColumnCache _columnCache; + /// + /// 参数管理器 + /// + private IParameterManager _parameterManager; + /// + /// Sql条件工厂 + /// + private IConditionFactory _conditionFactory; + /// + /// 起始子句 + /// + private IStartClause _startClause; + /// + /// Insert子句 + /// + private IInsertClause _insertClause; + /// + /// Select子句 + /// + private ISelectClause _selectClause; + /// + /// From子句 + /// + private IFromClause _fromClause; + /// + /// Join子句 + /// + private IJoinClause _joinClause; + /// + /// Where子句 + /// + private IWhereClause _whereClause; + /// + /// GroupBy子句 + /// + private IGroupByClause _groupByClause; + /// + /// OrderBy子句 + /// + private IOrderByClause _orderByClause; + /// + /// 结束子句 + /// + private IEndClause _endClause; + /// + /// Sql生成器集合 + /// + private ISqlBuilderSet _sqlBuilderSet; + + #endregion + + #region 构造方法 + + /// + /// 初始化Sql生成器 + /// + /// Sql参数管理器 + protected SqlBuilderBase( IParameterManager parameterManager = null ) { + _parameterManager = parameterManager; + } + + #endregion + + #region 属性 + + /// + /// Sql方言 + /// + public IDialect Dialect => _dialect ??= CreateDialect(); + /// + /// 列缓存 + /// + public IColumnCache ColumnCache => _columnCache ??= CreateColumnCache(); + /// + /// 参数管理器 + /// + public IParameterManager ParameterManager => _parameterManager ??= CreateParameterManager(); + /// + /// Sql条件工厂 + /// + public IConditionFactory ConditionFactory => _conditionFactory ??= CreateConditionFactory(); + /// + /// 起始子句 + /// + public IStartClause StartClause => _startClause ??= CreateStartClause(); + /// + /// Select子句 + /// + public ISelectClause SelectClause => _selectClause ??= CreateSelectClause(); + /// + /// From子句 + /// + public IFromClause FromClause => _fromClause ??= CreateFromClause(); + /// + /// Join子句 + /// + public IJoinClause JoinClause => _joinClause ??= CreateJoinClause(); + /// + /// Where子句 + /// + public IWhereClause WhereClause => _whereClause ??= CreatewWhereClause(); + /// + /// GroupBy子句 + /// + public IGroupByClause GroupByClause => _groupByClause ??= CreateGroupByClause(); + /// + /// OrderBy子句 + /// + public IOrderByClause OrderByClause => _orderByClause ??= CreateOrderByClause(); + /// + /// Insert子句 + /// + public IInsertClause InsertClause => _insertClause ??= CreateInsertClause(); + /// + /// 结束子句 + /// + public IEndClause EndClause => _endClause ??= CreateEndClause(); + /// + /// Sql生成器集合 + /// + public ISqlBuilderSet SqlBuilderSet => _sqlBuilderSet ??= CreateSqlBuilderSet(); + + #endregion + + #region 工厂方法 + + /// + /// 创建Sql方言 + /// + protected abstract IDialect CreateDialect(); + + /// + /// 创建列缓存 + /// + protected abstract IColumnCache CreateColumnCache(); + + /// + /// 创建参数管理器 + /// + protected virtual IParameterManager CreateParameterManager() { + return new ParameterManager( Dialect ); + } + + /// + /// 创建Sql条件工厂 + /// + protected virtual IConditionFactory CreateConditionFactory() { + return new SqlConditionFactory( ParameterManager ); + } + + /// + /// 创建起始子句 + /// + protected virtual IStartClause CreateStartClause() { + return new StartClause( this ); + } + + /// + /// 创建Insert子句 + /// + protected virtual IInsertClause CreateInsertClause() { + return new InsertClause( this ); + } + + /// + /// 创建Select子句 + /// + protected virtual ISelectClause CreateSelectClause() { + return new SelectClause( this ); + } + + /// + /// 创建From子句 + /// + protected virtual IFromClause CreateFromClause() { + return new FromClause( this ); + } + + /// + /// 创建Join子句 + /// + protected virtual IJoinClause CreateJoinClause() { + return new JoinClause( this ); + } + + /// + /// 创建Where子句 + /// + protected virtual IWhereClause CreatewWhereClause() { + return new WhereClause( this ); + } + + /// + /// 创建分组子句 + /// + protected virtual IGroupByClause CreateGroupByClause() { + return new GroupByClause( this ); + } + + /// + /// 创建排序子句 + /// + protected virtual IOrderByClause CreateOrderByClause() { + return new OrderByClause( this ); + } + + /// + /// 创建结束子句 + /// + protected virtual IEndClause CreateEndClause() { + return new EndClause( this ); + } + + /// + /// 创建Sql生成器集合 + /// + protected virtual ISqlBuilderSet CreateSqlBuilderSet() { + return new SqlBuilderSet( this ); + } + + #endregion + + #region Clone(复制Sql生成器) + + /// + public abstract ISqlBuilder Clone(); + + /// + /// 复制Sql生成器 + /// + /// 源Sql生成器 + protected void Clone( SqlBuilderBase source ) { + _dialect = source._dialect; + _columnCache = source._columnCache; + _parameterManager = source._parameterManager?.Clone(); + _startClause = source._startClause?.Clone( this ); + _insertClause = source._insertClause?.Clone( this ); + _selectClause = source._selectClause?.Clone( this ); + _fromClause = source._fromClause?.Clone( this ); + _joinClause = source._joinClause?.Clone( this ); + _whereClause = source._whereClause?.Clone( this ); + _groupByClause = source._groupByClause?.Clone( this ); + _orderByClause = source._orderByClause?.Clone( this ); + _endClause = source._endClause?.Clone( this ); + _sqlBuilderSet = source._sqlBuilderSet?.Clone( this ); + } + + #endregion + + #region Clear(清理) + + /// + /// 清理 + /// + public ISqlBuilder Clear() { + _parameterManager?.Clear(); + _startClause?.Clear(); + _insertClause?.Clear(); + _selectClause?.Clear(); + _fromClause?.Clear(); + _joinClause?.Clear(); + _whereClause?.Clear(); + _groupByClause?.Clear(); + _orderByClause?.Clear(); + _endClause?.Clear(); + _sqlBuilderSet?.Clear(); + return this; + } + + #endregion + + #region New(创建Sql生成器) + + /// + /// 创建Sql生成器 + /// + public abstract ISqlBuilder New(); + + #endregion + + #region GetSql(获取Sql语句) + + /// + /// 生成Sql语句 + /// + public virtual string GetSql() { + return SqlBuilderSet.ToResult(); + } + + #endregion + + #region AppendTo(添加到字符串生成器) + + /// + /// 添加到字符串生成器 + /// + /// 字符串生成器 + public void AppendTo( StringBuilder builder ) { + builder.CheckNull( nameof( builder ) ); + AppendSql( builder, _startClause ); + AppendSql( builder, _insertClause ); + AppendSql( builder, _selectClause ); + AppendSql( builder, _fromClause ); + AppendSql( builder, _joinClause ); + AppendSql( builder, _whereClause ); + AppendSql( builder, _groupByClause ); + AppendSql( builder, _orderByClause ); + AppendSql( builder, _endClause ); + builder.RemoveEnd( $" {Common.Line}" ); + } + + /// + /// 添加Sql + /// + protected void AppendSql( StringBuilder builder, ISqlClause content ) { + if ( content == null ) + return; + if( content.Validate() == false ) + return; + content.AppendTo( builder ); + builder.AppendLine( " " ); + } + + #endregion + } +} diff --git a/src/Util.Data.Sql/Builders/SqlBuilderResult.cs b/src/Util.Data.Sql/Builders/SqlBuilderResult.cs new file mode 100644 index 00000000..afb5cab6 --- /dev/null +++ b/src/Util.Data.Sql/Builders/SqlBuilderResult.cs @@ -0,0 +1,79 @@ +using System.Collections.Generic; +using Util.Data.Sql.Builders.Params; +using Util.Helpers; + +namespace Util.Data.Sql.Builders { + /// + /// Sql生成器结果 + /// + public class SqlBuilderResult { + /// + /// Sql生成器结果 + /// + private readonly string _sql; + /// + /// Sql参数列表 + /// + private readonly List _sqlParams; + /// + /// 参数字面值解析器 + /// + private readonly IParamLiteralsResolver _resolver; + /// + /// Sql参数管理器 + /// + private IParameterManager _parameterManager; + + /// + /// 初始化Sql生成器结果 + /// + /// Sql + /// Sql参数列表 + /// 参数字面值解析器 + /// Sql参数管理器 + public SqlBuilderResult( string sql, List sqlParams, IParamLiteralsResolver resolver, IParameterManager parameterManager ) { + _sql = sql; + _sqlParams = sqlParams ?? new List(); + _resolver = resolver; + _parameterManager = parameterManager; + } + + /// + /// 获取Sql语句 + /// + public string GetSql() { + return _sql; + } + + /// + /// 获取Sql参数列表 + /// + public List GetParams() { + return _sqlParams; + } + + /// + /// 获取Sql参数值 + /// + /// 参数值类型 + /// 参数名 + public T GetParam( string name ) { + name = _parameterManager.NormalizeName( name ); + var result = _sqlParams.Find( t => t.Name?.ToUpperInvariant() == name?.ToUpperInvariant() ); + if ( result == null ) + return default; + return Convert.To( result.Value ); + } + + /// + /// 获取调试Sql语句 + /// + public virtual string GetDebugSql() { + var sql = GetSql(); + var parameters = GetParams(); + foreach ( var parameter in parameters ) + sql = Regex.Replace( sql, $@"{parameter.Name}\b", _resolver.GetParamLiterals( parameter.Value ) ); + return sql; + } + } +} \ No newline at end of file diff --git a/src/Util.Data.Sql/Builders/SqlConditionFactory.cs b/src/Util.Data.Sql/Builders/SqlConditionFactory.cs new file mode 100644 index 00000000..2cebd685 --- /dev/null +++ b/src/Util.Data.Sql/Builders/SqlConditionFactory.cs @@ -0,0 +1,77 @@ +using System; +using Util.Data.Queries; +using Util.Data.Sql.Builders.Conditions; +using Util.Data.Sql.Builders.Params; + +namespace Util.Data.Sql.Builders { + /// + /// Sql条件工厂 + /// + public class SqlConditionFactory : IConditionFactory { + /// + /// Sql参数管理器 + /// + private readonly IParameterManager _parameterManager; + + /// + /// 初始化Sql条件工厂 + /// + /// Sql参数管理器 + public SqlConditionFactory( IParameterManager parameterManager ) { + _parameterManager = parameterManager ?? throw new ArgumentNullException( nameof( parameterManager ) ); + } + + /// + public virtual ISqlCondition Create( string column, object value, Operator @operator, bool isParameterization = true ) { + if( IsInCondition( @operator, value ) ) + return new InCondition( _parameterManager, column, value, isParameterization ); + if( IsNotInCondition( @operator, value ) ) + return new NotInCondition( _parameterManager, column, value, isParameterization ); + switch( @operator ) { + case Operator.Equal: + return new EqualCondition( _parameterManager, column, value, isParameterization ); + case Operator.NotEqual: + return new NotEqualCondition( _parameterManager, column, value, isParameterization ); + case Operator.Greater: + return new GreaterCondition( _parameterManager, column, value, isParameterization ); + case Operator.GreaterEqual: + return new GreaterEqualCondition( _parameterManager, column, value, isParameterization ); + case Operator.Less: + return new LessCondition( _parameterManager, column, value, isParameterization ); + case Operator.LessEqual: + return new LessEqualCondition( _parameterManager, column, value, isParameterization ); + case Operator.Contains: + return new ContainsCondition( _parameterManager, column, value, isParameterization ); + case Operator.Starts: + return new StartsCondition( _parameterManager, column, value, isParameterization ); + case Operator.Ends: + return new EndsCondition( _parameterManager, column, value, isParameterization ); + default: + throw new NotImplementedException(); + } + } + + /// + /// 是否In条件 + /// + private bool IsInCondition( Operator @operator, object value ) { + if( @operator == Operator.In ) + return true; + return false; + } + + /// + /// 是否Not In条件 + /// + private bool IsNotInCondition( Operator @operator, object value ) { + if( @operator == Operator.NotIn ) + return true; + return false; + } + + /// + public virtual ISqlCondition Create( string column, object minValue, object maxValue, Boundary boundary, bool isParameterization = true ) { + return new SegmentCondition( _parameterManager, column, minValue, maxValue, boundary, isParameterization ); + } + } +} diff --git a/src/Util.Data.Sql/Configs/ISqlOptions.cs b/src/Util.Data.Sql/Configs/ISqlOptions.cs new file mode 100644 index 00000000..c187d8c5 --- /dev/null +++ b/src/Util.Data.Sql/Configs/ISqlOptions.cs @@ -0,0 +1,7 @@ +namespace Util.Data.Sql.Configs { + /// + /// Sql配置操作 + /// + public interface ISqlOptions { + } +} diff --git a/src/Util.Data.Sql/Configs/ISqlOptionsAccessor.cs b/src/Util.Data.Sql/Configs/ISqlOptionsAccessor.cs new file mode 100644 index 00000000..e7312150 --- /dev/null +++ b/src/Util.Data.Sql/Configs/ISqlOptionsAccessor.cs @@ -0,0 +1,11 @@ +namespace Util.Data.Sql.Configs { + /// + /// Sql配置访问器 + /// + public interface ISqlOptionsAccessor { + /// + /// 获取Sql配置 + /// + SqlOptions GetOptions(); + } +} diff --git a/src/Util.Data.Sql/Database/IConnectionManager.cs b/src/Util.Data.Sql/Database/IConnectionManager.cs new file mode 100644 index 00000000..4f70e1ed --- /dev/null +++ b/src/Util.Data.Sql/Database/IConnectionManager.cs @@ -0,0 +1,18 @@ +using System.Data; + +namespace Util.Data.Sql.Database { + /// + /// 数据库连接管理器 + /// + public interface IConnectionManager { + /// + /// 设置数据库连接 + /// + /// 数据库连接 + void SetConnection( IDbConnection connection ); + /// + /// 获取数据库连接 + /// + IDbConnection GetConnection(); + } +} diff --git a/src/Util.Data.Sql/Database/ITransactionManager.cs b/src/Util.Data.Sql/Database/ITransactionManager.cs new file mode 100644 index 00000000..012053a6 --- /dev/null +++ b/src/Util.Data.Sql/Database/ITransactionManager.cs @@ -0,0 +1,35 @@ +using System.Data; + +namespace Util.Data.Sql.Database { + /// + /// 数据库事务管理器 + /// + public interface ITransactionManager { + /// + /// 设置数据库事务 + /// + /// 数据库事务 + void SetTransaction( IDbTransaction transaction ); + /// + /// 获取数据库事务 + /// + IDbTransaction GetTransaction(); + /// + /// 开始事务 + /// + IDbTransaction BeginTransaction(); + /// + /// 开始事务 + /// + /// 事务隔离级别 + IDbTransaction BeginTransaction( IsolationLevel isolationLevel ); + /// + /// 提交事务 + /// + void CommitTransaction(); + /// + /// 回滚事务 + /// + void RollbackTransaction(); + } +} diff --git a/src/Util.Data.Sql/EndClauseExtensions.cs b/src/Util.Data.Sql/EndClauseExtensions.cs new file mode 100644 index 00000000..f5068761 --- /dev/null +++ b/src/Util.Data.Sql/EndClauseExtensions.cs @@ -0,0 +1,106 @@ +using Util.Data.Queries; +using Util.Data.Sql.Builders; +using Util.Data.Sql.Builders.Operations; + +namespace Util.Data.Sql { + /// + /// 结束子句操作扩展 + /// + public static class EndClauseExtensions { + + #region Skip(设置跳过行数) + + /// + /// 设置跳过行数 + /// + /// 源 + /// 跳过的行数 + public static T Skip( this T source, int count ) where T : IEnd { + source.CheckNull( nameof( source ) ); + if( source is ISqlPartAccessor accessor ) + accessor.EndClause.Skip( count ); + return source; + } + + #endregion + + #region Take(设置获取行数) + + /// + /// 设置获取行数 + /// + /// 源 + /// 获取的行数 + public static T Take( this T source, int count ) where T : IEnd { + source.CheckNull( nameof( source ) ); + if( source is ISqlPartAccessor accessor ) + accessor.EndClause.Take( count ); + return source; + } + + #endregion + + #region Page(设置分页) + + /// + /// 设置分页 + /// + /// 源 + /// 分页参数 + public static T Page( this T source, IPage page ) where T : IEnd { + source.CheckNull( nameof( source ) ); + if( source is ISqlPartAccessor accessor ) + accessor.EndClause.Page( page ); + return source; + } + + #endregion + + #region AppendEnd(添加到Sql结束位置) + + /// + /// 添加到Sql结束位置 + /// + /// 源 + /// Sql语句 + /// 是否原样添加,默认会将[]替换为特定Sql转义符 + public static T AppendEnd( this T source, string sql, bool raw = false ) where T : IEnd { + source.CheckNull( nameof( source ) ); + if( source is ISqlPartAccessor accessor ) + accessor.EndClause.AppendSql( sql, raw ); + return source; + } + + #endregion + + #region ClearPage(清理分页) + + /// + /// 清理分页 + /// + /// 源 + public static T ClearPage( this T source ) where T : IEnd { + source.CheckNull( nameof( source ) ); + if( source is ISqlPartAccessor accessor ) + accessor.EndClause.ClearPage(); + return source; + } + + #endregion + + #region ClearEnd(清理结束子句) + + /// + /// 清理Sql结束子句 + /// + /// 源 + public static T ClearEnd( this T source ) where T : IEnd { + source.CheckNull( nameof( source ) ); + if( source is ISqlPartAccessor accessor ) + accessor.EndClause.Clear(); + return source; + } + + #endregion + } +} diff --git a/src/Util.Data.Sql/FromClauseExtensions.cs b/src/Util.Data.Sql/FromClauseExtensions.cs new file mode 100644 index 00000000..c4ee0f7d --- /dev/null +++ b/src/Util.Data.Sql/FromClauseExtensions.cs @@ -0,0 +1,85 @@ +using System; +using Util.Data.Sql.Builders; +using Util.Data.Sql.Builders.Operations; + +namespace Util.Data.Sql { + /// + /// From子句操作扩展 + /// + public static class FromClauseExtensions { + + #region From(设置表) + + /// + /// 设置表名 + /// + /// 源 + /// 表名 + public static T From( this T source, string table ) where T : IFrom { + source.CheckNull( nameof( source ) ); + if( source is ISqlPartAccessor accessor ) + accessor.FromClause.From( table ); + return source; + } + + /// + /// 设置子查询表 + /// + /// 源 + /// Sql生成器 + /// 表别名 + public static T From( this T source, ISqlBuilder builder, string alias ) where T : IFrom { + source.CheckNull( nameof( source ) ); + if( source is ISqlPartAccessor accessor ) + accessor.FromClause.From( builder, alias ); + return source; + } + + /// + /// 设置子查询表 + /// + /// 源 + /// 子查询操作 + /// 表别名 + public static T From( this T source, Action action, string alias ) where T : IFrom { + source.CheckNull( nameof( source ) ); + if( source is ISqlPartAccessor accessor ) + accessor.FromClause.From( action, alias ); + return source; + } + + #endregion + + #region AppendFrom(添加到From子句) + + /// + /// 添加到From子句 + /// + /// 源 + /// Sql语句 + /// 是否原样添加,默认会将[]替换为特定Sql转义符 + public static T AppendFrom( this T source, string sql,bool raw = false ) where T : IFrom { + source.CheckNull( nameof( source ) ); + if( source is ISqlPartAccessor accessor ) + accessor.FromClause.AppendSql( sql, raw ); + return source; + } + + #endregion + + #region ClearFrom(清空From子句) + + /// + /// 清空From子句 + /// + /// 源 + public static T ClearFrom( this T source ) where T : IFrom { + source.CheckNull( nameof( source ) ); + if( source is ISqlPartAccessor accessor ) + accessor.FromClause.Clear(); + return source; + } + + #endregion + } +} diff --git a/src/Util.Data.Sql/GroupByClauseExtensions.cs b/src/Util.Data.Sql/GroupByClauseExtensions.cs new file mode 100644 index 00000000..6525ab28 --- /dev/null +++ b/src/Util.Data.Sql/GroupByClauseExtensions.cs @@ -0,0 +1,94 @@ +using Util.Data.Sql.Builders; +using Util.Data.Sql.Builders.Operations; + +namespace Util.Data.Sql { + /// + /// Group By子句操作扩展 + /// + public static class GroupByClauseExtensions { + + #region GroupBy(添加分组列) + + /// + /// 添加分组列 + /// + /// 源 + /// 分组字段,范例:a.Id,b.Name + public static T GroupBy( this T source, string columns ) where T : IGroupBy { + source.CheckNull( nameof( source ) ); + if( source is ISqlPartAccessor accessor ) + accessor.GroupByClause.GroupBy( columns ); + return source; + } + + #endregion + + #region Having(添加分组条件) + + /// + /// 添加分组条件 + /// + /// 源 + /// 聚合表达式 + /// 值 + /// 运算符 + /// 是否参数化 + public static T Having( this T source, string expression, object value, Operator @operator = Operator.Equal, bool isParameterization = true ) where T : IGroupBy { + source.CheckNull( nameof( source ) ); + if( source is ISqlPartAccessor accessor ) + accessor.GroupByClause.Having( expression, value , @operator , isParameterization ); + return source; + } + + #endregion + + #region AppendGroupBy(添加到Group By子句) + + /// + /// 添加到Group By子句 + /// + /// 源 + /// Sql语句 + /// 是否原样添加,默认会将[]替换为特定Sql转义符 + public static T AppendGroupBy( this T source, string sql, bool raw = false ) where T : IGroupBy { + source.CheckNull( nameof( source ) ); + if( source is ISqlPartAccessor accessor ) + accessor.GroupByClause.AppendGroupBy( sql, raw ); + return source; + } + + #endregion + + #region AppendHaving(添加到Having子句) + + /// + /// 添加到Having子句 + /// + /// 源 + /// Sql语句 + /// 是否原样添加,默认会将[]替换为特定Sql转义符 + public static T AppendHaving( this T source, string sql, bool raw = false ) where T : IGroupBy { + source.CheckNull( nameof( source ) ); + if( source is ISqlPartAccessor accessor ) + accessor.GroupByClause.AppendHaving( sql, raw ); + return source; + } + + #endregion + + #region ClearGroupBy(清空Group By子句) + + /// + /// 清空Group By子句 + /// + /// 源 + public static T ClearGroupBy( this T source ) where T : IGroupBy { + source.CheckNull( nameof( source ) ); + if( source is ISqlPartAccessor accessor ) + accessor.GroupByClause.Clear(); + return source; + } + + #endregion + } +} diff --git a/src/Util.Data.Sql/ISqlBuilder.cs b/src/Util.Data.Sql/ISqlBuilder.cs new file mode 100644 index 00000000..c48a1375 --- /dev/null +++ b/src/Util.Data.Sql/ISqlBuilder.cs @@ -0,0 +1,26 @@ +using Util.Data.Sql.Builders; +using Util.Data.Sql.Builders.Operations; + +namespace Util.Data.Sql { + /// + /// Sql生成器 + /// + public interface ISqlBuilder : ISqlContent, ISqlOperation { + /// + /// 复制Sql生成器副本 + /// + ISqlBuilder Clone(); + /// + /// 创建一个新的Sql生成器 + /// + ISqlBuilder New(); + /// + /// 清理 + /// + ISqlBuilder Clear(); + /// + /// 获取Sql语句 + /// + string GetSql(); + } +} diff --git a/src/Util.Data.Sql/ISqlCondition.cs b/src/Util.Data.Sql/ISqlCondition.cs new file mode 100644 index 00000000..49e2f787 --- /dev/null +++ b/src/Util.Data.Sql/ISqlCondition.cs @@ -0,0 +1,9 @@ +using Util.Data.Sql.Builders; + +namespace Util.Data.Sql { + /// + /// Sql查询条件 + /// + public interface ISqlCondition : ISqlContent { + } +} diff --git a/src/Util.Data.Sql/ISqlExecutor.cs b/src/Util.Data.Sql/ISqlExecutor.cs new file mode 100644 index 00000000..d182700e --- /dev/null +++ b/src/Util.Data.Sql/ISqlExecutor.cs @@ -0,0 +1,21 @@ +using System.Threading.Tasks; +using Util.Data.Sql.Builders.Operations; + +namespace Util.Data.Sql { + /// + /// Sql执行器 + /// + public interface ISqlExecutor : ISqlQuery, ISqlOperation { + /// + /// 执行Sql增删改操作 + /// + /// 执行超时时间,单位:秒 + Task ExecuteAsync( int? timeout = null ); + /// + /// 执行存储过程增删改操作 + /// + /// 存储过程 + /// 执行超时时间,单位:秒 + Task ExecuteProcedureAsync( string procedure, int? timeout = null ); + } +} diff --git a/src/Util.Data.Sql/ISqlQuery.cs b/src/Util.Data.Sql/ISqlQuery.cs new file mode 100644 index 00000000..2cc59f4f --- /dev/null +++ b/src/Util.Data.Sql/ISqlQuery.cs @@ -0,0 +1,468 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Util.Data.Sql.Builders; +using Util.Data.Sql.Builders.Operations; +using Util.Data.Sql.Configs; + +namespace Util.Data.Sql { + /// + /// Sql查询对象 + /// + public interface ISqlQuery : ISqlQueryOperation, ISqlOptions, IDisposable { + /// + /// 上下文标识 + /// + string ContextId { get; } + /// + /// 前一次执行的Sql及参数 + /// + SqlBuilderResult PreviousSql { get; } + /// + /// 获取Sql生成器 + /// + ISqlBuilder SqlBuilder { get; } + /// + /// 判断是否存在 + /// + bool ExecuteExists(); + /// + /// 判断是否存在 + /// + Task ExecuteExistsAsync(); + /// + /// 获取单值 + /// + /// 执行超时时间,单位:秒 + object ExecuteScalar( int? timeout = null ); + /// + /// 获取单值 + /// + /// 执行超时时间,单位:秒 + T ExecuteScalar( int? timeout = null ); + /// + /// 获取单值 + /// + /// 执行超时时间,单位:秒 + Task ExecuteScalarAsync( int? timeout = null ); + /// + /// 获取单值 + /// + /// 执行超时时间,单位:秒 + Task ExecuteScalarAsync( int? timeout = null ); + /// + /// 执行存储过程获取单值 + /// + /// 存储过程 + /// 执行超时时间,单位:秒 + object ExecuteProcedureScalar( string procedure, int? timeout = null ); + /// + /// 执行存储过程获取单值 + /// + /// 存储过程 + /// 执行超时时间,单位:秒 + T ExecuteProcedureScalar( string procedure, int? timeout = null ); + /// + /// 执行存储过程获取单值 + /// + /// 存储过程 + /// 执行超时时间,单位:秒 + Task ExecuteProcedureScalarAsync( string procedure, int? timeout = null ); + /// + /// 执行存储过程获取单值 + /// + /// 存储过程 + /// 执行超时时间,单位:秒 + Task ExecuteProcedureScalarAsync( string procedure, int? timeout = null ); + /// + /// 获取单个实体 + /// + /// 实体类型 + /// 执行超时时间,单位:秒 + TEntity ExecuteSingle( int? timeout = null ); + /// + /// 获取单个实体 + /// + /// 实体类型 + /// 执行超时时间,单位:秒 + Task ExecuteSingleAsync( int? timeout = null ); + /// + /// 执行存储过程获取单个实体 + /// + /// 实体类型 + /// 存储过程 + /// 执行超时时间,单位:秒 + TEntity ExecuteProcedureSingle( string procedure, int? timeout = null ); + /// + /// 执行存储过程获取单个实体 + /// + /// 实体类型 + /// 存储过程 + /// 执行超时时间,单位:秒 + Task ExecuteProcedureSingleAsync( string procedure, int? timeout = null ); + /// + /// 获取实体集合 + /// + /// 执行超时时间,单位:秒 + /// 是否缓存,默认值: true + List ExecuteQuery( int? timeout = null, bool buffered = true ); + /// + /// 获取实体集合 + /// + /// 实体类型 + /// 执行超时时间,单位:秒 + /// 是否缓存,默认值: true + List ExecuteQuery( int? timeout = null, bool buffered = true ); + /// + /// 获取实体集合 + /// + /// 实体类型1 + /// 实体类型2 + /// 返回的实体类型 + /// 映射函数 + /// 执行超时时间,单位:秒 + /// 是否缓存,默认值: true + List ExecuteQuery( Func map, int? timeout = null, bool buffered = true ); + /// + /// 获取实体集合 + /// + /// 实体类型1 + /// 实体类型2 + /// 实体类型3 + /// 返回的实体类型 + /// 映射函数 + /// 执行超时时间,单位:秒 + /// 是否缓存,默认值: true + List ExecuteQuery( Func map, int? timeout = null, bool buffered = true ); + /// + /// 获取实体集合 + /// + /// 实体类型1 + /// 实体类型2 + /// 实体类型3 + /// 实体类型4 + /// 返回的实体类型 + /// 映射函数 + /// 执行超时时间,单位:秒 + /// 是否缓存,默认值: true + List ExecuteQuery( Func map, int? timeout = null, bool buffered = true ); + /// + /// 获取实体集合 + /// + /// 实体类型1 + /// 实体类型2 + /// 实体类型3 + /// 实体类型4 + /// 实体类型5 + /// 返回的实体类型 + /// 映射函数 + /// 执行超时时间,单位:秒 + /// 是否缓存,默认值: true + List ExecuteQuery( Func map, int? timeout = null, bool buffered = true ); + /// + /// 获取实体集合 + /// + /// 实体类型1 + /// 实体类型2 + /// 实体类型3 + /// 实体类型4 + /// 实体类型5 + /// 实体类型6 + /// 返回的实体类型 + /// 映射函数 + /// 执行超时时间,单位:秒 + /// 是否缓存,默认值: true + List ExecuteQuery( Func map, int? timeout = null, bool buffered = true ); + /// + /// 获取实体集合 + /// + /// 实体类型1 + /// 实体类型2 + /// 实体类型3 + /// 实体类型4 + /// 实体类型5 + /// 实体类型6 + /// 实体类型7 + /// 返回的实体类型 + /// 映射函数 + /// 执行超时时间,单位:秒 + /// 是否缓存,默认值: true + List ExecuteQuery( Func map, int? timeout = null, bool buffered = true ); + /// + /// 获取实体集合 + /// + /// 执行超时时间,单位:秒 + Task> ExecuteQueryAsync( int? timeout = null ); + /// + /// 获取实体集合 + /// + /// 实体类型 + /// 执行超时时间,单位:秒 + Task> ExecuteQueryAsync( int? timeout = null ); + /// + /// 获取实体集合 + /// + /// 实体类型1 + /// 实体类型2 + /// 返回的实体类型 + /// 映射函数 + /// 执行超时时间,单位:秒 + /// 是否缓存,默认值: true + Task> ExecuteQueryAsync( Func map, int? timeout = null, bool buffered = true ); + /// + /// 获取实体集合 + /// + /// 实体类型1 + /// 实体类型2 + /// 实体类型3 + /// 返回的实体类型 + /// 映射函数 + /// 执行超时时间,单位:秒 + /// 是否缓存,默认值: true + Task> ExecuteQueryAsync( Func map, int? timeout = null, bool buffered = true ); + /// + /// 获取实体集合 + /// + /// 实体类型1 + /// 实体类型2 + /// 实体类型3 + /// 实体类型4 + /// 返回的实体类型 + /// 映射函数 + /// 执行超时时间,单位:秒 + /// 是否缓存,默认值: true + Task> ExecuteQueryAsync( Func map, int? timeout = null, bool buffered = true ); + /// + /// 获取实体集合 + /// + /// 实体类型1 + /// 实体类型2 + /// 实体类型3 + /// 实体类型4 + /// 实体类型5 + /// 返回的实体类型 + /// 映射函数 + /// 执行超时时间,单位:秒 + /// 是否缓存,默认值: true + Task> ExecuteQueryAsync( Func map, int? timeout = null, bool buffered = true ); + /// + /// 获取实体集合 + /// + /// 实体类型1 + /// 实体类型2 + /// 实体类型3 + /// 实体类型4 + /// 实体类型5 + /// 实体类型6 + /// 返回的实体类型 + /// 映射函数 + /// 执行超时时间,单位:秒 + /// 是否缓存,默认值: true + Task> ExecuteQueryAsync( Func map, int? timeout = null, bool buffered = true ); + /// + /// 获取实体集合 + /// + /// 实体类型1 + /// 实体类型2 + /// 实体类型3 + /// 实体类型4 + /// 实体类型5 + /// 实体类型6 + /// 实体类型7 + /// 返回的实体类型 + /// 映射函数 + /// 执行超时时间,单位:秒 + /// 是否缓存,默认值: true + Task> ExecuteQueryAsync( Func map, int? timeout = null, bool buffered = true ); + /// + /// 执行存储过程获取实体集合 + /// + /// 存储过程 + /// 执行超时时间,单位:秒 + /// 是否缓存,默认值: true + List ExecuteProcedureQuery( string procedure, int? timeout = null, bool buffered = true ); + /// + /// 执行存储过程获取实体集合 + /// + /// 实体类型 + /// 存储过程 + /// 执行超时时间,单位:秒 + /// 是否缓存,默认值: true + List ExecuteProcedureQuery( string procedure, int? timeout = null, bool buffered = true ); + /// + /// 执行存储过程获取实体集合 + /// + /// 实体类型1 + /// 实体类型2 + /// 返回的实体类型 + /// 存储过程 + /// 映射函数 + /// 执行超时时间,单位:秒 + /// 是否缓存,默认值: true + List ExecuteProcedureQuery( string procedure, Func map, int? timeout = null, bool buffered = true ); + /// + /// 执行存储过程获取实体集合 + /// + /// 实体类型1 + /// 实体类型2 + /// 实体类型3 + /// 返回的实体类型 + /// 存储过程 + /// 映射函数 + /// 执行超时时间,单位:秒 + /// 是否缓存,默认值: true + List ExecuteProcedureQuery( string procedure, Func map, int? timeout = null, bool buffered = true ); + /// + /// 执行存储过程获取实体集合 + /// + /// 实体类型1 + /// 实体类型2 + /// 实体类型3 + /// 实体类型4 + /// 返回的实体类型 + /// 存储过程 + /// 映射函数 + /// 执行超时时间,单位:秒 + /// 是否缓存,默认值: true + List ExecuteProcedureQuery( string procedure, Func map, int? timeout = null, bool buffered = true ); + /// + /// 执行存储过程获取实体集合 + /// + /// 实体类型1 + /// 实体类型2 + /// 实体类型3 + /// 实体类型4 + /// 实体类型5 + /// 返回的实体类型 + /// 存储过程 + /// 映射函数 + /// 执行超时时间,单位:秒 + /// 是否缓存,默认值: true + List ExecuteProcedureQuery( string procedure, Func map, int? timeout = null, bool buffered = true ); + /// + /// 执行存储过程获取实体集合 + /// + /// 实体类型1 + /// 实体类型2 + /// 实体类型3 + /// 实体类型4 + /// 实体类型5 + /// 实体类型6 + /// 返回的实体类型 + /// 存储过程 + /// 映射函数 + /// 执行超时时间,单位:秒 + /// 是否缓存,默认值: true + List ExecuteProcedureQuery( string procedure, Func map, int? timeout = null, bool buffered = true ); + /// + /// 执行存储过程获取实体集合 + /// + /// 实体类型1 + /// 实体类型2 + /// 实体类型3 + /// 实体类型4 + /// 实体类型5 + /// 实体类型6 + /// 实体类型7 + /// 返回的实体类型 + /// 存储过程 + /// 映射函数 + /// 执行超时时间,单位:秒 + /// 是否缓存,默认值: true + List ExecuteProcedureQuery( string procedure, Func map, int? timeout = null, bool buffered = true ); + /// + /// 执行存储过程获取实体集合 + /// + /// 存储过程 + /// 执行超时时间,单位:秒 + Task> ExecuteProcedureQueryAsync( string procedure, int? timeout = null ); + /// + /// 执行存储过程获取实体集合 + /// + /// 实体类型 + /// 存储过程 + /// 执行超时时间,单位:秒 + Task> ExecuteProcedureQueryAsync( string procedure, int? timeout = null ); + /// + /// 执行存储过程获取实体集合 + /// + /// 实体类型1 + /// 实体类型2 + /// 返回的实体类型 + /// 存储过程 + /// 映射函数 + /// 执行超时时间,单位:秒 + /// 是否缓存,默认值: true + Task> ExecuteProcedureQueryAsync( string procedure, Func map, int? timeout = null, bool buffered = true ); + /// + /// 执行存储过程获取实体集合 + /// + /// 实体类型1 + /// 实体类型2 + /// 实体类型3 + /// 返回的实体类型 + /// 存储过程 + /// 映射函数 + /// 执行超时时间,单位:秒 + /// 是否缓存,默认值: true + Task> ExecuteProcedureQueryAsync( string procedure, Func map, int? timeout = null, bool buffered = true ); + /// + /// 执行存储过程获取实体集合 + /// + /// 实体类型1 + /// 实体类型2 + /// 实体类型3 + /// 实体类型4 + /// 返回的实体类型 + /// 存储过程 + /// 映射函数 + /// 执行超时时间,单位:秒 + /// 是否缓存,默认值: true + Task> ExecuteProcedureQueryAsync( string procedure, Func map, int? timeout = null, bool buffered = true ); + /// + /// 执行存储过程获取实体集合 + /// + /// 实体类型1 + /// 实体类型2 + /// 实体类型3 + /// 实体类型4 + /// 实体类型5 + /// 返回的实体类型 + /// 存储过程 + /// 映射函数 + /// 执行超时时间,单位:秒 + /// 是否缓存,默认值: true + Task> ExecuteProcedureQueryAsync( string procedure, Func map, int? timeout = null, bool buffered = true ); + /// + /// 执行存储过程获取实体集合 + /// + /// 实体类型1 + /// 实体类型2 + /// 实体类型3 + /// 实体类型4 + /// 实体类型5 + /// 实体类型6 + /// 返回的实体类型 + /// 存储过程 + /// 映射函数 + /// 执行超时时间,单位:秒 + /// 是否缓存,默认值: true + Task> ExecuteProcedureQueryAsync( string procedure, Func map, int? timeout = null, bool buffered = true ); + /// + /// 执行存储过程获取实体集合 + /// + /// 实体类型1 + /// 实体类型2 + /// 实体类型3 + /// 实体类型4 + /// 实体类型5 + /// 实体类型6 + /// 实体类型7 + /// 返回的实体类型 + /// 存储过程 + /// 映射函数 + /// 执行超时时间,单位:秒 + /// 是否缓存,默认值: true + Task> ExecuteProcedureQueryAsync( string procedure, Func map, int? timeout = null, bool buffered = true ); + } +} diff --git a/src/Util.Data.Sql/InsertClauseExtensions.cs b/src/Util.Data.Sql/InsertClauseExtensions.cs new file mode 100644 index 00000000..82a117e3 --- /dev/null +++ b/src/Util.Data.Sql/InsertClauseExtensions.cs @@ -0,0 +1,98 @@ +using System; +using Util.Data.Sql.Builders; +using Util.Data.Sql.Builders.Operations; + +namespace Util.Data.Sql { + /// + /// Insert子句操作扩展 + /// + public static class InsertClauseExtensions { + + #region Insert(设置插入的表和列名集合) + + /// + /// 设置插入的表和列名集合 + /// + /// 源 + /// 列名集合 + /// 表名 + public static T Insert( this T source, string columns, string table = null ) where T : IInsert { + if( source == null ) + throw new ArgumentNullException( nameof( source ) ); + if( source is ISqlPartAccessor accessor ) + accessor.InsertClause.Insert( columns,table ); + return source; + } + + #endregion + + #region Values(设置插入的值集合) + + /// + /// 设置Insert语句插入的参数值集合 + /// + /// 源 + /// 参数值集合 + public static T Values( this T source, params object[] values ) where T : IInsert { + if( source == null ) + throw new ArgumentNullException( nameof( source ) ); + if( source is ISqlPartAccessor accessor ) + accessor.InsertClause.Values( values ); + return source; + } + + #endregion + + #region AppendInsert(添加到Insert子句) + + /// + /// 添加到Insert子句 + /// + /// 源 + /// Sql语句 + /// 是否原样添加,默认会将[]替换为特定Sql转义符 + public static T AppendInsert( this T source, string sql,bool raw = false ) where T : IFrom { + if( source == null ) + throw new ArgumentNullException( nameof( source ) ); + if( source is ISqlPartAccessor accessor ) + accessor.InsertClause.AppendInsert( sql, raw ); + return source; + } + + #endregion + + #region AppendValues(添加到Values子句) + + /// + /// 添加到Values子句 + /// + /// 源 + /// Sql语句 + /// 是否原样添加,默认会将[]替换为特定Sql转义符 + public static T AppendValues( this T source, string sql, bool raw = false ) where T : IFrom { + if( source == null ) + throw new ArgumentNullException( nameof( source ) ); + if( source is ISqlPartAccessor accessor ) + accessor.InsertClause.AppendValues( sql, raw ); + return source; + } + + #endregion + + #region ClearInsert(清空Insert子句) + + /// + /// 清空Insert子句 + /// + /// 源 + public static T ClearInsert( this T source ) where T : IFrom { + if( source == null ) + throw new ArgumentNullException( nameof( source ) ); + if( source is ISqlPartAccessor accessor ) + accessor.InsertClause.Clear(); + return source; + } + + #endregion + } +} diff --git a/src/Util.Data.Sql/JoinClauseExtensions.cs b/src/Util.Data.Sql/JoinClauseExtensions.cs new file mode 100644 index 00000000..cffb89e4 --- /dev/null +++ b/src/Util.Data.Sql/JoinClauseExtensions.cs @@ -0,0 +1,239 @@ +using System; +using Util.Data.Sql.Builders; +using Util.Data.Sql.Builders.Operations; + +namespace Util.Data.Sql { + /// + /// Join子句操作扩展 + /// + public static class JoinClauseExtensions { + + #region Join(内连接) + + /// + /// 内连接 + /// + /// 源 + /// 表名 + public static T Join( this T source, string table ) where T : IJoin { + source.CheckNull( nameof( source ) ); + if( source is ISqlPartAccessor accessor ) + accessor.JoinClause.Join( table ); + return source; + } + + /// + /// 内连接子查询 + /// + /// 源 + /// Sql生成器 + /// 表别名 + public static T Join( this T source, ISqlBuilder builder, string alias ) where T : IJoin { + source.CheckNull( nameof( source ) ); + if( source is ISqlPartAccessor accessor ) + accessor.JoinClause.Join( builder, alias ); + return source; + } + + /// + /// 内连接子查询 + /// + /// 源 + /// 子查询操作 + /// 表别名 + public static T Join( this T source, Action action, string alias ) where T : IJoin { + source.CheckNull( nameof( source ) ); + if( source is ISqlPartAccessor accessor ) + accessor.JoinClause.Join( action, alias ); + return source; + } + + #endregion + + #region LeftJoin(左外连接) + + /// + /// 左外连接 + /// + /// 源 + /// 表名 + public static T LeftJoin( this T source, string table ) where T : IJoin { + source.CheckNull( nameof( source ) ); + if( source is ISqlPartAccessor accessor ) + accessor.JoinClause.LeftJoin( table ); + return source; + } + + /// + /// 左外连接子查询 + /// + /// 源 + /// Sql生成器 + /// 表别名 + public static T LeftJoin( this T source, ISqlBuilder builder, string alias ) where T : IJoin { + source.CheckNull( nameof( source ) ); + if( source is ISqlPartAccessor accessor ) + accessor.JoinClause.LeftJoin( builder, alias ); + return source; + } + + /// + /// 左外连接子查询 + /// + /// 源 + /// 子查询操作 + /// 表别名 + public static T LeftJoin( this T source, Action action, string alias ) where T : IJoin { + source.CheckNull( nameof( source ) ); + if( source is ISqlPartAccessor accessor ) + accessor.JoinClause.LeftJoin( action, alias ); + return source; + } + + #endregion + + #region RightJoin(右外连接) + + /// + /// 右外连接 + /// + /// 源 + /// 表名 + public static T RightJoin( this T source, string table ) where T : IJoin { + source.CheckNull( nameof( source ) ); + if( source is ISqlPartAccessor accessor ) + accessor.JoinClause.RightJoin( table ); + return source; + } + + /// + /// 右外连接子查询 + /// + /// 源 + /// Sql生成器 + /// 表别名 + public static T RightJoin( this T source, ISqlBuilder builder, string alias ) where T : IJoin { + source.CheckNull( nameof( source ) ); + if( source is ISqlPartAccessor accessor ) + accessor.JoinClause.RightJoin( builder, alias ); + return source; + } + + /// + /// 右外连接子查询 + /// + /// 源 + /// 子查询操作 + /// 表别名 + public static T RightJoin( this T source, Action action, string alias ) where T : IJoin { + source.CheckNull( nameof( source ) ); + if( source is ISqlPartAccessor accessor ) + accessor.JoinClause.RightJoin( action, alias ); + return source; + } + + #endregion + + #region On(设置连接条件) + + /// + /// 设置连接条件 + /// + /// 源 + /// 列名 + /// 值 + /// 运算符 + /// 是否参数化 + public static T On( this T source, string column, object value, Operator @operator = Operator.Equal, bool isParameterization = false ) where T : IJoin { + source.CheckNull( nameof( source ) ); + if( source is ISqlPartAccessor accessor ) + accessor.JoinClause.On( column, value, @operator, isParameterization ); + return source; + } + + #endregion + + #region AppendJoin(添加到内连接子句) + + /// + /// 添加到内连接子句 + /// + /// 源 + /// Sql语句 + /// 是否原样添加,默认会将[]替换为特定Sql转义符 + public static T AppendJoin( this T source, string sql, bool raw = false ) where T : IJoin { + source.CheckNull( nameof( source ) ); + if( source is ISqlPartAccessor accessor ) + accessor.JoinClause.AppendJoin( sql, raw ); + return source; + } + + #endregion + + #region AppendLeftJoin(添加到左外连接子句) + + /// + /// 添加到左外连接子句 + /// + /// 源 + /// Sql语句 + /// 是否原样添加,默认会将[]替换为特定Sql转义符 + public static T AppendLeftJoin( this T source, string sql, bool raw = false ) where T : IJoin { + source.CheckNull( nameof( source ) ); + if( source is ISqlPartAccessor accessor ) + accessor.JoinClause.AppendLeftJoin( sql, raw ); + return source; + } + + #endregion + + #region AppendRightJoin(添加到右外连接子句) + + /// + /// 添加到右外连接子句 + /// + /// 源 + /// Sql语句 + /// 是否原样添加,默认会将[]替换为特定Sql转义符 + public static T AppendRightJoin( this T source, string sql, bool raw = false ) where T : IJoin { + source.CheckNull( nameof( source ) ); + if( source is ISqlPartAccessor accessor ) + accessor.JoinClause.AppendRightJoin( sql, raw ); + return source; + } + + #endregion + + #region AppendOn(添加到On子句) + + /// + /// 添加到On子句 + /// + /// 源 + /// Sql语句 + /// 是否原样添加,默认会将[]替换为特定Sql转义符 + public static T AppendOn( this T source, string sql, bool raw = false ) where T : IJoin { + source.CheckNull( nameof( source ) ); + if( source is ISqlPartAccessor accessor ) + accessor.JoinClause.AppendOn( sql, raw ); + return source; + } + + #endregion + + #region ClearJoin(清空Join子句) + + /// + /// 清空Join子句 + /// + /// 源 + public static T ClearJoin( this T source ) where T : IJoin { + source.CheckNull( nameof( source ) ); + if( source is ISqlPartAccessor accessor ) + accessor.JoinClause.Clear(); + return source; + } + + #endregion + } +} diff --git a/src/Util.Data.Sql/OrderByClauseExtensions.cs b/src/Util.Data.Sql/OrderByClauseExtensions.cs new file mode 100644 index 00000000..57dd712d --- /dev/null +++ b/src/Util.Data.Sql/OrderByClauseExtensions.cs @@ -0,0 +1,58 @@ +using Util.Data.Sql.Builders; +using Util.Data.Sql.Builders.Operations; + +namespace Util.Data.Sql { + /// + /// OrderBy子句操作扩展 + /// + public static class OrderByClauseExtensions { + + #region OrderBy(排序) + + /// + /// 排序 + /// + /// 源 + /// 排序列表,范例:a.Id,b.Name desc + public static T OrderBy( this T source, string order ) where T : IOrderBy { + source.CheckNull( nameof( source ) ); + if( source is ISqlPartAccessor accessor ) + accessor.OrderByClause.OrderBy( order ); + return source; + } + + #endregion + + #region AppendOrderBy(添加到Order By子句) + + /// + /// 添加到Order By子句 + /// + /// 源 + /// Sql语句 + /// 是否原样添加,默认会将[]替换为特定Sql转义符 + public static T AppendOrderBy( this T source, string sql, bool raw = false ) where T : IOrderBy { + source.CheckNull( nameof( source ) ); + if( source is ISqlPartAccessor accessor ) + accessor.OrderByClause.AppendSql( sql, raw ); + return source; + } + + #endregion + + #region ClearOrderBy(清空Order By子句) + + /// + /// 清空Order By子句 + /// + /// 源 + public static T ClearOrderBy( this T source ) where T : IOrderBy { + source.CheckNull( nameof( source ) ); + if( source is ISqlPartAccessor accessor ) + accessor.OrderByClause.Clear(); + return source; + } + + #endregion + } +} diff --git a/src/Util.Data.Sql/ParameterExtensions.cs b/src/Util.Data.Sql/ParameterExtensions.cs new file mode 100644 index 00000000..e6edcae0 --- /dev/null +++ b/src/Util.Data.Sql/ParameterExtensions.cs @@ -0,0 +1,132 @@ +using System.Collections.Generic; +using System.Data; +using Util.Data.Sql.Builders; +using Util.Data.Sql.Builders.Operations; +using Util.Data.Sql.Builders.Params; + +namespace Util.Data.Sql { + /// + /// Sql参数操作扩展 + /// + public static class ParameterExtensions { + + #region AddDynamicParams(添加动态参数) + + /// + /// 添加动态参数 + /// + /// 源 + /// 动态参数,范例: new{ A=1,B=2 } + public static T AddDynamicParams( this T source, object param ) where T : ISqlParameter { + source.CheckNull( nameof( source ) ); + if( source is ISqlPartAccessor accessor ) + accessor.ParameterManager.AddDynamicParams( param ); + return source; + } + + #endregion + + #region AddParam(添加Sql参数) + + /// + /// 添加Sql参数 + /// + /// 源 + /// 参数名 + /// 参数类型 + /// 参数方向 + public static T AddParam( this T source, string name, DbType dbType, ParameterDirection direction ) where T : ISqlParameter { + source.CheckNull( nameof( source ) ); + if( source is ISqlPartAccessor accessor ) + accessor.ParameterManager.Add( name, null, dbType, direction ); + return source; + } + + /// + /// 添加Sql参数 + /// + /// 源 + /// 参数名 + /// 参数值 + /// 参数类型 + /// 参数方向 + /// 字段长度 + /// 数值有效位数 + /// 数值小数位数 + public static T AddParam( this T source, string name, object value = null, DbType? dbType = null, ParameterDirection? direction = null, int? size = null, byte? precision = null, byte? scale = null ) where T : ISqlParameter { + source.CheckNull( nameof( source ) ); + if( source is ISqlPartAccessor accessor ) + accessor.ParameterManager.Add( name, value, dbType, direction, size, precision, scale ); + return source; + } + + #endregion + + #region GetParams(获取参数列表) + + /// + /// 获取参数列表 + /// + /// 源 + public static IReadOnlyList GetParams( this ISqlParameter source ) { + source.CheckNull( nameof( source ) ); + if( source is ISqlPartAccessor accessor ) + return accessor.ParameterManager.GetParams(); + return default; + } + + #endregion + + #region GetDynamicParams(获取动态参数列表) + + /// + /// 获取动态参数列表 + /// + /// 源 + public static IReadOnlyList GetDynamicParams( this ISqlParameter source ) { + source.CheckNull( nameof( source ) ); + if ( source is ISqlPartAccessor accessor ) + return accessor.ParameterManager.GetDynamicParams(); + return default; + } + + #endregion + + #region GetParam(获取参数值) + + /// + /// 获取参数值 + /// + /// 源 + /// 参数名 + public static T GetParam( this ISqlParameter source, string name ) { + source.CheckNull( nameof( source ) ); + if( source is IGetParameter target ) + return target.GetParam( name ); + if( source is ISqlPartAccessor accessor ) + return (T)accessor.ParameterManager.GetValue( name ); + return default; + } + + #endregion + + #region ClearParams(清空Sql参数) + + /// + /// 清空Sql参数 + /// + /// 源 + public static T ClearParams( this T source ) where T : ISqlParameter { + source.CheckNull( nameof( source ) ); + if( source is IClearParameters target ) { + target.ClearParams(); + return source; + } + if( source is ISqlPartAccessor accessor ) + accessor.ParameterManager.Clear(); + return source; + } + + #endregion + } +} diff --git a/src/Util.Data.Sql/SelectClauseExtensions.cs b/src/Util.Data.Sql/SelectClauseExtensions.cs new file mode 100644 index 00000000..3d7b0cb7 --- /dev/null +++ b/src/Util.Data.Sql/SelectClauseExtensions.cs @@ -0,0 +1,120 @@ +using System; +using Util.Data.Sql.Builders; +using Util.Data.Sql.Builders.Operations; + +namespace Util.Data.Sql { + /// + /// Select子句操作扩展 + /// + public static class SelectClauseExtensions { + + #region Select(设置列) + + /// + /// 设置星号*列 + /// + /// 源 + public static T Select( this T source ) where T : ISelect { + source.CheckNull( nameof( source ) ); + if( source is ISqlPartAccessor accessor ) + accessor.SelectClause.Select(); + return source; + } + + /// + /// 设置列名 + /// + /// 源 + /// 列名,范例:a.AppId As Id,a.Name + public static T Select( this T source, string columns ) where T : ISelect { + source.CheckNull( nameof( source ) ); + if( source is ISqlPartAccessor accessor ) + accessor.SelectClause.Select( columns ); + return source; + } + + /// + /// 设置子查询列 + /// + /// 源 + /// Sql生成器 + /// 列别名 + public static T Select( this T source, ISqlBuilder builder, string alias ) where T : ISelect { + source.CheckNull( nameof( source ) ); + if( source is ISqlPartAccessor accessor ) + accessor.SelectClause.Select( builder, alias ); + return source; + } + + /// + /// 设置子查询列 + /// + /// 源 + /// 子查询操作 + /// 列别名 + public static T Select( this T source, Action action, string alias ) where T : ISelect { + source.CheckNull( nameof( source ) ); + if( source is ISqlPartAccessor accessor ) + accessor.SelectClause.Select( action, alias ); + return source; + } + + #endregion + + #region AppendSelect(添加到Select子句) + + /// + /// 添加到Select子句 + /// + /// 源 + /// Sql语句 + /// 是否原样添加,默认会将[]替换为特定Sql转义符 + public static T AppendSelect( this T source, string sql, bool raw = false ) where T : ISelect { + source.CheckNull( nameof( source ) ); + if( source is ISqlPartAccessor accessor ) + accessor.SelectClause.AppendSql( sql, raw ); + return source; + } + + /// + /// 添加子查询到Select子句 + /// + /// 源 + /// Sql生成器 + public static T AppendSelect( this T source, ISqlBuilder builder ) where T : ISelect { + source.CheckNull( nameof( source ) ); + if( source is ISqlPartAccessor accessor ) + accessor.SelectClause.AppendSql( builder ); + return source; + } + + /// + /// 添加子查询到Select子句 + /// + /// 源 + /// 子查询操作 + public static T AppendSelect( this T source, Action action ) where T : ISelect { + source.CheckNull( nameof( source ) ); + if( source is ISqlPartAccessor accessor ) + accessor.SelectClause.AppendSql( action ); + return source; + } + + #endregion + + #region ClearSelect(清空Select子句) + + /// + /// 清空Select子句 + /// + /// 源 + public static T ClearSelect( this T source ) where T : ISelect { + source.CheckNull( nameof( source ) ); + if( source is ISqlPartAccessor accessor ) + accessor.SelectClause.Clear(); + return source; + } + + #endregion + } +} diff --git a/src/Util.Data.Sql/SqlBuilderSetExtensions.cs b/src/Util.Data.Sql/SqlBuilderSetExtensions.cs new file mode 100644 index 00000000..b2a5c95a --- /dev/null +++ b/src/Util.Data.Sql/SqlBuilderSetExtensions.cs @@ -0,0 +1,138 @@ +using System.Collections.Generic; +using Util.Data.Sql.Builders; +using Util.Data.Sql.Builders.Operations; + +namespace Util.Data.Sql { + /// + /// Sql生成器集合操作扩展 + /// + public static class SqlBuilderSetExtensions { + + #region Union(合并结果集) + + /// + /// 合并结果集,排除重复结果行,并按默认规则排序 + /// + /// 源 + /// Sql生成器集合 + public static T Union( this T source, params ISqlBuilder[] builders ) where T : ISet { + source.CheckNull( nameof( source ) ); + if( source is ISqlPartAccessor accessor ) + accessor.SqlBuilderSet.Union( builders ); + return source; + } + + /// + /// 合并结果集,排除重复结果行,并按默认规则排序 + /// + /// 源 + /// Sql生成器集合 + public static T Union( this T source, IEnumerable builders ) where T : ISet { + source.CheckNull( nameof( source ) ); + if( source is ISqlPartAccessor accessor ) + accessor.SqlBuilderSet.Union( builders ); + return source; + } + + #endregion + + #region UnionAll(合并结果集) + + /// + /// 合并结果集,不会排除重复结果行 + /// + /// 源 + /// Sql生成器集合 + public static T UnionAll( this T source, params ISqlBuilder[] builders ) where T : ISet { + source.CheckNull( nameof( source ) ); + if( source is ISqlPartAccessor accessor ) + accessor.SqlBuilderSet.UnionAll( builders ); + return source; + } + + /// + /// 合并结果集,不会排除重复结果行 + /// + /// 源 + /// Sql生成器集合 + public static T UnionAll( this T source, IEnumerable builders ) where T : ISet { + source.CheckNull( nameof( source ) ); + if( source is ISqlPartAccessor accessor ) + accessor.SqlBuilderSet.UnionAll( builders ); + return source; + } + + #endregion + + #region Intersect(交集) + + /// + /// 交集 + /// + /// 源 + /// Sql生成器集合 + public static T Intersect( this T source, params ISqlBuilder[] builders ) where T : ISet { + source.CheckNull( nameof( source ) ); + if( source is ISqlPartAccessor accessor ) + accessor.SqlBuilderSet.Intersect( builders ); + return source; + } + + /// + /// 交集 + /// + /// 源 + /// Sql生成器集合 + public static T Intersect( this T source, IEnumerable builders ) where T : ISet { + source.CheckNull( nameof( source ) ); + if( source is ISqlPartAccessor accessor ) + accessor.SqlBuilderSet.Intersect( builders ); + return source; + } + + #endregion + + #region Except(差集) + + /// + /// 差集 + /// + /// 源 + /// Sql生成器集合 + public static T Except( this T source, params ISqlBuilder[] builders ) where T : ISet { + source.CheckNull( nameof( source ) ); + if( source is ISqlPartAccessor accessor ) + accessor.SqlBuilderSet.Except( builders ); + return source; + } + + /// + /// 差集 + /// + /// 源 + /// Sql生成器集合 + public static T Except( this T source, IEnumerable builders ) where T : ISet { + source.CheckNull( nameof( source ) ); + if( source is ISqlPartAccessor accessor ) + accessor.SqlBuilderSet.Except( builders ); + return source; + } + + #endregion + + #region ClearSets(清理集合) + + /// + /// 清理Union等集合操作 + /// + /// 源 + public static T ClearSets( this T source ) where T : ISet { + source.CheckNull( nameof( source ) ); + if( source is ISqlPartAccessor accessor ) + accessor.SqlBuilderSet.Clear(); + return source; + } + + #endregion + } +} diff --git a/src/Util.Data.Sql/SqlExecutorExtensions.cs b/src/Util.Data.Sql/SqlExecutorExtensions.cs new file mode 100644 index 00000000..a42f65e7 --- /dev/null +++ b/src/Util.Data.Sql/SqlExecutorExtensions.cs @@ -0,0 +1,143 @@ +using System.Data; +using Util.Data.Sql.Database; + +namespace Util.Data.Sql { + /// + /// Sql执行器操作扩展 + /// + public static class SqlExecutorExtensions { + + #region GetConnection(获取数据库连接) + + /// + /// 获取数据库连接 + /// + /// 源 + public static IDbConnection GetConnection( this ISqlExecutor source ) { + source.CheckNull( nameof( source ) ); + if ( source is IConnectionManager manager ) + return manager.GetConnection(); + return null; + } + + #endregion + + #region SetConnection(设置数据库连接) + + /// + /// 设置数据库连接 + /// + /// 源 + /// 数据库连接 + public static ISqlExecutor SetConnection( this ISqlExecutor source, IDbConnection connection ) { + source.CheckNull( nameof( source ) ); + if( source is IConnectionManager manager ) + manager.SetConnection( connection ); + return source; + } + + #endregion + + #region GetTransaction(获取数据库事务) + + /// + /// 获取数据库事务 + /// + /// 源 + public static IDbTransaction GetTransaction( this ISqlExecutor source ) { + source.CheckNull( nameof( source ) ); + if( source is ITransactionManager manager ) + return manager.GetTransaction(); + return null; + } + + #endregion + + #region SetTransaction(设置数据库事务) + + /// + /// 设置数据库事务 + /// + /// 源 + /// 数据库事务 + public static ISqlExecutor SetTransaction( this ISqlExecutor source, IDbTransaction transaction ) { + source.CheckNull( nameof( source ) ); + if( source is ITransactionManager manager ) + manager.SetTransaction( transaction ); + return source; + } + + #endregion + + #region BeginTransaction(开始事务) + + /// + /// 开始事务 + /// + /// 源 + public static IDbTransaction BeginTransaction( this ISqlExecutor source ) { + source.CheckNull( nameof( source ) ); + if( source is ITransactionManager manager ) + return manager.BeginTransaction(); + return null; + } + + /// + /// 开始事务 + /// + /// 源 + /// 事务隔离级别 + public static IDbTransaction BeginTransaction( this ISqlExecutor source, IsolationLevel isolationLevel ) { + source.CheckNull( nameof( source ) ); + if( source is ITransactionManager manager ) + return manager.BeginTransaction( isolationLevel ); + return null; + } + + #endregion + + #region CommitTransaction(提交事务) + + /// + /// 提交事务 + /// + /// 源 + public static ISqlExecutor CommitTransaction( this ISqlExecutor source ) { + source.CheckNull( nameof( source ) ); + if( source is ITransactionManager manager ) + manager.CommitTransaction(); + return source; + } + + #endregion + + #region RollbackTransaction(回滚事务) + + /// + /// 回滚事务 + /// + /// 源 + public static ISqlExecutor RollbackTransaction( this ISqlExecutor source ) { + source.CheckNull( nameof( source ) ); + if( source is ITransactionManager manager ) + manager.RollbackTransaction(); + return source; + } + + #endregion + + #region Clear(清理) + + /// + /// 清理 + /// + /// 源 + public static ISqlExecutor Clear( this ISqlExecutor source ) { + source.CheckNull( nameof( source ) ); + source.SqlBuilder.Clear(); + return source; + } + + #endregion + } +} diff --git a/src/Util.Data.Sql/SqlOptions.cs b/src/Util.Data.Sql/SqlOptions.cs new file mode 100644 index 00000000..114d15ed --- /dev/null +++ b/src/Util.Data.Sql/SqlOptions.cs @@ -0,0 +1,27 @@ +using System.Data; + +namespace Util.Data.Sql { + /// + /// Sql配置 + /// + public class SqlOptions : SqlOptions where T: class { + } + + /// + /// Sql配置 + /// + public class SqlOptions { + /// + /// 数据库连接字符串 + /// + public string ConnectionString { get; set; } + /// + /// 数据库连接 + /// + public IDbConnection Connection { get; set; } + /// + /// 日志类别 + /// + public string LogCategory { get; set; } = "Util.Data.Sql"; + } +} diff --git a/src/Util.Data.Sql/SqlOptionsExtensions.cs b/src/Util.Data.Sql/SqlOptionsExtensions.cs new file mode 100644 index 00000000..142a979d --- /dev/null +++ b/src/Util.Data.Sql/SqlOptionsExtensions.cs @@ -0,0 +1,54 @@ +using System.Data; + +namespace Util.Data.Sql { + /// + /// Sql配置扩展 + /// + public static class SqlOptionsExtensions { + + #region ConnectionString(设置数据库连接字符串) + + /// + /// 设置数据库连接字符串 + /// + /// 源 + /// 数据库连接字符串 + public static SqlOptions ConnectionString( this SqlOptions options, string connectionString ) { + options.CheckNull( nameof(options) ); + options.ConnectionString = connectionString; + return options; + } + + #endregion + + #region Connection(设置数据库连接) + + /// + /// 设置数据库连接 + /// + /// 源 + /// 数据库连接 + public static SqlOptions Connection( this SqlOptions options, IDbConnection connection ) { + options.CheckNull( nameof( options ) ); + options.Connection = connection; + return options; + } + + #endregion + + #region LogCategory(设置日志类别) + + /// + /// 设置日志类别 + /// + /// 源 + /// 日志类别 + public static SqlOptions LogCategory( this SqlOptions options, string logCategory ) { + options.CheckNull( nameof( options ) ); + options.LogCategory = logCategory; + return options; + } + + #endregion + } +} diff --git a/src/Util.Data.Sql/SqlQueryExtensions.Query.cs b/src/Util.Data.Sql/SqlQueryExtensions.Query.cs new file mode 100644 index 00000000..dea85ec6 --- /dev/null +++ b/src/Util.Data.Sql/SqlQueryExtensions.Query.cs @@ -0,0 +1,303 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace Util.Data.Sql { + /// + /// Sql查询对象操作扩展 - 查询扩展 + /// + public static partial class SqlQueryExtensions { + + #region ToEntity(获取单个实体) + + /// + /// 获取单个实体 + /// + /// 实体类型 + /// 源 + /// 执行超时时间,单位:秒 + public static TEntity ToEntity( this ISqlQuery source, int? timeout = null ) { + source.CheckNull( nameof( source ) ); + return source.ExecuteSingle( timeout ); + } + + #endregion + + #region ToEntityAsync(获取单个实体) + + /// + /// 获取单个实体 + /// + /// 实体类型 + /// 源 + /// 执行超时时间,单位:秒 + public static async Task ToEntityAsync( this ISqlQuery source, int? timeout = null ) { + source.CheckNull( nameof( source ) ); + return await source.ExecuteSingleAsync( timeout ); + } + + #endregion + + #region ToList(获取实体集合) + + /// + /// 获取实体集合 + /// + /// 源 + /// 执行超时时间,单位:秒 + /// 是否缓存,默认值: true + public static List ToList( this ISqlQuery source, int? timeout = null, bool buffered = true ) { + source.CheckNull( nameof( source ) ); + return source.ExecuteQuery( timeout, buffered ); + } + + /// + /// 获取实体集合 + /// + /// 实体类型 + /// 源 + /// 执行超时时间,单位:秒 + /// 是否缓存,默认值: true + public static List ToList( this ISqlQuery source, int? timeout = null, bool buffered = true ) { + source.CheckNull( nameof( source ) ); + return source.ExecuteQuery( timeout, buffered ); + } + + /// + /// 获取实体集合 + /// + /// 实体类型1 + /// 实体类型2 + /// 返回的实体类型 + /// 源 + /// 映射函数 + /// 执行超时时间,单位:秒 + /// 是否缓存,默认值: true + public static List ToList( this ISqlQuery source, Func map, int? timeout = null, bool buffered = true ) { + source.CheckNull( nameof( source ) ); + return source.ExecuteQuery( map, timeout, buffered ); + } + + /// + /// 获取实体集合 + /// + /// 实体类型1 + /// 实体类型2 + /// 实体类型3 + /// 返回的实体类型 + /// 源 + /// 映射函数 + /// 执行超时时间,单位:秒 + /// 是否缓存,默认值: true + public static List ToList( this ISqlQuery source, Func map, int? timeout = null, bool buffered = true ) { + source.CheckNull( nameof( source ) ); + return source.ExecuteQuery( map, timeout, buffered ); + } + + /// + /// 获取实体集合 + /// + /// 实体类型1 + /// 实体类型2 + /// 实体类型3 + /// 实体类型4 + /// 返回的实体类型 + /// 源 + /// 映射函数 + /// 执行超时时间,单位:秒 + /// 是否缓存,默认值: true + public static List ToList( this ISqlQuery source, Func map, int? timeout = null, bool buffered = true ) { + source.CheckNull( nameof( source ) ); + return source.ExecuteQuery( map, timeout, buffered ); + } + + /// + /// 获取实体集合 + /// + /// 实体类型1 + /// 实体类型2 + /// 实体类型3 + /// 实体类型4 + /// 实体类型5 + /// 返回的实体类型 + /// 源 + /// 映射函数 + /// 执行超时时间,单位:秒 + /// 是否缓存,默认值: true + public static List ToList( this ISqlQuery source, Func map, int? timeout = null, bool buffered = true ) { + source.CheckNull( nameof( source ) ); + return source.ExecuteQuery( map, timeout, buffered ); + } + + /// + /// 获取实体集合 + /// + /// 实体类型1 + /// 实体类型2 + /// 实体类型3 + /// 实体类型4 + /// 实体类型5 + /// 实体类型6 + /// 返回的实体类型 + /// 源 + /// 映射函数 + /// 执行超时时间,单位:秒 + /// 是否缓存,默认值: true + public static List ToList( this ISqlQuery source, Func map, int? timeout = null, bool buffered = true ) { + source.CheckNull( nameof( source ) ); + return source.ExecuteQuery( map, timeout, buffered ); + } + + /// + /// 获取实体集合 + /// + /// 实体类型1 + /// 实体类型2 + /// 实体类型3 + /// 实体类型4 + /// 实体类型5 + /// 实体类型6 + /// 实体类型7 + /// 返回的实体类型 + /// 源 + /// 映射函数 + /// 执行超时时间,单位:秒 + /// 是否缓存,默认值: true + public static List ToList( this ISqlQuery source, Func map, int? timeout = null, bool buffered = true ) { + source.CheckNull( nameof( source ) ); + return source.ExecuteQuery( map, timeout, buffered ); + } + + #endregion + + #region ToListAsync(获取实体集合) + + /// + /// 获取实体集合 + /// + /// 源 + /// 执行超时时间,单位:秒 + public static async Task> ToListAsync( this ISqlQuery source, int? timeout = null ) { + source.CheckNull( nameof( source ) ); + return await source.ExecuteQueryAsync( timeout ); + } + + /// + /// 获取实体集合 + /// + /// 实体类型 + /// 源 + /// 执行超时时间,单位:秒 + public static async Task> ToListAsync( this ISqlQuery source, int? timeout = null ) { + source.CheckNull( nameof( source ) ); + return await source.ExecuteQueryAsync( timeout ); + } + + /// + /// 获取实体集合 + /// + /// 实体类型1 + /// 实体类型2 + /// 返回的实体类型 + /// 源 + /// 映射函数 + /// 执行超时时间,单位:秒 + /// 是否缓存,默认值: true + public static async Task> ToListAsync( this ISqlQuery source, Func map, int? timeout = null, bool buffered = true ) { + source.CheckNull( nameof( source ) ); + return await source.ExecuteQueryAsync( map, timeout, buffered ); + } + + /// + /// 获取实体集合 + /// + /// 实体类型1 + /// 实体类型2 + /// 实体类型3 + /// 返回的实体类型 + /// 源 + /// 映射函数 + /// 执行超时时间,单位:秒 + /// 是否缓存,默认值: true + public static async Task> ToListAsync( this ISqlQuery source, Func map, int? timeout = null, bool buffered = true ) { + source.CheckNull( nameof( source ) ); + return await source.ExecuteQueryAsync( map, timeout, buffered ); + } + + /// + /// 获取实体集合 + /// + /// 实体类型1 + /// 实体类型2 + /// 实体类型3 + /// 实体类型4 + /// 返回的实体类型 + /// 源 + /// 映射函数 + /// 执行超时时间,单位:秒 + /// 是否缓存,默认值: true + public static async Task> ToListAsync( this ISqlQuery source, Func map, int? timeout = null, bool buffered = true ) { + source.CheckNull( nameof( source ) ); + return await source.ExecuteQueryAsync( map, timeout, buffered ); + } + + /// + /// 获取实体集合 + /// + /// 实体类型1 + /// 实体类型2 + /// 实体类型3 + /// 实体类型4 + /// 实体类型5 + /// 返回的实体类型 + /// 源 + /// 映射函数 + /// 执行超时时间,单位:秒 + /// 是否缓存,默认值: true + public static async Task> ToListAsync( this ISqlQuery source, Func map, int? timeout = null, bool buffered = true ) { + source.CheckNull( nameof( source ) ); + return await source.ExecuteQueryAsync( map, timeout, buffered ); + } + + /// + /// 获取实体集合 + /// + /// 实体类型1 + /// 实体类型2 + /// 实体类型3 + /// 实体类型4 + /// 实体类型5 + /// 实体类型6 + /// 返回的实体类型 + /// 源 + /// 映射函数 + /// 执行超时时间,单位:秒 + /// 是否缓存,默认值: true + public static async Task> ToListAsync( this ISqlQuery source, Func map, int? timeout = null, bool buffered = true ) { + source.CheckNull( nameof( source ) ); + return await source.ExecuteQueryAsync( map, timeout, buffered ); + } + + /// + /// 获取实体集合 + /// + /// 实体类型1 + /// 实体类型2 + /// 实体类型3 + /// 实体类型4 + /// 实体类型5 + /// 实体类型6 + /// 实体类型7 + /// 返回的实体类型 + /// 源 + /// 映射函数 + /// 执行超时时间,单位:秒 + /// 是否缓存,默认值: true + public static async Task> ToListAsync( this ISqlQuery source, Func map, int? timeout = null, bool buffered = true ) { + source.CheckNull( nameof( source ) ); + return await source.ExecuteQueryAsync( map, timeout, buffered ); + } + + #endregion + } +} diff --git a/src/Util.Data.Sql/SqlQueryExtensions.Scalar.cs b/src/Util.Data.Sql/SqlQueryExtensions.Scalar.cs new file mode 100644 index 00000000..52a358e6 --- /dev/null +++ b/src/Util.Data.Sql/SqlQueryExtensions.Scalar.cs @@ -0,0 +1,457 @@ +using System; +using System.Threading.Tasks; +using Convert = Util.Helpers.Convert; + +namespace Util.Data.Sql { + /// + /// Sql查询对象操作扩展 - 获取单值扩展 + /// + public static partial class SqlQueryExtensions { + + #region ToStringAsync(获取字符串值) + + /// + /// 获取字符串值 + /// + /// 源 + public static async Task ToStringAsync( this ISqlQuery source ) { + source.CheckNull( nameof( source ) ); + var result = await source.ExecuteScalarAsync(); + return result.SafeString(); + } + + #endregion + + #region ToInt(获取整型值) + + /// + /// 获取32位整型值 + /// + /// 源 + public static int ToInt( this ISqlQuery source ) { + source.CheckNull( nameof( source ) ); + return Convert.ToInt( source.ExecuteScalar() ); + } + + #endregion + + #region ToIntAsync(获取整型值) + + /// + /// 获取32位整型值 + /// + /// 源 + public static async Task ToIntAsync( this ISqlQuery source ) { + source.CheckNull( nameof( source ) ); + var result = await source.ExecuteScalarAsync(); + return Convert.ToInt( result ); + } + + #endregion + + #region ToIntOrNull(获取可空整型值) + + /// + /// 获取32位可空整型值 + /// + /// 源 + public static int? ToIntOrNull( this ISqlQuery source ) { + source.CheckNull( nameof( source ) ); + return Convert.ToIntOrNull( source.ExecuteScalar() ); + } + + #endregion + + #region ToIntOrNullAsync(获取可空整型值) + + /// + /// 获取32位可空整型值 + /// + /// 源 + public static async Task ToIntOrNullAsync( this ISqlQuery source ) { + source.CheckNull( nameof( source ) ); + var result = await source.ExecuteScalarAsync(); + return Convert.ToIntOrNull( result ); + } + + #endregion + + #region ToLong(获取整型值) + + /// + /// 获取64位整型值 + /// + /// 源 + public static long ToLong( this ISqlQuery source ) { + source.CheckNull( nameof( source ) ); + return Convert.ToLong( source.ExecuteScalar() ); + } + + #endregion + + #region ToLongAsync(获取整型值) + + /// + /// 获取64位整型值 + /// + /// 源 + public static async Task ToLongAsync( this ISqlQuery source ) { + source.CheckNull( nameof( source ) ); + var result = await source.ExecuteScalarAsync(); + return Convert.ToLong( result ); + } + + #endregion + + #region ToLongOrNull(获取可空整型值) + + /// + /// 获取64位可空整型值 + /// + /// 源 + public static long? ToLongOrNull( this ISqlQuery source ) { + source.CheckNull( nameof( source ) ); + return Convert.ToLongOrNull( source.ExecuteScalar() ); + } + + #endregion + + #region ToLongOrNullAsync(获取可空整型值) + + /// + /// 获取64位可空整型值 + /// + /// 源 + public static async Task ToLongOrNullAsync( this ISqlQuery source ) { + source.CheckNull( nameof( source ) ); + var result = await source.ExecuteScalarAsync(); + return Convert.ToLongOrNull( result ); + } + + #endregion + + #region ToGuid(获取Guid值) + + /// + /// 获取Guid值 + /// + /// 源 + public static Guid ToGuid( this ISqlQuery source ) { + source.CheckNull( nameof( source ) ); + return Convert.ToGuid( source.ExecuteScalar() ); + } + + #endregion + + #region ToGuidAsync(获取Guid值) + + /// + /// 获取Guid值 + /// + /// 源 + public static async Task ToGuidAsync( this ISqlQuery source ) { + source.CheckNull( nameof( source ) ); + var result = await source.ExecuteScalarAsync(); + return Convert.ToGuid( result ); + } + + #endregion + + #region ToGuidOrNull(获取可空Guid值) + + /// + /// 获取可空Guid值 + /// + /// 源 + public static Guid? ToGuidOrNull( this ISqlQuery source ) { + source.CheckNull( nameof( source ) ); + return Convert.ToGuidOrNull( source.ExecuteScalar() ); + } + + #endregion + + #region ToGuidOrNullAsync(获取可空Guid值) + + /// + /// 获取可空Guid值 + /// + /// 源 + public static async Task ToGuidOrNullAsync( this ISqlQuery source ) { + source.CheckNull( nameof( source ) ); + var result = await source.ExecuteScalarAsync(); + return Convert.ToGuidOrNull( result ); + } + + #endregion + + #region ToBool(获取布尔值) + + /// + /// 获取布尔值 + /// + /// 源 + public static bool ToBool( this ISqlQuery source ) { + source.CheckNull( nameof( source ) ); + return Convert.ToBool( source.ExecuteScalar() ); + } + + #endregion + + #region ToBoolAsync(获取布尔值) + + /// + /// 获取布尔值 + /// + /// 源 + public static async Task ToBoolAsync( this ISqlQuery source ) { + source.CheckNull( nameof( source ) ); + var result = await source.ExecuteScalarAsync(); + return Convert.ToBool( result ); + } + + #endregion + + #region ToBoolOrNull(获取可空布尔值) + + /// + /// 获取可空布尔值 + /// + /// 源 + public static bool? ToBoolOrNull( this ISqlQuery source ) { + source.CheckNull( nameof( source ) ); + return Convert.ToBoolOrNull( source.ExecuteScalar() ); + } + + #endregion + + #region ToBoolOrNullAsync(获取可空布尔值) + + /// + /// 获取可空布尔值 + /// + /// 源 + public static async Task ToBoolOrNullAsync( this ISqlQuery source ) { + source.CheckNull( nameof( source ) ); + var result = await source.ExecuteScalarAsync(); + return Convert.ToBoolOrNull( result ); + } + + #endregion + + #region ToFloat(获取浮点值) + + /// + /// 获取32位浮点值 + /// + /// 源 + public static float ToFloat( this ISqlQuery source ) { + source.CheckNull( nameof( source ) ); + return Convert.ToFloat( source.ExecuteScalar() ); + } + + #endregion + + #region ToFloatAsync(获取浮点值) + + /// + /// 获取32位浮点值 + /// + /// 源 + public static async Task ToFloatAsync( this ISqlQuery source ) { + source.CheckNull( nameof( source ) ); + var result = await source.ExecuteScalarAsync(); + return Convert.ToFloat( result ); + } + + #endregion + + #region ToFloatOrNull(获取可空浮点值) + + /// + /// 获取32位可空浮点值 + /// + /// 源 + public static float? ToFloatOrNull( this ISqlQuery source ) { + source.CheckNull( nameof( source ) ); + return Convert.ToFloatOrNull( source.ExecuteScalar() ); + } + + #endregion + + #region ToFloatOrNullAsync(获取可空浮点值) + + /// + /// 获取32位可空浮点值 + /// + /// 源 + public static async Task ToFloatOrNullAsync( this ISqlQuery source ) { + source.CheckNull( nameof( source ) ); + var result = await source.ExecuteScalarAsync(); + return Convert.ToFloatOrNull( result ); + } + + #endregion + + #region ToDouble(获取浮点值) + + /// + /// 获取64位浮点值 + /// + /// 源 + public static double ToDouble( this ISqlQuery source ) { + source.CheckNull( nameof( source ) ); + return Convert.ToDouble( source.ExecuteScalar() ); + } + + #endregion + + #region ToDoubleAsync(获取浮点值) + + /// + /// 获取64位浮点值 + /// + /// 源 + public static async Task ToDoubleAsync( this ISqlQuery source ) { + source.CheckNull( nameof( source ) ); + var result = await source.ExecuteScalarAsync(); + return Convert.ToDouble( result ); + } + + #endregion + + #region ToDoubleOrNull(获取可空浮点值) + + /// + /// 获取64位可空浮点值 + /// + /// 源 + public static double? ToDoubleOrNull( this ISqlQuery source ) { + source.CheckNull( nameof( source ) ); + return Convert.ToDoubleOrNull( source.ExecuteScalar() ); + } + + #endregion + + #region ToDoubleOrNullAsync(获取可空浮点值) + + /// + /// 获取64位可空浮点值 + /// + /// 源 + public static async Task ToDoubleOrNullAsync( this ISqlQuery source ) { + source.CheckNull( nameof( source ) ); + var result = await source.ExecuteScalarAsync(); + return Convert.ToDoubleOrNull( result ); + } + + #endregion + + #region ToDecimal(获取浮点值) + + /// + /// 获取128位浮点值 + /// + /// 源 + public static decimal ToDecimal( this ISqlQuery source ) { + source.CheckNull( nameof( source ) ); + return Convert.ToDecimal( source.ExecuteScalar() ); + } + + #endregion + + #region ToDecimalAsync(获取浮点值) + + /// + /// 获取128位浮点值 + /// + /// 源 + public static async Task ToDecimalAsync( this ISqlQuery source ) { + source.CheckNull( nameof( source ) ); + var result = await source.ExecuteScalarAsync(); + return Convert.ToDecimal( result ); + } + + #endregion + + #region ToDecimalOrNull(获取可空浮点值) + + /// + /// 获取128位可空浮点值 + /// + /// 源 + public static decimal? ToDecimalOrNull( this ISqlQuery source ) { + source.CheckNull( nameof( source ) ); + return Convert.ToDecimalOrNull( source.ExecuteScalar() ); + } + + #endregion + + #region ToDecimalOrNullAsync(获取可空浮点值) + + /// + /// 获取128位可空浮点值 + /// + /// 源 + public static async Task ToDecimalOrNullAsync( this ISqlQuery source ) { + source.CheckNull( nameof( source ) ); + var result = await source.ExecuteScalarAsync(); + return Convert.ToDecimalOrNull( result ); + } + + #endregion + + #region ToDateTime(获取日期值) + + /// + /// 获取日期值 + /// + /// 源 + public static DateTime ToDateTime( this ISqlQuery source ) { + source.CheckNull( nameof( source ) ); + return Convert.ToDateTime( source.ExecuteScalar() ); + } + + #endregion + + #region ToDateTimeAsync(获取日期值) + + /// + /// 获取日期值 + /// + /// 源 + public static async Task ToDateTimeAsync( this ISqlQuery source ) { + source.CheckNull( nameof( source ) ); + var result = await source.ExecuteScalarAsync(); + return Convert.ToDateTime( result ); + } + + #endregion + + #region ToDateTimeOrNull(获取可空日期值) + + /// + /// 获取可空日期值 + /// + /// 源 + public static DateTime? ToDateTimeOrNull( this ISqlQuery source ) { + source.CheckNull( nameof( source ) ); + return Convert.ToDateTimeOrNull( source.ExecuteScalar() ); + } + + #endregion + + #region ToDateTimeOrNullAsync(获取可空日期值) + + /// + /// 获取可空日期值 + /// + /// 源 + public static async Task ToDateTimeOrNullAsync( this ISqlQuery source ) { + source.CheckNull( nameof( source ) ); + var result = await source.ExecuteScalarAsync(); + return Convert.ToDateTimeOrNull( result ); + } + + #endregion + } +} diff --git a/src/Util.Data.Sql/SqlQueryExtensions.cs b/src/Util.Data.Sql/SqlQueryExtensions.cs new file mode 100644 index 00000000..83c807a4 --- /dev/null +++ b/src/Util.Data.Sql/SqlQueryExtensions.cs @@ -0,0 +1,68 @@ +using System.Data; +using Util.Data.Sql.Database; + +namespace Util.Data.Sql { + /// + /// Sql查询对象操作扩展 + /// + public static partial class SqlQueryExtensions { + + #region GetConnection(获取数据库连接) + + /// + /// 获取数据库连接 + /// + /// 源 + public static IDbConnection GetConnection( this ISqlQuery source ) { + source.CheckNull( nameof( source ) ); + if ( source is IConnectionManager manager ) + return manager.GetConnection(); + return null; + } + + #endregion + + #region SetConnection(设置数据库连接) + + /// + /// 设置数据库连接 + /// + /// 源 + /// 数据库连接 + public static ISqlQuery SetConnection( this ISqlQuery source, IDbConnection connection ) { + source.CheckNull( nameof( source ) ); + if( source is IConnectionManager manager ) + manager.SetConnection( connection ); + return source; + } + + #endregion + + #region Clear(清理) + + /// + /// 清理 + /// + /// 源 + public static ISqlQuery Clear( this ISqlQuery source ) { + source.CheckNull( nameof( source ) ); + source.SqlBuilder.Clear(); + return source; + } + + #endregion + + #region NewSqlBuilder(创建一个新的Sql生成器) + + /// + /// 创建一个新的Sql生成器 + /// + /// 源 + public static ISqlBuilder NewSqlBuilder( this ISqlQuery source ) { + source.CheckNull( nameof( source ) ); + return source.SqlBuilder.New(); + } + + #endregion + } +} diff --git a/src/Util.Data.Sql/StartClauseExtensions.cs b/src/Util.Data.Sql/StartClauseExtensions.cs new file mode 100644 index 00000000..9a2f603f --- /dev/null +++ b/src/Util.Data.Sql/StartClauseExtensions.cs @@ -0,0 +1,105 @@ +using Util.Data.Sql.Builders; +using Util.Data.Sql.Builders.Operations; + +namespace Util.Data.Sql { + /// + /// 起始子句操作扩展 + /// + public static class StartClauseExtensions { + + #region Cte(设置公用表表达式CTE) + + /// + /// 设置公用表表达式CTE + /// + /// 源 + /// 公用表表达式名称 + /// Sql生成器 + public static T Cte( this T source, string name, ISqlBuilder builder ) where T : IStart { + source.CheckNull( nameof( source ) ); + if( source is ISqlPartAccessor accessor ) + accessor.StartClause.Cte( name, builder ); + return source; + } + + #endregion + + #region Append(添加到Sql起始位置) + + /// + /// 添加到Sql起始位置,与AppendStart功能相同 + /// + /// 源 + /// Sql语句 + /// 是否原样添加,默认会将[]替换为特定Sql转义符 + public static T Append( this T source, string sql, bool raw = false ) where T : IStart { + source.CheckNull( nameof( source ) ); + if( source is ISqlPartAccessor accessor ) + accessor.StartClause.Append( sql, raw ); + return source; + } + + #endregion + + #region AppendLine(添加到Sql起始位置并换行) + + /// + /// 添加到Sql起始位置并换行 + /// + /// 源 + /// Sql语句 + /// 是否原样添加,默认会将[]替换为特定Sql转义符 + public static T AppendLine( this T source, string sql, bool raw = false ) where T : IStart { + source.CheckNull( nameof( source ) ); + if( source is ISqlPartAccessor accessor ) + accessor.StartClause.AppendLine( sql, raw ); + return source; + } + + #endregion + + #region AppendStart(添加到Sql起始位置) + + /// + /// 添加到Sql起始位置 + /// + /// 源 + /// Sql语句 + /// 是否原样添加,默认会将[]替换为特定Sql转义符 + public static T AppendStart( this T source, string sql, bool raw = false ) where T : IStart { + return source.Append( sql, raw ); + } + + #endregion + + #region ClearCte(清理公用表表达式CTE) + + /// + /// 清理公用表表达式CTE + /// + /// 源 + public static T ClearCte( this T source ) where T : IStart { + source.CheckNull( nameof( source ) ); + if( source is ISqlPartAccessor accessor ) + accessor.StartClause.ClearCte(); + return source; + } + + #endregion + + #region ClearStart(清理起始子句) + + /// + /// 清理Sql起始子句 + /// + /// 源 + public static T ClearStart( this T source ) where T : IStart { + source.CheckNull( nameof( source ) ); + if( source is ISqlPartAccessor accessor ) + accessor.StartClause.Clear(); + return source; + } + + #endregion + } +} diff --git a/src/Util.Data.Sql/WhereClauseExtensions.cs b/src/Util.Data.Sql/WhereClauseExtensions.cs new file mode 100644 index 00000000..d0ec8750 --- /dev/null +++ b/src/Util.Data.Sql/WhereClauseExtensions.cs @@ -0,0 +1,374 @@ +using System; +using System.Collections; +using Util.Data.Queries; +using Util.Data.Sql.Builders; +using Util.Data.Sql.Builders.Operations; + +namespace Util.Data.Sql { + /// + /// Where子句操作扩展 + /// + public static class WhereClauseExtensions { + + #region Where + + /// + /// 设置查询条件 + /// + /// 源 + /// 查询条件 + public static T Where( this T source, ISqlCondition condition ) where T : IWhere { + source.CheckNull( nameof( source ) ); + if ( source is ISqlPartAccessor accessor ) + accessor.WhereClause.And( condition ); + return source; + } + + /// + /// 设置查询条件 + /// + /// 源 + /// 列名 + /// 值 + /// 运算符 + public static T Where( this T source, string column, object value, Operator @operator = Operator.Equal ) where T : IWhere { + source.CheckNull( nameof( source ) ); + if( source is ISqlPartAccessor accessor ) + accessor.WhereClause.Where( column, value, @operator ); + return source; + } + + /// + /// 设置查询条件 + /// + /// 源 + /// 列名 + /// 子查询Sql生成器 + /// 运算符 + public static T Where( this T source, string column, ISqlBuilder builder, Operator @operator = Operator.Equal ) where T : IWhere { + source.CheckNull( nameof( source ) ); + if( source is ISqlPartAccessor accessor ) + accessor.WhereClause.Where( column, builder, @operator ); + return source; + } + + /// + /// 设置查询条件 + /// + /// 源 + /// 列名 + /// 子查询操作 + /// 运算符 + public static T Where( this T source, string column, Action action, Operator @operator = Operator.Equal ) where T : IWhere { + source.CheckNull( nameof( source ) ); + if( source is ISqlPartAccessor accessor ) + accessor.WhereClause.Where( column, action, @operator ); + return source; + } + + #endregion + + #region In + + /// + /// 设置In查询条件 + /// + /// 源 + /// 列名 + /// 值集合 + public static T In( this T source, string column, IEnumerable values ) where T : IWhere { + source.CheckNull( nameof( source ) ); + if( source is ISqlPartAccessor accessor ) + accessor.WhereClause.Where( column, values,Operator.In ); + return source; + } + + /// + /// 设置In子查询条件 + /// + /// 源 + /// 列名 + /// 子查询Sql生成器 + public static T In( this T source, string column, ISqlBuilder builder ) where T : IWhere { + source.CheckNull( nameof( source ) ); + if( source is ISqlPartAccessor accessor ) + accessor.WhereClause.Where( column, builder, Operator.In ); + return source; + } + + /// + /// 设置In子查询条件 + /// + /// 源 + /// 列名 + /// 子查询操作 + public static T In( this T source, string column, Action action ) where T : IWhere { + source.CheckNull( nameof( source ) ); + if( source is ISqlPartAccessor accessor ) + accessor.WhereClause.Where( column, action, Operator.In ); + return source; + } + + #endregion + + #region NotIn + + /// + /// 设置Not In查询条件 + /// + /// 源 + /// 列名 + /// 值集合 + public static T NotIn( this T source, string column, IEnumerable values ) where T : IWhere { + source.CheckNull( nameof( source ) ); + if( source is ISqlPartAccessor accessor ) + accessor.WhereClause.Where( column, values, Operator.NotIn ); + return source; + } + + /// + /// 设置Not In子查询条件 + /// + /// 源 + /// 列名 + /// 子查询Sql生成器 + public static T NotIn( this T source, string column, ISqlBuilder builder ) where T : IWhere { + source.CheckNull( nameof( source ) ); + if( source is ISqlPartAccessor accessor ) + accessor.WhereClause.Where( column, builder, Operator.NotIn ); + return source; + } + + /// + /// 设置Not In子查询条件 + /// + /// 源 + /// 列名 + /// 子查询操作 + public static T NotIn( this T source, string column, Action action ) where T : IWhere { + source.CheckNull( nameof( source ) ); + if( source is ISqlPartAccessor accessor ) + accessor.WhereClause.Where( column, action, Operator.NotIn ); + return source; + } + + #endregion + + #region IsNull + + /// + /// 设置Is Null查询条件 + /// + /// 源 + /// 列名 + public static T IsNull( this T source, string column ) where T : IWhere { + source.CheckNull( nameof( source ) ); + if ( source is ISqlPartAccessor accessor ) + accessor.WhereClause.IsNull( column ); + return source; + } + + #endregion + + #region IsNotNull + + /// + /// 设置Is Not Null查询条件 + /// + /// 源 + /// 列名 + public static T IsNotNull( this T source, string column ) where T : IWhere { + source.CheckNull( nameof( source ) ); + if ( source is ISqlPartAccessor accessor ) + accessor.WhereClause.IsNotNull( column ); + return source; + } + + #endregion + + #region IsEmpty + + /// + /// 设置空条件,范例:[Name] Is Null Or [Name]='' + /// + /// 源 + /// 列名 + public static T IsEmpty( this T source, string column ) where T : IWhere { + source.CheckNull( nameof( source ) ); + if ( source is ISqlPartAccessor accessor ) + accessor.WhereClause.IsEmpty( column ); + return source; + } + + #endregion + + #region IsNotEmpty + + /// + /// 设置非空条件,范例:[Name] Is Not Null And [Name]<>'' + /// + /// 源 + /// 列名 + public static T IsNotEmpty( this T source, string column ) where T : IWhere { + source.CheckNull( nameof( source ) ); + if ( source is ISqlPartAccessor accessor ) + accessor.WhereClause.IsNotEmpty( column ); + return source; + } + + #endregion + + #region Between + + /// + /// 添加范围查询条件 + /// + /// 源 + /// 列名 + /// 最小值 + /// 最大值 + /// 包含边界 + public static T Between( this T source, string column, int? min, int? max, Boundary boundary = Boundary.Both ) where T : IWhere { + source.CheckNull( nameof( source ) ); + if ( source is ISqlPartAccessor accessor ) + accessor.WhereClause.Between( column, min, max, boundary ); + return source; + } + + /// + /// 添加范围查询条件 + /// + /// 源 + /// 列名 + /// 最小值 + /// 最大值 + /// 包含边界 + public static T Between( this T source, string column, double? min, double? max, Boundary boundary = Boundary.Both ) where T : IWhere { + source.CheckNull( nameof( source ) ); + if ( source is ISqlPartAccessor accessor ) + accessor.WhereClause.Between( column, min, max, boundary ); + return source; + } + + /// + /// 添加范围查询条件 + /// + /// 源 + /// 列名 + /// 最小值 + /// 最大值 + /// 包含边界 + public static T Between( this T source, string column, decimal? min, decimal? max, Boundary boundary = Boundary.Both ) where T : IWhere { + source.CheckNull( nameof( source ) ); + if ( source is ISqlPartAccessor accessor ) + accessor.WhereClause.Between( column, min, max, boundary ); + return source; + } + + /// + /// 添加范围查询条件 + /// + /// 源 + /// 列名 + /// 最小值 + /// 最大值 + /// 是否包含时间 + /// 包含边界 + public static T Between( this T source, string column, DateTime? min, DateTime? max, bool includeTime = true, Boundary? boundary = null ) where T : IWhere { + source.CheckNull( nameof( source ) ); + if ( source is ISqlPartAccessor accessor ) + accessor.WhereClause.Between( column, min, max, includeTime, boundary ); + return source; + } + + #endregion + + #region Exists + + /// + /// 设置Exists查询条件 + /// + /// 源 + /// 子查询Sql生成器 + public static T Exists( this T source, ISqlBuilder builder ) where T : IWhere { + source.CheckNull( nameof( source ) ); + if ( source is ISqlPartAccessor accessor ) + accessor.WhereClause.Exists( builder ); + return source; + } + + /// + /// 设置Exists查询条件 + /// + /// 源 + /// 子查询操作 + public static T Exists( this T source, Action action ) where T : IWhere { + source.CheckNull( nameof( source ) ); + if ( source is ISqlPartAccessor accessor ) + accessor.WhereClause.Exists( action ); + return source; + } + + #endregion + + #region NotExists + + /// + /// 设置Not Exists查询条件 + /// + /// 源 + /// 子查询Sql生成器 + public static T NotExists( this T source, ISqlBuilder builder ) where T : IWhere { + source.CheckNull( nameof( source ) ); + if ( source is ISqlPartAccessor accessor ) + accessor.WhereClause.NotExists( builder ); + return source; + } + + /// + /// 设置Not Exists查询条件 + /// + /// 源 + /// 子查询操作 + public static T NotExists( this T source, Action action ) where T : IWhere { + source.CheckNull( nameof( source ) ); + if ( source is ISqlPartAccessor accessor ) + accessor.WhereClause.NotExists( action ); + return source; + } + + #endregion + + #region AppendWhere + + /// + /// 添加到Where子句 + /// + /// 源 + /// Sql语句 + /// 是否原样添加,默认会将[]替换为特定Sql转义符 + public static T AppendWhere( this T source, string sql, bool raw = false ) where T : IWhere { + source.CheckNull( nameof( source ) ); + if( source is ISqlPartAccessor accessor ) + accessor.WhereClause.AppendSql( sql, raw ); + return source; + } + + #endregion + + #region ClearWhere + + /// + /// 清空Where子句 + /// + /// 源 + public static T ClearWhere( this T source ) where T : IWhere { + source.CheckNull( nameof( source ) ); + if( source is ISqlPartAccessor accessor ) + accessor.WhereClause.Clear(); + return source; + } + + #endregion + } +} diff --git a/src/Util.Domain/Auditing/CreationAuditedSetter.cs b/src/Util.Domain/Auditing/CreationAuditedSetter.cs index 4ce1d2d3..9b9e9863 100644 --- a/src/Util.Domain/Auditing/CreationAuditedSetter.cs +++ b/src/Util.Domain/Auditing/CreationAuditedSetter.cs @@ -41,37 +41,37 @@ namespace Util.Domain.Auditing { if ( _entity == null ) return; if( _entity is ICreationAudited entity ) { - entity.CreationTime = Time.GetDateTime(); + entity.CreationTime = Time.Now; entity.CreatorId = _userId.ToGuid(); return; } if( _entity is ICreationAudited entity2 ) { - entity2.CreationTime = Time.GetDateTime(); + entity2.CreationTime = Time.Now; entity2.CreatorId = _userId.ToGuidOrNull(); return; } if( _entity is ICreationAudited entity3 ) { - entity3.CreationTime = Time.GetDateTime(); + entity3.CreationTime = Time.Now; entity3.CreatorId = _userId.ToInt(); return; } if( _entity is ICreationAudited entity4 ) { - entity4.CreationTime = Time.GetDateTime(); + entity4.CreationTime = Time.Now; entity4.CreatorId = _userId.ToIntOrNull(); return; } if( _entity is ICreationAudited entity5 ) { - entity5.CreationTime = Time.GetDateTime(); + entity5.CreationTime = Time.Now; entity5.CreatorId = _userId.SafeString(); return; } if( _entity is ICreationAudited entity6 ) { - entity6.CreationTime = Time.GetDateTime(); + entity6.CreationTime = Time.Now; entity6.CreatorId = _userId.ToLong(); return; } if( _entity is ICreationAudited entity7 ) { - entity7.CreationTime = Time.GetDateTime(); + entity7.CreationTime = Time.Now; entity7.CreatorId = _userId.ToLongOrNull(); return; } diff --git a/src/Util.Domain/Auditing/ModificationAuditedSetter.cs b/src/Util.Domain/Auditing/ModificationAuditedSetter.cs index 7d7721b9..336af7ec 100644 --- a/src/Util.Domain/Auditing/ModificationAuditedSetter.cs +++ b/src/Util.Domain/Auditing/ModificationAuditedSetter.cs @@ -41,37 +41,37 @@ namespace Util.Domain.Auditing { if ( _entity == null ) return; if( _entity is IModificationAudited entity ) { - entity.LastModificationTime = Time.GetDateTime(); + entity.LastModificationTime = Time.Now; entity.LastModifierId = _userId.ToGuid(); return; } if ( _entity is IModificationAudited entity2 ) { - entity2.LastModificationTime = Time.GetDateTime(); + entity2.LastModificationTime = Time.Now; entity2.LastModifierId = _userId.ToGuidOrNull(); return; } if ( _entity is IModificationAudited entity3 ) { - entity3.LastModificationTime = Time.GetDateTime(); + entity3.LastModificationTime = Time.Now; entity3.LastModifierId = _userId.ToInt(); return; } if ( _entity is IModificationAudited entity4 ) { - entity4.LastModificationTime = Time.GetDateTime(); + entity4.LastModificationTime = Time.Now; entity4.LastModifierId = _userId.ToIntOrNull(); return; } if ( _entity is IModificationAudited entity5 ) { - entity5.LastModificationTime = Time.GetDateTime(); + entity5.LastModificationTime = Time.Now; entity5.LastModifierId = _userId.SafeString(); return; } if ( _entity is IModificationAudited entity6 ) { - entity6.LastModificationTime = Time.GetDateTime(); + entity6.LastModificationTime = Time.Now; entity6.LastModifierId = _userId.ToLong(); return; } if ( _entity is IModificationAudited entity7 ) { - entity7.LastModificationTime = Time.GetDateTime(); + entity7.LastModificationTime = Time.Now; entity7.LastModifierId = _userId.ToLongOrNull(); return; } diff --git a/src/Util.Domain/Entities/EntityBase.cs b/src/Util.Domain/Entities/EntityBase.cs index f11e9262..63796d6b 100644 --- a/src/Util.Domain/Entities/EntityBase.cs +++ b/src/Util.Domain/Entities/EntityBase.cs @@ -118,7 +118,7 @@ namespace Util.Domain.Entities { if( typeof( TKey ) == typeof( int ) || typeof( TKey ) == typeof( long ) ) return; if( string.IsNullOrWhiteSpace( Id.SafeString() ) || Id.Equals( default( TKey ) ) ) - results.Add( new ValidationResult( UtilCoreResource.IdIsEmpty ) ); + results.Add( new ValidationResult( R.IdIsEmpty ) ); } } } diff --git a/src/Util.Domain/Extending/ExtraProperty.cs b/src/Util.Domain/Extending/ExtraProperty.cs index 5e0da559..48a7384a 100644 --- a/src/Util.Domain/Extending/ExtraProperty.cs +++ b/src/Util.Domain/Extending/ExtraProperty.cs @@ -30,7 +30,7 @@ /// /// 扩展属性集合 public TProperty GetProperty( ExtraPropertyDictionary properties ) { - _properties = properties; + _properties = properties ?? new ExtraPropertyDictionary(); var property = _properties.GetProperty( _propertyName ); if ( property == null ) return null; diff --git a/src/Util.Events/01-Util.Events.csproj b/src/Util.Events/01-Util.Events.csproj index 52ac646c..e8164a96 100644 --- a/src/Util.Events/01-Util.Events.csproj +++ b/src/Util.Events/01-Util.Events.csproj @@ -5,7 +5,7 @@ icon.jpg Util.Events Util.Events - Util.Events是Util应用框架的事件总线操作类库 + Util.Events是Util应用框架的事件总线操作核心类库,包含了本地领域事件总线 @@ -27,7 +27,7 @@ - + diff --git a/src/Util.Events/Infrastructure/LocalEventBusServiceRegistrar.cs b/src/Util.Events/Infrastructure/LocalEventBusServiceRegistrar.cs index 136a609d..cc96f131 100644 --- a/src/Util.Events/Infrastructure/LocalEventBusServiceRegistrar.cs +++ b/src/Util.Events/Infrastructure/LocalEventBusServiceRegistrar.cs @@ -1,8 +1,8 @@ using System; using System.Linq; -using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; +using Microsoft.Extensions.Hosting; using Util.Infrastructure; using Util.Reflections; @@ -29,12 +29,13 @@ namespace Util.Events.Infrastructure { /// /// 注册服务 /// - /// 服务集合 - /// 配置 + /// 主机生成器 /// 类型查找器 - public Action Register( IServiceCollection services, IConfiguration configuration, ITypeFinder finder ) { - RegisterDependency( services ); - RegisterEventHandlers( services, finder ); + public Action Register( IHostBuilder hostBuilder, ITypeFinder finder ) { + hostBuilder.ConfigureServices( ( context, services ) => { + RegisterDependency( services ); + RegisterEventHandlers( services, finder ); + } ); return null; } diff --git a/src/Util.Localization/04-Util.Localization.csproj b/src/Util.Localization/04-Util.Localization.csproj new file mode 100644 index 00000000..5b75fc6e --- /dev/null +++ b/src/Util.Localization/04-Util.Localization.csproj @@ -0,0 +1,36 @@ + + + + $(NetTargetFramework) + icon.jpg + Util.Localization + Util.Localization + Util.Localization是Util应用框架的本地化封装类库 + + + + + .\obj\Debug\$(NetTargetFramework)\Util.Localization.xml + + + + + .\obj\Release\$(NetTargetFramework)\Util.Localization.xml + + + + + True + False + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Util.Localization/Json/IPathResolver.cs b/src/Util.Localization/Json/IPathResolver.cs new file mode 100644 index 00000000..c8eeaa7a --- /dev/null +++ b/src/Util.Localization/Json/IPathResolver.cs @@ -0,0 +1,34 @@ +using System.Globalization; +using System.Reflection; + +namespace Util.Localization.Json { + /// + /// 路径解析器 + /// + public interface IPathResolver { + /// + /// 获取根命名空间 + /// + /// 资源类型所在的程序集 + string GetRootNamespace( Assembly assembly ); + /// + /// 获取资源根目录路径 + /// + /// 资源类型所在的程序集 + /// 配置的根路径 + string GetResourcesRootPath( Assembly assembly,string rootPath ); + /// + /// 获取资源基名称 + /// + /// 资源类型所在的程序集 + /// 资源类型完全限定名 + string GetResourcesBaseName( Assembly assembly,string typeFullName ); + /// + /// 获取Json资源文件绝对路径 + /// + /// 资源根目录路径 + /// 资源基名称 + /// 区域文化 + string GetJsonResourcePath( string rootPath, string baseName,CultureInfo culture ); + } +} diff --git a/src/Util.Localization/Json/JsonStringLocalizer.cs b/src/Util.Localization/Json/JsonStringLocalizer.cs new file mode 100644 index 00000000..f2942f5e --- /dev/null +++ b/src/Util.Localization/Json/JsonStringLocalizer.cs @@ -0,0 +1,156 @@ +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Linq; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Localization; +using Microsoft.Extensions.Logging; + +namespace Util.Localization.Json { + /// + /// Json字符串定位器 + /// + public class JsonStringLocalizer : IStringLocalizer { + /// + /// 路径解析器 + /// + private readonly IPathResolver _pathResolver; + /// + /// 资源根目录路径 + /// + private readonly string _resourcesRootPath; + /// + /// 资源基名称 + /// + private readonly string _resourcesBaseName; + /// + /// 日志 + /// + private readonly ILogger _logger; + /// + /// 资源缓存 + /// + private readonly ConcurrentDictionary>> _resourcesCache; + /// + /// 搜索位置 + /// + private readonly string _searchedLocation; + + /// + /// 初始化Json字符串定位器 + /// + /// 路径解析器 + /// 资源根目录路径 + /// 资源基名称 + /// 资源基名称 + public JsonStringLocalizer( IPathResolver pathResolver, string resourcesRootPath, string resourcesBaseName, ILogger logger ) { + _pathResolver = pathResolver; + _resourcesRootPath = resourcesRootPath; + _resourcesBaseName = resourcesBaseName; + _logger = logger; + _resourcesCache = new ConcurrentDictionary>>(); + _searchedLocation = $"{resourcesRootPath}.{resourcesBaseName}"; + } + + /// + /// 获取本地化字符串 + /// + /// 本地化字符串名称 + public LocalizedString this[string name] { + get { + name.CheckNull( nameof( name ) ); + var value = GetValue( name, _resourcesBaseName ) ?? GetValue( name, null ); + return new LocalizedString( name, value ?? name, value == null, _searchedLocation ); + } + } + + /// + /// 获取本地化字符串 + /// + /// 本地化字符串名称 + /// 参数列表 + public LocalizedString this[ string name, params object[] arguments ] { + get { + name.CheckNull( nameof( name ) ); + var format = GetValue( name, _resourcesBaseName ) ?? GetValue( name, null ); + var value = string.Format( format ?? name, arguments ); + return new LocalizedString( name, value, format == null, _searchedLocation ); + } + } + + /// + /// 获取资源值 + /// + /// 资源名称 + /// 资源基名称 + protected virtual string GetValue( string name,string resourcesBaseName ) { + var cultures = Util.Helpers.Culture.GetCurrentUICultures(); + foreach ( var culture in cultures ) { + var resources = GetResourcesByCache( culture, resourcesBaseName ); + if ( resources == null ) + continue; + var resource = resources.SingleOrDefault( t => t.Key == name ); + var result = resource.Value; + _logger.SearchedLocation( name, _searchedLocation, culture ); + return result; + } + return null; + } + + /// + /// 从缓存获取资源列表 + /// + /// 区域文化 + /// 资源基名称 + protected virtual IEnumerable> GetResourcesByCache( CultureInfo culture, string resourcesBaseName ) { + return _resourcesCache.GetOrAdd( $"{culture.Name}_{resourcesBaseName}", t => GetResources( culture, resourcesBaseName ) ); + } + + /// + /// 获取资源列表 + /// + /// 区域文化 + /// 资源基名称 + protected virtual IEnumerable> GetResources( CultureInfo culture, string resourcesBaseName ) { + var path = _pathResolver.GetJsonResourcePath( _resourcesRootPath, resourcesBaseName, culture ); + if ( File.Exists( path ) == false ) { + if ( resourcesBaseName.IsEmpty() ) + return null; + path = _pathResolver.GetJsonResourcePath( _resourcesRootPath, resourcesBaseName.Replace( '.', Path.DirectorySeparatorChar ), culture ); + } + if ( File.Exists( path ) == false ) + return null; + var builder = new ConfigurationBuilder() + .AddJsonFile( path, optional: false, reloadOnChange: true ); + var config = builder.Build(); + return config.AsEnumerable(); + } + + /// + /// 获取全部本地化字符串 + /// + /// 是否包含父区域 + public virtual IEnumerable GetAllStrings( bool includeParentCultures ) { + var result = new List(); + var cultures = Util.Helpers.Culture.GetCurrentUICultures(); + foreach ( var culture in cultures ) { + var resources = ToLocalizedStrings( GetResourcesByCache( culture,_resourcesBaseName ) ); + result.AddRange( resources ); + if ( includeParentCultures == false ) + return result; + } + return result; + } + + /// + /// 转换为LocalizedString集合 + /// + protected virtual IEnumerable ToLocalizedStrings( IEnumerable> resources ) { + var result = new List(); + foreach ( var resource in resources ) + result.Add( new LocalizedString( resource.Key, resource.Value, false, _searchedLocation ) ); + return result; + } + } +} diff --git a/src/Util.Localization/Json/JsonStringLocalizerFactory.cs b/src/Util.Localization/Json/JsonStringLocalizerFactory.cs new file mode 100644 index 00000000..4e6e239c --- /dev/null +++ b/src/Util.Localization/Json/JsonStringLocalizerFactory.cs @@ -0,0 +1,62 @@ +using System; +using System.Reflection; +using Microsoft.Extensions.Localization; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; + +namespace Util.Localization.Json { + /// + /// Json字符串定位器工厂 + /// + public class JsonStringLocalizerFactory : IStringLocalizerFactory { + /// + /// 资源根目录路径 + /// + private readonly string _rootPath; + /// + /// 路径解析器 + /// + private readonly IPathResolver _pathResolver; + /// + /// 日志工厂 + /// + private readonly ILoggerFactory _loggerFactory; + + /// + /// 初始化Json字符串定位器工厂 + /// + /// 本地化配置 + /// 本地化配置 + /// 本地化配置 + public JsonStringLocalizerFactory( IOptions options, IPathResolver pathResolver, ILoggerFactory loggerFactory ) { + options.CheckNull( nameof( options ) ); + _rootPath = options.Value.ResourcesPath; + _pathResolver = pathResolver ?? throw new ArgumentNullException( nameof( pathResolver ) ); + _loggerFactory = loggerFactory ?? throw new ArgumentNullException( nameof(loggerFactory) ); + } + + /// + /// 创建Json字符串定位器 + /// + /// 资源类型 + public IStringLocalizer Create( Type resourceSource ) { + resourceSource.CheckNull( nameof( resourceSource ) ); + var assembly = resourceSource.Assembly; + var rootPath = _pathResolver.GetResourcesRootPath( assembly, _rootPath ); + var baseName = _pathResolver.GetResourcesBaseName( assembly, resourceSource.FullName ); + return new JsonStringLocalizer( _pathResolver, rootPath, baseName, _loggerFactory.CreateLogger() ); + } + + /// + /// 创建Json字符串定位器 + /// + /// 资源名称 + /// 资源位置 + public IStringLocalizer Create( string baseName, string location ) { + var assemblyName = new AssemblyName( location ); + var assembly = Assembly.Load( assemblyName ); + var rootPath = _pathResolver.GetResourcesRootPath( assembly, _rootPath ); + return new JsonStringLocalizer( _pathResolver, rootPath, baseName, _loggerFactory.CreateLogger() ); + } + } +} diff --git a/src/Util.Localization/Json/JsonStringLocalizerLoggerExtensions.cs b/src/Util.Localization/Json/JsonStringLocalizerLoggerExtensions.cs new file mode 100644 index 00000000..cd36650e --- /dev/null +++ b/src/Util.Localization/Json/JsonStringLocalizerLoggerExtensions.cs @@ -0,0 +1,23 @@ +using System; +using System.Globalization; +using Microsoft.Extensions.Logging; + +namespace Util.Localization.Json { + /// + /// Json本地化日志扩展 + /// + internal static class JsonStringLocalizerLoggerExtensions { + private static readonly Action _searchedLocation; + + static JsonStringLocalizerLoggerExtensions() { + _searchedLocation = LoggerMessage.Define( + LogLevel.Debug, + 1, + $"{nameof( JsonStringLocalizer )} searched for '{{Key}}' in '{{LocationSearched}}' with culture '{{Culture}}'." ); + } + + public static void SearchedLocation( this ILogger logger, string key, string searchedLocation, CultureInfo culture ) { + _searchedLocation( logger, key, searchedLocation, culture, null ); + } + } +} diff --git a/src/Util.Localization/Json/PathResolver.cs b/src/Util.Localization/Json/PathResolver.cs new file mode 100644 index 00000000..130fcf83 --- /dev/null +++ b/src/Util.Localization/Json/PathResolver.cs @@ -0,0 +1,49 @@ +using System.Globalization; +using System.IO; +using System.Reflection; +using Microsoft.Extensions.Localization; +using Util.Helpers; + +namespace Util.Localization.Json { + /// + /// 路径解析器 + /// + public class PathResolver : IPathResolver { + /// + public string GetRootNamespace( Assembly assembly ) { + assembly.CheckNull( nameof(assembly) ); + var attribute = assembly.GetCustomAttribute(); + return attribute == null ? assembly.GetName().Name : attribute.RootNamespace; + } + + /// + public string GetResourcesRootPath( Assembly assembly, string rootPath ) { + if ( assembly == null ) + return rootPath; + var attribute = assembly.GetCustomAttribute(); + return attribute == null ? rootPath : attribute.ResourceLocation; + } + + /// + public string GetResourcesBaseName( Assembly assembly, string typeFullName ) { + var rootNamespace = GetRootNamespace( assembly ); + return typeFullName.RemoveStart( $"{rootNamespace}." ); + } + + /// + public string GetJsonResourcePath( string rootPath, string baseName, CultureInfo culture ) { + if( baseName.IsEmpty() ) + return Path.Combine( Platform.ApplicationBaseDirectory, rootPath, $"{culture.Name}.json" ); + baseName = FixInnerClassPath( baseName ); + return Path.Combine( Platform.ApplicationBaseDirectory, rootPath, $"{baseName}.{culture.Name}.json" ); + } + + /// + /// 修复内部类分隔符+ + /// + private string FixInnerClassPath( string path ) { + const char innerClassSeparator = '+'; + return path.Contains( innerClassSeparator ) ? path.Replace( innerClassSeparator, '.' ) : path; + } + } +} diff --git a/src/Util.Localization/Json/StringLocalizer.cs b/src/Util.Localization/Json/StringLocalizer.cs new file mode 100644 index 00000000..187b7e83 --- /dev/null +++ b/src/Util.Localization/Json/StringLocalizer.cs @@ -0,0 +1,43 @@ +using System.Collections.Generic; +using System.Reflection; +using Microsoft.Extensions.Localization; + +namespace Util.Localization.Json { + /// + /// Json字符串定位器 + /// + internal class StringLocalizer : IStringLocalizer { + /// + /// Json字符串定位器 + /// + private readonly IStringLocalizer _localizer; + + /// + /// 初始化Json字符串定位器 + /// + /// Json字符串定位器工厂 + public StringLocalizer( IStringLocalizerFactory factory ) { + var assemblyName = new AssemblyName( GetType().Assembly.FullName ); + _localizer = factory.Create( null, assemblyName.FullName ); + } + + /// + /// 获取本地化字符串 + /// + /// 本地化字符串名称 + public LocalizedString this[string name] => _localizer[name]; + + /// + /// 获取本地化字符串 + /// + /// 本地化字符串名称 + /// 参数列表 + public LocalizedString this[string name, params object[] arguments] => _localizer[name, arguments]; + + /// + /// 获取全部本地化字符串 + /// + /// 是否包含父区域 + public IEnumerable GetAllStrings( bool includeParentCultures ) => _localizer.GetAllStrings( includeParentCultures ); + } +} diff --git a/src/Util.Localization/JsonLocalizationOptionsExtension.cs b/src/Util.Localization/JsonLocalizationOptionsExtension.cs new file mode 100644 index 00000000..467c0a50 --- /dev/null +++ b/src/Util.Localization/JsonLocalizationOptionsExtension.cs @@ -0,0 +1,38 @@ +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Localization; +using Util.Configs; +using Util.Localization.Json; + +namespace Util.Localization { + /// + /// Json本地化配置扩展 + /// + public class JsonLocalizationOptionsExtension : OptionsExtensionBase { + /// + /// 资源路径 + /// + private readonly string _resourcesPath; + + /// + /// 初始化Json本地化配置扩展 + /// + /// 资源路径 + public JsonLocalizationOptionsExtension( string resourcesPath ) { + _resourcesPath = resourcesPath; + } + + /// + public override void ConfigureServices( HostBuilderContext context, IServiceCollection services ) { + services.RemoveAll( typeof( IStringLocalizerFactory ) ); + services.RemoveAll( typeof( IStringLocalizer<> ) ); + services.RemoveAll( typeof( IStringLocalizer ) ); + services.TryAddSingleton(); + services.TryAddSingleton(); + services.TryAddTransient( typeof( IStringLocalizer<> ), typeof( StringLocalizer<> ) ); + services.TryAddTransient( typeof( IStringLocalizer ), typeof( StringLocalizer ) ); + services.Configure( options => options.ResourcesPath = _resourcesPath ); + } + } +} diff --git a/src/Util.Localization/OptionsExtensions.cs b/src/Util.Localization/OptionsExtensions.cs new file mode 100644 index 00000000..6c1e36c8 --- /dev/null +++ b/src/Util.Localization/OptionsExtensions.cs @@ -0,0 +1,18 @@ +using Util.Configs; + +namespace Util.Localization { + /// + /// 本地化操作扩展 + /// + public static class OptionsExtensions { + /// + /// 配置Json本地化 + /// + /// 配置项 + /// 资源路径,默认值: Resources + public static Options UseJsonLocalization( this Options options,string resourcesPath = "Resources" ) { + options.Extensions.Add( new JsonLocalizationOptionsExtension( resourcesPath ) ); + return options; + } + } +} diff --git a/src/Util.Logging.Serilog.Exceptionless/03-Util.Logging.Serilog.Exceptionless.csproj b/src/Util.Logging.Serilog.Exceptionless/03-Util.Logging.Serilog.Exceptionless.csproj index a28032db..d0a93e1e 100644 --- a/src/Util.Logging.Serilog.Exceptionless/03-Util.Logging.Serilog.Exceptionless.csproj +++ b/src/Util.Logging.Serilog.Exceptionless/03-Util.Logging.Serilog.Exceptionless.csproj @@ -27,8 +27,8 @@ - - + + diff --git a/src/Util.Logging.Serilog.Exceptionless/ExceptionlessOptionsExtension.cs b/src/Util.Logging.Serilog.Exceptionless/ExceptionlessOptionsExtension.cs index bda62614..755f34f6 100644 --- a/src/Util.Logging.Serilog.Exceptionless/ExceptionlessOptionsExtension.cs +++ b/src/Util.Logging.Serilog.Exceptionless/ExceptionlessOptionsExtension.cs @@ -2,6 +2,7 @@ using Exceptionless; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using Serilog; using Util.Configs; @@ -10,7 +11,7 @@ namespace Util.Logging.Serilog { /// /// Exceptionless日志操作配置扩展 /// - public class ExceptionlessOptionsExtension : IOptionsExtension { + public class ExceptionlessOptionsExtension : OptionsExtensionBase { /// /// Exceptionless日志配置操作 /// @@ -30,15 +31,12 @@ namespace Util.Logging.Serilog { _isClearProviders = isClearProviders; } - /// - /// 添加服务 - /// - /// 服务集合 - public void AddServices( IServiceCollection services ) { + /// + public override void ConfigureServices( HostBuilderContext context, IServiceCollection services ) { + var configuration = context.Configuration; services.AddLogging( loggingBuilder => { - if( _isClearProviders ) + if ( _isClearProviders ) loggingBuilder.ClearProviders(); - var configuration = services.GetConfiguration(); ConfigExceptionless( configuration ); Log.Logger = new LoggerConfiguration() .Enrich.FromLogContext() diff --git a/src/Util.Logging.Serilog.Exceptionless/OptionsExtensions.cs b/src/Util.Logging.Serilog.Exceptionless/OptionsExtensions.cs index 34979945..c3b09305 100644 --- a/src/Util.Logging.Serilog.Exceptionless/OptionsExtensions.cs +++ b/src/Util.Logging.Serilog.Exceptionless/OptionsExtensions.cs @@ -7,12 +7,12 @@ namespace Util.Logging.Serilog { /// public static class OptionsExtensions { /// - /// 配置Serilog日志操作 + /// 启用Serilog日志操作 /// /// 配置项 /// Exceptionless日志配置操作 /// 是否清除默认设置的日志提供程序 - public static Options UseSerilog( this Options options,Action configAction, bool isClearProviders = true ) { + public static Options UseSerilog( this Options options,Action configAction, bool isClearProviders = false ) { configAction.CheckNull( nameof( configAction ) ); var config = new SerilogExceptionlessConfiguration(); configAction( config ); diff --git a/src/Util.Logging.Serilog/02-Util.Logging.Serilog.csproj b/src/Util.Logging.Serilog/02-Util.Logging.Serilog.csproj index 3675d648..26e1f268 100644 --- a/src/Util.Logging.Serilog/02-Util.Logging.Serilog.csproj +++ b/src/Util.Logging.Serilog/02-Util.Logging.Serilog.csproj @@ -30,7 +30,7 @@ - + diff --git a/src/Util.Logging.Serilog/SerilogOptionsExtension.cs b/src/Util.Logging.Serilog/SerilogOptionsExtension.cs index b4dee246..e3439db9 100644 --- a/src/Util.Logging.Serilog/SerilogOptionsExtension.cs +++ b/src/Util.Logging.Serilog/SerilogOptionsExtension.cs @@ -1,4 +1,5 @@ using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using Serilog; using Util.Configs; @@ -7,7 +8,7 @@ namespace Util.Logging.Serilog { /// /// Serilog日志操作配置扩展 /// - public class SerilogOptionsExtension : IOptionsExtension { + public class SerilogOptionsExtension : OptionsExtensionBase { /// /// 是否清除日志提供程序 /// @@ -21,15 +22,12 @@ namespace Util.Logging.Serilog { _isClearProviders = isClearProviders; } - /// - /// 添加服务 - /// - /// 服务集合 - public void AddServices( IServiceCollection services ) { + /// + public override void ConfigureServices( HostBuilderContext context, IServiceCollection services ) { + var configuration = context.Configuration; services.AddLogging( loggingBuilder => { - if( _isClearProviders ) + if ( _isClearProviders ) loggingBuilder.ClearProviders(); - var configuration = services.GetConfiguration(); Log.Logger = new LoggerConfiguration() .Enrich.FromLogContext() .Enrich.WithLogLevel() diff --git a/src/Util.Logging/ILogExtensions.cs b/src/Util.Logging/ILogExtensions.cs index e333813d..40269678 100644 --- a/src/Util.Logging/ILogExtensions.cs +++ b/src/Util.Logging/ILogExtensions.cs @@ -2,14 +2,70 @@ namespace Util.Logging { /// - /// Serilog日志操作扩展 + /// 日志操作扩展 /// public static class ILogExtensions { + /// + /// 添加消息 + /// + /// 配置项 + /// 消息 + /// 日志消息参数 + public static ILog Append( this ILog log,string message, params object[] args ) { + log.CheckNull( nameof( log ) ); + log.Message( message, args ); + return log; + } + + /// + /// 当条件为true添加消息 + /// + /// 配置项 + /// 消息 + /// 条件,值为true则添加消息 + /// 日志消息参数 + public static ILog AppendIf( this ILog log, string message,bool condition, params object[] args ) { + log.CheckNull( nameof( log ) ); + if ( condition ) + log.Message( message, args ); + return log; + } + + /// + /// 添加消息并换行 + /// + /// 配置项 + /// 消息 + /// 日志消息参数 + public static ILog AppendLine( this ILog log, string message, params object[] args ) { + log.CheckNull( nameof( log ) ); + log.Message( message, args ); + log.Message( Environment.NewLine ); + return log; + } + + /// + /// 当条件为true添加消息并换行 + /// + /// 配置项 + /// 消息 + /// 条件,值为true则添加消息 + /// 日志消息参数 + public static ILog AppendLineIf( this ILog log, string message, bool condition, params object[] args ) { + log.CheckNull( nameof( log ) ); + if ( condition ) { + log.Message( message, args ); + log.Message( Environment.NewLine ); + } + return log; + } + /// /// 消息换行 /// /// 配置项 public static ILog Line( this ILog log ) { + log.CheckNull( nameof(log) ); log.Message( Environment.NewLine ); return log; } diff --git a/src/Util.Logging/Log.cs b/src/Util.Logging/Log.cs index 231aa7dc..b70e5f0d 100644 --- a/src/Util.Logging/Log.cs +++ b/src/Util.Logging/Log.cs @@ -25,6 +25,15 @@ namespace Util.Logging { #endregion + #region Null(空日志操作实例) + + /// + /// 空日志操作实例 + /// + public static ILog Null = NullLog.Instance; + + #endregion + #region 属性 /// diff --git a/src/Util.Logging/NullLog.cs b/src/Util.Logging/NullLog.cs new file mode 100644 index 00000000..1e5c3757 --- /dev/null +++ b/src/Util.Logging/NullLog.cs @@ -0,0 +1,80 @@ +using System; +using Microsoft.Extensions.Logging; + +namespace Util.Logging { + /// + /// 空日志操作 + /// + /// 日志类别 + public class NullLog : ILog { + /// + /// 空日志操作实例 + /// + public static readonly ILog Instance = new NullLog(); + + /// + public ILog EventId( EventId eventId ) { + return this; + } + + /// + public ILog Exception( Exception exception ) { + return this; + } + + /// + public ILog Property( string propertyName, string propertyValue ) { + return this; + } + + /// + public ILog State( object state ) { + return this; + } + + /// + public ILog Message( string message, params object[] args ) { + return this; + } + + /// + public bool IsEnabled( LogLevel logLevel ) { + return false; + } + + /// + public IDisposable BeginScope( TState state ) { + return new DisposeAction( () => { } ); + } + + /// + public ILog LogTrace() { + return this; + } + + /// + public ILog LogDebug() { + return this; + } + + /// + public ILog LogInformation() { + return this; + } + + /// + public ILog LogWarning() { + return this; + } + + /// + public ILog LogError() { + return this; + } + + /// + public ILog LogCritical() { + return this; + } + } +} diff --git a/src/Util.ObjectMapping.AutoMapper/03-Util.ObjectMapping.AutoMapper.csproj b/src/Util.ObjectMapping.AutoMapper/02-Util.ObjectMapping.AutoMapper.csproj similarity index 94% rename from src/Util.ObjectMapping.AutoMapper/03-Util.ObjectMapping.AutoMapper.csproj rename to src/Util.ObjectMapping.AutoMapper/02-Util.ObjectMapping.AutoMapper.csproj index 35e59bb4..3720ae0a 100644 --- a/src/Util.ObjectMapping.AutoMapper/03-Util.ObjectMapping.AutoMapper.csproj +++ b/src/Util.ObjectMapping.AutoMapper/02-Util.ObjectMapping.AutoMapper.csproj @@ -27,7 +27,7 @@ - + diff --git a/src/Util.ObjectMapping.AutoMapper/Infrastructure/AutoMapperServiceRegistrar.cs b/src/Util.ObjectMapping.AutoMapper/Infrastructure/AutoMapperServiceRegistrar.cs index 4c303791..1c170dfd 100644 --- a/src/Util.ObjectMapping.AutoMapper/Infrastructure/AutoMapperServiceRegistrar.cs +++ b/src/Util.ObjectMapping.AutoMapper/Infrastructure/AutoMapperServiceRegistrar.cs @@ -2,6 +2,7 @@ using System.Linq; using AutoMapper; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; using Util.Helpers; using Util.Infrastructure; using Util.Reflections; @@ -29,17 +30,18 @@ namespace Util.ObjectMapping.Infrastructure { /// /// 注册服务 /// - /// 服务集合 - /// 配置 + /// 主机生成器 /// 类型查找器 - public Action Register( IServiceCollection services, Microsoft.Extensions.Configuration.IConfiguration configuration, ITypeFinder finder ) { + public Action Register( IHostBuilder hostBuilder, ITypeFinder finder ) { var types = finder.Find(); var instances = types.Select( type => Reflection.CreateInstance( type ) ).ToList(); var expression = new MapperConfigurationExpression(); instances.ForEach( t => t.Config( expression ) ); var mapper = new ObjectMapper( expression ); ObjectMapperExtensions.SetMapper( mapper ); - services.AddSingleton( mapper ); + hostBuilder.ConfigureServices( ( context, services ) => { + services.AddSingleton( mapper ); + } ); return null; } } diff --git a/src/Util.ObjectMapping.AutoMapper/ObjectMapper.cs b/src/Util.ObjectMapping.AutoMapper/ObjectMapper.cs index ebc8033f..bcd25383 100644 --- a/src/Util.ObjectMapping.AutoMapper/ObjectMapper.cs +++ b/src/Util.ObjectMapping.AutoMapper/ObjectMapper.cs @@ -31,7 +31,7 @@ namespace Util.ObjectMapping { /// 配置表达式 public ObjectMapper( MapperConfigurationExpression expression ) { _configExpression = expression ?? throw new ArgumentNullException( nameof( expression ) ); - _config = new MapperConfiguration( expression ); + _config = new MapperConfiguration( expression ); _mapper = _config.CreateMapper(); } @@ -54,13 +54,13 @@ namespace Util.ObjectMapping { /// 目标对象 public TDestination Map( TSource source, TDestination destination ) { try { - if ( source == null ) + if( source == null ) return default; var sourceType = GetType( source ); var destinationType = GetType( destination ); return GetResult( sourceType, destinationType, source, destination ); } - catch ( AutoMapperMappingException ex ) { + catch( AutoMapperMappingException ex ) { return GetResult( GetType( ex.MemberMap.SourceType ), GetType( ex.MemberMap.DestinationType ), source, destination ); } } @@ -69,7 +69,7 @@ namespace Util.ObjectMapping { /// 获取类型 /// private Type GetType( T obj ) { - if ( obj == null ) + if( obj == null ) return GetType( typeof( T ) ); return GetType( obj.GetType() ); } @@ -85,10 +85,10 @@ namespace Util.ObjectMapping { /// 获取结果 /// private TDestination GetResult( Type sourceType, Type destinationType, object source, TDestination destination ) { - if ( Exists( sourceType, destinationType ) ) + if( Exists( sourceType, destinationType ) ) return GetResult( source, destination ); - lock ( Sync ) { - if ( Exists( sourceType, destinationType ) ) + lock( Sync ) { + if( Exists( sourceType, destinationType ) ) return GetResult( source, destination ); ConfigMap( sourceType, destinationType ); } diff --git a/src/Util.Templates.Handlebars/03-Util.Templates.Handlebars.csproj b/src/Util.Templates.Handlebars/03-Util.Templates.Handlebars.csproj index addc608d..3d031f87 100644 --- a/src/Util.Templates.Handlebars/03-Util.Templates.Handlebars.csproj +++ b/src/Util.Templates.Handlebars/03-Util.Templates.Handlebars.csproj @@ -27,7 +27,7 @@ - + diff --git a/src/Util.Templates.Handlebars/Infrastructure/HandlebarsServiceRegistrar.cs b/src/Util.Templates.Handlebars/Infrastructure/HandlebarsServiceRegistrar.cs index 26143901..2259dbfe 100644 --- a/src/Util.Templates.Handlebars/Infrastructure/HandlebarsServiceRegistrar.cs +++ b/src/Util.Templates.Handlebars/Infrastructure/HandlebarsServiceRegistrar.cs @@ -1,6 +1,6 @@ using System; -using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; using Util.Infrastructure; using Util.Reflections; using Util.Templates.HandlebarsDotNet; @@ -28,12 +28,13 @@ namespace Util.Templates.Infrastructure { /// /// 注册服务 /// - /// 服务集合 - /// 配置 + /// 主机生成器 /// 类型查找器 - public Action Register( IServiceCollection services, IConfiguration configuration, ITypeFinder finder ) { - services.AddSingleton(); - services.AddSingleton(); + public Action Register( IHostBuilder hostBuilder, ITypeFinder finder ) { + hostBuilder.ConfigureServices( ( context, services ) => { + services.AddSingleton(); + services.AddSingleton(); + } ); return null; } } diff --git a/src/Util.Templates.Razor/02-Util.Templates.Razor.csproj b/src/Util.Templates.Razor/02-Util.Templates.Razor.csproj index 043f5467..137f836f 100644 --- a/src/Util.Templates.Razor/02-Util.Templates.Razor.csproj +++ b/src/Util.Templates.Razor/02-Util.Templates.Razor.csproj @@ -33,12 +33,11 @@ - - - + + diff --git a/src/Util.Templates.Razor/Infrastructure/RazorServiceRegistrar.cs b/src/Util.Templates.Razor/Infrastructure/RazorServiceRegistrar.cs index ff4353a2..28a6a6e3 100644 --- a/src/Util.Templates.Razor/Infrastructure/RazorServiceRegistrar.cs +++ b/src/Util.Templates.Razor/Infrastructure/RazorServiceRegistrar.cs @@ -1,6 +1,6 @@ using System; -using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; using RazorEngineCore; using Util.Infrastructure; using Util.Reflections; @@ -30,11 +30,12 @@ namespace Util.Templates.Infrastructure { /// /// 注册服务 /// - /// 服务集合 - /// 配置 + /// 主机生成器 /// 类型查找器 - public Action Register( IServiceCollection services, IConfiguration configuration, ITypeFinder finder ) { - RegisterDependency( services ); + public Action Register( IHostBuilder hostBuilder, ITypeFinder finder ) { + hostBuilder.ConfigureServices( ( context, services ) => { + RegisterDependency( services ); + } ); RegisterAssemblyReference( finder ); RegisterFilters(); return null; diff --git a/src/Util.Validation/05-Util.Validation.csproj b/src/Util.Validation/05-Util.Validation.csproj index 64928105..ecbd0e7b 100644 --- a/src/Util.Validation/05-Util.Validation.csproj +++ b/src/Util.Validation/05-Util.Validation.csproj @@ -27,7 +27,7 @@ - + diff --git a/test/Util.Aop.AspectCore.Tests/Startup.cs b/test/Util.Aop.AspectCore.Tests/Startup.cs index a0ef05cc..e9c16c02 100644 --- a/test/Util.Aop.AspectCore.Tests/Startup.cs +++ b/test/Util.Aop.AspectCore.Tests/Startup.cs @@ -1,4 +1,3 @@ -using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using Xunit.DependencyInjection; @@ -13,14 +12,7 @@ namespace Util.Aop.AspectCore.Tests { /// ÅäÖÃÖ÷»ú /// public void ConfigureHost( IHostBuilder hostBuilder ) { - hostBuilder.EnableAop(); - } - - /// - /// ÅäÖ÷þÎñ - /// - public void ConfigureServices( IServiceCollection services ) { - services.AddUtil(); + hostBuilder.AddUtil( t => t.UseAop() ); } /// diff --git a/test/Util.Aop.AspectCore.Tests/Util.Aop.AspectCore.Tests.csproj b/test/Util.Aop.AspectCore.Tests/Util.Aop.AspectCore.Tests.csproj index 90c3cf66..88d31e00 100644 --- a/test/Util.Aop.AspectCore.Tests/Util.Aop.AspectCore.Tests.csproj +++ b/test/Util.Aop.AspectCore.Tests/Util.Aop.AspectCore.Tests.csproj @@ -6,23 +6,23 @@ - - + + - - - + + + runtime; build; native; contentfiles; analyzers; buildtransitive all - + runtime; build; native; contentfiles; analyzers; buildtransitive all - + diff --git a/test/Util.Application.EntityFrameworkCore.MySql.Tests.Integration/Startup.cs b/test/Util.Application.EntityFrameworkCore.MySql.Tests.Integration/Startup.cs new file mode 100644 index 00000000..ee2490ad --- /dev/null +++ b/test/Util.Application.EntityFrameworkCore.MySql.Tests.Integration/Startup.cs @@ -0,0 +1,54 @@ +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using Xunit.DependencyInjection; +using Xunit.DependencyInjection.Logging; +using Util.Aop; +using Util.Data.EntityFrameworkCore; +using Util.Helpers; +using Util.Sessions; +using Util.Tests.Infrastructure; +using Util.Tests.UnitOfWorks; + +namespace Util.Applications { + /// + /// Æô¶¯ÅäÖà + /// + public class Startup { + /// + /// ÅäÖÃÖ÷»ú + /// + public void ConfigureHost( IHostBuilder hostBuilder ) { + hostBuilder.ConfigureDefaults( null ) + .AddUtil( options => { + Environment.SetDevelopment(); + options.UseAop() + .UseMySqlUnitOfWork( Config.GetConnectionString( "connection" ) ); + } ); + } + + /// + /// ÅäÖ÷þÎñ + /// + public void ConfigureServices( IServiceCollection services ) { + services.AddSingleton(); + InitDatabase( services ); + } + + /// + /// ³õʼ»¯Êý¾ݿâ + /// + private void InitDatabase( IServiceCollection services ) { + var unitOfWork = services.BuildServiceProvider().GetService(); + unitOfWork.EnsureDeleted(); + unitOfWork.EnsureCreated(); + } + + /// + /// ÅäÖÃÈÕ־Ìṩ³ÌÐò + /// + public void Configure( ILoggerFactory loggerFactory, ITestOutputHelperAccessor accessor ) { + loggerFactory.AddProvider( new XunitTestOutputLoggerProvider( accessor, ( s, logLevel ) => logLevel >= LogLevel.Trace ) ); + } + } +} \ No newline at end of file diff --git a/test/Util.Application.EntityFrameworkCore.MySql.Tests.Integration/Tests/CustomerQueryServiceTest.cs b/test/Util.Application.EntityFrameworkCore.MySql.Tests.Integration/Tests/CustomerQueryServiceTest.cs new file mode 100644 index 00000000..f65ff4c7 --- /dev/null +++ b/test/Util.Application.EntityFrameworkCore.MySql.Tests.Integration/Tests/CustomerQueryServiceTest.cs @@ -0,0 +1,215 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Util.Data.EntityFrameworkCore; +using Util.Tests.Fakes; +using Util.Tests.Infrastructure; +using Util.Tests.Models; +using Util.Tests.Queries; +using Util.Tests.Repositories; +using Util.Tests.Services; +using Util.Tests.UnitOfWorks; +using Xunit; +using Xunit.Abstractions; +using Xunit.DependencyInjection; + +namespace Util.Applications.Tests { + /// + /// 客户查询服务测试 + /// 说明: + /// 1. 测试查询服务操作 + /// + public class CustomerQueryServiceTest : TestBase { + + #region 测试初始化 + + /// + /// 测试输出 + /// + private readonly ITestOutputHelper _testOutputHelper; + /// + /// 客户仓储 + /// + private readonly ICustomerRepository _repository; + /// + /// 客户查询服务 + /// + private readonly ICustomerQueryService _service; + + /// + /// 测试初始化 + /// + public CustomerQueryServiceTest( ITestOutputHelperAccessor testOutputHelperAccessor, ICustomerRepository repository, + ICustomerQueryService service, ITestUnitOfWork unitOfWork ) : base( unitOfWork ) { + _testOutputHelper = testOutputHelperAccessor.Output; + _repository = repository; + _service = service; + } + + #endregion + + #region 辅助方法 + + /// + /// 添加客户 + /// + public async Task AddCustomerAsync() { + return ( await AddCustomersAsync( 1 ) ).First(); + } + + /// + /// 添加客户列表 + /// + /// 添加数量 + /// 客户姓名 + public async Task> AddCustomersAsync( int count = 2, string name = null ) { + var customers = CustomerFakeService.GetCustomers( count ); + customers.ForEach( customer => { + if ( name.IsEmpty() == false ) + customer.Name = name; + } ); + await _repository.AddAsync( customers ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + return customers.OrderBy( t => t.Code ).ToList(); + } + + /// + /// 打印更改跟踪调试信息 + /// + private void WriteTrackerDebug() { + _testOutputHelper.WriteLine( UnitOfWork.GetChangeTrackerDebugView() ); + } + + #endregion + + #region GetAllAsync + + /// + /// 测试获取全部实体 + /// + [Fact] + public async Task TestGetAllAsync() { + var entities = await AddCustomersAsync(); + var dtos = await _service.GetAllAsync(); + Assert.True( dtos.Count >= entities.Count ); + Assert.Equal( entities[0].Name, dtos.Find( t => t.Id == entities[0].Id.ToString() )?.Name ); + } + + #endregion + + #region GetByIdAsync + + /// + /// 测试通过标识获取实体 + /// + [Fact] + public async Task TestGetByIdAsync() { + var entity = await AddCustomerAsync(); + var dto = await _service.GetByIdAsync( entity.Id ); + Assert.Equal( entity.Name, dto.Name ); + } + + #endregion + + #region GetByIdsAsync + + /// + /// 测试通过标识列表获取实体列表 + /// + [Fact] + public async Task TestGetByIdsAsync() { + var entities = await AddCustomersAsync(); + var dtos = await _service.GetByIdsAsync( entities.Select( t => t.Id ).Join() ); + Assert.Equal( entities.Count, dtos.Count ); + Assert.Equal( entities[0].Name, dtos.Find( t => t.Id == entities[0].Id.ToString() )?.Name ); + } + + #endregion + + #region QueryAsync + + /// + /// 测试查询 + /// + [Fact] + public async Task TestQueryAsync() { + //常量 + var name = "TestQueryAsync"; + + //添加客户实体列表 + await AddCustomersAsync(); + var entities = await AddCustomersAsync( 5, name ); + + //查询 + var query = new CustomerQuery { + Name = name, + Order = "Code" + }; + var dtos = await _service.QueryAsync( query ); + WriteTrackerDebug(); + Assert.True( dtos.Count == entities.Count ); + Assert.Equal( entities[0].Id.ToString(), dtos[0].Id ); + Assert.Equal( entities[4].Id.ToString(), dtos[4].Id ); + } + + #endregion + + #region PageQueryAsync + + /// + /// 测试分页查询 - 第1页 + /// + [Fact] + public async Task TestPageQueryAsync_1() { + //常量 + var name = "TestPageQueryAsync_1"; + + //添加客户实体列表 + await AddCustomersAsync(); + var entities = await AddCustomersAsync( 5, name ); + + //查询 + var query = new CustomerQuery { + PageSize = 3, + Page = 1, + Name = name, + Order = "Code" + }; + var dtos = await _service.PageQueryAsync( query ); + WriteTrackerDebug(); + Assert.Equal( 3, dtos.Data.Count ); + Assert.Equal( entities[0].Id.ToString(), dtos.Data[0].Id ); + Assert.Equal( entities[1].Id.ToString(), dtos.Data[1].Id ); + Assert.Equal( entities[2].Id.ToString(), dtos.Data[2].Id ); + } + + /// + /// 测试分页查询 - 第2页 + /// + [Fact] + public async Task TestPageQueryAsync_2() { + //常量 + var name = "TestPageQueryAsync_2"; + + //添加客户实体列表 + await AddCustomersAsync(); + var entities = await AddCustomersAsync( 5, name ); + + //查询 + var query = new CustomerQuery { + PageSize = 3, + Page = 2, + Name = name, + Order = "Code" + }; + var dtos = await _service.PageQueryAsync( query ); + WriteTrackerDebug(); + Assert.Equal( 2, dtos.Data.Count ); + Assert.Equal( entities[3].Id.ToString(), dtos.Data[0].Id ); + Assert.Equal( entities[4].Id.ToString(), dtos.Data[1].Id ); + } + + #endregion + } +} diff --git a/test/Util.Application.EntityFrameworkCore.MySql.Tests.Integration/Tests/CustomerServiceTest.cs b/test/Util.Application.EntityFrameworkCore.MySql.Tests.Integration/Tests/CustomerServiceTest.cs new file mode 100644 index 00000000..2d5a475b --- /dev/null +++ b/test/Util.Application.EntityFrameworkCore.MySql.Tests.Integration/Tests/CustomerServiceTest.cs @@ -0,0 +1,40 @@ +using System.Threading.Tasks; +using Util.Tests.Fakes; +using Util.Tests.Services; +using Xunit; + +namespace Util.Applications.Tests { + /// + /// 客户服务测试 + /// + public class CustomerServiceTest { + /// + /// 客户服务 + /// + private readonly ICustomerService _service; + + /// + /// 测试初始化 + /// + public CustomerServiceTest( ICustomerService service ) { + _service = service; + } + + /// + /// 测试创建 + /// + [Fact] + public async Task TestCreateAsync() { + //创建 + var dto = CustomerFakeService.GetCustomerDto(); + var id = await _service.CreateAsync( dto ); + + //验证 + var result = await _service.GetByIdAsync( id ); + Assert.NotNull( result ); + Assert.Equal( id, result.Id ); + Assert.Equal( dto.Code, result.Code ); + Assert.Equal( dto.Name, result.Name ); + } + } +} \ No newline at end of file diff --git a/test/Util.Application.EntityFrameworkCore.MySql.Tests.Integration/Tests/ProductServiceTest.cs b/test/Util.Application.EntityFrameworkCore.MySql.Tests.Integration/Tests/ProductServiceTest.cs new file mode 100644 index 00000000..c5665ec1 --- /dev/null +++ b/test/Util.Application.EntityFrameworkCore.MySql.Tests.Integration/Tests/ProductServiceTest.cs @@ -0,0 +1,217 @@ +using System.Threading.Tasks; +using Util.Tests.Dtos; +using Util.Tests.Fakes; +using Util.Tests.Models; +using Util.Tests.Services; +using Xunit; + +namespace Util.Applications.Tests { + /// + /// 产品服务测试 + /// + public class ProductServiceTest { + + #region 测试初始化 + + /// + /// 产品服务 + /// + private readonly IProductService _service; + + /// + /// 测试初始化 + /// + public ProductServiceTest( IProductService service ) { + _service = service; + } + + #endregion + + #region CreateAsync + + /// + /// 测试创建 + /// + [Fact] + public async Task TestCreateAsync() { + //创建 + var dto = ProductFakeService.GetProductDto(); + var id = await _service.CreateAsync( dto ); + + //验证 + var result = await _service.GetByIdAsync( id ); + Assert.NotNull( result ); + Assert.Equal( id, result.Id ); + Assert.Equal( dto.Code, result.Code ); + Assert.Equal( dto.Name, result.Name ); + } + + #endregion + + #region UpdateAsync + + /// + /// 测试修改 + /// + [Fact] + public async Task TestUpdateAsync() { + //常量 + var code = "TestUpdateAsync"; + + //创建 + var dto = ProductFakeService.GetProductDto(); + var id = await _service.CreateAsync( dto ); + + //修改 + var updateDto = await _service.GetByIdAsync( id ); + updateDto.Code = code; + await _service.UpdateAsync( updateDto ); + + //验证 + var result = await _service.GetByIdAsync( id ); + Assert.Equal( code, result.Code ); + } + + #endregion + + #region DeleteAsync + + /// + /// 测试删除 + /// + [Fact] + public async Task TestDeleteAsync() { + //创建 + var dto = ProductFakeService.GetProductDto(); + var id = await _service.CreateAsync( dto ); + + //删除 + await _service.DeleteAsync( id ); + + //验证 + var result = await _service.GetByIdAsync( id ); + Assert.Null( result ); + } + + #endregion + + #region ExtraProperties + + /// + /// 测试扩展属性 - 添加简单扩展属性 + /// + [Fact] + public async Task TestExtraProperties_1() { + //常量 + var value = "TestExtraProperties_1"; + + //创建 + var dto = new ProductDto { TestProperty1 = value }; + var id = await _service.CreateAsync( dto ); + + //验证 + var result = await _service.GetByIdAsync( id ); + Assert.Equal( value, result.TestProperty1 ); + } + + /// + /// 测试扩展属性 - 修改简单扩展属性 + /// + [Fact] + public async Task TestExtraProperties_2() { + //常量 + var oldValue = "TestExtraProperties_2_1"; + var newValue = "TestExtraProperties_2_2"; + + //添加实体 + var dto = new ProductDto { TestProperty1 = oldValue }; + var id = await _service.CreateAsync( dto ); + + //验证 + var oldDto = await _service.GetByIdAsync( id ); + Assert.Equal( oldValue, oldDto.TestProperty1 ); + + //修改实体 + oldDto.TestProperty1 = newValue; + await _service.UpdateAsync( oldDto ); + + //验证 + var result = await _service.GetByIdAsync( id ); + Assert.Equal( newValue, result.TestProperty1 ); + } + + /// + /// 测试扩展属性 - 添加复杂扩展属性 + /// + [Fact] + public async Task TestExtraProperties_3() { + //常量 + var code = 2; + var name = "TestExtraProperties_3"; + + //添加实体 + var dto = new ProductDto { TestProperty2 = { Code = code, Name = name } }; + var id = await _service.CreateAsync( dto ); + + //验证 + var result = await _service.GetByIdAsync( id ); + Assert.Equal( code, result.TestProperty2.Code ); + Assert.Equal( name, result.TestProperty2.Name ); + } + + /// + /// 测试扩展属性 - 修改复杂扩展属性 + /// + [Fact] + public async Task TestExtraProperties_4() { + //常量 + var code = 2; + var oldName = "TestExtraProperties_4_1"; + var newName = "TestExtraProperties_4_2"; + + //添加实体 + var dto = new ProductDto { TestProperty2 = { Code = code, Name = oldName } }; + var id = await _service.CreateAsync( dto ); + + //验证 + var oldDto = await _service.GetByIdAsync( id ); + Assert.Equal( code, oldDto.TestProperty2.Code ); + Assert.Equal( oldName, oldDto.TestProperty2.Name ); + + //修改实体 + oldDto.TestProperty2.Name = newName; + await _service.UpdateAsync( oldDto ); + + //验证 + var result = await _service.GetByIdAsync( id ); + Assert.Equal( newName, result.TestProperty2.Name ); + } + + /// + /// 测试扩展属性 - 添加对象集合扩展属性 + /// + [Fact] + public async Task TestExtraProperties_5() { + //常量 + var code = 1; + var name1 = "TestExtraProperties_5_1"; + var name2 = "TestExtraProperties_5_2"; + + //添加实体 + var dto = new ProductDto(); + dto.TestProperties.Add( new ProductItem2 { Code = code, Name = name1 } ); + dto.TestProperties.Add( new ProductItem2 { Code = code, Name = name2 } ); + var id = await _service.CreateAsync( dto ); + + //验证 + var result = await _service.GetByIdAsync( id ); + Assert.Equal( 2, result.TestProperties.Count ); + Assert.Equal( code, result.TestProperties[0].Code ); + Assert.Equal( name1, result.TestProperties[0].Name ); + Assert.Equal( code, result.TestProperties[1].Code ); + Assert.Equal( name2, result.TestProperties[1].Name ); + } + + #endregion + } +} \ No newline at end of file diff --git a/test/Util.Application.EntityFrameworkCore.MySql.Tests.Integration/Util.Application.EntityFrameworkCore.MySql.Tests.Integration.csproj b/test/Util.Application.EntityFrameworkCore.MySql.Tests.Integration/Util.Application.EntityFrameworkCore.MySql.Tests.Integration.csproj new file mode 100644 index 00000000..159a9916 --- /dev/null +++ b/test/Util.Application.EntityFrameworkCore.MySql.Tests.Integration/Util.Application.EntityFrameworkCore.MySql.Tests.Integration.csproj @@ -0,0 +1,39 @@ + + + + $(NetTargetFramework) + false + Util.Applications + Util.Applications.Startup + + + + + Always + + + Always + + + + + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + \ No newline at end of file diff --git a/test/Util.Application.EntityFrameworkCore.MySql.Tests.Integration/appsettings.Development.json b/test/Util.Application.EntityFrameworkCore.MySql.Tests.Integration/appsettings.Development.json new file mode 100644 index 00000000..99e7cbbf --- /dev/null +++ b/test/Util.Application.EntityFrameworkCore.MySql.Tests.Integration/appsettings.Development.json @@ -0,0 +1,11 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Trace", + "Microsoft": "Trace" + } + }, + "ConnectionStrings": { + "connection": "server=192.168.31.157;user=root;password=admin;database=Util.Application.EntityFrameworkCore.Test;port=3306;charset=utf8" + } +} \ No newline at end of file diff --git a/test/Util.Application.EntityFrameworkCore.MySql.Tests.Integration/appsettings.json b/test/Util.Application.EntityFrameworkCore.MySql.Tests.Integration/appsettings.json new file mode 100644 index 00000000..37997047 --- /dev/null +++ b/test/Util.Application.EntityFrameworkCore.MySql.Tests.Integration/appsettings.json @@ -0,0 +1,11 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Error", + "Microsoft": "Error" + } + }, + "ConnectionStrings": { + "connection": "server=mysql.common;user=root;password=admin;database=Util.Application.EntityFrameworkCore.Test;port=3306;charset=utf8" + } +} \ No newline at end of file diff --git a/test/Util.Application.EntityFrameworkCore.PostgreSql.Tests.Integration/Startup.cs b/test/Util.Application.EntityFrameworkCore.PostgreSql.Tests.Integration/Startup.cs new file mode 100644 index 00000000..3f314a6c --- /dev/null +++ b/test/Util.Application.EntityFrameworkCore.PostgreSql.Tests.Integration/Startup.cs @@ -0,0 +1,56 @@ +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using Xunit.DependencyInjection; +using Xunit.DependencyInjection.Logging; +using Util.Aop; +using Util.Data.EntityFrameworkCore; +using Util.Dates; +using Util.Helpers; +using Util.Sessions; +using Util.Tests.Infrastructure; +using Util.Tests.UnitOfWorks; + +namespace Util.Applications { + /// + /// Æô¶¯ÅäÖà + /// + public class Startup { + /// + /// ÅäÖÃÖ÷»ú + /// + public void ConfigureHost( IHostBuilder hostBuilder ) { + hostBuilder.ConfigureDefaults( null ) + .AddUtil( options => { + Environment.SetDevelopment(); + options.UseUtc() + .UseAop() + .UsePgSqlUnitOfWork( Config.GetConnectionString( "connection" ) ); + } ); + } + + /// + /// ÅäÖ÷þÎñ + /// + public void ConfigureServices( IServiceCollection services ) { + services.AddSingleton(); + InitDatabase( services ); + } + + /// + /// ³õʼ»¯Êý¾ݿâ + /// + private void InitDatabase( IServiceCollection services ) { + var unitOfWork = services.BuildServiceProvider().GetService(); + unitOfWork.EnsureDeleted(); + unitOfWork.EnsureCreated(); + } + + /// + /// ÅäÖÃÈÕ־Ìṩ³ÌÐò + /// + public void Configure( ILoggerFactory loggerFactory, ITestOutputHelperAccessor accessor ) { + loggerFactory.AddProvider( new XunitTestOutputLoggerProvider( accessor, ( s, logLevel ) => logLevel >= LogLevel.Trace ) ); + } + } +} \ No newline at end of file diff --git a/test/Util.Application.EntityFrameworkCore.PostgreSql.Tests.Integration/Tests/CustomerQueryServiceTest.cs b/test/Util.Application.EntityFrameworkCore.PostgreSql.Tests.Integration/Tests/CustomerQueryServiceTest.cs new file mode 100644 index 00000000..f65ff4c7 --- /dev/null +++ b/test/Util.Application.EntityFrameworkCore.PostgreSql.Tests.Integration/Tests/CustomerQueryServiceTest.cs @@ -0,0 +1,215 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Util.Data.EntityFrameworkCore; +using Util.Tests.Fakes; +using Util.Tests.Infrastructure; +using Util.Tests.Models; +using Util.Tests.Queries; +using Util.Tests.Repositories; +using Util.Tests.Services; +using Util.Tests.UnitOfWorks; +using Xunit; +using Xunit.Abstractions; +using Xunit.DependencyInjection; + +namespace Util.Applications.Tests { + /// + /// 客户查询服务测试 + /// 说明: + /// 1. 测试查询服务操作 + /// + public class CustomerQueryServiceTest : TestBase { + + #region 测试初始化 + + /// + /// 测试输出 + /// + private readonly ITestOutputHelper _testOutputHelper; + /// + /// 客户仓储 + /// + private readonly ICustomerRepository _repository; + /// + /// 客户查询服务 + /// + private readonly ICustomerQueryService _service; + + /// + /// 测试初始化 + /// + public CustomerQueryServiceTest( ITestOutputHelperAccessor testOutputHelperAccessor, ICustomerRepository repository, + ICustomerQueryService service, ITestUnitOfWork unitOfWork ) : base( unitOfWork ) { + _testOutputHelper = testOutputHelperAccessor.Output; + _repository = repository; + _service = service; + } + + #endregion + + #region 辅助方法 + + /// + /// 添加客户 + /// + public async Task AddCustomerAsync() { + return ( await AddCustomersAsync( 1 ) ).First(); + } + + /// + /// 添加客户列表 + /// + /// 添加数量 + /// 客户姓名 + public async Task> AddCustomersAsync( int count = 2, string name = null ) { + var customers = CustomerFakeService.GetCustomers( count ); + customers.ForEach( customer => { + if ( name.IsEmpty() == false ) + customer.Name = name; + } ); + await _repository.AddAsync( customers ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + return customers.OrderBy( t => t.Code ).ToList(); + } + + /// + /// 打印更改跟踪调试信息 + /// + private void WriteTrackerDebug() { + _testOutputHelper.WriteLine( UnitOfWork.GetChangeTrackerDebugView() ); + } + + #endregion + + #region GetAllAsync + + /// + /// 测试获取全部实体 + /// + [Fact] + public async Task TestGetAllAsync() { + var entities = await AddCustomersAsync(); + var dtos = await _service.GetAllAsync(); + Assert.True( dtos.Count >= entities.Count ); + Assert.Equal( entities[0].Name, dtos.Find( t => t.Id == entities[0].Id.ToString() )?.Name ); + } + + #endregion + + #region GetByIdAsync + + /// + /// 测试通过标识获取实体 + /// + [Fact] + public async Task TestGetByIdAsync() { + var entity = await AddCustomerAsync(); + var dto = await _service.GetByIdAsync( entity.Id ); + Assert.Equal( entity.Name, dto.Name ); + } + + #endregion + + #region GetByIdsAsync + + /// + /// 测试通过标识列表获取实体列表 + /// + [Fact] + public async Task TestGetByIdsAsync() { + var entities = await AddCustomersAsync(); + var dtos = await _service.GetByIdsAsync( entities.Select( t => t.Id ).Join() ); + Assert.Equal( entities.Count, dtos.Count ); + Assert.Equal( entities[0].Name, dtos.Find( t => t.Id == entities[0].Id.ToString() )?.Name ); + } + + #endregion + + #region QueryAsync + + /// + /// 测试查询 + /// + [Fact] + public async Task TestQueryAsync() { + //常量 + var name = "TestQueryAsync"; + + //添加客户实体列表 + await AddCustomersAsync(); + var entities = await AddCustomersAsync( 5, name ); + + //查询 + var query = new CustomerQuery { + Name = name, + Order = "Code" + }; + var dtos = await _service.QueryAsync( query ); + WriteTrackerDebug(); + Assert.True( dtos.Count == entities.Count ); + Assert.Equal( entities[0].Id.ToString(), dtos[0].Id ); + Assert.Equal( entities[4].Id.ToString(), dtos[4].Id ); + } + + #endregion + + #region PageQueryAsync + + /// + /// 测试分页查询 - 第1页 + /// + [Fact] + public async Task TestPageQueryAsync_1() { + //常量 + var name = "TestPageQueryAsync_1"; + + //添加客户实体列表 + await AddCustomersAsync(); + var entities = await AddCustomersAsync( 5, name ); + + //查询 + var query = new CustomerQuery { + PageSize = 3, + Page = 1, + Name = name, + Order = "Code" + }; + var dtos = await _service.PageQueryAsync( query ); + WriteTrackerDebug(); + Assert.Equal( 3, dtos.Data.Count ); + Assert.Equal( entities[0].Id.ToString(), dtos.Data[0].Id ); + Assert.Equal( entities[1].Id.ToString(), dtos.Data[1].Id ); + Assert.Equal( entities[2].Id.ToString(), dtos.Data[2].Id ); + } + + /// + /// 测试分页查询 - 第2页 + /// + [Fact] + public async Task TestPageQueryAsync_2() { + //常量 + var name = "TestPageQueryAsync_2"; + + //添加客户实体列表 + await AddCustomersAsync(); + var entities = await AddCustomersAsync( 5, name ); + + //查询 + var query = new CustomerQuery { + PageSize = 3, + Page = 2, + Name = name, + Order = "Code" + }; + var dtos = await _service.PageQueryAsync( query ); + WriteTrackerDebug(); + Assert.Equal( 2, dtos.Data.Count ); + Assert.Equal( entities[3].Id.ToString(), dtos.Data[0].Id ); + Assert.Equal( entities[4].Id.ToString(), dtos.Data[1].Id ); + } + + #endregion + } +} diff --git a/test/Util.Application.EntityFrameworkCore.PostgreSql.Tests.Integration/Tests/CustomerServiceTest.cs b/test/Util.Application.EntityFrameworkCore.PostgreSql.Tests.Integration/Tests/CustomerServiceTest.cs new file mode 100644 index 00000000..2d5a475b --- /dev/null +++ b/test/Util.Application.EntityFrameworkCore.PostgreSql.Tests.Integration/Tests/CustomerServiceTest.cs @@ -0,0 +1,40 @@ +using System.Threading.Tasks; +using Util.Tests.Fakes; +using Util.Tests.Services; +using Xunit; + +namespace Util.Applications.Tests { + /// + /// 客户服务测试 + /// + public class CustomerServiceTest { + /// + /// 客户服务 + /// + private readonly ICustomerService _service; + + /// + /// 测试初始化 + /// + public CustomerServiceTest( ICustomerService service ) { + _service = service; + } + + /// + /// 测试创建 + /// + [Fact] + public async Task TestCreateAsync() { + //创建 + var dto = CustomerFakeService.GetCustomerDto(); + var id = await _service.CreateAsync( dto ); + + //验证 + var result = await _service.GetByIdAsync( id ); + Assert.NotNull( result ); + Assert.Equal( id, result.Id ); + Assert.Equal( dto.Code, result.Code ); + Assert.Equal( dto.Name, result.Name ); + } + } +} \ No newline at end of file diff --git a/test/Util.Application.EntityFrameworkCore.PostgreSql.Tests.Integration/Tests/ProductServiceTest.cs b/test/Util.Application.EntityFrameworkCore.PostgreSql.Tests.Integration/Tests/ProductServiceTest.cs new file mode 100644 index 00000000..c5665ec1 --- /dev/null +++ b/test/Util.Application.EntityFrameworkCore.PostgreSql.Tests.Integration/Tests/ProductServiceTest.cs @@ -0,0 +1,217 @@ +using System.Threading.Tasks; +using Util.Tests.Dtos; +using Util.Tests.Fakes; +using Util.Tests.Models; +using Util.Tests.Services; +using Xunit; + +namespace Util.Applications.Tests { + /// + /// 产品服务测试 + /// + public class ProductServiceTest { + + #region 测试初始化 + + /// + /// 产品服务 + /// + private readonly IProductService _service; + + /// + /// 测试初始化 + /// + public ProductServiceTest( IProductService service ) { + _service = service; + } + + #endregion + + #region CreateAsync + + /// + /// 测试创建 + /// + [Fact] + public async Task TestCreateAsync() { + //创建 + var dto = ProductFakeService.GetProductDto(); + var id = await _service.CreateAsync( dto ); + + //验证 + var result = await _service.GetByIdAsync( id ); + Assert.NotNull( result ); + Assert.Equal( id, result.Id ); + Assert.Equal( dto.Code, result.Code ); + Assert.Equal( dto.Name, result.Name ); + } + + #endregion + + #region UpdateAsync + + /// + /// 测试修改 + /// + [Fact] + public async Task TestUpdateAsync() { + //常量 + var code = "TestUpdateAsync"; + + //创建 + var dto = ProductFakeService.GetProductDto(); + var id = await _service.CreateAsync( dto ); + + //修改 + var updateDto = await _service.GetByIdAsync( id ); + updateDto.Code = code; + await _service.UpdateAsync( updateDto ); + + //验证 + var result = await _service.GetByIdAsync( id ); + Assert.Equal( code, result.Code ); + } + + #endregion + + #region DeleteAsync + + /// + /// 测试删除 + /// + [Fact] + public async Task TestDeleteAsync() { + //创建 + var dto = ProductFakeService.GetProductDto(); + var id = await _service.CreateAsync( dto ); + + //删除 + await _service.DeleteAsync( id ); + + //验证 + var result = await _service.GetByIdAsync( id ); + Assert.Null( result ); + } + + #endregion + + #region ExtraProperties + + /// + /// 测试扩展属性 - 添加简单扩展属性 + /// + [Fact] + public async Task TestExtraProperties_1() { + //常量 + var value = "TestExtraProperties_1"; + + //创建 + var dto = new ProductDto { TestProperty1 = value }; + var id = await _service.CreateAsync( dto ); + + //验证 + var result = await _service.GetByIdAsync( id ); + Assert.Equal( value, result.TestProperty1 ); + } + + /// + /// 测试扩展属性 - 修改简单扩展属性 + /// + [Fact] + public async Task TestExtraProperties_2() { + //常量 + var oldValue = "TestExtraProperties_2_1"; + var newValue = "TestExtraProperties_2_2"; + + //添加实体 + var dto = new ProductDto { TestProperty1 = oldValue }; + var id = await _service.CreateAsync( dto ); + + //验证 + var oldDto = await _service.GetByIdAsync( id ); + Assert.Equal( oldValue, oldDto.TestProperty1 ); + + //修改实体 + oldDto.TestProperty1 = newValue; + await _service.UpdateAsync( oldDto ); + + //验证 + var result = await _service.GetByIdAsync( id ); + Assert.Equal( newValue, result.TestProperty1 ); + } + + /// + /// 测试扩展属性 - 添加复杂扩展属性 + /// + [Fact] + public async Task TestExtraProperties_3() { + //常量 + var code = 2; + var name = "TestExtraProperties_3"; + + //添加实体 + var dto = new ProductDto { TestProperty2 = { Code = code, Name = name } }; + var id = await _service.CreateAsync( dto ); + + //验证 + var result = await _service.GetByIdAsync( id ); + Assert.Equal( code, result.TestProperty2.Code ); + Assert.Equal( name, result.TestProperty2.Name ); + } + + /// + /// 测试扩展属性 - 修改复杂扩展属性 + /// + [Fact] + public async Task TestExtraProperties_4() { + //常量 + var code = 2; + var oldName = "TestExtraProperties_4_1"; + var newName = "TestExtraProperties_4_2"; + + //添加实体 + var dto = new ProductDto { TestProperty2 = { Code = code, Name = oldName } }; + var id = await _service.CreateAsync( dto ); + + //验证 + var oldDto = await _service.GetByIdAsync( id ); + Assert.Equal( code, oldDto.TestProperty2.Code ); + Assert.Equal( oldName, oldDto.TestProperty2.Name ); + + //修改实体 + oldDto.TestProperty2.Name = newName; + await _service.UpdateAsync( oldDto ); + + //验证 + var result = await _service.GetByIdAsync( id ); + Assert.Equal( newName, result.TestProperty2.Name ); + } + + /// + /// 测试扩展属性 - 添加对象集合扩展属性 + /// + [Fact] + public async Task TestExtraProperties_5() { + //常量 + var code = 1; + var name1 = "TestExtraProperties_5_1"; + var name2 = "TestExtraProperties_5_2"; + + //添加实体 + var dto = new ProductDto(); + dto.TestProperties.Add( new ProductItem2 { Code = code, Name = name1 } ); + dto.TestProperties.Add( new ProductItem2 { Code = code, Name = name2 } ); + var id = await _service.CreateAsync( dto ); + + //验证 + var result = await _service.GetByIdAsync( id ); + Assert.Equal( 2, result.TestProperties.Count ); + Assert.Equal( code, result.TestProperties[0].Code ); + Assert.Equal( name1, result.TestProperties[0].Name ); + Assert.Equal( code, result.TestProperties[1].Code ); + Assert.Equal( name2, result.TestProperties[1].Name ); + } + + #endregion + } +} \ No newline at end of file diff --git a/test/Util.Application.EntityFrameworkCore.PostgreSql.Tests.Integration/Util.Application.EntityFrameworkCore.PostgreSql.Tests.Integration.csproj b/test/Util.Application.EntityFrameworkCore.PostgreSql.Tests.Integration/Util.Application.EntityFrameworkCore.PostgreSql.Tests.Integration.csproj new file mode 100644 index 00000000..06bb2a89 --- /dev/null +++ b/test/Util.Application.EntityFrameworkCore.PostgreSql.Tests.Integration/Util.Application.EntityFrameworkCore.PostgreSql.Tests.Integration.csproj @@ -0,0 +1,39 @@ + + + + $(NetTargetFramework) + false + Util.Applications + Util.Applications.Startup + + + + + Always + + + Always + + + + + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + \ No newline at end of file diff --git a/test/Util.Application.EntityFrameworkCore.PostgreSql.Tests.Integration/appsettings.Development.json b/test/Util.Application.EntityFrameworkCore.PostgreSql.Tests.Integration/appsettings.Development.json new file mode 100644 index 00000000..1ca55f6e --- /dev/null +++ b/test/Util.Application.EntityFrameworkCore.PostgreSql.Tests.Integration/appsettings.Development.json @@ -0,0 +1,11 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Trace", + "Microsoft": "Trace" + } + }, + "ConnectionStrings": { + "connection": "server=192.168.31.158;User Id=admin;password=admin;database=Util.Application.EntityFrameworkCore.Test" + } +} \ No newline at end of file diff --git a/test/Util.Application.EntityFrameworkCore.PostgreSql.Tests.Integration/appsettings.json b/test/Util.Application.EntityFrameworkCore.PostgreSql.Tests.Integration/appsettings.json new file mode 100644 index 00000000..395b3db1 --- /dev/null +++ b/test/Util.Application.EntityFrameworkCore.PostgreSql.Tests.Integration/appsettings.json @@ -0,0 +1,11 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Error", + "Microsoft": "Error" + } + }, + "ConnectionStrings": { + "connection": "server=postgresql.common;User Id=admin;password=admin;database=Util.Application.EntityFrameworkCore.Test" + } +} \ No newline at end of file diff --git a/test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/Models/Customer.cs b/test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/Models/Customer.cs deleted file mode 100644 index 1db49788..00000000 --- a/test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/Models/Customer.cs +++ /dev/null @@ -1,116 +0,0 @@ -using System; -using System.ComponentModel; -using System.ComponentModel.DataAnnotations; -using Util.Domain; -using Util.Domain.Biz.Enums; -using Util.Domain.Entities; - -namespace Util.Applications.Models { - /// - /// 客户 - /// - [Description( "客户" )] - public class Customer : AggregateRoot,IDelete{ - /// - /// 初始化客户 - /// - public Customer() : this( 0 ) { - } - - /// - /// 初始化客户 - /// - /// 客户标识 - public Customer( int id ) : base( id ) { - } - - /// - /// 编码 - /// - [Description( "编码" )] - [MaxLength( 100 )] - public string Code { get; set; } - /// - /// 姓名 - /// - [Description( "姓名" )] - [MaxLength( 200 )] - public string Name { get; set; } - /// - /// 昵称 - /// - [Description( "昵称" )] - [MaxLength( 50 )] - public string Nickname { get; set; } - /// - /// 性别 - /// - [Description( "性别" )] - public Gender? Gender { get; set; } - /// - /// 出生日期 - /// - [Description( "出生日期" )] - public DateTime? Birthday { get; set; } - /// - /// 民族 - /// - [Description( "民族" )] - public Nation? Nation { get; set; } - /// - /// 手机号 - /// - [Description( "手机号" )] - [MaxLength( 50 )] - public string Phone { get; set; } - /// - /// 电子邮件 - /// - [Description( "电子邮件" )] - [MaxLength( 500 )] - public string Email { get; set; } - /// - /// 创建时间 - /// - [Description( "创建时间" )] - public DateTime? CreationTime { get; set; } - /// - /// 创建人 - /// - [Description( "创建人" )] - public Guid? CreatorId { get; set; } - /// - /// 最后修改时间 - /// - [Description( "最后修改时间" )] - public DateTime? LastModificationTime { get; set; } - /// - /// 最后修改人 - /// - [Description( "最后修改人" )] - public Guid? LastModifierId { get; set; } - /// - /// 是否删除 - /// - [Description( "是否删除" )] - public bool IsDeleted { get; set; } - - /// - /// 添加变更列表 - /// - protected override void AddChanges( Customer other ) { - AddChange( t => t.Code, other.Code ); - AddChange( t => t.Name, other.Name ); - AddChange( t => t.Nickname, other.Nickname ); - AddChange( t => t.Gender, other.Gender ); - AddChange( t => t.Birthday, other.Birthday ); - AddChange( t => t.Nation, other.Nation ); - AddChange( t => t.Phone, other.Phone ); - AddChange( t => t.Email, other.Email ); - AddChange( t => t.CreationTime, other.CreationTime ); - AddChange( t => t.CreatorId, other.CreatorId ); - AddChange( t => t.LastModificationTime, other.LastModificationTime ); - AddChange( t => t.LastModifierId, other.LastModifierId ); - } - } -} \ No newline at end of file diff --git a/test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/Models/Product.cs b/test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/Models/Product.cs deleted file mode 100644 index 6040c8c5..00000000 --- a/test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/Models/Product.cs +++ /dev/null @@ -1,127 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.ComponentModel.DataAnnotations; -using System.ComponentModel.DataAnnotations.Schema; -using Util.Domain; -using Util.Domain.Auditing; -using Util.Domain.Entities; -using Util.Domain.Extending; - -namespace Util.Applications.Models { - /// - /// 产品 - /// - [Description( "产品" )] - public class Product : AggregateRoot, IDelete, IAudited, IExtraProperties { - /// - /// 初始化产品 - /// - public Product() : this( Guid.Empty ) { - } - - /// - /// 初始化产品 - /// - /// 产品标识 - public Product( Guid id ) : base( id ) { - } - - /// - /// 产品编码 - /// - [Description( "产品编码" )] - [MaxLength( 50 )] - public string Code { get; set; } - /// - /// 产品名称 - /// - [Description( "产品名称" )] - [MaxLength( 500 )] - public string Name { get; set; } - /// - /// 价格 - /// - [Description( "价格" )] - public decimal Price { get; set; } - /// - /// 描述 - /// - [Description( "描述" )] - public string Description { get; set; } - /// - /// 启用 - /// - [Description( "启用" )] - public bool Enabled { get; set; } - /// - /// 创建时间 - /// - [Description( "创建时间" )] - public DateTime? CreationTime { get; set; } - /// - /// 创建人 - /// - [Description( "创建人" )] - public Guid? CreatorId { get; set; } - /// - /// 最后修改时间 - /// - [Description( "最后修改时间" )] - public DateTime? LastModificationTime { get; set; } - /// - /// 最后修改人 - /// - [Description( "最后修改人" )] - public Guid? LastModifierId { get; set; } - /// - /// 是否删除 - /// - [Description( "是否删除" )] - public bool IsDeleted { get; set; } - - /// - /// 简单扩展属性 - /// - [NotMapped] - public string TestProperty1 { - get => ExtraProperties.GetProperty( nameof( TestProperty1 ) ); - set => ExtraProperties.SetProperty( nameof( TestProperty1 ), value ); - } - - private readonly ExtraProperty _property2 = new( nameof( TestProperty2 ) ); - /// - /// 对象扩展属性 - /// - [NotMapped] - public ProductItem TestProperty2 { - get => _property2.GetProperty( ExtraProperties ); - set => _property2.SetProperty( ExtraProperties, value ); - } - - private readonly ExtraProperty> _properties = new( nameof( TestProperties ) ); - /// - /// 对象集合扩展属性 - /// - [NotMapped] - public List TestProperties { - get => _properties.GetProperty( ExtraProperties ); - set => _properties.SetProperty( ExtraProperties, value ); - } - - /// - /// 添加变更列表 - /// - protected override void AddChanges( Product other ) { - AddChange( t => t.Code, other.Code ); - AddChange( t => t.Name, other.Name ); - AddChange( t => t.Price, other.Price ); - AddChange( t => t.Description, other.Description ); - AddChange( t => t.Enabled, other.Enabled ); - AddChange( t => t.CreationTime, other.CreationTime ); - AddChange( t => t.CreatorId, other.CreatorId ); - AddChange( t => t.LastModificationTime, other.LastModificationTime ); - AddChange( t => t.LastModifierId, other.LastModifierId ); - } - } -} \ No newline at end of file diff --git a/test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/Models/ProductItem.cs b/test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/Models/ProductItem.cs deleted file mode 100644 index 8a0ff683..00000000 --- a/test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/Models/ProductItem.cs +++ /dev/null @@ -1,15 +0,0 @@ -namespace Util.Applications.Models { - /// - /// 用于测试扩展属性 - /// - public class ProductItem { - /// - /// 编码 - /// - public int Code { get; set; } - /// - /// 名称 - /// - public string Name { get; set; } - } -} diff --git a/test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/Models/ProductItem2.cs b/test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/Models/ProductItem2.cs deleted file mode 100644 index 97a29162..00000000 --- a/test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/Models/ProductItem2.cs +++ /dev/null @@ -1,15 +0,0 @@ -namespace Util.Applications.Models { - /// - /// 用于测试扩展属性2 - /// - public class ProductItem2 { - /// - /// 编码 - /// - public int Code { get; set; } - /// - /// 名称 - /// - public string Name { get; set; } - } -} diff --git a/test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/Repositories/ICustomerRepository.cs b/test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/Repositories/ICustomerRepository.cs deleted file mode 100644 index 522b0901..00000000 --- a/test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/Repositories/ICustomerRepository.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Util.Applications.Models; -using Util.Domain.Repositories; - -namespace Util.Applications.Repositories { - /// - /// 客户仓储 - /// - public interface ICustomerRepository : IRepository { - } -} \ No newline at end of file diff --git a/test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/Services/CustomerService.cs b/test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/Services/CustomerService.cs deleted file mode 100644 index bf5e90be..00000000 --- a/test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/Services/CustomerService.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System; -using System.Linq; -using Util.Applications.Dtos; -using Util.Applications.Models; -using Util.Applications.Queries; -using Util.Applications.Repositories; -using Util.Applications.UnitOfWorks; - -namespace Util.Applications.Services { - /// - /// 客户服务 - /// - public class CustomerService : CrudServiceBase, ICustomerService { - /// - /// 初始化客户服务 - /// - /// 服务提供器 - /// 工作单元 - /// 仓储 - public CustomerService( IServiceProvider serviceProvider,ISqlServerUnitOfWork unitOfWork, ICustomerRepository repository ) : base( serviceProvider,unitOfWork, repository ) { - } - } -} \ No newline at end of file diff --git a/test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/Services/ICustomerService.cs b/test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/Services/ICustomerService.cs deleted file mode 100644 index 58431fe0..00000000 --- a/test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/Services/ICustomerService.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Util.Applications.Dtos; -using Util.Applications.Queries; - -namespace Util.Applications.Services { - /// - /// 客户服务 - /// - public interface ICustomerService : ICrudService { - } -} \ No newline at end of file diff --git a/test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/Services/IProductService.cs b/test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/Services/IProductService.cs deleted file mode 100644 index ac9fc8e6..00000000 --- a/test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/Services/IProductService.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Util.Applications.Dtos; -using Util.Applications.Queries; - -namespace Util.Applications.Services { - /// - /// 产品服务 - /// - public interface IProductService : ICrudService { - } -} \ No newline at end of file diff --git a/test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/Startup.cs b/test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/Startup.cs index e20bb86d..c4073e86 100644 --- a/test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/Startup.cs +++ b/test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/Startup.cs @@ -1,12 +1,14 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; -using Util.Aop; -using Util.Applications.UnitOfWorks; -using Util.Data.EntityFrameworkCore; -using Util.Helpers; using Xunit.DependencyInjection; using Xunit.DependencyInjection.Logging; +using Util.Aop; +using Util.Data.EntityFrameworkCore; +using Util.Helpers; +using Util.Sessions; +using Util.Tests.Infrastructure; +using Util.Tests.UnitOfWorks; namespace Util.Applications { /// @@ -17,16 +19,19 @@ namespace Util.Applications { /// ÅäÖÃÖ÷»ú /// public void ConfigureHost( IHostBuilder hostBuilder ) { - hostBuilder.ConfigureDefaults( null ).UseEnvironment( "Development" ).EnableAop(); + hostBuilder.ConfigureDefaults( null ) + .AddUtil( options => { + Environment.SetDevelopment(); + options.UseAop() + .UseSqlServerUnitOfWork( Config.GetConnectionString( "connection" ) ); + } ); } /// /// ÅäÖ÷þÎñ /// public void ConfigureServices( IServiceCollection services ) { - services.AddUtil( options => { - options.UseSqlServerUnitOfWork( Config.GetConnectionString( "connection" ) ); - } ); + services.AddSingleton(); InitDatabase( services ); } @@ -34,7 +39,7 @@ namespace Util.Applications { /// ³õʼ»¯Êý¾ݿâ /// private void InitDatabase( IServiceCollection services ) { - var unitOfWork = services.BuildServiceProvider().GetService(); + var unitOfWork = services.BuildServiceProvider().GetService(); unitOfWork.EnsureDeleted(); unitOfWork.EnsureCreated(); } @@ -46,4 +51,4 @@ namespace Util.Applications { loggerFactory.AddProvider( new XunitTestOutputLoggerProvider( accessor, ( s, logLevel ) => logLevel >= LogLevel.Trace ) ); } } -} +} \ No newline at end of file diff --git a/test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/Tests/CustomerQueryServiceTest.cs b/test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/Tests/CustomerQueryServiceTest.cs index ef520e37..f65ff4c7 100644 --- a/test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/Tests/CustomerQueryServiceTest.cs +++ b/test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/Tests/CustomerQueryServiceTest.cs @@ -1,14 +1,14 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; -using Util.Applications.Fakes; -using Util.Applications.Infrastructure; -using Util.Applications.Models; -using Util.Applications.Queries; -using Util.Applications.Repositories; -using Util.Applications.Services; -using Util.Applications.UnitOfWorks; using Util.Data.EntityFrameworkCore; +using Util.Tests.Fakes; +using Util.Tests.Infrastructure; +using Util.Tests.Models; +using Util.Tests.Queries; +using Util.Tests.Repositories; +using Util.Tests.Services; +using Util.Tests.UnitOfWorks; using Xunit; using Xunit.Abstractions; using Xunit.DependencyInjection; @@ -40,7 +40,7 @@ namespace Util.Applications.Tests { /// 测试初始化 /// public CustomerQueryServiceTest( ITestOutputHelperAccessor testOutputHelperAccessor, ICustomerRepository repository, - ICustomerQueryService service, ISqlServerUnitOfWork unitOfWork ) : base( unitOfWork ) { + ICustomerQueryService service, ITestUnitOfWork unitOfWork ) : base( unitOfWork ) { _testOutputHelper = testOutputHelperAccessor.Output; _repository = repository; _service = service; @@ -50,13 +50,6 @@ namespace Util.Applications.Tests { #region 辅助方法 - /// - /// 添加客户 - /// - public Customer AddCustomer() { - return AddCustomers( 1 ).First(); - } - /// /// 添加客户 /// @@ -64,23 +57,6 @@ namespace Util.Applications.Tests { return ( await AddCustomersAsync( 1 ) ).First(); } - /// - /// 添加客户列表 - /// - /// 添加数量 - /// 客户姓名 - public List AddCustomers( int count = 2, string name = null ) { - var customers = CustomerFakeService.GetCustomers( count ); - customers.ForEach( customer => { - if ( name.IsEmpty() == false ) - customer.Name = name; - } ); - _repository.Add( customers ); - UnitOfWork.Commit(); - UnitOfWork.ClearCache(); - return customers.OrderBy( t => t.Code ).ToList(); - } - /// /// 添加客户列表 /// diff --git a/test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/Tests/CustomerServiceTest.cs b/test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/Tests/CustomerServiceTest.cs index 92b26f45..2d5a475b 100644 --- a/test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/Tests/CustomerServiceTest.cs +++ b/test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/Tests/CustomerServiceTest.cs @@ -1,6 +1,6 @@ using System.Threading.Tasks; -using Util.Applications.Fakes; -using Util.Applications.Services; +using Util.Tests.Fakes; +using Util.Tests.Services; using Xunit; namespace Util.Applications.Tests { diff --git a/test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/Tests/ProductServiceTest.cs b/test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/Tests/ProductServiceTest.cs index 39bc6cc3..c5665ec1 100644 --- a/test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/Tests/ProductServiceTest.cs +++ b/test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/Tests/ProductServiceTest.cs @@ -1,8 +1,8 @@ using System.Threading.Tasks; -using Util.Applications.Dtos; -using Util.Applications.Fakes; -using Util.Applications.Models; -using Util.Applications.Services; +using Util.Tests.Dtos; +using Util.Tests.Fakes; +using Util.Tests.Models; +using Util.Tests.Services; using Xunit; namespace Util.Applications.Tests { @@ -212,44 +212,6 @@ namespace Util.Applications.Tests { Assert.Equal( name2, result.TestProperties[1].Name ); } - /// - /// 测试扩展属性 - 修改对象集合扩展属性 - /// - [Fact] - public async Task TestExtraProperties_6() { - //常量 - var code = 1; - var oldName = "TestExtraProperties_6_1"; - var newName = "TestExtraProperties_6_2"; - var name3 = "TestExtraProperties_6_3"; - - //添加实体 - var dto = new ProductDto(); - dto.TestProperties.Add( new ProductItem2 { Code = code, Name = oldName } ); - dto.TestProperties.Add( new ProductItem2 { Code = code, Name = oldName } ); - var id = await _service.CreateAsync( dto ); - - //验证 - var oldDto = await _service.GetByIdAsync( id ); - Assert.Equal( 2, oldDto.TestProperties.Count ); - - //修改实体 - oldDto.TestProperties[0].Name = newName; - oldDto.TestProperties[1].Name = newName; - oldDto.TestProperties.Add( new ProductItem2 { Code = code, Name = name3 } ); - await _service.UpdateAsync( oldDto ); - - //验证 - var result = await _service.GetByIdAsync( id ); - Assert.Equal( 3, result.TestProperties.Count ); - Assert.Equal( code, result.TestProperties[0].Code ); - Assert.Equal( newName, result.TestProperties[0].Name ); - Assert.Equal( code, result.TestProperties[1].Code ); - Assert.Equal( newName, result.TestProperties[1].Name ); - Assert.Equal( code, result.TestProperties[2].Code ); - Assert.Equal( name3, result.TestProperties[2].Name ); - } - #endregion } } \ No newline at end of file diff --git a/test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/UnitOfWorks/ISqlServerUnitOfWork.cs b/test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/UnitOfWorks/ISqlServerUnitOfWork.cs deleted file mode 100644 index 22dbb0d4..00000000 --- a/test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/UnitOfWorks/ISqlServerUnitOfWork.cs +++ /dev/null @@ -1,9 +0,0 @@ -using Util.Data; - -namespace Util.Applications.UnitOfWorks { - /// - /// 工作单元 - /// - public interface ISqlServerUnitOfWork : IUnitOfWork { - } -} \ No newline at end of file diff --git a/test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/UnitOfWorks/SqlServerUnitOfWork.cs b/test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/UnitOfWorks/SqlServerUnitOfWork.cs deleted file mode 100644 index 0ee18207..00000000 --- a/test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/UnitOfWorks/SqlServerUnitOfWork.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System; -using Microsoft.EntityFrameworkCore; -using Util.Data.EntityFrameworkCore; - -namespace Util.Applications.UnitOfWorks { - /// - /// SqlServer工作单元 - /// - public class SqlServerUnitOfWork : SqlServerUnitOfWorkBase, ISqlServerUnitOfWork { - /// - /// 初始化工作单元 - /// - /// 服务提供器 - /// 配置项 - public SqlServerUnitOfWork( IServiceProvider serviceProvider,DbContextOptions options ) : base( serviceProvider, options ) { - } - } -} \ No newline at end of file diff --git a/test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration.csproj b/test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration.csproj index 4e9356cb..cac3e54b 100644 --- a/test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration.csproj +++ b/test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration.csproj @@ -7,39 +7,33 @@ Util.Applications.Startup - - - + + + Always + + + Always + + - - Always - true - PreserveNewest - - - - - - - - - + + + + - + runtime; build; native; contentfiles; analyzers; buildtransitive all - + runtime; build; native; contentfiles; analyzers; buildtransitive all - - - + diff --git a/test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/appsettings.Development.json b/test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/appsettings.Development.json new file mode 100644 index 00000000..f6264891 --- /dev/null +++ b/test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/appsettings.Development.json @@ -0,0 +1,11 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Trace", + "Microsoft": "Trace" + } + }, + "ConnectionStrings": { + "connection": "Server=.\\sql2014;Database=Util.Application.EntityFrameworkCore.Test;uid=sa;pwd=sa;MultipleActiveResultSets=true" + } +} diff --git a/test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/appsettings.json b/test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/appsettings.json index b403de6d..c0b8f396 100644 --- a/test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/appsettings.json +++ b/test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/appsettings.json @@ -1,5 +1,11 @@ { + "Logging": { + "LogLevel": { + "Default": "Error", + "Microsoft": "Error" + } + }, "ConnectionStrings": { - "connection": "Server=.\\sql2014;Database=Util.Application.Test;uid=sa;pwd=sa;MultipleActiveResultSets=true" + "connection": "Server=192.168.31.123\\sql2014;Database=Util.Application.EntityFrameworkCore.Test;uid=sa;pwd=sa;MultipleActiveResultSets=true;" } } \ No newline at end of file diff --git a/test/Util.Application.Tests/Util.Application.Tests.csproj b/test/Util.Application.Tests/Util.Application.Tests.csproj index 3ae173a4..0d17ae20 100644 --- a/test/Util.Application.Tests/Util.Application.Tests.csproj +++ b/test/Util.Application.Tests/Util.Application.Tests.csproj @@ -14,14 +14,14 @@ - - + + - + runtime; build; native; contentfiles; analyzers; buildtransitive all - + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/test/Util.Application.WebApi.MySql.Tests.Integration/Properties/launchSettings.json b/test/Util.Application.WebApi.MySql.Tests.Integration/Properties/launchSettings.json new file mode 100644 index 00000000..e1f3c401 --- /dev/null +++ b/test/Util.Application.WebApi.MySql.Tests.Integration/Properties/launchSettings.json @@ -0,0 +1,12 @@ +{ + "profiles": { + "Util.Application.WebApi.MySql.Tests.Integration": { + "commandName": "Project", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "applicationUrl": "https://localhost:65194;http://localhost:65195" + } + } +} \ No newline at end of file diff --git a/test/Util.Application.WebApi.Tests.Integration/Startup.cs b/test/Util.Application.WebApi.MySql.Tests.Integration/Startup.cs similarity index 78% rename from test/Util.Application.WebApi.Tests.Integration/Startup.cs rename to test/Util.Application.WebApi.MySql.Tests.Integration/Startup.cs index a0408aa1..efa5cefc 100644 --- a/test/Util.Application.WebApi.Tests.Integration/Startup.cs +++ b/test/Util.Application.WebApi.MySql.Tests.Integration/Startup.cs @@ -4,10 +4,11 @@ using Microsoft.AspNetCore.TestHost; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; -using Util.Applications.UnitOfWorks; +using Util.Aop; using Util.Data.EntityFrameworkCore; using Util.Helpers; using Util.Http; +using Util.Tests.UnitOfWorks; using Xunit.DependencyInjection; using Xunit.DependencyInjection.Logging; @@ -20,16 +21,21 @@ namespace Util.Applications { /// ÅäÖÃÖ÷»ú /// public void ConfigureHost( IHostBuilder hostBuilder ) { - hostBuilder.ConfigureDefaults( null ).ConfigureWebHostDefaults( webHostBuilder => { - webHostBuilder.UseTestServer() - .UseEnvironment( "Development" ) + hostBuilder.ConfigureDefaults( null ) + .ConfigureWebHostDefaults( webHostBuilder => { + webHostBuilder.UseTestServer() .Configure( t => { t.UseRouting(); t.UseEndpoints( endpoints => { endpoints.MapControllers(); } ); } ); - } ); + } ) + .AddUtil( options => { + Environment.SetDevelopment(); + options.UseAop() + .UseMySqlUnitOfWork( Config.GetConnectionString( "connection" ) ); + } ); } /// @@ -42,9 +48,6 @@ namespace Util.Applications { client.SetHttpClient( t.GetService().GetTestClient() ); return client; } ); - services.AddUtil( options => { - options.UseSqlServerUnitOfWork( Config.GetConnectionString( "connection" ) ); - } ); InitDatabase( services ); } @@ -52,7 +55,7 @@ namespace Util.Applications { /// ³õʼ»¯Êý¾ݿâ /// private void InitDatabase( IServiceCollection services ) { - var unitOfWork = services.BuildServiceProvider().GetService(); + var unitOfWork = services.BuildServiceProvider().GetService(); unitOfWork.EnsureDeleted(); unitOfWork.EnsureCreated(); } diff --git a/test/Util.Application.WebApi.Tests.Integration/Tests/CustomerControllerTest.cs b/test/Util.Application.WebApi.MySql.Tests.Integration/Tests/CustomerControllerTest.cs similarity index 88% rename from test/Util.Application.WebApi.Tests.Integration/Tests/CustomerControllerTest.cs rename to test/Util.Application.WebApi.MySql.Tests.Integration/Tests/CustomerControllerTest.cs index 26bfab59..a5095b48 100644 --- a/test/Util.Application.WebApi.Tests.Integration/Tests/CustomerControllerTest.cs +++ b/test/Util.Application.WebApi.MySql.Tests.Integration/Tests/CustomerControllerTest.cs @@ -1,14 +1,14 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; -using Util.Applications.Dtos; -using Util.Applications.Fakes; -using Util.Applications.Infrastructure; -using Util.Applications.Queries; -using Util.Applications.Services; using Util.Data; using Util.Helpers; using Util.Http; +using Util.Tests.Dtos; +using Util.Tests.Fakes; +using Util.Tests.Infrastructure; +using Util.Tests.Queries; +using Util.Tests.Services; using Xunit; using Xunit.Abstractions; using Xunit.DependencyInjection; @@ -17,7 +17,7 @@ namespace Util.Applications.Tests { /// /// 客户控制器测试 /// - public class CustomerControllerTest : TestBase { + public class CustomerControllerTest : ControllerTestBase { /// /// 输出工具 /// @@ -90,8 +90,8 @@ namespace Util.Applications.Tests { var name = "TestPageQueryAsync"; var url = "/api/customer"; - //创建5个实体,前4个设置了名称,并使用Code属性排序 - var dtos = CustomerFakeService.GetCustomerDtos( 5 ).OrderBy( t => t.Code ).ToList(); + //创建5个实体,前4个设置了名称,并使用Id属性排序 + var dtos = CustomerFakeService.GetCustomerDtos( 5 ).OrderBy( t => t.Id ).ToList(); for ( int i = 0; i < 4; i++ ) { dtos[i].Name = name; } @@ -99,8 +99,8 @@ namespace Util.Applications.Tests { await _service.CreateAsync( dto ); } - //使用名称查询第二页,每页2行,并使用Code属性排序 - var query = new CustomerQuery { Page = 2, PageSize = 2, Name = name,Order = "Code" }; + //使用名称查询第二页,每页2行,并使用Id属性排序 + var query = new CustomerQuery { Page = 2, PageSize = 2, Name = name,Order = "Id" }; var result = await GetAsync>( url, query ); //验证 diff --git a/test/Util.Application.WebApi.Tests.Integration/Tests/ProductControllerTest.cs b/test/Util.Application.WebApi.MySql.Tests.Integration/Tests/ProductControllerTest.cs similarity index 95% rename from test/Util.Application.WebApi.Tests.Integration/Tests/ProductControllerTest.cs rename to test/Util.Application.WebApi.MySql.Tests.Integration/Tests/ProductControllerTest.cs index 5d25be24..1a18932d 100644 --- a/test/Util.Application.WebApi.Tests.Integration/Tests/ProductControllerTest.cs +++ b/test/Util.Application.WebApi.MySql.Tests.Integration/Tests/ProductControllerTest.cs @@ -1,10 +1,10 @@ using System.Threading.Tasks; -using Util.Applications.Dtos; -using Util.Applications.Fakes; -using Util.Applications.Infrastructure; -using Util.Applications.Services; using Util.Helpers; using Util.Http; +using Util.Tests.Dtos; +using Util.Tests.Fakes; +using Util.Tests.Infrastructure; +using Util.Tests.Services; using Xunit; using Xunit.Abstractions; using Xunit.DependencyInjection; @@ -13,7 +13,7 @@ namespace Util.Applications.Tests { /// /// 产品控制器测试 /// - public class ProductControllerTest : TestBase { + public class ProductControllerTest : ControllerTestBase { /// /// 输出工具 /// diff --git a/test/Util.Application.WebApi.MySql.Tests.Integration/Util.Application.WebApi.MySql.Tests.Integration.csproj b/test/Util.Application.WebApi.MySql.Tests.Integration/Util.Application.WebApi.MySql.Tests.Integration.csproj new file mode 100644 index 00000000..868310cf --- /dev/null +++ b/test/Util.Application.WebApi.MySql.Tests.Integration/Util.Application.WebApi.MySql.Tests.Integration.csproj @@ -0,0 +1,42 @@ + + + + $(NetTargetFramework) + false + Util.Applications + Util.Applications.Startup + + + + + + + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + + + Always + + + Always + + + + \ No newline at end of file diff --git a/test/Util.Application.WebApi.MySql.Tests.Integration/appsettings.Development.json b/test/Util.Application.WebApi.MySql.Tests.Integration/appsettings.Development.json new file mode 100644 index 00000000..e175f6a8 --- /dev/null +++ b/test/Util.Application.WebApi.MySql.Tests.Integration/appsettings.Development.json @@ -0,0 +1,11 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Trace", + "Microsoft": "Trace" + } + }, + "ConnectionStrings": { + "connection": "server=192.168.31.157;user=root;password=admin;database=Util.WebApi.Test;port=3306;charset=utf8" + } +} \ No newline at end of file diff --git a/test/Util.Application.WebApi.MySql.Tests.Integration/appsettings.json b/test/Util.Application.WebApi.MySql.Tests.Integration/appsettings.json new file mode 100644 index 00000000..b851f256 --- /dev/null +++ b/test/Util.Application.WebApi.MySql.Tests.Integration/appsettings.json @@ -0,0 +1,11 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Error", + "Microsoft": "Error" + } + }, + "ConnectionStrings": { + "connection": "server=mysql.common;user=root;password=admin;database=Util.WebApi.Test;port=3306;charset=utf8" + } +} \ No newline at end of file diff --git a/test/Util.Application.WebApi.PostgreSql.Tests.Integration/Properties/launchSettings.json b/test/Util.Application.WebApi.PostgreSql.Tests.Integration/Properties/launchSettings.json new file mode 100644 index 00000000..f7f9942a --- /dev/null +++ b/test/Util.Application.WebApi.PostgreSql.Tests.Integration/Properties/launchSettings.json @@ -0,0 +1,12 @@ +{ + "profiles": { + "Util.Application.WebApi.PostgreSql.Tests.Integration": { + "commandName": "Project", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "applicationUrl": "https://localhost:3603;http://localhost:3604" + } + } +} \ No newline at end of file diff --git a/test/Util.Application.WebApi.PostgreSql.Tests.Integration/Startup.cs b/test/Util.Application.WebApi.PostgreSql.Tests.Integration/Startup.cs new file mode 100644 index 00000000..3d8e92cc --- /dev/null +++ b/test/Util.Application.WebApi.PostgreSql.Tests.Integration/Startup.cs @@ -0,0 +1,72 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.TestHost; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using Util.Aop; +using Util.Data.EntityFrameworkCore; +using Util.Dates; +using Util.Helpers; +using Util.Http; +using Util.Tests.UnitOfWorks; +using Xunit.DependencyInjection; +using Xunit.DependencyInjection.Logging; + +namespace Util.Applications { + /// + /// Æô¶¯ÅäÖà + /// + public class Startup { + /// + /// ÅäÖÃÖ÷»ú + /// + public void ConfigureHost( IHostBuilder hostBuilder ) { + hostBuilder.ConfigureDefaults( null ) + .ConfigureWebHostDefaults( webHostBuilder => { + webHostBuilder.UseTestServer() + .Configure( t => { + t.UseRouting(); + t.UseEndpoints( endpoints => { + endpoints.MapControllers(); + } ); + } ); + } ) + .AddUtil( options => { + Environment.SetDevelopment(); + options.UseUtc() + .UseAop() + .UsePgSqlUnitOfWork( Config.GetConnectionString( "connection" ) ); + } ); + } + + /// + /// ÅäÖ÷þÎñ + /// + public void ConfigureServices( IServiceCollection services ) { + services.AddControllers(); + services.AddTransient( t => { + var client = new HttpClientService(); + client.SetHttpClient( t.GetService().GetTestClient() ); + return client; + } ); + InitDatabase( services ); + } + + /// + /// ³õʼ»¯Êý¾ݿâ + /// + private void InitDatabase( IServiceCollection services ) { + var unitOfWork = services.BuildServiceProvider().GetService(); + unitOfWork.EnsureDeleted(); + unitOfWork.EnsureCreated(); + } + + /// + /// ÅäÖÃÈÕ־Ìṩ³ÌÐò + /// + public void Configure( ILoggerFactory loggerFactory, ITestOutputHelperAccessor accessor ) { + loggerFactory.AddProvider( new XunitTestOutputLoggerProvider( accessor ) ); + } + } +} diff --git a/test/Util.Application.WebApi.PostgreSql.Tests.Integration/Tests/CustomerControllerTest.cs b/test/Util.Application.WebApi.PostgreSql.Tests.Integration/Tests/CustomerControllerTest.cs new file mode 100644 index 00000000..a5095b48 --- /dev/null +++ b/test/Util.Application.WebApi.PostgreSql.Tests.Integration/Tests/CustomerControllerTest.cs @@ -0,0 +1,115 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Util.Data; +using Util.Helpers; +using Util.Http; +using Util.Tests.Dtos; +using Util.Tests.Fakes; +using Util.Tests.Infrastructure; +using Util.Tests.Queries; +using Util.Tests.Services; +using Xunit; +using Xunit.Abstractions; +using Xunit.DependencyInjection; + +namespace Util.Applications.Tests { + /// + /// 客户控制器测试 + /// + public class CustomerControllerTest : ControllerTestBase { + /// + /// 输出工具 + /// + private readonly ITestOutputHelper _testOutputHelper; + /// + /// 客户服务 + /// + private readonly ICustomerService _service; + + /// + /// 测试初始化 + /// + public CustomerControllerTest( ITestOutputHelperAccessor testOutputHelperAccessor, ICustomerService service,IHttpClient client ) : base(client){ + _testOutputHelper = testOutputHelperAccessor.Output; + _service = service; + } + + /// + /// 测试获取单个实体 + /// + [Fact] + public async Task TestGetAsync() { + //创建实体 + var dto = CustomerFakeService.GetCustomerDto(); + var id = await _service.CreateAsync( dto ); + + //获取单个实体 + var url = $"/api/customer/{id}"; + var result = await GetAsync( url, dto ); + + //验证 + Assert.Equal( StateCode.Ok, result.Code ); + Assert.Equal( dto.Email, result.Data.Email ); + _testOutputHelper.WriteLine( Json.ToJson( result ) ); + } + + /// + /// 测试查询 + /// + [Fact] + public async Task TestQueryAsync() { + //常量 + var name = "TestQueryAsync"; + var url = "/api/customer/query"; + + //创建3个实体,前两个设置了名称 + var dtos = CustomerFakeService.GetCustomerDtos(3); + dtos[0].Name = name; + dtos[1].Name = name; + await _service.CreateAsync( dtos[0] ); + await _service.CreateAsync( dtos[1] ); + await _service.CreateAsync( dtos[2] ); + + //使用名称查询 + var query = new CustomerQuery { Name = name }; + var result = await GetAsync>( url, query ); + + //验证 + Assert.Equal( StateCode.Ok, result.Code ); + Assert.Equal( 2, result.Data.Count ); + _testOutputHelper.WriteLine( Json.ToJson( result ) ); + } + + /// + /// 测试分页查询 + /// + [Fact] + public async Task TestPageQueryAsync() { + //常量 + var name = "TestPageQueryAsync"; + var url = "/api/customer"; + + //创建5个实体,前4个设置了名称,并使用Id属性排序 + var dtos = CustomerFakeService.GetCustomerDtos( 5 ).OrderBy( t => t.Id ).ToList(); + for ( int i = 0; i < 4; i++ ) { + dtos[i].Name = name; + } + foreach ( var dto in dtos ) { + await _service.CreateAsync( dto ); + } + + //使用名称查询第二页,每页2行,并使用Id属性排序 + var query = new CustomerQuery { Page = 2, PageSize = 2, Name = name,Order = "Id" }; + var result = await GetAsync>( url, query ); + + //验证 + Assert.Equal( StateCode.Ok, result.Code ); + Assert.Equal( 2, result.Data.PageCount ); + Assert.Equal( 4, result.Data.Total ); + Assert.Equal( dtos[2].Email, result.Data.Data[0].Email ); + Assert.Equal( dtos[3].Email, result.Data.Data[1].Email ); + _testOutputHelper.WriteLine( Json.ToJson( result ) ); + } + } +} diff --git a/test/Util.Application.WebApi.PostgreSql.Tests.Integration/Tests/ProductControllerTest.cs b/test/Util.Application.WebApi.PostgreSql.Tests.Integration/Tests/ProductControllerTest.cs new file mode 100644 index 00000000..1a18932d --- /dev/null +++ b/test/Util.Application.WebApi.PostgreSql.Tests.Integration/Tests/ProductControllerTest.cs @@ -0,0 +1,132 @@ +using System.Threading.Tasks; +using Util.Helpers; +using Util.Http; +using Util.Tests.Dtos; +using Util.Tests.Fakes; +using Util.Tests.Infrastructure; +using Util.Tests.Services; +using Xunit; +using Xunit.Abstractions; +using Xunit.DependencyInjection; + +namespace Util.Applications.Tests { + /// + /// 产品控制器测试 + /// + public class ProductControllerTest : ControllerTestBase { + /// + /// 输出工具 + /// + private readonly ITestOutputHelper _testOutputHelper; + /// + /// 产品服务 + /// + private readonly IProductService _service; + + /// + /// 测试初始化 + /// + public ProductControllerTest( ITestOutputHelperAccessor testOutputHelperAccessor, IProductService service, IHttpClient client ) : base( client ) { + _testOutputHelper = testOutputHelperAccessor.Output; + _service = service; + } + + /// + /// 测试创建 + /// + [Fact] + public async Task TestCreateAsync() { + //服务地址 + var url = "/api/product"; + + //创建实体 + var dto = ProductFakeService.GetProductDto(); + var result = await PostAsync( url, dto ); + + //验证 + Assert.Equal( StateCode.Ok, result.Code ); + Assert.NotEmpty( result.Data.Id ); + _testOutputHelper.WriteLine( Json.ToJson( result ) ); + } + + /// + /// 测试修改 + /// + [Fact] + public async Task TestUpdateAsync() { + //常量 + var name = "TestUpdateAsync"; + + //创建实体 + var dto = ProductFakeService.GetProductDto(); + var id = await _service.CreateAsync( dto ); + + //服务地址 + var url = $"/api/product/{id}"; + + //修改实体 + dto = await _service.GetByIdAsync( id ); + dto.Name = name; + var result = await PutAsync( url, dto ); + + //重新获取实体 + dto = await _service.GetByIdAsync( id ); + + //验证 + Assert.Equal( StateCode.Ok, result.Code ); + Assert.Equal( name, dto.Name ); + _testOutputHelper.WriteLine( Json.ToJson( result ) ); + } + + /// + /// 测试删除 + /// + [Fact] + public async Task TestDeleteAsync() { + //创建实体 + var dto = ProductFakeService.GetProductDto(); + var id = await _service.CreateAsync( dto ); + + //服务地址 + var url = $"/api/product/{id}"; + + //删除实体 + var result = await DeleteAsync( url ); + + //重新获取实体 + dto = await _service.GetByIdAsync( id ); + + //验证 + Assert.Equal( StateCode.Ok, result.Code ); + Assert.Null( dto ); + _testOutputHelper.WriteLine( Json.ToJson( result ) ); + } + + /// + /// 测试批量删除 + /// + [Fact] + public async Task TestBatchDeleteAsync() { + //创建实体 + var dtos = ProductFakeService.GetProductDtos(2); + var id = await _service.CreateAsync( dtos[0] ); + var id2 = await _service.CreateAsync( dtos[1] ); + + //服务地址 + var url = "/api/product/delete"; + + //删除实体列表 + var result = await PostAsync( url,$"{id},{id2}" ); + + //重新获取实体 + var dto = await _service.GetByIdAsync( id ); + var dto2 = await _service.GetByIdAsync( id2 ); + + //验证 + Assert.Equal( StateCode.Ok, result.Code ); + Assert.Null( dto ); + Assert.Null( dto2 ); + _testOutputHelper.WriteLine( Json.ToJson( result ) ); + } + } +} \ No newline at end of file diff --git a/test/Util.Application.WebApi.PostgreSql.Tests.Integration/Util.Application.WebApi.PostgreSql.Tests.Integration.csproj b/test/Util.Application.WebApi.PostgreSql.Tests.Integration/Util.Application.WebApi.PostgreSql.Tests.Integration.csproj new file mode 100644 index 00000000..81314493 --- /dev/null +++ b/test/Util.Application.WebApi.PostgreSql.Tests.Integration/Util.Application.WebApi.PostgreSql.Tests.Integration.csproj @@ -0,0 +1,42 @@ + + + + $(NetTargetFramework) + false + Util.Applications + Util.Applications.Startup + + + + + + + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + + + Always + + + Always + + + + \ No newline at end of file diff --git a/test/Util.Application.WebApi.PostgreSql.Tests.Integration/appsettings.Development.json b/test/Util.Application.WebApi.PostgreSql.Tests.Integration/appsettings.Development.json new file mode 100644 index 00000000..4c2b4852 --- /dev/null +++ b/test/Util.Application.WebApi.PostgreSql.Tests.Integration/appsettings.Development.json @@ -0,0 +1,11 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Trace", + "Microsoft": "Trace" + } + }, + "ConnectionStrings": { + "connection": "server=192.168.31.158;User Id=admin;password=admin;database=Util.WebApi.Test" + } +} \ No newline at end of file diff --git a/test/Util.Application.WebApi.PostgreSql.Tests.Integration/appsettings.json b/test/Util.Application.WebApi.PostgreSql.Tests.Integration/appsettings.json new file mode 100644 index 00000000..a388986d --- /dev/null +++ b/test/Util.Application.WebApi.PostgreSql.Tests.Integration/appsettings.json @@ -0,0 +1,11 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Error", + "Microsoft": "Error" + } + }, + "ConnectionStrings": { + "connection": "server=postgresql.common;User Id=admin;password=admin;database=Util.WebApi.Test" + } +} \ No newline at end of file diff --git a/test/Util.Application.WebApi.Tests.Integration/Properties/launchSettings.json b/test/Util.Application.WebApi.SqlServer.Tests.Integration/Properties/launchSettings.json similarity index 100% rename from test/Util.Application.WebApi.Tests.Integration/Properties/launchSettings.json rename to test/Util.Application.WebApi.SqlServer.Tests.Integration/Properties/launchSettings.json diff --git a/test/Util.Application.WebApi.SqlServer.Tests.Integration/Startup.cs b/test/Util.Application.WebApi.SqlServer.Tests.Integration/Startup.cs new file mode 100644 index 00000000..c2a3a350 --- /dev/null +++ b/test/Util.Application.WebApi.SqlServer.Tests.Integration/Startup.cs @@ -0,0 +1,70 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.TestHost; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using Util.Aop; +using Util.Data.EntityFrameworkCore; +using Util.Helpers; +using Util.Http; +using Util.Tests.UnitOfWorks; +using Xunit.DependencyInjection; +using Xunit.DependencyInjection.Logging; + +namespace Util.Applications { + /// + /// Æô¶¯ÅäÖà + /// + public class Startup { + /// + /// ÅäÖÃÖ÷»ú + /// + public void ConfigureHost( IHostBuilder hostBuilder ) { + hostBuilder.ConfigureDefaults( null ) + .ConfigureWebHostDefaults( webHostBuilder => { + webHostBuilder.UseTestServer() + .Configure( t => { + t.UseRouting(); + t.UseEndpoints( endpoints => { + endpoints.MapControllers(); + } ); + } ); + } ) + .AddUtil( options => { + Environment.SetDevelopment(); + options.UseAop() + .UseSqlServerUnitOfWork( Config.GetConnectionString( "connection" ) ); + } ); + } + + /// + /// ÅäÖ÷þÎñ + /// + public void ConfigureServices( IServiceCollection services ) { + services.AddControllers(); + services.AddTransient( t => { + var client = new HttpClientService(); + client.SetHttpClient( t.GetService().GetTestClient() ); + return client; + } ); + InitDatabase( services ); + } + + /// + /// ³õʼ»¯Êý¾ݿâ + /// + private void InitDatabase( IServiceCollection services ) { + var unitOfWork = services.BuildServiceProvider().GetService(); + unitOfWork.EnsureDeleted(); + unitOfWork.EnsureCreated(); + } + + /// + /// ÅäÖÃÈÕ־Ìṩ³ÌÐò + /// + public void Configure( ILoggerFactory loggerFactory, ITestOutputHelperAccessor accessor ) { + loggerFactory.AddProvider( new XunitTestOutputLoggerProvider( accessor ) ); + } + } +} diff --git a/test/Util.Application.WebApi.SqlServer.Tests.Integration/Tests/CustomerControllerTest.cs b/test/Util.Application.WebApi.SqlServer.Tests.Integration/Tests/CustomerControllerTest.cs new file mode 100644 index 00000000..a5095b48 --- /dev/null +++ b/test/Util.Application.WebApi.SqlServer.Tests.Integration/Tests/CustomerControllerTest.cs @@ -0,0 +1,115 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Util.Data; +using Util.Helpers; +using Util.Http; +using Util.Tests.Dtos; +using Util.Tests.Fakes; +using Util.Tests.Infrastructure; +using Util.Tests.Queries; +using Util.Tests.Services; +using Xunit; +using Xunit.Abstractions; +using Xunit.DependencyInjection; + +namespace Util.Applications.Tests { + /// + /// 客户控制器测试 + /// + public class CustomerControllerTest : ControllerTestBase { + /// + /// 输出工具 + /// + private readonly ITestOutputHelper _testOutputHelper; + /// + /// 客户服务 + /// + private readonly ICustomerService _service; + + /// + /// 测试初始化 + /// + public CustomerControllerTest( ITestOutputHelperAccessor testOutputHelperAccessor, ICustomerService service,IHttpClient client ) : base(client){ + _testOutputHelper = testOutputHelperAccessor.Output; + _service = service; + } + + /// + /// 测试获取单个实体 + /// + [Fact] + public async Task TestGetAsync() { + //创建实体 + var dto = CustomerFakeService.GetCustomerDto(); + var id = await _service.CreateAsync( dto ); + + //获取单个实体 + var url = $"/api/customer/{id}"; + var result = await GetAsync( url, dto ); + + //验证 + Assert.Equal( StateCode.Ok, result.Code ); + Assert.Equal( dto.Email, result.Data.Email ); + _testOutputHelper.WriteLine( Json.ToJson( result ) ); + } + + /// + /// 测试查询 + /// + [Fact] + public async Task TestQueryAsync() { + //常量 + var name = "TestQueryAsync"; + var url = "/api/customer/query"; + + //创建3个实体,前两个设置了名称 + var dtos = CustomerFakeService.GetCustomerDtos(3); + dtos[0].Name = name; + dtos[1].Name = name; + await _service.CreateAsync( dtos[0] ); + await _service.CreateAsync( dtos[1] ); + await _service.CreateAsync( dtos[2] ); + + //使用名称查询 + var query = new CustomerQuery { Name = name }; + var result = await GetAsync>( url, query ); + + //验证 + Assert.Equal( StateCode.Ok, result.Code ); + Assert.Equal( 2, result.Data.Count ); + _testOutputHelper.WriteLine( Json.ToJson( result ) ); + } + + /// + /// 测试分页查询 + /// + [Fact] + public async Task TestPageQueryAsync() { + //常量 + var name = "TestPageQueryAsync"; + var url = "/api/customer"; + + //创建5个实体,前4个设置了名称,并使用Id属性排序 + var dtos = CustomerFakeService.GetCustomerDtos( 5 ).OrderBy( t => t.Id ).ToList(); + for ( int i = 0; i < 4; i++ ) { + dtos[i].Name = name; + } + foreach ( var dto in dtos ) { + await _service.CreateAsync( dto ); + } + + //使用名称查询第二页,每页2行,并使用Id属性排序 + var query = new CustomerQuery { Page = 2, PageSize = 2, Name = name,Order = "Id" }; + var result = await GetAsync>( url, query ); + + //验证 + Assert.Equal( StateCode.Ok, result.Code ); + Assert.Equal( 2, result.Data.PageCount ); + Assert.Equal( 4, result.Data.Total ); + Assert.Equal( dtos[2].Email, result.Data.Data[0].Email ); + Assert.Equal( dtos[3].Email, result.Data.Data[1].Email ); + _testOutputHelper.WriteLine( Json.ToJson( result ) ); + } + } +} diff --git a/test/Util.Application.WebApi.SqlServer.Tests.Integration/Tests/ProductControllerTest.cs b/test/Util.Application.WebApi.SqlServer.Tests.Integration/Tests/ProductControllerTest.cs new file mode 100644 index 00000000..1a18932d --- /dev/null +++ b/test/Util.Application.WebApi.SqlServer.Tests.Integration/Tests/ProductControllerTest.cs @@ -0,0 +1,132 @@ +using System.Threading.Tasks; +using Util.Helpers; +using Util.Http; +using Util.Tests.Dtos; +using Util.Tests.Fakes; +using Util.Tests.Infrastructure; +using Util.Tests.Services; +using Xunit; +using Xunit.Abstractions; +using Xunit.DependencyInjection; + +namespace Util.Applications.Tests { + /// + /// 产品控制器测试 + /// + public class ProductControllerTest : ControllerTestBase { + /// + /// 输出工具 + /// + private readonly ITestOutputHelper _testOutputHelper; + /// + /// 产品服务 + /// + private readonly IProductService _service; + + /// + /// 测试初始化 + /// + public ProductControllerTest( ITestOutputHelperAccessor testOutputHelperAccessor, IProductService service, IHttpClient client ) : base( client ) { + _testOutputHelper = testOutputHelperAccessor.Output; + _service = service; + } + + /// + /// 测试创建 + /// + [Fact] + public async Task TestCreateAsync() { + //服务地址 + var url = "/api/product"; + + //创建实体 + var dto = ProductFakeService.GetProductDto(); + var result = await PostAsync( url, dto ); + + //验证 + Assert.Equal( StateCode.Ok, result.Code ); + Assert.NotEmpty( result.Data.Id ); + _testOutputHelper.WriteLine( Json.ToJson( result ) ); + } + + /// + /// 测试修改 + /// + [Fact] + public async Task TestUpdateAsync() { + //常量 + var name = "TestUpdateAsync"; + + //创建实体 + var dto = ProductFakeService.GetProductDto(); + var id = await _service.CreateAsync( dto ); + + //服务地址 + var url = $"/api/product/{id}"; + + //修改实体 + dto = await _service.GetByIdAsync( id ); + dto.Name = name; + var result = await PutAsync( url, dto ); + + //重新获取实体 + dto = await _service.GetByIdAsync( id ); + + //验证 + Assert.Equal( StateCode.Ok, result.Code ); + Assert.Equal( name, dto.Name ); + _testOutputHelper.WriteLine( Json.ToJson( result ) ); + } + + /// + /// 测试删除 + /// + [Fact] + public async Task TestDeleteAsync() { + //创建实体 + var dto = ProductFakeService.GetProductDto(); + var id = await _service.CreateAsync( dto ); + + //服务地址 + var url = $"/api/product/{id}"; + + //删除实体 + var result = await DeleteAsync( url ); + + //重新获取实体 + dto = await _service.GetByIdAsync( id ); + + //验证 + Assert.Equal( StateCode.Ok, result.Code ); + Assert.Null( dto ); + _testOutputHelper.WriteLine( Json.ToJson( result ) ); + } + + /// + /// 测试批量删除 + /// + [Fact] + public async Task TestBatchDeleteAsync() { + //创建实体 + var dtos = ProductFakeService.GetProductDtos(2); + var id = await _service.CreateAsync( dtos[0] ); + var id2 = await _service.CreateAsync( dtos[1] ); + + //服务地址 + var url = "/api/product/delete"; + + //删除实体列表 + var result = await PostAsync( url,$"{id},{id2}" ); + + //重新获取实体 + var dto = await _service.GetByIdAsync( id ); + var dto2 = await _service.GetByIdAsync( id2 ); + + //验证 + Assert.Equal( StateCode.Ok, result.Code ); + Assert.Null( dto ); + Assert.Null( dto2 ); + _testOutputHelper.WriteLine( Json.ToJson( result ) ); + } + } +} \ No newline at end of file diff --git a/test/Util.Application.WebApi.Tests.Integration/Util.Application.WebApi.Tests.Integration.csproj b/test/Util.Application.WebApi.SqlServer.Tests.Integration/Util.Application.WebApi.SqlServer.Tests.Integration.csproj similarity index 68% rename from test/Util.Application.WebApi.Tests.Integration/Util.Application.WebApi.Tests.Integration.csproj rename to test/Util.Application.WebApi.SqlServer.Tests.Integration/Util.Application.WebApi.SqlServer.Tests.Integration.csproj index 6e998abe..128a79e9 100644 --- a/test/Util.Application.WebApi.Tests.Integration/Util.Application.WebApi.Tests.Integration.csproj +++ b/test/Util.Application.WebApi.SqlServer.Tests.Integration/Util.Application.WebApi.SqlServer.Tests.Integration.csproj @@ -9,41 +9,34 @@ - - - + + + - - + + - + runtime; build; native; contentfiles; analyzers; buildtransitive all - + runtime; build; native; contentfiles; analyzers; buildtransitive all - - - - - + Always - - - - + Always - + diff --git a/test/Util.Application.WebApi.Tests.Integration/appsettings.json b/test/Util.Application.WebApi.SqlServer.Tests.Integration/appsettings.Development.json similarity index 58% rename from test/Util.Application.WebApi.Tests.Integration/appsettings.json rename to test/Util.Application.WebApi.SqlServer.Tests.Integration/appsettings.Development.json index 8900ac75..8c9b4078 100644 --- a/test/Util.Application.WebApi.Tests.Integration/appsettings.json +++ b/test/Util.Application.WebApi.SqlServer.Tests.Integration/appsettings.Development.json @@ -1,5 +1,11 @@ { + "Logging": { + "LogLevel": { + "Default": "Trace", + "Microsoft": "Trace" + } + }, "ConnectionStrings": { "connection": "Server=.\\sql2014;Database=Util.WebApi.Test;uid=sa;pwd=sa;MultipleActiveResultSets=true" } -} \ No newline at end of file +} diff --git a/test/Util.Application.WebApi.SqlServer.Tests.Integration/appsettings.json b/test/Util.Application.WebApi.SqlServer.Tests.Integration/appsettings.json new file mode 100644 index 00000000..10f0ee77 --- /dev/null +++ b/test/Util.Application.WebApi.SqlServer.Tests.Integration/appsettings.json @@ -0,0 +1,11 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Error", + "Microsoft": "Error" + } + }, + "ConnectionStrings": { + "connection": "Server=192.168.31.123\\sql2014;Database=Util.WebApi.Test;uid=sa;pwd=sa;MultipleActiveResultSets=true;" + } +} \ No newline at end of file diff --git a/test/Util.Application.WebApi.Tests.Integration/Dtos/CustomerDto.cs b/test/Util.Application.WebApi.Tests.Integration/Dtos/CustomerDto.cs deleted file mode 100644 index f6b56818..00000000 --- a/test/Util.Application.WebApi.Tests.Integration/Dtos/CustomerDto.cs +++ /dev/null @@ -1,87 +0,0 @@ -using System; -using System.ComponentModel; -using System.ComponentModel.DataAnnotations; -using Util.Domain.Biz.Enums; - -namespace Util.Applications.Dtos { - /// - /// 客户参数 - /// - public class CustomerDto : DtoBase { - /// - /// 编码 - /// - [Description( "编码" )] - [MaxLength( 100 )] - public string Code { get; set; } - /// - /// 姓名 - /// - [Description( "姓名" )] - [MaxLength( 200 )] - public string Name { get; set; } - /// - /// 昵称 - /// - [Description( "昵称" )] - [MaxLength( 50 )] - public string Nickname { get; set; } - /// - /// 性别 - /// - [Description( "性别" )] - public Gender? Gender { get; set; } - /// - /// 出生日期 - /// - [Description( "出生日期" )] - public DateTime? Birthday { get; set; } - /// - /// 民族 - /// - [Description( "民族" )] - public Nation? Nation { get; set; } - /// - /// 手机号 - /// - [Description( "手机号" )] - [MaxLength( 50 )] - public string Phone { get; set; } - /// - /// 电子邮件 - /// - [Description( "电子邮件" )] - [MaxLength( 500 )] - public string Email { get; set; } - /// - /// 创建时间 - /// - [Description( "创建时间" )] - public DateTime? CreationTime { get; set; } - /// - /// 创建人 - /// - [Description( "创建人" )] - public Guid? CreatorId { get; set; } - /// - /// 最后修改时间 - /// - [Description( "最后修改时间" )] - public DateTime? LastModificationTime { get; set; } - /// - /// 最后修改人 - /// - [Description( "最后修改人" )] - public Guid? LastModifierId { get; set; } - /// - /// 是否删除 - /// - [Description( "是否删除" )] - public bool IsDeleted { get; set; } - /// - /// 版本号 - /// - [Description( "版本号" )] - public byte[] Version { get; set; } - } -} \ No newline at end of file diff --git a/test/Util.Application.WebApi.Tests.Integration/Dtos/ProductDto.cs b/test/Util.Application.WebApi.Tests.Integration/Dtos/ProductDto.cs deleted file mode 100644 index eb61a41d..00000000 --- a/test/Util.Application.WebApi.Tests.Integration/Dtos/ProductDto.cs +++ /dev/null @@ -1,71 +0,0 @@ -using System; -using System.ComponentModel; -using System.ComponentModel.DataAnnotations; - -namespace Util.Applications.Dtos { - /// - /// 产品参数 - /// - public class ProductDto : DtoBase { - /// - /// 产品编码 - /// - [Description( "产品编码" )] - [Required(ErrorMessage = "产品编码不能为空")] - [MaxLength( 50 )] - public string Code { get; set; } - /// - /// 产品名称 - /// - [Description( "产品名称" )] - [Required(ErrorMessage = "产品名称不能为空")] - [MaxLength( 500 )] - public string Name { get; set; } - /// - /// 价格 - /// - [Description( "价格" )] - [Required(ErrorMessage = "价格不能为空")] - public decimal Price { get; set; } - /// - /// 描述 - /// - [Description( "描述" )] - public string Description { get; set; } - /// - /// 启用 - /// - [Description( "启用" )] - public bool Enabled { get; set; } - /// - /// 创建时间 - /// - [Description( "创建时间" )] - public DateTime? CreationTime { get; set; } - /// - /// 创建人 - /// - [Description( "创建人" )] - public Guid? CreatorId { get; set; } - /// - /// 最后修改时间 - /// - [Description( "最后修改时间" )] - public DateTime? LastModificationTime { get; set; } - /// - /// 最后修改人 - /// - [Description( "最后修改人" )] - public Guid? LastModifierId { get; set; } - /// - /// 是否删除 - /// - [Description( "是否删除" )] - public bool IsDeleted { get; set; } - /// - /// 版本号 - /// - [Description( "版本号" )] - public byte[] Version { get; set; } - } -} \ No newline at end of file diff --git a/test/Util.Application.WebApi.Tests.Integration/Fakes/CustomerFakeService.cs b/test/Util.Application.WebApi.Tests.Integration/Fakes/CustomerFakeService.cs deleted file mode 100644 index 523fdc8d..00000000 --- a/test/Util.Application.WebApi.Tests.Integration/Fakes/CustomerFakeService.cs +++ /dev/null @@ -1,49 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using AutoBogus; -using Util.Applications.Dtos; -using Util.Applications.Models; - -namespace Util.Applications.Fakes { - /// - /// 客户模拟数据服务 - /// - public static class CustomerFakeService { - /// - /// 获取客户 - /// - public static Customer GetCustomer() { - return GetCustomers( 1 ).First(); - } - - /// - /// 获取客户列表 - /// - /// 行数 - public static List GetCustomers( int count ) { - return new AutoFaker() - .RuleFor( t => t.IsDeleted, false ) - .Generate( count ); - } - - /// - /// 获取客户 - /// - public static CustomerDto GetCustomerDto() { - return GetCustomerDtos( 1 ).First(); - } - - /// - /// 获取客户列表 - /// - /// 行数 - public static List GetCustomerDtos( int count ) { - return new AutoFaker() - .Configure( builder => builder - .WithSkip( t => t.Id ) - ) - .RuleFor( t => t.IsDeleted, false ) - .Generate( count ); - } - } -} \ No newline at end of file diff --git a/test/Util.Application.WebApi.Tests.Integration/Fakes/ProductFakeService.cs b/test/Util.Application.WebApi.Tests.Integration/Fakes/ProductFakeService.cs deleted file mode 100644 index ae176fda..00000000 --- a/test/Util.Application.WebApi.Tests.Integration/Fakes/ProductFakeService.cs +++ /dev/null @@ -1,49 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using AutoBogus; -using Util.Applications.Dtos; -using Util.Applications.Models; - -namespace Util.Applications.Fakes { - /// - /// 产品模拟数据服务 - /// - public static class ProductFakeService { - /// - /// 获取产品 - /// - public static Product GetProduct() { - return GetProducts( 1 ).First(); - } - - /// - /// 获取产品列表 - /// - /// 行数 - public static List GetProducts( int count ) { - return new AutoFaker() - .RuleFor( t => t.IsDeleted, false ) - .Generate( count ); - } - - /// - /// 获取产品 - /// - public static ProductDto GetProductDto() { - return GetProductDtos( 1 ).First(); - } - - /// - /// 获取产品列表 - /// - /// 行数 - public static List GetProductDtos( int count ) { - return new AutoFaker() - .Configure( builder => builder - .WithSkip( t => t.Id ) - ) - .RuleFor( t => t.IsDeleted,false ) - .Generate( count ); - } - } -} \ No newline at end of file diff --git a/test/Util.Application.WebApi.Tests.Integration/Models/Customer.cs b/test/Util.Application.WebApi.Tests.Integration/Models/Customer.cs deleted file mode 100644 index 1db49788..00000000 --- a/test/Util.Application.WebApi.Tests.Integration/Models/Customer.cs +++ /dev/null @@ -1,116 +0,0 @@ -using System; -using System.ComponentModel; -using System.ComponentModel.DataAnnotations; -using Util.Domain; -using Util.Domain.Biz.Enums; -using Util.Domain.Entities; - -namespace Util.Applications.Models { - /// - /// 客户 - /// - [Description( "客户" )] - public class Customer : AggregateRoot,IDelete{ - /// - /// 初始化客户 - /// - public Customer() : this( 0 ) { - } - - /// - /// 初始化客户 - /// - /// 客户标识 - public Customer( int id ) : base( id ) { - } - - /// - /// 编码 - /// - [Description( "编码" )] - [MaxLength( 100 )] - public string Code { get; set; } - /// - /// 姓名 - /// - [Description( "姓名" )] - [MaxLength( 200 )] - public string Name { get; set; } - /// - /// 昵称 - /// - [Description( "昵称" )] - [MaxLength( 50 )] - public string Nickname { get; set; } - /// - /// 性别 - /// - [Description( "性别" )] - public Gender? Gender { get; set; } - /// - /// 出生日期 - /// - [Description( "出生日期" )] - public DateTime? Birthday { get; set; } - /// - /// 民族 - /// - [Description( "民族" )] - public Nation? Nation { get; set; } - /// - /// 手机号 - /// - [Description( "手机号" )] - [MaxLength( 50 )] - public string Phone { get; set; } - /// - /// 电子邮件 - /// - [Description( "电子邮件" )] - [MaxLength( 500 )] - public string Email { get; set; } - /// - /// 创建时间 - /// - [Description( "创建时间" )] - public DateTime? CreationTime { get; set; } - /// - /// 创建人 - /// - [Description( "创建人" )] - public Guid? CreatorId { get; set; } - /// - /// 最后修改时间 - /// - [Description( "最后修改时间" )] - public DateTime? LastModificationTime { get; set; } - /// - /// 最后修改人 - /// - [Description( "最后修改人" )] - public Guid? LastModifierId { get; set; } - /// - /// 是否删除 - /// - [Description( "是否删除" )] - public bool IsDeleted { get; set; } - - /// - /// 添加变更列表 - /// - protected override void AddChanges( Customer other ) { - AddChange( t => t.Code, other.Code ); - AddChange( t => t.Name, other.Name ); - AddChange( t => t.Nickname, other.Nickname ); - AddChange( t => t.Gender, other.Gender ); - AddChange( t => t.Birthday, other.Birthday ); - AddChange( t => t.Nation, other.Nation ); - AddChange( t => t.Phone, other.Phone ); - AddChange( t => t.Email, other.Email ); - AddChange( t => t.CreationTime, other.CreationTime ); - AddChange( t => t.CreatorId, other.CreatorId ); - AddChange( t => t.LastModificationTime, other.LastModificationTime ); - AddChange( t => t.LastModifierId, other.LastModifierId ); - } - } -} \ No newline at end of file diff --git a/test/Util.Application.WebApi.Tests.Integration/Models/Product.cs b/test/Util.Application.WebApi.Tests.Integration/Models/Product.cs deleted file mode 100644 index 26f968cb..00000000 --- a/test/Util.Application.WebApi.Tests.Integration/Models/Product.cs +++ /dev/null @@ -1,97 +0,0 @@ -using System; -using System.ComponentModel; -using System.ComponentModel.DataAnnotations; -using Util.Domain; -using Util.Domain.Entities; - -namespace Util.Applications.Models { - /// - /// 产品 - /// - [Description( "产品" )] - public class Product : AggregateRoot, IDelete { - /// - /// 初始化产品 - /// - public Product() : this( Guid.Empty ) { - } - - /// - /// 初始化产品 - /// - /// 产品标识 - public Product( Guid id ) : base( id ) { - } - - /// - /// 产品编码 - /// - [Description( "产品编码" )] - [Required( ErrorMessage = "产品编码不能为空" )] - [MaxLength( 50 )] - public string Code { get; set; } - /// - /// 产品名称 - /// - [Description( "产品名称" )] - [Required( ErrorMessage = "产品名称不能为空" )] - [MaxLength( 500 )] - public string Name { get; set; } - /// - /// 价格 - /// - [Description( "价格" )] - [Required( ErrorMessage = "价格不能为空" )] - public decimal Price { get; set; } - /// - /// 描述 - /// - [Description( "描述" )] - public string Description { get; set; } - /// - /// 启用 - /// - [Description( "启用" )] - public bool Enabled { get; set; } - /// - /// 创建时间 - /// - [Description( "创建时间" )] - public DateTime? CreationTime { get; set; } - /// - /// 创建人 - /// - [Description( "创建人" )] - public Guid? CreatorId { get; set; } - /// - /// 最后修改时间 - /// - [Description( "最后修改时间" )] - public DateTime? LastModificationTime { get; set; } - /// - /// 最后修改人 - /// - [Description( "最后修改人" )] - public Guid? LastModifierId { get; set; } - /// - /// 是否删除 - /// - [Description( "是否删除" )] - public bool IsDeleted { get; set; } - - /// - /// 添加变更列表 - /// - protected override void AddChanges( Product other ) { - AddChange( t => t.Code, other.Code ); - AddChange( t => t.Name, other.Name ); - AddChange( t => t.Price, other.Price ); - AddChange( t => t.Description, other.Description ); - AddChange( t => t.Enabled, other.Enabled ); - AddChange( t => t.CreationTime, other.CreationTime ); - AddChange( t => t.CreatorId, other.CreatorId ); - AddChange( t => t.LastModificationTime, other.LastModificationTime ); - AddChange( t => t.LastModifierId, other.LastModifierId ); - } - } -} \ No newline at end of file diff --git a/test/Util.Application.WebApi.Tests.Integration/Queries/CustomerQuery.cs b/test/Util.Application.WebApi.Tests.Integration/Queries/CustomerQuery.cs deleted file mode 100644 index 5ee316e1..00000000 --- a/test/Util.Application.WebApi.Tests.Integration/Queries/CustomerQuery.cs +++ /dev/null @@ -1,85 +0,0 @@ -using System; -using System.ComponentModel; -using Util.Data.Queries; - -namespace Util.Applications.Queries { - /// - /// 客户查询参数 - /// - public class CustomerQuery : QueryParameter { - /// - /// 客户标识 - /// - [Description( "客户标识" )] - public int? CustomerId { get; set; } - /// - /// 编码 - /// - [Description( "编码" )] - public string Code { get; set; } - /// - /// 姓名 - /// - [Description( "姓名" )] - public string Name { get; set; } - /// - /// 昵称 - /// - [Description( "昵称" )] - public string Nickname { get; set; } - /// - /// 性别 - /// - [Description( "性别" )] - public int? Gender { get; set; } - /// - /// 起始出生日期 - /// - public DateTime? BeginBirthday { get; set; } - /// - /// 结束出生日期 - /// - public DateTime? EndBirthday { get; set; } - /// - /// 民族 - /// - [Description( "民族" )] - public int? Nation { get; set; } - /// - /// 手机号 - /// - [Description( "手机号" )] - public string Phone { get; set; } - /// - /// 电子邮件 - /// - [Description( "电子邮件" )] - public string Email { get; set; } - /// - /// 起始创建时间 - /// - public DateTime? BeginCreationTime { get; set; } - /// - /// 结束创建时间 - /// - public DateTime? EndCreationTime { get; set; } - /// - /// 创建人 - /// - [Description( "创建人" )] - public Guid? CreatorId { get; set; } - /// - /// 起始最后修改时间 - /// - public DateTime? BeginLastModificationTime { get; set; } - /// - /// 结束最后修改时间 - /// - public DateTime? EndLastModificationTime { get; set; } - /// - /// 最后修改人 - /// - [Description( "最后修改人" )] - public Guid? LastModifierId { get; set; } - } -} \ No newline at end of file diff --git a/test/Util.Application.WebApi.Tests.Integration/Queries/ProductQuery.cs b/test/Util.Application.WebApi.Tests.Integration/Queries/ProductQuery.cs deleted file mode 100644 index 7da7c5b2..00000000 --- a/test/Util.Application.WebApi.Tests.Integration/Queries/ProductQuery.cs +++ /dev/null @@ -1,67 +0,0 @@ -using System; -using System.ComponentModel; -using Util.Data.Queries; - -namespace Util.Applications.Queries { - /// - /// 产品查询参数 - /// - public class ProductQuery : QueryParameter { - /// - /// 产品标识 - /// - [Description( "产品标识" )] - public Guid? ProductId { get; set; } - /// - /// 产品编码 - /// - [Description( "产品编码" )] - public string Code { get; set; } - /// - /// 产品名称 - /// - [Description( "产品名称" )] - public string Name { get; set; } - /// - /// 价格 - /// - [Description( "价格" )] - public decimal? Price { get; set; } - /// - /// 描述 - /// - [Description( "描述" )] - public string Description { get; set; } - /// - /// 启用 - /// - [Description( "启用" )] - public bool? Enabled { get; set; } - /// - /// 起始创建时间 - /// - public DateTime? BeginCreationTime { get; set; } - /// - /// 结束创建时间 - /// - public DateTime? EndCreationTime { get; set; } - /// - /// 创建人 - /// - [Description( "创建人" )] - public Guid? CreatorId { get; set; } - /// - /// 起始最后修改时间 - /// - public DateTime? BeginLastModificationTime { get; set; } - /// - /// 结束最后修改时间 - /// - public DateTime? EndLastModificationTime { get; set; } - /// - /// 最后修改人 - /// - [Description( "最后修改人" )] - public Guid? LastModifierId { get; set; } - } -} \ No newline at end of file diff --git a/test/Util.Application.WebApi.Tests.Integration/Repositories/IProductRepository.cs b/test/Util.Application.WebApi.Tests.Integration/Repositories/IProductRepository.cs deleted file mode 100644 index 07a2dcc3..00000000 --- a/test/Util.Application.WebApi.Tests.Integration/Repositories/IProductRepository.cs +++ /dev/null @@ -1,15 +0,0 @@ -using Util.Applications.Models; -using Util.Domain.Repositories; - -namespace Util.Applications.Repositories { - /// - /// 产品仓储 - /// - public interface IProductRepository : IRepository { - /// - /// 更新产品 - /// - /// 产品 - public void UpdateProduct( Product product ); - } -} \ No newline at end of file diff --git a/test/Util.Application.WebApi.Tests.Integration/Services/ProductService.cs b/test/Util.Application.WebApi.Tests.Integration/Services/ProductService.cs deleted file mode 100644 index cafd5995..00000000 --- a/test/Util.Application.WebApi.Tests.Integration/Services/ProductService.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System; -using Util.Applications.Dtos; -using Util.Applications.Models; -using Util.Applications.Queries; -using Util.Applications.Repositories; -using Util.Applications.UnitOfWorks; - -namespace Util.Applications.Services { - /// - /// 产品服务 - /// - public class ProductService : CrudServiceBase, IProductService { - /// - /// 初始化产品服务 - /// - /// 服务提供器 - /// 工作单元 - /// 仓储 - public ProductService( IServiceProvider serviceProvider,ISqlServerUnitOfWork unitOfWork, IProductRepository repository ) : base( serviceProvider,unitOfWork, repository ) { - } - } -} \ No newline at end of file diff --git a/test/Util.Application.WebApi.Tests.Integration/UnitOfWorks/ISqlServerUnitOfWork.cs b/test/Util.Application.WebApi.Tests.Integration/UnitOfWorks/ISqlServerUnitOfWork.cs deleted file mode 100644 index 22dbb0d4..00000000 --- a/test/Util.Application.WebApi.Tests.Integration/UnitOfWorks/ISqlServerUnitOfWork.cs +++ /dev/null @@ -1,9 +0,0 @@ -using Util.Data; - -namespace Util.Applications.UnitOfWorks { - /// - /// 工作单元 - /// - public interface ISqlServerUnitOfWork : IUnitOfWork { - } -} \ No newline at end of file diff --git a/test/Util.Application.WebApi.Tests.Integration/UnitOfWorks/SqlServerUnitOfWork.cs b/test/Util.Application.WebApi.Tests.Integration/UnitOfWorks/SqlServerUnitOfWork.cs deleted file mode 100644 index 0ee18207..00000000 --- a/test/Util.Application.WebApi.Tests.Integration/UnitOfWorks/SqlServerUnitOfWork.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System; -using Microsoft.EntityFrameworkCore; -using Util.Data.EntityFrameworkCore; - -namespace Util.Applications.UnitOfWorks { - /// - /// SqlServer工作单元 - /// - public class SqlServerUnitOfWork : SqlServerUnitOfWorkBase, ISqlServerUnitOfWork { - /// - /// 初始化工作单元 - /// - /// 服务提供器 - /// 配置项 - public SqlServerUnitOfWork( IServiceProvider serviceProvider,DbContextOptions options ) : base( serviceProvider, options ) { - } - } -} \ No newline at end of file diff --git a/test/Util.AspNetCore.Tests/Samples/Certificate/apiclient_cert.p12 b/test/Util.AspNetCore.Tests/Samples/Certificate/apiclient_cert.p12 new file mode 100644 index 0000000000000000000000000000000000000000..3d03b770ea9ba308edcd26a7b96e0022d86efc8e GIT binary patch literal 2710 zcmY+Ec{~#iAIG;DMw8^WiIVh-vN;wVzudX+n_M%JV{*+|%-l`po`p~&a->x>camem zkI2fkQlvSSBD5aA*Xwzn-}C(Od3|5s_vici{`p4W1#>|_9t2*{oloFYs&VR;5Re~u z7cXc5#tWM4V?zWU{OX^I?=BwPvX5vWAYgyg|I+{wa6Z9*e}Dq{5C_4KykAn?*G86D zAP@wQhzBPQCOWb!%=H7$A9TIxWOSp4D~tHt?`M^!eraz*QjfDfCes54Z*{3CO_Xjr zYm)LaqgQRkXO=)Hc1v3e?{lupRgh!C*AiJHq)^U0u`<)BiDOQZH;HZ+SS5{G!^GUM zP7}9pB=)0k8farfMhN$hzmF<4rC-#8Tz2Vem1m2*AO(vF7Z&Gec?KQWw@uGXFv zy(WIz_fW<8hb(6#pi4q8qGDZUyg3Bg>X3EaT+B+UR=!&b7N@Bq@dg!BKYyWHr=g6S zB>16rz(_;7zBOjR1T&{TDAM&qv3kg2iqOCvyq@Kl&@at!i0wp`c(iW3h&y08Em{d` zcg;+=>7LuUxTR8mpmLI6_^oglOS!T2k(2zxjqQVtBVzP$EwDv`=ov5NqOs-N6XJ~{>M zd#YNu?>vtB6Pb#qWxG?^zRyMcz~ANT2BsLEa-7la9s};g_J#=QOZ2P(UxEXf}BDR)~Rl>8HPBCc@U zna3g#ft-u5Z~R1;W0~2S#YtI{Gv*=-(t5cY zYlBv!-|UA}kG_fMP%<;oTx22ugP=p9Lbju0?u~yvoH`RuC?$%$OG?9+UUq*pV;Vu5 z$m|`=_$1k=$?tYzyZ7oNZ|w*4_iNma0ZS>uaR$7?0&3Y9H#d^7_C#S}t%L&l~kW!n%v+^#|j5(finQKW=;n{-ZBJAZXuntNVic@_$z2`P*vr z1DKua+%o0Atp>(}`(X?D5UYm5avV?d-im&RL#k56YqIBR`8I56tNyQxC>@`)H<;)A z9Mwh1Dmj}1s-|$vr&}s}Mns*_(UxE&)=`m>Zi@6ZFApcT2xNc@HSC`=^Uy^UWa$*o zDD@i8`&%A2y_93n#M%5Pe($nfA>I0@absEzK(rvWX}C7;%e&YdVFq%ID6h9`bP zDjO4jH6Zz=&1wcKe`g0wV$Zi_*g>m|B5Cl?*i+y-z3nKt0K2*NDQ)?jZSN1BnZNwU z&sc0Y@}MC0tL5vbtZYJo1=dEm+V72r35j-LQ-)vWn|-oy94*a-(0cQtpG&)}h~Z+U z>oZHG_4E^T0XvI&n5pPl+cD>-R!U#w>t^%sz)maez+xx0)Ylbh27TUde$8D@y`nIO zqE~e|F@C(f2RSsH%o_4k5Yvyj?Hl%!oM#GK*6pcL`8>URGre61rnGiNcTS|wA;%kEO3&1)RkQ}yMKrJ16ZQ~d{EctWxkyy(@&)uk0 zXWU;6J)p8fRm|$^qI(z4x-#xPC{d7#)z>n_CjW8iM^OwH7KEdwZ%-AoZLdxFbq`^i z8sYgfU8WBD*sPrNq)pL=lT&K01wSte4i<=wZ3a{YgjK$a7u}JGw}Kwtd?L%>msy@I z4Oh_~T1ia|)UOT>6KG!7z7+y=D~);#YIjf!_E}AeuJn>&TCc=H|9t275J1B0S^_76 zXT;6Vi%S3tJJ6my55@ytUK}G`fF2A|FwiJfQr|6qzj&1?kLE{ej+eT)nYRA&Rnpix>oO)lYRW!$BxQoEb~VN` za_c-waA2-Lu2}qp=w3OA_ooaJeP3HW;N~}X^&Q5Duk%$_6F^q)^me44NYZSEPEFr% zIDsy)@Uc_;^s-BBnZ`TKX>qQ3km4rSH~dn4>KL;B05a20j%$9P~_{b%oEEBvaXHSA`{qYTP8U}ZAtCCGb)EC zhAPff34+HheFV?9CjTkg-wTZ3pc+*^{T`uukm-uYlH4arVl6`&yJ{3$&0`NLFK)tV zHC^M(r3pj+MXgR?Q`yP*K=_H-N1?iAUz48*OvPZhD4R6w7y8H0o-!$xd9kbvW`$q` z8m_R1C4U7Mm6XKgi4)z!W!}i@LMG?!B6q&q6#GNjzH2C)+J}5ygAf*Q%)av3tVJeNC~i* z88{TzHcO-M8FzDIq@qigo7)-?>i-;xAx|7R4zLGc03m=-fHxopAP>;r-@*V9fB=Bs ze$e|g0)RoBMjS;5@bM}i0>EP7)4`J{s(9UvwwE=SyvKHh1d~88q*VIoVaFuA G&%Xc$KmsuU literal 0 HcmV?d00001 diff --git a/test/Util.AspNetCore.Tests/Samples/Certificate/apiclient_cert.pem b/test/Util.AspNetCore.Tests/Samples/Certificate/apiclient_cert.pem new file mode 100644 index 00000000..7b80a20d --- /dev/null +++ b/test/Util.AspNetCore.Tests/Samples/Certificate/apiclient_cert.pem @@ -0,0 +1,23 @@ +-----BEGIN CERTIFICATE----- +MIID7DCCAtSgAwIBAgIULTQ1TmSotcbvSPsnVmPvfq6NqicwDQYJKoZIhvcNAQEL +BQAwXjELMAkGA1UEBhMCQ04xEzARBgNVBAoTClRlbnBheS5jb20xHTAbBgNVBAsT +FFRlbnBheS5jb20gQ0EgQ2VudGVyMRswGQYDVQQDExJUZW5wYXkuY29tIFJvb3Qg +Q0EwHhcNMjExMDEzMDgyMDMxWhcNMjYxMDEyMDgyMDMxWjB+MRMwEQYDVQQDDAox +NjA5NjUyNzM1MRswGQYDVQQKDBLlvq7kv6HllYbmiLfns7vnu58xKjAoBgNVBAsM +IeWbm+W3neiFvumjnuaJrOenkeaKgOaciemZkOWFrOWPuDELMAkGA1UEBgwCQ04x +ETAPBgNVBAcMCFNoZW5aaGVuMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC +AQEAp8Qc11qNPnF/iO88GMHgjjq/BUZpXAeExpNFs3+D0dKkloD5ssV/kvVXZPIp +INRjyl0mCovjyAZ4J8VLg/XZbG9f5Od6p0eXWMULubooI7Ii+K8pLE6eowwrieuY +4AXRLi339q8kiQC1gKZc0jN3YOWpdtss3ioFIaxLpHPNzaNG2aqeiEjQtJmkV17P +XFaM8hkqY2Csewb/yFXtUBcyJhrKGDgverNNu0Pz4DhVmw1cyjYTUOOY5cBErxza +FdMDXyAL3MJ3yN2h+zOJWSRwtYUwzqurBGvEwFlv/DTSmOoszPbSbB9rkPRlv2Zg +lBI55udovKZDbN+dRGy+08WO2QIDAQABo4GBMH8wCQYDVR0TBAIwADALBgNVHQ8E +BAMCBPAwZQYDVR0fBF4wXDBaoFigVoZUaHR0cDovL2V2Y2EuaXRydXMuY29tLmNu +L3B1YmxpYy9pdHJ1c2NybD9DQT0xQkQ0MjIwRTUwREJDMDRCMDZBRDM5NzU0OTg0 +NkMwMUMzRThFQkQyMA0GCSqGSIb3DQEBCwUAA4IBAQA8uLOYkgqJMfN6YdS5ZqBl +Q0BuaOADR8+GJAC828CGce4DAaeVLHo3lR/cuYeS4ursegw82tq1MW0kxTELhaCE +MeOVm2dui7ydQXuEx4GUVXK+VC5KN4HlnQe4roFqDXeVEcRrlkRQP+af9Tek9Vip +oywBdCLh3W58QlaPrNd565lqq+77HGn/7uj3aWjPVomr0M8Hc/LOiSyhefU0ot2i +PKBSpwM9j0l4Syk7bDk48BGWqq1UdggXZqLJ7HNIyX0lW3AaHGhIYopAK2b3d4X5 +DR6mDLekmLRc1QeUFUhw5dJ+pnLxvH6PUJeMq7RNf/k9EyGZJdTvBKsHpKdnWgfD +-----END CERTIFICATE----- diff --git a/test/Util.AspNetCore.Tests/Samples/Certificate/apiclient_key.pem b/test/Util.AspNetCore.Tests/Samples/Certificate/apiclient_key.pem new file mode 100644 index 00000000..e3170e3b --- /dev/null +++ b/test/Util.AspNetCore.Tests/Samples/Certificate/apiclient_key.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCnxBzXWo0+cX+I +7zwYweCOOr8FRmlcB4TGk0Wzf4PR0qSWgPmyxX+S9Vdk8ikg1GPKXSYKi+PIBngn +xUuD9dlsb1/k53qnR5dYxQu5uigjsiL4ryksTp6jDCuJ65jgBdEuLff2rySJALWA +plzSM3dg5al22yzeKgUhrEukc83No0bZqp6ISNC0maRXXs9cVozyGSpjYKx7Bv/I +Ve1QFzImGsoYOC96s027Q/PgOFWbDVzKNhNQ45jlwESvHNoV0wNfIAvcwnfI3aH7 +M4lZJHC1hTDOq6sEa8TAWW/8NNKY6izM9tJsH2uQ9GW/ZmCUEjnm52i8pkNs351E +bL7TxY7ZAgMBAAECggEATp0RPsDJ6vbYYlxodtly1nMky94AxQUo7LxaLxCTvqDM +S1JIr8LoUv7wYvcu2plr4Yngp5SBult9tnU3O7Dan3tZHjRyPyzG+Ovs4K0g3gk9 +Zfb+fiqhH5o2VLy3uFJBgTg9N7U+k4xngM90M3O2fwtfa7isv7ZFDVBlabxyNeeI +RYo7NYzkJCJjPq+LyW58F1y3BCs4s7ycN9PgxrkH52QFxq829p0zpXYcLhYygYH7 +EgUu+Cc/rFsuwp4DLslBVHmW0s1q40/8nRU3ytA1VWgTL7SRrWYGPm+3exgbFLh5 +RffTSHWFWqfx2W8VRN7qzZgvO5LeHXQAMzwCcYj4AQKBgQDdjfg7FM1vBHewqGCa +FGFrIeIZ4yOSBhMW3HvNmeswfSsrXn9szXTdZ+2n6kSgMbRJQKfrss91tNiInrF/ +tIo7av8ITKyIFFGR1Oauk3lxPxOINe925xImtyFMSoRZWzwd8MeckWC/GRNTUGe0 +1TNqYzcUuqPJunoF/UKmK10zgQKBgQDB2VJzdUgeEvogn2GesMoWtgQ6Y/o9sZQH +bXXJQwT0iROFoMnm/W9vliCmHy3OUnP/Nsr7pFy6rU4kWYll2ACsXRJ3DBL0YlAk +6gPsbXj6+yilg50ZPVAeAdV5g+lGIlMg5Uc5dAm7p7NaWHJE8iKvd2SpzfEfUJSo +vXOBmIYnWQKBgGj/hlvhoPZzJJIpShbbf8u49CGWnt3uWQ+lkFrBDlAdkd7s2vDi +cfcX8O56POm6hJmOtcYjKOS8vz4ID1DZbAV60MDLLZ0UHBBD2Mt1gsFjxkrwXLt6 +CQUmFvbD/fMnJNd/q+oMj9Ag/yKl4XA29jX+LTV6unK5GGlMPFDqDjKBAoGAEORu +Qe9zdGN09ojNCfYf9jCwV6JEuUGTQ75vKDW15dVYJSnozj9BibjMaY2IAVXAE/pj +X+Bn0ECv8Yz34y8ah+qoZEViFXfHwh++bcjwZPakCSBZ/UwRgjvorWkoV9s/4Tr5 +pPEOtBKeF35jnsx251GBLSbsHy13dujjeuSetCkCgYB7jzPMYLpQWbzYfqnQsUX1 +ZqKDWK+HOE3ZrxUZMBnbfs+0txnkgeF7yF1J52DLuAt1GlH+cYYA0oR6XajyOChd +BqKF1oi7Lsq/FqUi3eYaAlOPjVTZ+u4jqYrukzipWWbV9avfn02O/XLB8sm5ug2D +OYiAx6Hssmet8+KrcUA27A== +-----END PRIVATE KEY----- diff --git a/test/Util.AspNetCore.Tests/Startup.cs b/test/Util.AspNetCore.Tests/Startup.cs index f5544a00..37c42938 100644 --- a/test/Util.AspNetCore.Tests/Startup.cs +++ b/test/Util.AspNetCore.Tests/Startup.cs @@ -25,7 +25,8 @@ namespace Util.AspNetCore.Tests { endpoints.MapControllers(); } ); } ); - } ); + } ) + .AddUtil(); } /// @@ -38,7 +39,6 @@ namespace Util.AspNetCore.Tests { client.SetHttpClient( t.GetService().GetTestClient() ); return client; } ); - services.AddUtil(); } /// diff --git a/test/Util.AspNetCore.Tests/Util.AspNetCore.Tests.csproj b/test/Util.AspNetCore.Tests/Util.AspNetCore.Tests.csproj index f16cc716..2de0451f 100644 --- a/test/Util.AspNetCore.Tests/Util.AspNetCore.Tests.csproj +++ b/test/Util.AspNetCore.Tests/Util.AspNetCore.Tests.csproj @@ -6,24 +6,24 @@ - - - + + + - - - + + + runtime; build; native; contentfiles; analyzers; buildtransitive all - + runtime; build; native; contentfiles; analyzers; buildtransitive all - + diff --git a/test/Util.Core.Tests.Integration/Helpers/ConfigTest.cs b/test/Util.Core.Tests.Integration/Helpers/ConfigTest.cs index 9305a139..67f41f28 100644 --- a/test/Util.Core.Tests.Integration/Helpers/ConfigTest.cs +++ b/test/Util.Core.Tests.Integration/Helpers/ConfigTest.cs @@ -15,15 +15,5 @@ namespace Util.Tests.Helpers { Assert.Equal( 1,options.Code ); Assert.Equal( "a", options.Name ); } - - /// - /// 测试从根目录的appsettings2.json文件读取配置 - /// - [Fact] - public void TestGet_2() { - TestOptions options = Util.Helpers.Config.Get( "Test", "appsettings2.json" ); - Assert.Equal( 2, options.Code ); - Assert.Equal( "b", options.Name ); - } } } diff --git a/test/Util.Core.Tests.Integration/Infrastructure/BootstrapperTest.cs b/test/Util.Core.Tests.Integration/Infrastructure/BootstrapperTest.cs index a5305711..232d2616 100644 --- a/test/Util.Core.Tests.Integration/Infrastructure/BootstrapperTest.cs +++ b/test/Util.Core.Tests.Integration/Infrastructure/BootstrapperTest.cs @@ -1,4 +1,6 @@ -using Util.Dependency; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Util.Dependency; using Util.Infrastructure; using Util.Tests.Samples; using Xunit; @@ -17,11 +19,12 @@ namespace Util.Tests.Infrastructure { /// [Fact] public void TestStart_1() { - var container = new Container(); - var bootstrapper = new Bootstrapper( container.GetServices() ); + var builder = new HostBuilder(); + var bootstrapper = new Bootstrapper( builder ); bootstrapper.Start(); - Assert.Equal( "a", container.GetService().Value ); - Assert.Equal( "a", container.GetService().Value ); + var host = builder.Build(); + Assert.Equal( "a", host.Services.GetService()?.Value ); + Assert.Equal( "a", host.Services.GetService()?.Value ); } /// @@ -33,10 +36,11 @@ namespace Util.Tests.Infrastructure { /// [Fact] public void TestStart_2() { - var container = new Container(); - var bootstrapper = new Bootstrapper( container.GetServices(), options => options.UseTest() ); + var builder = new HostBuilder(); + var bootstrapper = new Bootstrapper( builder, options => options.UseTest() ); bootstrapper.Start(); - Assert.Equal( "Options", container.GetService().Value ); + var host = builder.Build(); + Assert.Equal( "Options", host.Services.GetService()?.Value ); } /// @@ -48,10 +52,11 @@ namespace Util.Tests.Infrastructure { /// [Fact] public void TestStart_3() { - var container = new Container(); - var bootstrapper = new Bootstrapper( container.GetServices(), options => options.UseTest() ); + var builder = new HostBuilder(); + var bootstrapper = new Bootstrapper( builder, options => options.UseTest() ); bootstrapper.Start(); - Assert.Equal( "a", container.GetService().Value ); + var host = builder.Build(); + Assert.Equal( "a", host.Services.GetService()?.Value ); } /// @@ -63,10 +68,11 @@ namespace Util.Tests.Infrastructure { /// [Fact] public void TestStart_4() { - var container = new Container(); - var bootstrapper = new Bootstrapper( container.GetServices(), options => options.UseTest() ); + var builder = new HostBuilder(); + var bootstrapper = new Bootstrapper( builder, options => options.UseTest() ); bootstrapper.Start(); - Assert.Equal( "Options", container.GetService().Value ); + var host = builder.Build(); + Assert.Equal( "Options", host.Services.GetService()?.Value ); } } } diff --git a/test/Util.Core.Tests.Integration/Infrastructure/DependencyServiceRegistrarTest.cs b/test/Util.Core.Tests.Integration/Infrastructure/DependencyServiceRegistrarTest.cs index ed034956..f8b1b771 100644 --- a/test/Util.Core.Tests.Integration/Infrastructure/DependencyServiceRegistrarTest.cs +++ b/test/Util.Core.Tests.Integration/Infrastructure/DependencyServiceRegistrarTest.cs @@ -1,4 +1,5 @@ -using Util.Dependency; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; using Util.Infrastructure; using Util.Tests.Samples; using Xunit; @@ -25,14 +26,15 @@ namespace Util.Tests.Infrastructure { /// [Fact] public void TestRegisterDependency_1() { - var container = new Container(); - var bootstrapper = new Bootstrapper( container.GetServices() ); + var builder = new HostBuilder(); + var bootstrapper = new Bootstrapper( builder ); bootstrapper.Start(); - Assert.Equal( typeof( TestService4 ), container.GetService().GetType() ); - Assert.NotEqual( typeof( TestService4 ), container.GetService()?.GetType() ); - Assert.NotEqual( typeof( TestService4 ), container.GetService()?.GetType() ); - Assert.NotEqual( typeof( TestService4 ), container.GetService()?.GetType() ); - Assert.Equal( typeof( TestService5 ), container.GetService>().GetType() ); + var host = builder.Build(); + Assert.Equal( typeof( TestService4 ), host.Services.GetService()?.GetType() ); + Assert.NotEqual( typeof( TestService4 ), host.Services.GetService()?.GetType() ); + Assert.NotEqual( typeof( TestService4 ), host.Services.GetService()?.GetType() ); + Assert.NotEqual( typeof( TestService4 ), host.Services.GetService()?.GetType() ); + Assert.Equal( typeof( TestService5 ), host.Services.GetService>()?.GetType() ); } /// @@ -40,10 +42,11 @@ namespace Util.Tests.Infrastructure { /// [Fact] public void TestRegisterDependency_2() { - var container = new Container(); - var bootstrapper = new Bootstrapper( container.GetServices() ); + var builder = new HostBuilder(); + var bootstrapper = new Bootstrapper( builder ); bootstrapper.Start(); - Assert.Equal( typeof( TestService8 ), container.GetService().GetType() ); + var host = builder.Build(); + Assert.Equal( typeof( TestService8 ), host.Services.GetService()?.GetType() ); } /// @@ -52,10 +55,11 @@ namespace Util.Tests.Infrastructure { [Fact] public void TestDisableDependencyServiceRegistrar() { ServiceRegistrarConfig.Instance.DisableDependencyServiceRegistrar(); - var container = new Container(); - var bootstrapper = new Bootstrapper( container.GetServices() ); + var builder = new HostBuilder(); + var bootstrapper = new Bootstrapper( builder ); bootstrapper.Start(); - Assert.NotEqual( typeof( TestService4 ), container.GetService()?.GetType() ); + var host = builder.Build(); + Assert.NotEqual( typeof( TestService4 ), host.Services.GetService()?.GetType() ); } } } diff --git a/test/Util.Core.Tests.Integration/Samples/TestOptionsExtension.cs b/test/Util.Core.Tests.Integration/Samples/TestOptionsExtension.cs index f41cf561..e380e68b 100644 --- a/test/Util.Core.Tests.Integration/Samples/TestOptionsExtension.cs +++ b/test/Util.Core.Tests.Integration/Samples/TestOptionsExtension.cs @@ -1,5 +1,6 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; +using Microsoft.Extensions.Hosting; using Util.Configs; namespace Util.Tests.Samples { @@ -19,8 +20,9 @@ namespace Util.Tests.Samples { /// /// 测试配置项扩展 /// - public class TestOptionsExtension : IOptionsExtension { - public void AddServices( IServiceCollection services ) { + public class TestOptionsExtension : OptionsExtensionBase { + /// + public override void ConfigureServices( HostBuilderContext context, IServiceCollection services ) { var service = new TestService { Value = "Options" }; services.TryAddSingleton( service ); diff --git a/test/Util.Core.Tests.Integration/Samples/TestServiceRegistrar.cs b/test/Util.Core.Tests.Integration/Samples/TestServiceRegistrar.cs index 95ba1a26..aba3e29c 100644 --- a/test/Util.Core.Tests.Integration/Samples/TestServiceRegistrar.cs +++ b/test/Util.Core.Tests.Integration/Samples/TestServiceRegistrar.cs @@ -1,7 +1,6 @@ using System; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; +using Microsoft.Extensions.Hosting; using Util.Infrastructure; using Util.Reflections; @@ -13,9 +12,11 @@ namespace Util.Tests.Samples { /// /// 注册服务 /// - public Action Register( IServiceCollection services, IConfiguration configuration, ITypeFinder finder ) { + public Action Register( IHostBuilder hostBuilder, ITypeFinder finder ) { A a = new A { Value = "a" }; - services.TryAddSingleton( a ); + hostBuilder.ConfigureServices( ( context, services ) => { + services.TryAddSingleton( a ); + } ); return null; } @@ -37,9 +38,11 @@ namespace Util.Tests.Samples { /// /// 注册服务 /// - public Action Register( IServiceCollection services, IConfiguration configuration, ITypeFinder finder ) { + public Action Register( IHostBuilder hostBuilder, ITypeFinder finder ) { A a = new A { Value = "b" }; - services.TryAddSingleton( a ); + hostBuilder.ConfigureServices( ( context, services ) => { + services.TryAddSingleton( a ); + } ); return null; } @@ -61,9 +64,11 @@ namespace Util.Tests.Samples { /// /// 注册服务 /// - public Action Register( IServiceCollection services, IConfiguration configuration, ITypeFinder finder ) { + public Action Register( IHostBuilder hostBuilder, ITypeFinder finder ) { var service = new TestService2 { Value = "a" }; - services.TryAddSingleton( service ); + hostBuilder.ConfigureServices( ( context, services ) => { + services.TryAddSingleton( service ); + } ); return null; } @@ -85,10 +90,12 @@ namespace Util.Tests.Samples { /// /// 注册服务 /// - public Action Register( IServiceCollection services, IConfiguration configuration, ITypeFinder finder ) { + public Action Register( IHostBuilder hostBuilder, ITypeFinder finder ) { return () => { var service = new TestService3 { Value = "a" }; - services.TryAddSingleton( service ); + hostBuilder.ConfigureServices( ( context, services ) => { + services.TryAddSingleton( service ); + } ); }; } diff --git a/test/Util.Core.Tests.Integration/Util.Core.Tests.Integration.csproj b/test/Util.Core.Tests.Integration/Util.Core.Tests.Integration.csproj index b29c19b2..5517e474 100644 --- a/test/Util.Core.Tests.Integration/Util.Core.Tests.Integration.csproj +++ b/test/Util.Core.Tests.Integration/Util.Core.Tests.Integration.csproj @@ -8,15 +8,9 @@ - - - PreserveNewest - true - PreserveNewest - PreserveNewest true @@ -25,13 +19,14 @@ - + + - + runtime; build; native; contentfiles; analyzers; buildtransitive all - + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/test/Util.Core.Tests.Integration/appsettings2.json b/test/Util.Core.Tests.Integration/appsettings2.json deleted file mode 100644 index 4b5d1ef8..00000000 --- a/test/Util.Core.Tests.Integration/appsettings2.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "Test": { - "Code": 2, - "Name": "b" - } -} diff --git a/test/Util.Core.Tests/Exceptions/WarningTest.cs b/test/Util.Core.Tests/Exceptions/WarningTest.cs index c004c111..549b3df0 100644 --- a/test/Util.Core.Tests/Exceptions/WarningTest.cs +++ b/test/Util.Core.Tests/Exceptions/WarningTest.cs @@ -21,7 +21,7 @@ namespace Util.Tests.Exceptions { /// [Fact] public void TestMessage_Null() { - Warning warning = new Warning( null, "A" ); + Warning warning = new Warning( "" ); Assert.Equal( string.Empty, warning.Message ); } @@ -30,7 +30,7 @@ namespace Util.Tests.Exceptions { /// [Fact] public void TestCode() { - Warning warning = new Warning( "", "B" ); + Warning warning = new Warning( "", code:"B" ); Assert.Equal( "B", warning.Code ); } @@ -49,7 +49,7 @@ namespace Util.Tests.Exceptions { /// [Fact] public void TestMessageAndException() { - Warning warning = new Warning( "A", "", new Exception( "C" ) ); + Warning warning = new Warning( "A", new Exception( "C" ) ); Assert.Equal( "A", warning.Message ); Assert.Equal( $"A{Environment.NewLine}C", warning.GetMessage() ); } @@ -59,7 +59,7 @@ namespace Util.Tests.Exceptions { /// [Fact] public void TestException_2Layer() { - Warning warning = new Warning( "A", "",new Exception( "C", new NotImplementedException( "D" ) ) ); + Warning warning = new Warning( "A", new Exception( "C", new NotImplementedException( "D" ) ) ); Assert.Equal( 3, warning.GetExceptions().Count ); Assert.Equal( typeof( Warning ), warning.GetExceptions()[0].GetType() ); Assert.Equal( typeof( Exception ), warning.GetExceptions()[1].GetType() ); diff --git a/test/Util.Core.Tests/Extensions/DateTimeExtensionsTest.cs b/test/Util.Core.Tests/Extensions/DateTimeExtensionsTest.cs index 2a959967..1fc99cea 100644 --- a/test/Util.Core.Tests/Extensions/DateTimeExtensionsTest.cs +++ b/test/Util.Core.Tests/Extensions/DateTimeExtensionsTest.cs @@ -1,82 +1,180 @@ using System; +using Util.Helpers; using Xunit; +using Convert = Util.Helpers.Convert; namespace Util.Tests.Extensions { /// /// 日期扩展测试 /// - public class DateTimeExtensionsTest { + public class DateTimeExtensionsTest : IDisposable { + + #region 测试初始化 + + /// + /// 日期字符串1,值为 2012-12-12 12:12:12 + /// + private string _dateString1 = "2012-12-12 12:12:12"; + /// + /// 日期字符串2,值为 2012-12-12 20:12:12 + /// + private string _dateString2 = "2012-12-12 20:12:12"; + /// + /// 日期字符串3,值为 2012-12-12 12:12 + /// + private string _dateString3 = "2012-12-12 12:12"; + /// + /// 日期字符串4,值为 2012-12-12 20:12 + /// + private string _dateString4 = "2012-12-12 20:12"; + /// + /// 日期1,值为 2012-12-12 12:12:12 + /// + private DateTime _date = new DateTime( 2012, 12, 12, 12, 12, 12 ); + /// + /// Utc日期,值为 2012-12-12 12:12:12 + /// + private DateTime _utcDate = new DateTime( 2012, 12, 12, 12, 12, 12,DateTimeKind.Utc ); + /// + /// 可空日期1,值为 2012-12-12 12:12:12 + /// + private DateTime? _nullabledate = new DateTime( 2012, 12, 12, 12, 12, 12 ); + /// + /// 可空Utc日期,值为 2012-12-12 12:12:12 + /// + private DateTime? _nullableUtcDate = new DateTime( 2012, 12, 12, 12, 12, 12, DateTimeKind.Utc ); + + #endregion + + #region 测试清理 + + /// + /// 测试清理 + /// + public void Dispose() { + Time.Reset(); + } + + #endregion + + #region ToDateTimeString + /// /// 测试获取格式化日期时间字符串 /// [Fact] public void TestToDateTimeString() { - string date = "2012-01-02 11:11:11"; - Assert.Equal( date, Util.Helpers.Convert.ToDateTime( date ).ToDateTimeString() ); - Assert.Equal( "2012-01-02 11:11", Util.Helpers.Convert.ToDateTime( date ).ToDateTimeString( true ) ); - Assert.Equal( "", Util.Helpers.Convert.ToDateTimeOrNull( "" ).ToDateTimeString() ); - Assert.Equal( date, Util.Helpers.Convert.ToDateTimeOrNull( date ).ToDateTimeString() ); + Assert.Equal( _dateString1, _date.ToDateTimeString() ); + Assert.Equal( _dateString3, _date.ToDateTimeString( true ) ); + Assert.Equal( "", Convert.ToDateTimeOrNull( "" ).ToDateTimeString() ); + Assert.Equal( _dateString1, _nullabledate.ToDateTimeString() ); + Assert.Equal( _dateString3, _nullabledate.ToDateTimeString( true ) ); + Assert.Equal( _dateString2, _utcDate.ToDateTimeString() ); + Assert.Equal( _dateString4, _utcDate.ToDateTimeString( true ) ); + Assert.Equal( _dateString2, _nullableUtcDate.ToDateTimeString() ); + Assert.Equal( _dateString4, _nullableUtcDate.ToDateTimeString( true ) ); } + /// + /// 测试获取格式化日期时间字符串 - 使用Utc + /// + [Fact] + public void TestToDateTimeString_Utc() { + Time.UseUtc(); + Assert.Equal( _dateString2, _date.ToDateTimeString() ); + Assert.Equal( _dateString4, _date.ToDateTimeString( true ) ); + Assert.Equal( "", Convert.ToDateTimeOrNull( "" ).ToDateTimeString() ); + Assert.Equal( _dateString2, _nullabledate.ToDateTimeString() ); + Assert.Equal( _dateString4, _nullabledate.ToDateTimeString( true ) ); + Assert.Equal( _dateString2, _utcDate.ToDateTimeString() ); + Assert.Equal( _dateString4, _utcDate.ToDateTimeString( true ) ); + Assert.Equal( _dateString2, _nullableUtcDate.ToDateTimeString() ); + Assert.Equal( _dateString4, _nullableUtcDate.ToDateTimeString( true ) ); + } + + #endregion + + #region ToDateString + /// /// 获取格式化日期字符串 /// [Fact] public void TestToDateString() { string date = "2012-01-02"; - Assert.Equal( date, Util.Helpers.Convert.ToDateTime( date ).ToDateString() ); - Assert.Equal( "", Util.Helpers.Convert.ToDateTimeOrNull( "" ).ToDateString() ); - Assert.Equal( date, Util.Helpers.Convert.ToDateTimeOrNull( date ).ToDateString() ); + Assert.Equal( date, Convert.ToDateTime( date ).ToDateString() ); + Assert.Equal( "", Convert.ToDateTimeOrNull( "" ).ToDateString() ); + Assert.Equal( date, Convert.ToDateTimeOrNull( date ).ToDateString() ); } + #endregion + + #region ToTimeString + /// /// 获取格式化时间字符串 /// [Fact] public void TestToTimeString() { string date = "2012-01-02 11:11:11"; - Assert.Equal( "11:11:11", Util.Helpers.Convert.ToDateTime( date ).ToTimeString() ); - Assert.Equal( "", Util.Helpers.Convert.ToDateTimeOrNull( "" ).ToTimeString() ); - Assert.Equal( "11:11:11", Util.Helpers.Convert.ToDateTimeOrNull( date ).ToTimeString() ); + Assert.Equal( "11:11:11", Convert.ToDateTime( date ).ToTimeString() ); + Assert.Equal( "", Convert.ToDateTimeOrNull( "" ).ToTimeString() ); + Assert.Equal( "11:11:11", Convert.ToDateTimeOrNull( date ).ToTimeString() ); } + #endregion + + #region ToMillisecondString + /// /// 获取格式化毫秒字符串 /// [Fact] public void TestToMillisecondString() { string date = "2012-01-02 11:11:11.123"; - Assert.Equal( date, Util.Helpers.Convert.ToDateTime( date ).ToMillisecondString() ); - Assert.Equal( "", Util.Helpers.Convert.ToDateTimeOrNull( "" ).ToMillisecondString() ); - Assert.Equal( date, Util.Helpers.Convert.ToDateTimeOrNull( date ).ToMillisecondString() ); + Assert.Equal( date, Convert.ToDateTime( date ).ToMillisecondString() ); + Assert.Equal( "", Convert.ToDateTimeOrNull( "" ).ToMillisecondString() ); + Assert.Equal( date, Convert.ToDateTimeOrNull( date ).ToMillisecondString() ); } + #endregion + + #region ToChineseDateString + /// /// 获取格式化中文日期字符串 /// [Fact] public void TestToChineseDateString() { string date = "2012-01-02"; - Assert.Equal( "2012年1月2日", Util.Helpers.Convert.ToDateTime( date ).ToChineseDateString() ); - Assert.Equal( "2012年12月12日", Util.Helpers.Convert.ToDateTime( "2012-12-12" ).ToChineseDateString() ); - Assert.Equal( "", Util.Helpers.Convert.ToDateTimeOrNull( "" ).ToChineseDateString() ); - Assert.Equal( "2012年1月2日", Util.Helpers.Convert.ToDateTimeOrNull( date ).ToChineseDateString() ); + Assert.Equal( "2012年1月2日", Convert.ToDateTime( date ).ToChineseDateString() ); + Assert.Equal( "2012年12月12日", Convert.ToDateTime( "2012-12-12" ).ToChineseDateString() ); + Assert.Equal( "", Convert.ToDateTimeOrNull( "" ).ToChineseDateString() ); + Assert.Equal( "2012年1月2日", Convert.ToDateTimeOrNull( date ).ToChineseDateString() ); } + #endregion + + #region ToChineseDateTimeString + /// /// 获取格式化中文日期时间字符串 /// [Fact] public void TestToChineseDateTimeString() { string date = "2012-01-02 11:11:11"; - Assert.Equal( "2012年1月2日 11时11分11秒", Util.Helpers.Convert.ToDateTime( date ).ToChineseDateTimeString() ); - Assert.Equal( "2012年12月12日 11时11分11秒", Util.Helpers.Convert.ToDateTime( "2012-12-12 11:11:11" ).ToChineseDateTimeString() ); - Assert.Equal( "2012年1月2日 11时11分", Util.Helpers.Convert.ToDateTime( date ).ToChineseDateTimeString( true ) ); - Assert.Equal( "", Util.Helpers.Convert.ToDateTimeOrNull( "" ).ToChineseDateTimeString() ); - Assert.Equal( "2012年1月2日 11时11分11秒", Util.Helpers.Convert.ToDateTimeOrNull( date ).ToChineseDateTimeString() ); - Assert.Equal( "2012年1月2日 11时11分", Util.Helpers.Convert.ToDateTimeOrNull( date ).ToChineseDateTimeString( true ) ); + Assert.Equal( "2012年1月2日 11时11分11秒", Convert.ToDateTime( date ).ToChineseDateTimeString() ); + Assert.Equal( "2012年12月12日 11时11分11秒", Convert.ToDateTime( "2012-12-12 11:11:11" ).ToChineseDateTimeString() ); + Assert.Equal( "2012年1月2日 11时11分", Convert.ToDateTime( date ).ToChineseDateTimeString( true ) ); + Assert.Equal( "", Convert.ToDateTimeOrNull( "" ).ToChineseDateTimeString() ); + Assert.Equal( "2012年1月2日 11时11分11秒", Convert.ToDateTimeOrNull( date ).ToChineseDateTimeString() ); + Assert.Equal( "2012年1月2日 11时11分", Convert.ToDateTimeOrNull( date ).ToChineseDateTimeString( true ) ); } + #endregion + + #region TimeSpan_Description + /// /// 测试获取时间间隔描述 /// @@ -97,5 +195,7 @@ namespace Util.Tests.Extensions { timeSpan = "2000-1-1 06:10:10.1000001".ToDateTime() - "2000-1-1 06:10:10.1000000".ToDateTime(); Assert.Equal( "0.0001毫秒", timeSpan.Description() ); } + + #endregion } } diff --git a/test/Util.Core.Tests/Helpers/ConvertTest.cs b/test/Util.Core.Tests/Helpers/ConvertTest.cs index 18358779..192656e9 100644 --- a/test/Util.Core.Tests/Helpers/ConvertTest.cs +++ b/test/Util.Core.Tests/Helpers/ConvertTest.cs @@ -248,10 +248,13 @@ namespace Util.Tests.Helpers { /// 输入值 /// 结果 [Theory] - [InlineData( null, false )] - [InlineData( "", false )] + [InlineData( null, null )] [InlineData( "false", false )] [InlineData( "true", true )] + [InlineData( 0, false )] + [InlineData( 1, true )] + [InlineData( "0", false )] + [InlineData( "1", true )] public void TestToBool( object input, bool result ) { Assert.Equal( result, Convert.ToBool( input ) ); } @@ -269,6 +272,10 @@ namespace Util.Tests.Helpers { [InlineData( null, null )] [InlineData( "false", false )] [InlineData( "true", true )] + [InlineData( 0, false )] + [InlineData( 1, true )] + [InlineData( "0", false )] + [InlineData( "1", true )] public void TestToBoolOrNull( object input, bool? result ) { Assert.Equal( result, Convert.ToBoolOrNull( input ) ); } @@ -465,12 +472,12 @@ namespace Util.Tests.Helpers { public void TestTo_3() { //序列化再反序列化字典 var dic = new Dictionary { - {"a", new Sample3 {StringValue = "a"}}, + {"a", new Sample3 {StringValue = "a"}}, {"b", new Sample3 {StringValue = "b"}} }; var json = Json.ToJson( dic ); dic = Json.ToObject>( json ); - + //从字典中获取元素并转换 var element = dic["b"]; var result = Convert.To( element ); @@ -496,11 +503,11 @@ namespace Util.Tests.Helpers { Display = "Display", NullableBoolValue = true, DisplayName = "DisplayName", - Test3 = new Sample3 {StringValue = "a"}, - TestList = new List {new() {StringValue = "a"}, new() {StringValue = "b"}} + Test3 = new Sample3 { StringValue = "a" }, + TestList = new List { new() { StringValue = "a" }, new() { StringValue = "b" } } }; var result = Convert.ToDictionary( sample ); - Assert.Equal( 9,result.Count ); + Assert.Equal( 9, result.Count ); Assert.Equal( "Display", result["Display"] ); Assert.Equal( 2, result["IntValue"] ); } diff --git a/test/Util.Core.Tests/Helpers/CultureTest.cs b/test/Util.Core.Tests/Helpers/CultureTest.cs new file mode 100644 index 00000000..1768cfcd --- /dev/null +++ b/test/Util.Core.Tests/Helpers/CultureTest.cs @@ -0,0 +1,22 @@ +using System.Globalization; +using Xunit; + +namespace Util.Tests.Helpers { + /// + /// 区域文化测试 + /// + public class CultureTest { + /// + /// 测试获取区域文化信息列表 + /// + [Fact] + public void TestGetCultures() { + var culture = new CultureInfo( "zh-CN" ); + var cultures = Util.Helpers.Culture.GetCultures( culture ); + Assert.Equal( 3, cultures.Count ); + Assert.Equal( "zh-CN", cultures[0].Name ); + Assert.Equal( "zh-Hans", cultures[1].Name ); + Assert.Equal( "zh", cultures[2].Name ); + } + } +} diff --git a/test/Util.Core.Tests/Helpers/JsonTest.cs b/test/Util.Core.Tests/Helpers/JsonTest.cs index 505f4e45..5c5c77be 100644 --- a/test/Util.Core.Tests/Helpers/JsonTest.cs +++ b/test/Util.Core.Tests/Helpers/JsonTest.cs @@ -1,6 +1,11 @@ using System.Text; +using System.Text.Encodings.Web; +using System.Text.Json; +using System.Text.Json.Serialization; +using System.Text.Unicode; using System.Threading.Tasks; using Util.Helpers; +using Util.SystemTextJson; using Util.Tests.Samples; using Xunit; @@ -10,22 +15,45 @@ namespace Util.Tests.Helpers { /// public class JsonTest { /// - /// 测试转成Json + /// 测试转成Json - 转换为本地日期 /// [Fact] - public void TestToJson() { + public void TestToJson_Local() { + Time.UseUtc( false ); var result = new StringBuilder(); - result.Append("{"); - result.Append("\"Name\":\"a\","); - result.Append("\"nickname\":\"b\","); - result.Append("\"firstName\":\"c\","); - result.Append("\"Value\":null,"); - result.Append("\"Date\":\"2012/1/1 0:00:00\","); - result.Append("\"Age\":1,"); - result.Append("\"IsShow\":true"); - result.Append("}"); + result.Append( "{" ); + result.Append( "\"Name\":\"a\"," ); + result.Append( "\"nickname\":\"b\"," ); + result.Append( "\"firstName\":\"c\"," ); + result.Append( "\"Value\":null," ); + result.Append( "\"Date\":\"2012-12-12 20:12:12\"," ); + result.Append( "\"UtcDate\":\"2012-12-12 20:12:12\"," ); + result.Append( "\"Age\":1," ); + result.Append( "\"IsShow\":true" ); + result.Append( "}" ); var sample = JsonTestSample.Create(); - Assert.Equal(result.ToString(), Json.ToJson(sample)); + Assert.Equal( result.ToString(), Json.ToJson( sample ) ); + } + + /// + /// 测试转成Json - 转换为Utc日期 + /// + [Fact] + public void TestToJson_Utc() { + Time.UseUtc(); + var result = new StringBuilder(); + result.Append( "{" ); + result.Append( "\"Name\":\"a\"," ); + result.Append( "\"nickname\":\"b\"," ); + result.Append( "\"firstName\":\"c\"," ); + result.Append( "\"Value\":null," ); + result.Append( "\"Date\":\"2012-12-12 12:12:12\"," ); + result.Append( "\"UtcDate\":\"2012-12-12 12:12:12\"," ); + result.Append( "\"Age\":1," ); + result.Append( "\"IsShow\":true" ); + result.Append( "}" ); + var sample = JsonTestSample.Create(); + Assert.Equal( result.ToString(), Json.ToJson( sample ) ); } /// @@ -39,12 +67,13 @@ namespace Util.Tests.Helpers { result.Append( "nickname:b," ); result.Append( "firstName:c," ); result.Append( "Value:null," ); - result.Append( "Date:2012/1/1 0:00:00," ); + result.Append( "Date:2012-12-12 20:12:12," ); + result.Append( "UtcDate:2012-12-12 20:12:12," ); result.Append( "Age:1," ); result.Append( "IsShow:true" ); result.Append( "}" ); var sample = JsonTestSample.Create(); - Assert.Equal( result.ToString(), Json.ToJson( sample,removeQuotationMarks:true ) ); + Assert.Equal( result.ToString(), Json.ToJson( sample,removeQuotationMarks: true ) ); } /// @@ -53,18 +82,19 @@ namespace Util.Tests.Helpers { [Fact] public async Task TestToJsonAsync() { var result = new StringBuilder(); - result.Append("{"); - result.Append("\"Name\":\"a\","); - result.Append("\"nickname\":\"b\","); - result.Append("\"firstName\":\"c\","); - result.Append("\"Value\":null,"); - result.Append("\"Date\":\"2012/1/1 0:00:00\","); - result.Append("\"Age\":1,"); - result.Append("\"IsShow\":true"); - result.Append("}"); + result.Append( "{" ); + result.Append( "\"Name\":\"a\"," ); + result.Append( "\"nickname\":\"b\"," ); + result.Append( "\"firstName\":\"c\"," ); + result.Append( "\"Value\":null," ); + result.Append( "\"Date\":\"2012-12-12 20:12:12\"," ); + result.Append( "\"UtcDate\":\"2012-12-12 20:12:12\"," ); + result.Append( "\"Age\":1," ); + result.Append( "\"IsShow\":true" ); + result.Append( "}" ); var sample = JsonTestSample.Create(); - var json = await Json.ToJsonAsyc(sample); - Assert.Equal(result.ToString(), json); + var json = await Json.ToJsonAsyc( sample ); + Assert.Equal( result.ToString(), json ); } /// @@ -72,8 +102,8 @@ namespace Util.Tests.Helpers { /// [Fact] public void TestToObject() { - var sample = Json.ToObject("{\"Name\":\"a\"}"); - Assert.Equal("a", sample.Name); + var sample = Json.ToObject( "{\"Name\":\"a\"}" ); + Assert.Equal( "a", sample.Name ); } /// @@ -81,8 +111,38 @@ namespace Util.Tests.Helpers { /// [Fact] public async Task TestToObjectAsync() { - var sample = await Json.ToObjectAsync("{\"Name\":\"a\"}"); - Assert.Equal("a", sample.Name); + var sample = await Json.ToObjectAsync( "{\"Name\":\"a\"}" ); + Assert.Equal( "a", sample.Name ); + } + + /// + /// 测试转成Json - 不转义中文字符 + /// + [Fact] + public void TestToJson_Encoder() { + var result = new StringBuilder(); + result.Append( "{" ); + result.Append( "\"Name\":\"哈哈\"," ); + result.Append( "\"nickname\":\"b\"," ); + result.Append( "\"firstName\":\"c\"," ); + result.Append( "\"Date\":\"2012-12-12 12:12:12\"," ); + result.Append( "\"Age\":1," ); + result.Append( "\"IsShow\":true" ); + result.Append( "}" ); + var sample = new JsonTestSample() { + Name = "哈哈", + nickname = "b", + FirstName = "c", + Value = null, + Date = Util.Helpers.Convert.ToDateTime( "2012-12-12 12:12:12" ), + Age = 1, + IsShow = true + }; + Assert.Equal( result.ToString(), Json.ToJson( sample, new JsonSerializerOptions { + DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, + Encoder = JavaScriptEncoder.Create( UnicodeRanges.All ), + Converters = { new NullableDateTimeJsonConverter() } + } ) ); } } } diff --git a/test/Util.Core.Tests/Helpers/TimeTest.cs b/test/Util.Core.Tests/Helpers/TimeTest.cs index 86802685..d4f3ade3 100644 --- a/test/Util.Core.Tests/Helpers/TimeTest.cs +++ b/test/Util.Core.Tests/Helpers/TimeTest.cs @@ -7,6 +7,46 @@ namespace Util.Tests.Helpers { /// 时间操作测试 /// public class TimeTest : IDisposable { + + #region 测试初始化 + + /// + /// 日期格式 + /// + private static string _dateFormat = "yyyy-MM-dd HH:mm:ss"; + /// + /// 测试日期时间字符串,2012-12-12 12:12:12 + /// + private static readonly string _testDateString = "2012-12-12 12:12:12"; + /// + /// 测试日期时间,2012-12-12 12:12:12 + /// + private static readonly DateTime _testDate = DateTime.Parse( _testDateString ); + /// + /// 本地日期时间,2012-12-12 12:12:12 + /// + private static readonly DateTime _localDate = new DateTime( 2012, 12, 12, 12, 12, 12, DateTimeKind.Local ); + /// + /// 本地日期时间,2012-12-12 20:12:12 + /// + private static readonly DateTime _localDate2 = new DateTime( 2012, 12, 12, 20, 12, 12, DateTimeKind.Local ); + /// + /// utc日期时间,2012-12-12 4:12:12 + /// + private static readonly DateTime _utcDate = new DateTime( 2012, 12, 12, 4, 12, 12, DateTimeKind.Utc ); + /// + /// utc日期时间,2012-12-12 12:12:12 + /// + private static readonly DateTime _utcDate2 = new DateTime( 2012, 12, 12, 12, 12, 12, DateTimeKind.Utc ); + /// + /// 未指定日期时间,2012-12-12 12:12:12 + /// + private static readonly DateTime _unspecifiedDate = new DateTime( 2012, 12, 12, 12, 12, 12, DateTimeKind.Unspecified ); + + #endregion + + #region 测试清理 + /// /// 测试清理 /// @@ -14,26 +54,162 @@ namespace Util.Tests.Helpers { Time.Reset(); } - /// - /// 日期时间字符串,"2012-01-02 01:02:03" - /// - public const string DatetimeString1 = "2012-01-02 01:02:03"; + #endregion + + #region 辅助方法 /// - /// 日期时间,2012-01-02 01:02:03 + /// 相等断言 /// - public static readonly DateTime Datetime1 = DateTime.Parse( DatetimeString1 ); + /// 预期日期字符串 + /// 实际日期 + private void AssertEqual( string expected,DateTime actual ) { + Assert.Equal( expected, actual.ToString( _dateFormat ) ); + } + + /// + /// 不相等断言 + /// + /// 预期日期字符串 + /// 实际日期 + private void AssertNotEqual( string expected, DateTime actual ) { + Assert.NotEqual( expected, actual.ToString( _dateFormat ) ); + } + + #endregion + + #region SetTime + /// /// 测试设置时间 /// [Fact] public void TestSetTime() { - Time.SetTime( Datetime1 ); - Assert.Equal( Datetime1, Time.GetDateTime() ); + Time.SetTime( _testDate ); + AssertEqual( _testDateString, Time.Now ); Time.Reset(); - Assert.NotEqual( Datetime1, Time.GetDateTime() ); + AssertNotEqual( _testDateString, Time.Now ); } + #endregion + + #region UseUtc + + /// + /// 测试设置Utc日期 + /// + [Fact] + public void TestUseUtc() { + Time.UseUtc(); + Assert.Equal( DateTime.UtcNow.ToString( _dateFormat ), Time.Now.ToString( _dateFormat ) ); + Time.UseUtc( false ); + Assert.Equal( DateTime.Now.ToString( _dateFormat ), Time.Now.ToString( _dateFormat ) ); + } + + #endregion + + #region Normalize + + /// + /// 测试本地日期转换为本地日期 + /// + [Fact] + public void TestNormalize_1() { + //使用本地日期 + Time.UseUtc( false ); + + //转换本地日期为本地日期 + var result = Time.Normalize( _localDate ); + + //验证 + AssertEqual( _testDateString, result ); + Assert.Equal( DateTimeKind.Local, result.Kind ); + } + + /// + /// 测试Utc日期转换为本地日期 + /// + [Fact] + public void TestNormalize_2() { + //使用本地日期 + Time.UseUtc( false ); + + //转换Utc日期为本地日期 + var result = Time.Normalize( _utcDate ); + + //验证 + AssertEqual( _testDateString, result ); + Assert.Equal( DateTimeKind.Local, result.Kind ); + } + + /// + /// 测试本地日期转换为Utc日期 + /// + [Fact] + public void TestNormalize_3() { + //使用Utc日期 + Time.UseUtc(); + + //转换本地日期为Utc日期 + var result = Time.Normalize( _localDate2 ); + + //验证 + AssertEqual( _testDateString, result ); + Assert.Equal( DateTimeKind.Utc, result.Kind ); + } + + /// + /// 测试Utc日期转换为Utc日期 + /// + [Fact] + public void TestNormalize_4() { + //使用Utc日期 + Time.UseUtc(); + + //转换Utc日期为Utc日期 + var result = Time.Normalize( _utcDate2 ); + + //验证 + AssertEqual( _testDateString, result ); + Assert.Equal( DateTimeKind.Utc, result.Kind ); + } + + /// + /// 测试未指定日期转换为本地日期 + /// + [Fact] + public void TestNormalize_5() { + //使用本地日期 + Time.UseUtc( false ); + + //转换本地日期为本地日期 + var result = Time.Normalize( _unspecifiedDate ); + + //验证 + AssertEqual( _testDateString, result ); + Assert.Equal( DateTimeKind.Local, result.Kind ); + } + + /// + /// 测试未指定日期转换为Utc日期 + /// + [Fact] + public void TestNormalize_6() { + //使用本地日期 + Time.UseUtc(); + + //转换本地日期为本地日期 + var result = Time.Normalize( _unspecifiedDate ); + + //验证 + AssertEqual( _testDateString, result ); + Assert.Equal( DateTimeKind.Utc, result.Kind ); + } + + #endregion + + #region GetUnixTimestamp + /// /// 测试获取Unix时间戳 /// @@ -44,6 +220,10 @@ namespace Util.Tests.Helpers { Assert.Equal( 1392668699, Time.GetUnixTimestamp( new DateTime( 2014, 02, 18, 04, 24, 59 ) ) ); } + #endregion + + #region GetTimeFromUnixTimestamp + /// /// 测试从Unix时间戳获取时间 /// @@ -54,17 +234,6 @@ namespace Util.Tests.Helpers { Assert.Equal( new DateTime( 2014, 02, 18, 04, 24, 59 ), Time.GetTimeFromUnixTimestamp( 1392668699 ) ); } - /// - /// 测试并发执行 - /// - [Fact] - public void TestConcurrency() { - Util.Helpers.Thread.ParallelFor( () => { - Time.SetTime( Datetime1 ); - Assert.Equal( Datetime1, Time.GetDateTime() ); - Time.Reset(); - Assert.NotEqual( Datetime1, Time.GetDateTime() ); - }, 100 ); - } + #endregion } } diff --git a/test/Util.Core.Tests/Samples/JsonTestSample.cs b/test/Util.Core.Tests/Samples/JsonTestSample.cs index b11b6971..0dfcb169 100644 --- a/test/Util.Core.Tests/Samples/JsonTestSample.cs +++ b/test/Util.Core.Tests/Samples/JsonTestSample.cs @@ -1,4 +1,5 @@ -using System.Text.Json.Serialization; +using System; +using System.Text.Json.Serialization; namespace Util.Tests.Samples { public class A { @@ -44,7 +45,11 @@ namespace Util.Tests.Samples { /// /// 日期 /// - public string Date { get; set; } + public DateTime? Date { get; set; } + /// + /// Utc日期 + /// + public DateTime? UtcDate { get; set; } /// /// 测试整型,不添加引号 /// @@ -64,7 +69,8 @@ namespace Util.Tests.Samples { nickname = "b", FirstName = "c", Value = null, - Date = Util.Helpers.Convert.ToDateTime( "2012-1-1" ).SafeString(), + Date = new DateTime( 2012,12,12,20,12,12, DateTimeKind.Local ), + UtcDate = new DateTime( 2012, 12, 12, 12, 12, 12,DateTimeKind.Utc ), Age = 1, IsShow = true }; diff --git a/test/Util.Core.Tests/Util.Core.Tests.csproj b/test/Util.Core.Tests/Util.Core.Tests.csproj index 31909664..f02c65d8 100644 --- a/test/Util.Core.Tests/Util.Core.Tests.csproj +++ b/test/Util.Core.Tests/Util.Core.Tests.csproj @@ -7,14 +7,14 @@ - - + + - + runtime; build; native; contentfiles; analyzers; buildtransitive all - + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/test/Util.Data.Dapper.MySql.Tests.Integration/Infrastructure/DatabaseScript.cs b/test/Util.Data.Dapper.MySql.Tests.Integration/Infrastructure/DatabaseScript.cs new file mode 100644 index 00000000..f6ef8005 --- /dev/null +++ b/test/Util.Data.Dapper.MySql.Tests.Integration/Infrastructure/DatabaseScript.cs @@ -0,0 +1,126 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; + +namespace Util.Data.Dapper.Tests.Infrastructure { + /// + /// 数据库初始化脚本 + /// + public class DatabaseScript { + /// + /// 初始化 + /// + public static void InitProcedures( DatabaseFacade database ) { + CreateGetProductCodeProcedure( database ); + CreateGetProductProcedure( database ); + CreateGetProductsProcedure( database ); + CreateGetOrderItemProcedure( database ); + CreateGetProductCodeOutputProcedure( database ); + CreateInsertProductProcedure( database ); + } + + /// + /// 创建Proc_GetProductCode存储过程 + /// + private static void CreateGetProductCodeProcedure( DatabaseFacade database ) { + var sql = @" + Create Procedure Proc_GetProductCode ( + id char(36) + ) + Begin + Select Code + From Product + Where ProductId = id; + End + "; + database.ExecuteSqlRaw( sql ); + } + + /// + /// 创建Proc_GetProduct存储过程 + /// + private static void CreateGetProductProcedure( DatabaseFacade database ) { + var sql = @" + Create Procedure Proc_GetProduct ( + id char(36) + ) + Begin + Select * + From Product + Where ProductId = id; + End + "; + database.ExecuteSqlRaw( sql ); + } + + /// + /// 创建Proc_GetProducts存储过程 + /// + private static void CreateGetProductsProcedure( DatabaseFacade database ) { + var sql = @" + Create Procedure Proc_GetProducts ( + id char(36), + id2 char(36) + ) + Begin + Select p.ProductId As Id,p.* + From Product As p + Where p.ProductId in ( id,id2 ); + End + "; + database.ExecuteSqlRaw( sql ); + } + + /// + /// 创建Proc_GetOrderItem存储过程 + /// + private static void CreateGetOrderItemProcedure( DatabaseFacade database ) { + var sql = @" + Create Procedure Proc_GetOrderItem ( + id char(36) + ) + Begin + Select i.OrderItemId As Id,i.*,o.OrderId As Id,o.* + From OrderItem As i + Left Join `Order` As o On o.OrderId=i.OrderId + Where i.OrderItemId=id; + End + "; + database.ExecuteSqlRaw( sql ); + } + + /// + /// 创建Proc_GetProductCode_Output存储过程 + /// + private static void CreateGetProductCodeOutputProcedure( DatabaseFacade database ) { + var sql = @" + Create Procedure Proc_GetProductCode_Output ( + id char(36), + out code_output varchar(50) + ) + Begin + Select `Code` into code_output + From `Product` + Where `ProductId` = id; + End + "; + database.ExecuteSqlRaw( sql ); + } + + /// + /// 创建Proc_InsertProduct存储过程 + /// + private static void CreateInsertProductProcedure( DatabaseFacade database ) { + var sql = @" + Create Procedure Proc_InsertProduct ( + id char(36), + codeValue varchar(50) + ) + Begin + Insert Into Product(ProductId,Code) + Values( id,codeValue ); + End + "; + database.ExecuteSqlRaw( sql ); + } + } +} diff --git a/test/Util.Data.Dapper.MySql.Tests.Integration/Metadata/MySqlMetadataServiceTest.cs b/test/Util.Data.Dapper.MySql.Tests.Integration/Metadata/MySqlMetadataServiceTest.cs new file mode 100644 index 00000000..ba6dd559 --- /dev/null +++ b/test/Util.Data.Dapper.MySql.Tests.Integration/Metadata/MySqlMetadataServiceTest.cs @@ -0,0 +1,112 @@ +using System.Linq; +using Util.Data.Metadata; +using Xunit; + +namespace Util.Data.Dapper.Tests.Metadata { + /// + /// MySql数据库元数据服务测试 + /// + public class MySqlMetadataServiceTest { + /// + /// 数据库元信息 + /// + private readonly DatabaseInfo _databaseInfo; + + /// + /// 测试初始化 + /// + public MySqlMetadataServiceTest( IMetadataService service ) { + _databaseInfo = service.GetDatabaseInfo(); + } + + /// + /// 测试获取数据库名称 + /// + [Fact] + public void TestDatabaseName() { + Assert.Equal( "Util.Data.Dapper.Test", _databaseInfo.Name ); + } + + /// + /// 测试获取表信息 + /// + [Fact] + public void TestTableInfo() { + var table = _databaseInfo.Tables.FirstOrDefault( t => t.Name == "Product" ); + Assert.NotNull( table ); + Assert.Null( table.Schema ); + Assert.Equal( "产品", table.Comment ); + } + + /// + /// 测试获取主键信息 + /// + [Fact] + public void TestPrimaryKey() { + var table = _databaseInfo.Tables.First( t => t.Name == "OrderItem" ); + var pkColumn = table.Columns.FirstOrDefault( t => t.Name == "OrderItemId" ); + Assert.NotNull( pkColumn ); + Assert.True( pkColumn.IsPrimaryKey ); + var fkColumn = table.Columns.FirstOrDefault( t => t.Name == "OrderId" ); + Assert.NotNull( fkColumn ); + Assert.False( fkColumn.IsPrimaryKey ); + } + + /// + /// 测试获取自增信息 + /// + [Fact] + public void TestAutoIncrement() { + var table = _databaseInfo.Tables.FirstOrDefault( t => t.Name == "Customer" ); + Assert.NotNull( table ); + var column = table.Columns.FirstOrDefault( t => t.Name == "CustomerId" ); + Assert.NotNull( column ); + Assert.True( column.IsAutoIncrement ); + Assert.Equal( "int", column.DataType ); + } + + /// + /// 测试获取数值精度信息 + /// + [Fact] + public void TestPrecision() { + var table = _databaseInfo.Tables.FirstOrDefault( t => t.Name == "Product" ); + Assert.NotNull( table ); + var column = table.Columns.FirstOrDefault( t => t.Name == "Price" ); + Assert.NotNull( column ); + Assert.Equal( 12, column.Precision ); + Assert.Equal( 2, column.Scale ); + } + + /// + /// 测试获取字符串列信息 + /// + [Fact] + public void TestStringInfo() { + var table = _databaseInfo.Tables.FirstOrDefault( t => t.Name == "Product" ); + Assert.NotNull( table ); + var count = table.Columns.Count( t => t.Name == "Code" ); + Assert.Equal( 1, count ); + var column = table.Columns.FirstOrDefault( t => t.Name == "Code" ); + Assert.NotNull( column ); + Assert.Equal( "产品编码", column.Comment ); + Assert.False( column.IsPrimaryKey ); + Assert.True( column.IsNullable ); + Assert.Equal( "varchar", column.DataType ); + Assert.Equal( 50, column.Length ); + } + + /// + /// 测试获取布尔列信息 + /// + [Fact] + public void TestBoolInfo() { + var table = _databaseInfo.Tables.FirstOrDefault( t => t.Name == "Product" ); + Assert.NotNull( table ); + var column = table.Columns.FirstOrDefault( t => t.Name == "IsDeleted" ); + Assert.NotNull( column ); + Assert.Equal( "tinyint", column.DataType ); + Assert.Equal( 1, column.Length ); + } + } +} diff --git a/test/Util.Data.Dapper.MySql.Tests.Integration/SqlBuilders/MySqlExistsSqlBuilderTest.cs b/test/Util.Data.Dapper.MySql.Tests.Integration/SqlBuilders/MySqlExistsSqlBuilderTest.cs new file mode 100644 index 00000000..4536ad8e --- /dev/null +++ b/test/Util.Data.Dapper.MySql.Tests.Integration/SqlBuilders/MySqlExistsSqlBuilderTest.cs @@ -0,0 +1,48 @@ +using System.Text; +using Util.Data.Sql; +using Util.Data.Sql.Builders; +using Xunit; +using Xunit.Abstractions; + +namespace Util.Data.Dapper.Tests.SqlBuilders { + /// + /// 测试判断是否存在的Sql生成器 + /// + public class MySqlExistsSqlBuilderTest { + /// + /// 输出工具 + /// + private readonly ITestOutputHelper _output; + + /// + /// 测试初始化 + /// + public MySqlExistsSqlBuilderTest( ITestOutputHelper output ) { + _output = output; + } + + /// + /// 测试生成的Sql + /// + [Fact] + public void TestToSql() { + var sql = new StringBuilder(); + sql.AppendLine( "Select Case" ); + sql.AppendLine( " When Exists (" ); + sql.AppendLine( "Select 1 " ); + sql.Append( "From `b`" ); + sql.AppendLine( ")" ); + sql.AppendLine( " Then true" ); + sql.AppendLine( " Else false " ); + sql.Append( "End" ); + + var subQuery = new MySqlBuilder() + .Select("a") + .From( "b" ); + var sqlBuilder = new MySqlExistsSqlBuilder( subQuery ); + var result = sqlBuilder.GetSql(); + _output.WriteLine( result ); + Assert.Equal( sql.ToString(),result ); + } + } +} diff --git a/test/Util.Data.Dapper.MySql.Tests.Integration/SqlExecutor/MySqlExecutorTest.Execute.cs b/test/Util.Data.Dapper.MySql.Tests.Integration/SqlExecutor/MySqlExecutorTest.Execute.cs new file mode 100644 index 00000000..09538efd --- /dev/null +++ b/test/Util.Data.Dapper.MySql.Tests.Integration/SqlExecutor/MySqlExecutorTest.Execute.cs @@ -0,0 +1,28 @@ +using System; +using System.Threading.Tasks; +using Util.Data.Sql; +using Util.Tests.Configs; +using Xunit; + +namespace Util.Data.Dapper.Tests.SqlExecutor { + /// + /// MySql Sql执行器测试 - 执行Sql测试 + /// + public partial class MySqlExecutorTest { + /// + /// 测试执行Sql增删改操作 + /// + [Fact] + public async Task TestExecuteAsync() { + var id = Guid.NewGuid(); + await _sqlExecutor + .AppendLine( "Insert Product(ProductId,Code) " ) + .Append( "Values(@ProductId,@Code)" ) + .AddParam( "@ProductId", id ) + .AddParam( "Code", TestConfig.Value ) + .ExecuteAsync(); + var result = await _sqlExecutor.Select( "Code" ).From( "Product" ).Where( "ProductId", id ).ToStringAsync(); + Assert.Equal( TestConfig.Value, result ); + } + } +} diff --git a/test/Util.Data.Dapper.MySql.Tests.Integration/SqlExecutor/MySqlExecutorTest.Id.cs b/test/Util.Data.Dapper.MySql.Tests.Integration/SqlExecutor/MySqlExecutorTest.Id.cs new file mode 100644 index 00000000..ac2bbada --- /dev/null +++ b/test/Util.Data.Dapper.MySql.Tests.Integration/SqlExecutor/MySqlExecutorTest.Id.cs @@ -0,0 +1,67 @@ +using System; +using System.Threading.Tasks; +using Util.Data.Sql; +using Util.Helpers; +using Util.Tests.Configs; +using Xunit; + +namespace Util.Data.Dapper.Tests.SqlExecutor { + /// + /// MySql Sql执行器测试 - 标识列测试 + /// + public partial class MySqlExecutorTest { + /// + /// 测试插入Guid主键 + /// + [Fact] + public async Task TestInsert_Guid() { + var id = Guid.NewGuid(); + await _sqlExecutor + .Insert( "ProductId,Code", "Product" ) + .Values( id, TestConfig.Value ) + .ExecuteAsync(); + var result = await _sqlExecutor + .Select( "Code" ) + .From( "Product" ) + .Where( "ProductId", id ) + .ToStringAsync(); + Assert.Equal( TestConfig.Value, result ); + } + + /// + /// 测试插入int自增长主键 + /// + [Fact] + public async Task TestInsert_Int() { + var value = Id.Create(); + await _sqlExecutor + .Insert( "Code", "Customer" ) + .Values( value ) + .ExecuteAsync(); + var result = await _sqlExecutor + .Select( "CustomerId" ) + .From( "Customer" ) + .Where( "Code", value ) + .ToIntAsync(); + Assert.True( result > 0 ); + } + + /// + /// 测试插入string主键 + /// + [Fact] + public async Task TestInsert_String() { + var id = Id.Create(); + await _sqlExecutor + .Insert( "OrderId,CustomerName", "Order" ) + .Values( id, TestConfig.Value ) + .ExecuteAsync(); + var result = await _sqlExecutor + .Select( "CustomerName" ) + .From( "Order" ) + .Where( "OrderId", id ) + .ToStringAsync(); + Assert.Equal( TestConfig.Value, result ); + } + } +} diff --git a/test/Util.Data.Dapper.MySql.Tests.Integration/SqlExecutor/MySqlExecutorTest.Insert.cs b/test/Util.Data.Dapper.MySql.Tests.Integration/SqlExecutor/MySqlExecutorTest.Insert.cs new file mode 100644 index 00000000..4c282f38 --- /dev/null +++ b/test/Util.Data.Dapper.MySql.Tests.Integration/SqlExecutor/MySqlExecutorTest.Insert.cs @@ -0,0 +1,83 @@ +using System; +using System.Threading.Tasks; +using Util.Data.Sql; +using Util.Tests.Configs; +using Xunit; + +namespace Util.Data.Dapper.Tests.SqlExecutor { + /// + /// MySql Sql执行器测试 - 插入测试 + /// + public partial class MySqlExecutorTest { + /// + /// 测试使用Insert Values语句插入一条数据 + /// + [Fact] + public async Task TestInsert_1() { + //插入一条数据 + var id = Guid.NewGuid(); + await _sqlExecutor + .Insert( "ProductId,Code", "Product" ) + .Values( id, TestConfig.Value ) + .ExecuteAsync(); + + //获取值 + var result = await _sqlExecutor + .Select( "Code" ) + .From( "Product" ) + .Where( "ProductId", id ) + .ToStringAsync(); + + //验证 + Assert.Equal( TestConfig.Value, result ); + } + + /// + /// 测试使用Insert Values语句插入2条数据 + /// + [Fact] + public async Task TestInsert_2() { + //插入一条数据 + var id = Guid.NewGuid(); + var id2 = Guid.NewGuid(); + await _sqlExecutor + .Insert( "ProductId,Code", "Product" ) + .Values( id, TestConfig.Value ) + .Values( id2, TestConfig.Value ) + .ExecuteAsync(); + + //获取值 + var result = await _sqlExecutor + .AppendSelect( "Count(*)" ) + .From( "Product" ) + .In( "ProductId", new[]{id,id2} ) + .ToIntAsync(); + + //验证 + Assert.Equal( 2, result ); + } + + /// + /// 测试使用Insert Select语句插入 + /// + [Fact] + public async Task TestInsert_3() { + //用Insert Select插入一条数据 + var id = Guid.NewGuid(); + await _sqlExecutor + .Insert( "ProductId,Code", "Product" ) + .AppendSelect( $"'{id}','{TestConfig.Value}'" ) + .ExecuteAsync(); + + //获取值 + var result = await _sqlExecutor + .Select( "Code" ) + .From( "Product" ) + .Where( "ProductId", id ) + .ToStringAsync(); + + //验证 + Assert.Equal( TestConfig.Value, result ); + } + } +} diff --git a/test/Util.Data.Dapper.MySql.Tests.Integration/SqlExecutor/MySqlExecutorTest.Param.cs b/test/Util.Data.Dapper.MySql.Tests.Integration/SqlExecutor/MySqlExecutorTest.Param.cs new file mode 100644 index 00000000..554e5b54 --- /dev/null +++ b/test/Util.Data.Dapper.MySql.Tests.Integration/SqlExecutor/MySqlExecutorTest.Param.cs @@ -0,0 +1,81 @@ +using System; +using System.Data; +using System.Threading.Tasks; +using Util.Data.Sql; +using Util.Tests.Configs; +using Xunit; + +namespace Util.Data.Dapper.Tests.SqlExecutor { + /// + /// MySql Sql执行器测试 - 执行存储过程参数测试 + /// + public partial class MySqlExecutorTest { + /// + /// 测试添加动态参数 + /// + [Fact] + public async Task TestAddParam_Dynamic() { + var id = Guid.NewGuid(); + await _sqlExecutor + .AppendLine( "Insert Product(ProductId,Code) " ) + .Append( "Values(@ProductId,@Code)" ) + .AddDynamicParams( new { ProductId=id, Code= TestConfig.Value } ) + .ExecuteAsync(); + var result = await _sqlExecutor.Select( "Code" ).From( "Product" ).Where( "ProductId", id ).ToStringAsync(); + Assert.Equal( TestConfig.Value, result ); + } + + /// + /// 测试添加和获取输出参数 + /// + [Fact] + public async Task TestAddParam_Output() { + //定义变量 + var id = Guid.NewGuid(); + + //插入数据 + await _sqlExecutor + .AppendLine( "Insert Product(ProductId,Code) " ) + .Append( "Values(@ProductId,@Code)" ) + .AddParam( "@ProductId", id ) + .AddParam( "Code", TestConfig.Value ) + .ExecuteAsync(); + + //执行存储过程 - 添加输出参数 + await _sqlExecutor + .AddParam( "id", id ) + .AddParam( "code_output", dbType: DbType.String,direction: ParameterDirection.Output,size:50 ) + .ExecuteProcedureAsync( "Proc_GetProductCode_Output" ); + + //验证 - 使用GetParam获取输出参数 + Assert.Equal( TestConfig.Value, _sqlExecutor.GetParam( "code_output" ) ); + } + + /// + /// 测试添加参数 - 在执行前添加并获取参数 + /// + [Fact] + public async Task TestAddParam_1() { + var id = Guid.NewGuid(); + + //添加第一个参数 + _sqlExecutor + .AppendLine( "Insert Product(ProductId,Code) " ) + .Append( "Values(@ProductId,@Code)" ) + .AddParam( "@ProductId", id ); + + //获取参数 + var param = _sqlExecutor.GetParam( "ProductId" ); + Assert.Equal( id, param ); + + //添加第二个参数并执行 + await _sqlExecutor + .AddParam( "Code", TestConfig.Value ) + .ExecuteAsync(); + + //验证 + var result = await _sqlExecutor.Select( "Code" ).From( "Product" ).Where( "ProductId", id ).ToStringAsync(); + Assert.Equal( TestConfig.Value, result ); + } + } +} diff --git a/test/Util.Data.Dapper.MySql.Tests.Integration/SqlExecutor/MySqlExecutorTest.Procedure.cs b/test/Util.Data.Dapper.MySql.Tests.Integration/SqlExecutor/MySqlExecutorTest.Procedure.cs new file mode 100644 index 00000000..71e29f32 --- /dev/null +++ b/test/Util.Data.Dapper.MySql.Tests.Integration/SqlExecutor/MySqlExecutorTest.Procedure.cs @@ -0,0 +1,35 @@ +using System; +using System.Threading.Tasks; +using Util.Data.Sql; +using Util.Tests.Configs; +using Xunit; + +namespace Util.Data.Dapper.Tests.SqlExecutor { + /// + /// MySql Sql执行器测试 - 执行存储过程测试 + /// + public partial class MySqlExecutorTest { + /// + /// 测试执行存储过程增删改操作 + /// + [Fact] + public async Task TestExecuteProcedureScalarAsync() { + //定义变量 + var id = Guid.NewGuid(); + + //插入数据,参数无论是否加@前缀均可 + await _sqlExecutor + .AddParam( "id", id ) + .AddParam( "codeValue", TestConfig.Value ) + .ExecuteProcedureAsync( "Proc_InsertProduct" ); + + //获取IntValue值 + var result = await _sqlExecutor + .AddParam( "id", id ) + .ExecuteProcedureScalarAsync( "Proc_GetProductCode" ); + + //验证 + Assert.Equal( TestConfig.Value, result ); + } + } +} diff --git a/test/Util.Data.Dapper.MySql.Tests.Integration/SqlExecutor/MySqlExecutorTest.Transaction.cs b/test/Util.Data.Dapper.MySql.Tests.Integration/SqlExecutor/MySqlExecutorTest.Transaction.cs new file mode 100644 index 00000000..e14b6707 --- /dev/null +++ b/test/Util.Data.Dapper.MySql.Tests.Integration/SqlExecutor/MySqlExecutorTest.Transaction.cs @@ -0,0 +1,250 @@ +using System; +using System.Threading.Tasks; +using Util.Data.Sql; +using Util.Tests.Configs; +using Xunit; + +namespace Util.Data.Dapper.Tests.SqlExecutor { + /// + /// MySql Sql执行器测试 - 事务测试 + /// + public partial class MySqlExecutorTest { + /// + /// 测试事务操作 - 不使用事务,第一次操作成功,第二次失败 + /// + [Fact] + public async Task TestTransaction_1() { + //创建两个Id + var id = Guid.NewGuid(); + var id2 = Guid.NewGuid(); + + try { + //插入Id成功 + await _sqlExecutor + .Insert( "ProductId,Code", "Product" ) + .Values( id, TestConfig.Value ) + .ExecuteAsync(); + + //Code2列名错误,插入Id2失败 + await _sqlExecutor + .Insert( "ProductId,Code,Code2", "Product" ) + .Values( id2, TestConfig.Value, TestConfig.Value ) + .ExecuteAsync(); + } + catch { + // ignored + } + + //断言 + var exists = await _sqlExecutor.From( "Product" ).Where( "ProductId", id ).ExecuteExistsAsync(); + var exists2 = await _sqlExecutor.From( "Product" ).Where( "ProductId", id2 ).ExecuteExistsAsync(); + Assert.True( exists ); + Assert.False( exists2 ); + } + + /// + /// 测试事务操作 - 调用BeginTransaction,CommitTransaction,RollbackTransaction + /// + [Fact] + public async Task TestTransaction_2() { + //开始事务 + _sqlExecutor.BeginTransaction(); + + //创建两个Id + var id = Guid.NewGuid(); + var id2 = Guid.NewGuid(); + + try { + //插入Id成功 + await _sqlExecutor + .Insert( "ProductId,Code", "Product" ) + .Values( id, TestConfig.Value ) + .ExecuteAsync(); + + //Code2列名错误,插入Id2失败 + await _sqlExecutor + .Insert( "ProductId,Code,Code2", "Product" ) + .Values( id2, TestConfig.Value, TestConfig.Value ) + .ExecuteAsync(); + + //提交事务 + _sqlExecutor.CommitTransaction(); + } + catch { + //回滚事务 + _sqlExecutor.RollbackTransaction(); + } + + //断言 + var exists = await _sqlExecutor.From( "Product" ).Where( "ProductId", id ).ExecuteExistsAsync(); + var exists2 = await _sqlExecutor.From( "Product" ).Where( "ProductId", id2 ).ExecuteExistsAsync(); + Assert.False( exists ); + Assert.False( exists2 ); + } + + /// + /// 测试事务操作 - 使用using调用BeginTransaction + /// + [Fact] + public async Task TestTransaction_3() { + //创建两个Id + var id = Guid.NewGuid(); + var id2 = Guid.NewGuid(); + + try { + using var transaction = _sqlExecutor.BeginTransaction(); + //插入Id成功 + await _sqlExecutor + .Insert( "ProductId,Code", "Product" ) + .Values( id, TestConfig.Value ) + .ExecuteAsync(); + + //Code2列名错误,插入Id2失败 + await _sqlExecutor + .Insert( "ProductId,Code,Code2", "Product" ) + .Values( id2, TestConfig.Value, TestConfig.Value ) + .ExecuteAsync(); + + //提交事务 + transaction.Commit(); + } + catch { + // ignored + } + + //断言 + var exists = await _sqlExecutor.From( "Product" ).Where( "ProductId", id ).ExecuteExistsAsync(); + var exists2 = await _sqlExecutor.From( "Product" ).Where( "ProductId", id2 ).ExecuteExistsAsync(); + Assert.False( exists ); + Assert.False( exists2 ); + } + + /// + /// 测试事务操作 - 外部传入事务 - 回滚 + /// + [Fact] + public async Task TestTransaction_4() { + //Sql执行器实例2开始事务 + _sqlExecutor2.BeginTransaction(); + var transaction = _sqlExecutor2.GetTransaction(); + + //设置Sql执行器实例1事务 + _sqlExecutor.SetTransaction( transaction ); + + //创建两个Id + var id = Guid.NewGuid(); + var id2 = Guid.NewGuid(); + + try { + //插入Id成功 + await _sqlExecutor + .Insert( "ProductId,Code", "Product" ) + .Values( id, TestConfig.Value ) + .ExecuteAsync(); + + //Code2列名错误,插入Id2失败 + await _sqlExecutor2 + .Insert( "ProductId,Code,Code2", "Product" ) + .Values( id2, TestConfig.Value, TestConfig.Value ) + .ExecuteAsync(); + + //提交事务 + _sqlExecutor.CommitTransaction(); + } + catch { + //回滚事务 + _sqlExecutor.RollbackTransaction(); + } + + //断言 + var exists = await _sqlExecutor.From( "Product" ).Where( "ProductId", id ).ExecuteExistsAsync(); + var exists2 = await _sqlExecutor.From( "Product" ).Where( "ProductId", id2 ).ExecuteExistsAsync(); + Assert.False( exists ); + Assert.False( exists2 ); + } + + /// + /// 测试事务操作 - 外部传入事务 - 成功 + /// + [Fact] + public async Task TestTransaction_5() { + //Sql执行器实例2开始事务 + _sqlExecutor2.BeginTransaction(); + var transaction = _sqlExecutor2.GetTransaction(); + + //设置Sql执行器实例1事务 + _sqlExecutor.SetTransaction( transaction ); + + //创建两个Id + var id = Guid.NewGuid(); + var id2 = Guid.NewGuid(); + + try { + //插入Id成功 + await _sqlExecutor + .Insert( "ProductId,Code", "Product" ) + .Values( id, TestConfig.Value ) + .ExecuteAsync(); + + //Code2列名错误,插入Id2失败 + await _sqlExecutor2 + .Insert( "ProductId,Code", "Product" ) + .Values( id2, TestConfig.Value ) + .ExecuteAsync(); + + //提交事务 + _sqlExecutor.CommitTransaction(); + } + catch { + //回滚事务 + _sqlExecutor.RollbackTransaction(); + } + + //断言 + var exists = await _sqlExecutor.From( "Product" ).Where( "ProductId", id ).ExecuteExistsAsync(); + var exists2 = await _sqlExecutor.From( "Product" ).Where( "ProductId", id2 ).ExecuteExistsAsync(); + Assert.True( exists ); + Assert.True( exists2 ); + } + + /// + /// 测试事务操作 - 成功提交 + /// + [Fact] + public async Task TestTransaction_6() { + //开始事务 + _sqlExecutor.BeginTransaction(); + + //创建两个Id + var id = Guid.NewGuid(); + var id2 = Guid.NewGuid(); + + try { + //插入Id成功 + await _sqlExecutor + .Insert( "ProductId,Code", "Product" ) + .Values( id, TestConfig.Value ) + .ExecuteAsync(); + + //插入Id2成功 + await _sqlExecutor + .Insert( "ProductId,Code", "Product" ) + .Values( id2, TestConfig.Value ) + .ExecuteAsync(); + + //提交事务 + _sqlExecutor.CommitTransaction(); + } + catch { + //回滚事务 + _sqlExecutor.RollbackTransaction(); + } + + //断言 + var exists = await _sqlExecutor.From( "Product" ).Where( "ProductId", id ).ExecuteExistsAsync(); + var exists2 = await _sqlExecutor.From( "Product" ).Where( "ProductId", id2 ).ExecuteExistsAsync(); + Assert.True( exists ); + Assert.True( exists2 ); + } + } +} diff --git a/test/Util.Data.Dapper.MySql.Tests.Integration/SqlExecutor/MySqlExecutorTest.cs b/test/Util.Data.Dapper.MySql.Tests.Integration/SqlExecutor/MySqlExecutorTest.cs new file mode 100644 index 00000000..f7b50159 --- /dev/null +++ b/test/Util.Data.Dapper.MySql.Tests.Integration/SqlExecutor/MySqlExecutorTest.cs @@ -0,0 +1,31 @@ +using Util.Data.Sql; +using Xunit.Abstractions; + +namespace Util.Data.Dapper.Tests.SqlExecutor { + /// + /// MySql Sql执行器测试 + /// + public partial class MySqlExecutorTest { + /// + /// 测试输出工具 + /// + private readonly ITestOutputHelper _output; + /// + /// Sql执行器 + /// + private readonly ISqlExecutor _sqlExecutor; + /// + /// Sql执行器2 + /// + private readonly ISqlExecutor _sqlExecutor2; + + /// + /// 测试初始化 + /// + public MySqlExecutorTest( ITestOutputHelper output, ISqlExecutor sqlExecutor, ISqlExecutor sqlExecutor2 ) { + _output = output; + _sqlExecutor = sqlExecutor; + _sqlExecutor2 = sqlExecutor2; + } + } +} diff --git a/test/Util.Data.Dapper.MySql.Tests.Integration/SqlQuery/MySqlQueryTest.Exists.cs b/test/Util.Data.Dapper.MySql.Tests.Integration/SqlQuery/MySqlQueryTest.Exists.cs new file mode 100644 index 00000000..3b3ebb48 --- /dev/null +++ b/test/Util.Data.Dapper.MySql.Tests.Integration/SqlQuery/MySqlQueryTest.Exists.cs @@ -0,0 +1,48 @@ +using System; +using System.Threading.Tasks; +using Util.Data.Sql; +using Util.Tests.Configs; +using Xunit; + +namespace Util.Data.Dapper.Tests.SqlQuery { + /// + /// MySql Sql²éѯ¶ÔÏó²âÊÔ - ÅжÏÊǷñ´æÔڲâÊÔ + /// + public partial class MySqlQueryTest { + /// + /// ²âÊÔÅжÏÊǷñ´æÔÚ - ´æÔÚ + /// + [Fact] + public void TestExecuteExists_1() { + var result = _sqlQuery.From( "Product" ).Where( "ProductId", TestConfig.Id ).ExecuteExists(); + Assert.True( result ); + } + + /// + /// ²âÊÔÅжÏÊǷñ´æÔÚ - ²»´æÔÚ + /// + [Fact] + public void TestExecuteExists_2() { + var result = _sqlQuery.From( "Product" ).Where( "ProductId", Guid.NewGuid() ).ExecuteExists(); + Assert.False( result ); + } + + /// + /// ²âÊÔÅжÏÊǷñ´æÔÚ - ´æÔÚ + /// + [Fact] + public async Task TestExecuteExistsAsync_1() { + var result = await _sqlQuery.From( "Product" ).Where( "ProductId", TestConfig.Id ).ExecuteExistsAsync(); + Assert.True( result ); + } + + /// + /// ²âÊÔÅжÏÊǷñ´æÔÚ - ²»´æÔÚ + /// + [Fact] + public async Task TestExecuteExistsAsync_2() { + var result = await _sqlQuery.From( "Product" ).Where( "ProductId", Guid.NewGuid() ).ExecuteExistsAsync(); + Assert.False( result ); + } + } +} diff --git a/test/Util.Data.Dapper.MySql.Tests.Integration/SqlQuery/MySqlQueryTest.Procedure.cs b/test/Util.Data.Dapper.MySql.Tests.Integration/SqlQuery/MySqlQueryTest.Procedure.cs new file mode 100644 index 00000000..2a1bbcf7 --- /dev/null +++ b/test/Util.Data.Dapper.MySql.Tests.Integration/SqlQuery/MySqlQueryTest.Procedure.cs @@ -0,0 +1,301 @@ +using System; +using System.Collections; +using System.Threading.Tasks; +using Util.Data.Sql; +using Util.Helpers; +using Util.Tests.Configs; +using Util.Tests.Models; +using Xunit; + +namespace Util.Data.Dapper.Tests.SqlQuery { + /// + /// MySql Sql²éѯ¶ÔÏó²âÊÔ - ִÐд洢¹ý³̲âÊÔ + /// + public partial class MySqlQueryTest { + + #region ExecuteProcedureScalar + + /// + /// ²âÊÔִÐд洢¹ý³̻ñȡµ¥ֵ + /// + [Fact] + public void TestExecuteProcedureScalar_1() { + //ִÐд洢¹ý³Ì + var result = _sqlQuery + .AddParam( "id", TestConfig.Id ) + .ExecuteProcedureScalar( "Proc_GetProductCode" ); + + //¶ÏÑÔ + Assert.Equal( TestConfig.Value, result ); + Assert.Equal( "`Proc_GetProductCode`", _sqlQuery.PreviousSql.GetSql() ); + } + + /// + /// ²âÊÔִÐд洢¹ý³̻ñȡµ¥ֵ - ·ºÐͷ½·¨ + /// + [Fact] + public void TestExecuteProcedureScalar_2() { + //ִÐд洢¹ý³Ì + var result = _sqlQuery + .AddParam( "id", TestConfig.Id ) + .ExecuteProcedureScalar( "Proc_GetProductCode" ); + + //¶ÏÑÔ + Assert.Equal( TestConfig.Value, result ); + Assert.Equal( "`Proc_GetProductCode`", _sqlQuery.PreviousSql.GetSql() ); + } + + #endregion + + #region ExecuteProcedureScalarAsync + + /// + /// ²âÊÔִÐд洢¹ý³̻ñȡµ¥ֵ + /// + [Fact] + public async Task TestExecuteProcedureScalarAsync_1() { + //ִÐд洢¹ý³Ì + var result = await _sqlQuery + .AddParam( "id", TestConfig.Id ) + .ExecuteProcedureScalarAsync( "Proc_GetProductCode" ); + + //¶ÏÑÔ + Assert.Equal( TestConfig.Value, result ); + Assert.Equal( "`Proc_GetProductCode`", _sqlQuery.PreviousSql.GetSql() ); + } + + /// + /// ²âÊÔִÐд洢¹ý³̻ñȡµ¥ֵ - ·ºÐͷ½·¨ + /// + [Fact] + public async Task TestExecuteProcedureScalarAsync_2() { + //ִÐд洢¹ý³Ì + var result = await _sqlQuery + .AddParam( "id", TestConfig.Id ) + .ExecuteProcedureScalarAsync( "Proc_GetProductCode" ); + + //¶ÏÑÔ + Assert.Equal( TestConfig.Value, result ); + Assert.Equal( "`Proc_GetProductCode`", _sqlQuery.PreviousSql.GetSql() ); + } + + #endregion + + #region ExecuteProcedureSingle + + /// + /// ²âÊÔִÐд洢¹ý³̻ñȡµ¥¸öʵÌå + /// + [Fact] + public void TestExecuteProcedureSingle() { + //ִÐд洢¹ý³Ì + var result = _sqlQuery + .AddParam( "id", TestConfig.Id ) + .ExecuteProcedureSingle( "Proc_GetProduct" ); + + //¶ÏÑÔ + Assert.Equal( TestConfig.Value, result.Code ); + Assert.Equal( "`Proc_GetProduct`", _sqlQuery.PreviousSql.GetSql() ); + } + + #endregion + + #region ExecuteProcedureSingleAsync + + /// + /// ²âÊÔִÐд洢¹ý³̻ñȡµ¥¸öʵÌå + /// + [Fact] + public async Task TestExecuteProcedureSingleAsync() { + //ִÐд洢¹ý³Ì + var result = await _sqlQuery + .AddParam( "id", TestConfig.Id ) + .ExecuteProcedureSingleAsync( "Proc_GetProduct" ); + + //¶ÏÑÔ + Assert.Equal( TestConfig.Value, result.Code ); + Assert.Equal( "`Proc_GetProduct`", _sqlQuery.PreviousSql.GetSql() ); + } + + #endregion + + #region ExecuteProcedureQuery + + /// + /// ²âÊÔִÐд洢¹ý³̻ñȡʵÌ弯ºÏ + /// + [Fact] + public async Task TestExecuteProcedureQuery_1() { + //²åÈë2ÌõÊý¾Ý + var id = Guid.NewGuid(); + var id2 = Guid.NewGuid(); + await _sqlExecutor.Insert( "ProductId,Code", "Product" ) + .Values( id, "a" ) + .Values( id2, "b" ) + .ExecuteAsync(); + + //ִÐд洢¹ý³Ì + var result = _sqlQuery + .AddParam( "id", id ) + .AddParam( "id2", id2 ) + .ExecuteProcedureQuery( "Proc_GetProducts" ); + + //¶ÏÑÔ + Assert.Equal( 2, result.Count ); + Assert.Contains( result, t => t.Id == id && t.Code == "a" ); + Assert.Contains( result, t => t.Id == id2 && t.Code == "b" ); + Assert.Equal( "`Proc_GetProducts`", _sqlQuery.PreviousSql.GetSql() ); + } + + /// + /// ²âÊԻñȡʵÌ弯ºÏ - 1¸ö·ºÐͲÎÊý + /// + [Fact] + public async Task TestExecuteProcedureQuery_2() { + //²åÈë2ÌõÊý¾Ý + var id = Guid.NewGuid(); + var id2 = Guid.NewGuid(); + await _sqlExecutor.Insert( "ProductId,Code", "Product" ) + .Values( id, "a" ) + .Values( id2, "b" ) + .ExecuteAsync(); + + //ִÐд洢¹ý³Ì + var result = _sqlQuery + .AddParam( "id", id ) + .AddParam( "id2", id2 ) + .ExecuteProcedureQuery( "Proc_GetProducts" ); + + //¶ÏÑÔ + Assert.Equal( 2, result.Count ); + Assert.Contains( result, t => t.Id == id && t.Code == "a" ); + Assert.Contains( result, t => t.Id == id2 && t.Code == "b" ); + Assert.Equal( "`Proc_GetProducts`", _sqlQuery.PreviousSql.GetSql() ); + } + + /// + /// ²âÊԻñȡʵÌ弯ºÏ - 3¸ö·ºÐͲÎÊý - Ö÷´ӱí,ÉèÖùØÁªÊôÐÔ + /// + [Fact] + public async Task TestExecuteProcedureQuery_3() { + //²åÈ붩µ¥ + var orderId = Id.Create(); + var customerName = "customerName"; + await _sqlExecutor.Insert( "OrderId,CustomerName", "Order" ) + .Values( orderId, customerName ) + .ExecuteAsync(); + + //²åÈ붩µ¥Ã÷ϸ + var orderItemId = Id.CreateGuid(); + await _sqlExecutor.Insert( "OrderItemId,OrderId,Price", "OrderItem" ) + .Values( orderItemId, orderId, TestConfig.DecimalValue ) + .ExecuteAsync(); + + //»ñȡ¶ÔÏó + var result = _sqlQuery + .AddParam( "id", orderItemId ) + .ExecuteProcedureQuery( "Proc_GetOrderItem", ( item, order ) => { + item.Order = order; + return item; + } ); + + //¶ÏÑÔ + Assert.Single( (IEnumerable)result ); + Assert.Equal( orderItemId, result[0].Id ); + Assert.Equal( TestConfig.DecimalValue, result[0].Price ); + Assert.Equal( orderId, result[0].OrderId ); + Assert.Equal( orderId, result[0].Order.Id ); + Assert.Equal( customerName, result[0].Order.CustomerName ); + } + + #endregion + + #region ExecuteProcedureQueryAsync + + /// + /// ²âÊÔִÐд洢¹ý³̻ñȡʵÌ弯ºÏ + /// + [Fact] + public async Task TestExecuteProcedureQueryAsync_1() { + //²åÈë2ÌõÊý¾Ý + var id = Guid.NewGuid(); + var id2 = Guid.NewGuid(); + await _sqlExecutor.Insert( "ProductId,Code", "Product" ) + .Values( id, "a" ) + .Values( id2, "b" ) + .ExecuteAsync(); + + //ִÐд洢¹ý³Ì + var result = await _sqlQuery + .AddDynamicParams( new{ id, id2 } ) + .ExecuteProcedureQueryAsync( "Proc_GetProducts" ); + + //¶ÏÑÔ + Assert.Equal( 2, result.Count ); + Assert.Contains( result, t => t.Id == id && t.Code == "a" ); + Assert.Contains( result, t => t.Id == id2 && t.Code == "b" ); + } + + /// + /// ²âÊԻñȡʵÌ弯ºÏ - 1¸ö·ºÐͲÎÊý + /// + [Fact] + public async Task TestExecuteProcedureQueryAsync_2() { + //²åÈë2ÌõÊý¾Ý + var id = Guid.NewGuid(); + var id2 = Guid.NewGuid(); + await _sqlExecutor.Insert( "ProductId,Code", "Product" ) + .Values( id, "a" ) + .Values( id2, "b" ) + .ExecuteAsync(); + + //ִÐд洢¹ý³Ì + var result = await _sqlQuery + .AddParam( "id", id ) + .AddParam( "id2", id2 ) + .ExecuteProcedureQueryAsync( "Proc_GetProducts" ); + + //¶ÏÑÔ + Assert.Equal( 2, result.Count ); + Assert.Contains( result, t => t.Id == id && t.Code == "a" ); + Assert.Contains( result, t => t.Id == id2 && t.Code == "b" ); + } + + /// + /// ²âÊԻñȡʵÌ弯ºÏ - 3¸ö·ºÐͲÎÊý - Ö÷´ӱí,ÉèÖùØÁªÊôÐÔ + /// + [Fact] + public async Task TestExecuteProcedureQueryAsync_3() { + //²åÈ붩µ¥ + var orderId = Id.Create(); + var customerName = "customerName"; + await _sqlExecutor.Insert( "OrderId,CustomerName", "Order" ) + .Values( orderId, customerName ) + .ExecuteAsync(); + + //²åÈ붩µ¥Ã÷ϸ + var orderItemId = Id.CreateGuid(); + await _sqlExecutor.Insert( "OrderItemId,OrderId,Price", "OrderItem" ) + .Values( orderItemId, orderId, TestConfig.DecimalValue ) + .ExecuteAsync(); + + //»ñȡ¶ÔÏó + var result = await _sqlQuery + .AddParam( "id", orderItemId ) + .ExecuteProcedureQueryAsync( "Proc_GetOrderItem", ( item, order ) => { + item.Order = order; + return item; + } ); + + //¶ÏÑÔ + Assert.Single( (IEnumerable)result ); + Assert.Equal( orderItemId, result[0].Id ); + Assert.Equal( TestConfig.DecimalValue, result[0].Price ); + Assert.Equal( orderId, result[0].OrderId ); + Assert.Equal( orderId, result[0].Order.Id ); + Assert.Equal( customerName, result[0].Order.CustomerName ); + } + + #endregion + } +} diff --git a/test/Util.Data.Dapper.MySql.Tests.Integration/SqlQuery/MySqlQueryTest.Query.cs b/test/Util.Data.Dapper.MySql.Tests.Integration/SqlQuery/MySqlQueryTest.Query.cs new file mode 100644 index 00000000..1355a7e0 --- /dev/null +++ b/test/Util.Data.Dapper.MySql.Tests.Integration/SqlQuery/MySqlQueryTest.Query.cs @@ -0,0 +1,388 @@ +using System; +using System.Collections; +using System.Threading.Tasks; +using Util.Data.Sql; +using Util.Helpers; +using Util.Tests.Configs; +using Util.Tests.Models; +using Xunit; + +namespace Util.Data.Dapper.Tests.SqlQuery { + /// + /// MySql Sql²éѯ¶ÔÏó²âÊÔ - ²éѯ²âÊÔ + /// + public partial class MySqlQueryTest { + + #region ExecuteQuery + + /// + /// ²âÊԻñȡʵÌ弯ºÏ + /// + [Fact] + public async Task TestExecuteQuery_1() { + //²åÈë2ÌõÊý¾Ý + var id = Guid.NewGuid(); + var id2 = Guid.NewGuid(); + var code = "TestExecuteQuery_1"; + await _sqlExecutor.Insert( "ProductId,Code", "Product" ) + .Values( id, code ) + .Values( id2, code ) + .ExecuteAsync(); + + //»ñȡ¶ÔÏó + var result = _sqlQuery.Select().From( "Product" ).In( "ProductId", new[] { id, id2 } ).ExecuteQuery(); + + //¶ÏÑÔ + Assert.NotNull( result ); + Assert.Equal( 2, result.Count ); + Assert.Contains( result, t => t.ProductId == id ); + Assert.Contains( result, t => t.ProductId == id2 ); + Assert.Contains( result, t => t.Code == code ); + } + + /// + /// ²âÊԻñȡʵÌ弯ºÏ - 1¸ö·ºÐͲÎÊý + /// + [Fact] + public async Task TestExecuteQuery_2() { + //²åÈë2ÌõÊý¾Ý + var id = Guid.NewGuid(); + var id2 = Guid.NewGuid(); + var code = "TestExecuteQuery_2"; + await _sqlExecutor.Insert( "ProductId,Code", "Product" ) + .Values( id, code ) + .Values( id2, code ) + .ExecuteAsync(); + + //»ñȡ¶ÔÏó + var result = _sqlQuery.Select("ProductId As Id,Code").From( "Product" ).In( "ProductId", new[] { id, id2 } ).ExecuteQuery(); + + //¶ÏÑÔ + Assert.NotNull( result ); + Assert.Equal( 2, result.Count ); + Assert.Contains( result, t => t.Id == id ); + Assert.Contains( result, t => t.Id == id2 ); + Assert.Contains( result, t => t.Code == code ); + } + + /// + /// ²âÊԻñȡʵÌ弯ºÏ - 3¸ö·ºÐͲÎÊý - Ö÷´ӱí,ÉèÖùØÁªÊôÐÔ + /// + [Fact] + public async Task TestExecuteQuery_3() { + //²åÈ붩µ¥ + var orderId = Id.Create(); + var customerName = "customerName"; + await _sqlExecutor.Insert( "OrderId,CustomerName", "Order" ) + .Values( orderId, customerName ) + .ExecuteAsync(); + + //²åÈ붩µ¥Ã÷ϸ + var orderItemId = Id.CreateGuid(); + await _sqlExecutor.Insert( "OrderItemId,OrderId,Price", "OrderItem" ) + .Values( orderItemId, orderId,TestConfig.DecimalValue ) + .ExecuteAsync(); + + ////»ñȡ¶ÔÏó + var result = _sqlQuery + .Select( "i.OrderItemId As Id,i.*" ) //½«OrderItemIdӳÉäΪId,±ØÐëÔÚ֮ºó½ô¸úOrderItemÏà¹صÄÁÐ + .Select( "o.OrderId As Id,o.*" ) //½«OrderIdӳÉäΪId,½«¸î¶Ï֮ǰOrderItem±íÖеÄÐÅϢ,֮ºó¼ÌÐøÌí¼ÓOrder±íÖеÄÁÐ + .From( "OrderItem As i" ) + .LeftJoin( "Order As o" ).On( "o.OrderId", "i.OrderId" ) + .Where( "i.OrderItemId", orderItemId ) + .ExecuteQuery( ( item, order ) => { + item.Order = order; + return item; + } ); + + //¶ÏÑÔ + Assert.Single( (IEnumerable)result ); + Assert.Equal( orderItemId, result[0].Id ); + Assert.Equal( TestConfig.DecimalValue, result[0].Price ); + Assert.Equal( orderId, result[0].OrderId ); + Assert.Equal( orderId, result[0].Order.Id ); + Assert.Equal( customerName, result[0].Order.CustomerName ); + } + + #endregion + + #region ExecuteQueryAsync + + /// + /// ²âÊԻñȡʵÌ弯ºÏ + /// + [Fact] + public async Task TestExecuteQueryAsync_1() { + //²åÈë2ÌõÊý¾Ý + var id = Guid.NewGuid(); + var id2 = Guid.NewGuid(); + var code = "TestExecuteQueryAsync_1"; + await _sqlExecutor.Insert( "ProductId,Code", "Product" ) + .Values( id, code ) + .Values( id2, code ) + .ExecuteAsync(); + + //»ñȡ¶ÔÏó + var result = await _sqlQuery.Select().From( "Product" ).In( "ProductId", new[] { id, id2 } ).ExecuteQueryAsync(); + + //¶ÏÑÔ + Assert.NotNull( result ); + Assert.Equal( 2, result.Count ); + Assert.Contains( result, t => t.ProductId == id ); + Assert.Contains( result, t => t.ProductId == id2 ); + Assert.Contains( result, t => t.Code == code ); + } + + /// + /// ²âÊԻñȡʵÌ弯ºÏ + /// + [Fact] + public async Task TestExecuteQueryAsync_2() { + //²åÈë2ÌõÊý¾Ý + var id = Guid.NewGuid(); + var id2 = Guid.NewGuid(); + var code = "TestExecuteQueryAsync_2"; + await _sqlExecutor.Insert( "ProductId,Code", "Product" ) + .Values( id, code ) + .Values( id2, code ) + .ExecuteAsync(); + + //»ñȡ¶ÔÏó + var result = await _sqlQuery.Select( "ProductId As Id,Code" ).From( "Product" ).In( "ProductId", new[] { id, id2 } ).ExecuteQueryAsync(); + + //¶ÏÑÔ + Assert.NotNull( result ); + Assert.Equal( 2, result.Count ); + Assert.Contains( result, t => t.Id == id ); + Assert.Contains( result, t => t.Id == id2 ); + Assert.Contains( result, t => t.Code == code ); + } + + /// + /// ²âÊԻñȡʵÌ弯ºÏ - 3¸ö·ºÐͲÎÊý - Ö÷´ӱí,ÉèÖùØÁªÊôÐÔ + /// + [Fact] + public async Task TestExecuteQueryAsync_3() { + //²åÈ붩µ¥ + var orderId = Id.Create(); + var customerName = "customerName"; + await _sqlExecutor.Insert( "OrderId,CustomerName", "Order" ) + .Values( orderId, customerName ) + .ExecuteAsync(); + + //²åÈ붩µ¥Ã÷ϸ + var orderItemId = Id.CreateGuid(); + await _sqlExecutor.Insert( "OrderItemId,OrderId,Price", "OrderItem" ) + .Values( orderItemId, orderId, TestConfig.DecimalValue ) + .ExecuteAsync(); + + ////»ñȡ¶ÔÏó + var result = await _sqlQuery + .Select( "i.OrderItemId As Id,i.*" ) //½«OrderItemIdӳÉäΪId,±ØÐëÔÚ֮ºó½ô¸úOrderItemÏà¹صÄÁÐ + .Select( "o.OrderId As Id,o.*" ) //½«OrderIdӳÉäΪId,½«¸î¶Ï֮ǰOrderItem±íÖеÄÐÅϢ,֮ºó¼ÌÐøÌí¼ÓOrder±íÖеÄÁÐ + .From( "OrderItem As i" ) + .LeftJoin( "Order As o" ).On( "o.OrderId", "i.OrderId" ) + .Where( "i.OrderItemId", orderItemId ) + .ExecuteQueryAsync( ( item, order ) => { + item.Order = order; + return item; + } ); + + //¶ÏÑÔ + Assert.Single( (IEnumerable)result ); + Assert.Equal( orderItemId, result[0].Id ); + Assert.Equal( TestConfig.DecimalValue, result[0].Price ); + Assert.Equal( orderId, result[0].OrderId ); + Assert.Equal( orderId, result[0].Order.Id ); + Assert.Equal( customerName, result[0].Order.CustomerName ); + } + + #endregion + + #region ToList + + /// + /// ²âÊԻñȡʵÌ弯ºÏ + /// + [Fact] + public async Task TestToList_1() { + //²åÈë2ÌõÊý¾Ý + var id = Guid.NewGuid(); + var id2 = Guid.NewGuid(); + var code = "TestToList_1"; + await _sqlExecutor.Insert( "ProductId,Code", "Product" ) + .Values( id, code ) + .Values( id2, code ) + .ExecuteAsync(); + + //»ñȡ¶ÔÏó + var result = _sqlQuery.Select().From( "Product" ).In( "ProductId", new[] { id, id2 } ).ToList(); + + //¶ÏÑÔ + Assert.NotNull( result ); + Assert.Equal( 2, result.Count ); + Assert.Contains( result, t => t.ProductId == id ); + Assert.Contains( result, t => t.ProductId == id2 ); + Assert.Contains( result, t => t.Code == code ); + } + + /// + /// ²âÊԻñȡʵÌ弯ºÏ - 1¸ö·ºÐͲÎÊý + /// + [Fact] + public async Task TestToList_2() { + //²åÈë2ÌõÊý¾Ý + var id = Guid.NewGuid(); + var id2 = Guid.NewGuid(); + var code = "TestToList_2"; + await _sqlExecutor.Insert( "ProductId,Code", "Product" ) + .Values( id, code ) + .Values( id2, code ) + .ExecuteAsync(); + + //»ñȡ¶ÔÏó + var result = _sqlQuery.Select( "ProductId As Id,Code" ).From( "Product" ).In( "ProductId", new[] { id, id2 } ).ToList(); + + //¶ÏÑÔ + Assert.NotNull( result ); + Assert.Equal( 2, result.Count ); + Assert.Contains( result, t => t.Id == id ); + Assert.Contains( result, t => t.Id == id2 ); + Assert.Contains( result, t => t.Code == code ); + } + + /// + /// ²âÊԻñȡʵÌ弯ºÏ - 3¸ö·ºÐͲÎÊý - Ö÷´ӱí,ÉèÖùØÁªÊôÐÔ + /// + [Fact] + public async Task TestToList_3() { + //²åÈ붩µ¥ + var orderId = Id.Create(); + var customerName = "customerName"; + await _sqlExecutor.Insert( "OrderId,CustomerName", "Order" ) + .Values( orderId, customerName ) + .ExecuteAsync(); + + //²åÈ붩µ¥Ã÷ϸ + var orderItemId = Id.CreateGuid(); + await _sqlExecutor.Insert( "OrderItemId,OrderId,Price", "OrderItem" ) + .Values( orderItemId, orderId, TestConfig.DecimalValue ) + .ExecuteAsync(); + + ////»ñȡ¶ÔÏó + var result = _sqlQuery + .Select( "i.OrderItemId As Id,i.*" ) //½«OrderItemIdӳÉäΪId,±ØÐëÔÚ֮ºó½ô¸úOrderItemÏà¹صÄÁÐ + .Select( "o.OrderId As Id,o.*" ) //½«OrderIdӳÉäΪId,½«¸î¶Ï֮ǰOrderItem±íÖеÄÐÅϢ,֮ºó¼ÌÐøÌí¼ÓOrder±íÖеÄÁÐ + .From( "OrderItem As i" ) + .LeftJoin( "Order As o" ).On( "o.OrderId", "i.OrderId" ) + .Where( "i.OrderItemId", orderItemId ) + .ToList( ( item, order ) => { + item.Order = order; + return item; + } ); + + //¶ÏÑÔ + Assert.Single( (IEnumerable)result ); + Assert.Equal( orderItemId, result[0].Id ); + Assert.Equal( TestConfig.DecimalValue, result[0].Price ); + Assert.Equal( orderId, result[0].OrderId ); + Assert.Equal( orderId, result[0].Order.Id ); + Assert.Equal( customerName, result[0].Order.CustomerName ); + } + + #endregion + + #region ToListAsync + + /// + /// ²âÊԻñȡʵÌ弯ºÏ + /// + [Fact] + public async Task TestToListAsync_1() { + //²åÈë2ÌõÊý¾Ý + var id = Guid.NewGuid(); + var id2 = Guid.NewGuid(); + var code = "TestToListAsync_1"; + await _sqlExecutor.Insert( "ProductId,Code", "Product" ) + .Values( id, code ) + .Values( id2, code ) + .ExecuteAsync(); + + //»ñȡ¶ÔÏó + var result = await _sqlQuery.Select().From( "Product" ).In( "ProductId", new[] { id, id2 } ).ToListAsync(); + + //¶ÏÑÔ + Assert.NotNull( result ); + Assert.Equal( 2, result.Count ); + Assert.Contains( result, t => t.ProductId == id ); + Assert.Contains( result, t => t.ProductId == id2 ); + Assert.Contains( result, t => t.Code == code ); + } + + /// + /// ²âÊԻñȡʵÌ弯ºÏ + /// + [Fact] + public async Task TestToListAsync_2() { + //²åÈë2ÌõÊý¾Ý + var id = Guid.NewGuid(); + var id2 = Guid.NewGuid(); + var code = "TestToListAsync_2"; + await _sqlExecutor.Insert( "ProductId,Code", "Product" ) + .Values( id, code ) + .Values( id2, code ) + .ExecuteAsync(); + + //»ñȡ¶ÔÏó + var result = await _sqlQuery.Select( "ProductId As Id,Code" ).From( "Product" ).In( "ProductId", new[] { id, id2 } ).ToListAsync(); + + //¶ÏÑÔ + Assert.NotNull( result ); + Assert.Equal( 2, result.Count ); + Assert.Contains( result, t => t.Id == id ); + Assert.Contains( result, t => t.Id == id2 ); + Assert.Contains( result, t => t.Code == code ); + } + + /// + /// ²âÊԻñȡʵÌ弯ºÏ - 3¸ö·ºÐͲÎÊý - Ö÷´ӱí,ÉèÖùØÁªÊôÐÔ + /// + [Fact] + public async Task TestToListAsync_3() { + //²åÈ붩µ¥ + var orderId = Id.Create(); + var customerName = "customerName"; + await _sqlExecutor.Insert( "OrderId,CustomerName", "Order" ) + .Values( orderId, customerName ) + .ExecuteAsync(); + + //²åÈ붩µ¥Ã÷ϸ + var orderItemId = Id.CreateGuid(); + await _sqlExecutor.Insert( "OrderItemId,OrderId,Price", "OrderItem" ) + .Values( orderItemId, orderId, TestConfig.DecimalValue ) + .ExecuteAsync(); + + ////»ñȡ¶ÔÏó + var result = await _sqlQuery + .Select( "i.OrderItemId As Id,i.*" ) //½«OrderItemIdӳÉäΪId,±ØÐëÔÚ֮ºó½ô¸úOrderItemÏà¹صÄÁÐ + .Select( "o.OrderId As Id,o.*" ) //½«OrderIdӳÉäΪId,½«¸î¶Ï֮ǰOrderItem±íÖеÄÐÅϢ,֮ºó¼ÌÐøÌí¼ÓOrder±íÖеÄÁÐ + .From( "OrderItem As i" ) + .LeftJoin( "Order As o" ).On( "o.OrderId", "i.OrderId" ) + .Where( "i.OrderItemId", orderItemId ) + .ToListAsync( ( item, order ) => { + item.Order = order; + return item; + } ); + + //¶ÏÑÔ + Assert.Single( (IEnumerable)result ); + Assert.Equal( orderItemId, result[0].Id ); + Assert.Equal( TestConfig.DecimalValue, result[0].Price ); + Assert.Equal( orderId, result[0].OrderId ); + Assert.Equal( orderId, result[0].Order.Id ); + Assert.Equal( customerName, result[0].Order.CustomerName ); + } + + #endregion + } +} diff --git a/test/Util.Data.Dapper.MySql.Tests.Integration/SqlQuery/MySqlQueryTest.Scalar.cs b/test/Util.Data.Dapper.MySql.Tests.Integration/SqlQuery/MySqlQueryTest.Scalar.cs new file mode 100644 index 00000000..084e3e0d --- /dev/null +++ b/test/Util.Data.Dapper.MySql.Tests.Integration/SqlQuery/MySqlQueryTest.Scalar.cs @@ -0,0 +1,629 @@ +using System.Threading.Tasks; +using Util.Data.Sql; +using Util.Tests.Configs; +using Xunit; + +namespace Util.Data.Dapper.Tests.SqlQuery { + /// + /// MySql Sql²éѯ¶ÔÏó²âÊÔ - µ¥ֵ²âÊÔ + /// + public partial class MySqlQueryTest { + + #region ExecuteScalar + + /// + /// ²âÊԻñȡµ¥ֵ + /// + [Fact] + public void TestExecuteScalar_1() { + var result = _sqlQuery.Select( "Code" ).From( "Product" ).Where( "ProductId", TestConfig.Id ).ExecuteScalar(); + Assert.Equal( TestConfig.Value, result.SafeString() ); + } + + /// + /// ²âÊԻñȡµ¥ֵ - ·ºÐÍ + /// + [Fact] + public void TestExecuteScalar_2() { + var result = _sqlQuery.Select( "Code" ).From( "Product" ).Where( "ProductId", TestConfig.Id ).ExecuteScalar(); + Assert.Equal( TestConfig.Value, result ); + } + + #endregion + + #region ExecuteScalarAsync + + /// + /// ²âÊԻñȡµ¥ֵ + /// + [Fact] + public async Task TestExecuteScalarAsync_1() { + var result = await _sqlQuery.Select( "Code" ).From( "Product" ).Where( "ProductId", TestConfig.Id ).ExecuteScalarAsync(); + Assert.Equal( TestConfig.Value, result.SafeString() ); + } + + /// + /// ²âÊԻñȡµ¥ֵ - ·ºÐÍ + /// + [Fact] + public async Task TestExecuteScalarAsync_2() { + var result = await _sqlQuery.Select( "Code" ).From( "Product" ).Where( "ProductId", TestConfig.Id ).ExecuteScalarAsync(); + Assert.Equal( TestConfig.Value, result ); + } + + #endregion + + #region ToStringAsync + + /// + /// ²âÊԻñȡ×ַû´®ֵ + /// + [Fact] + public async Task TestToStringAsync() { + var result = await _sqlQuery.Select( "Code" ).From( "Product" ).Where( "ProductId", TestConfig.Id ).ToStringAsync(); + Assert.Equal( TestConfig.Value, result ); + } + + #endregion + + #region ToInt + + /// + /// ²âÊԻñȡ32λÕûÐÍֵ + /// + [Fact] + public void TestToInt() { + var result = _sqlQuery.Select( "IntPrice" ).From( "Product" ).Where( "ProductId", TestConfig.Id ).ToInt(); + Assert.Equal( TestConfig.IntValue, result ); + } + + #endregion + + #region ToIntAsync + + /// + /// ²âÊԻñȡ32λÕûÐÍֵ + /// + [Fact] + public async Task TestToIntAsync() { + var result = await _sqlQuery.Select( "IntPrice" ).From( "Product" ).Where( "ProductId", TestConfig.Id ).ToIntAsync(); + Assert.Equal( TestConfig.IntValue, result ); + } + + #endregion + + #region ToIntOrNull + + /// + /// ²âÊԻñȡ32λÕûÐÍֵ - ÓÐֵ + /// + [Fact] + public void TestToIntOrNull_1() { + var result = _sqlQuery.Select( "IntPrice" ).From( "Product" ).Where( "ProductId", TestConfig.Id ).ToIntOrNull(); + Assert.Equal( TestConfig.IntValue, result ); + } + + /// + /// ²âÊԻñȡ32λ¿ɿÕÕûÐÍֵ - ¿Õֵ + /// + [Fact] + public void TestToIntOrNull_2() { + var result = _sqlQuery.Select( "Code" ).From( "Product" ).Where( "ProductId", TestConfig.Id ).ToIntOrNull(); + Assert.Null( result ); + } + + #endregion + + #region ToIntOrNullAsync + + /// + /// ²âÊԻñȡ32λ¿ɿÕÕûÐÍֵ - ÓÐֵ + /// + [Fact] + public async Task TestToIntOrNullAsync_1() { + var result = await _sqlQuery.Select( "IntPrice" ).From( "Product" ).Where( "ProductId", TestConfig.Id ).ToIntOrNullAsync(); + Assert.Equal( TestConfig.IntValue, result ); + } + + /// + /// ²âÊԻñȡ32λ¿ɿÕÕûÐÍֵ - ¿Õֵ + /// + [Fact] + public async Task TestToIntOrNullAsync_2() { + var result = await _sqlQuery.Select( "Code" ).From( "Product" ).Where( "ProductId", TestConfig.Id ).ToIntOrNullAsync(); + Assert.Null( result ); + } + + #endregion + + #region ToLong + + /// + /// ²âÊԻñȡ64λÕûÐÍֵ + /// + [Fact] + public void TestToLong() { + var result = _sqlQuery.Select( "LongPrice" ).From( "Product" ).Where( "ProductId", TestConfig.Id ).ToLong(); + Assert.Equal( TestConfig.LongValue, result ); + } + + #endregion + + #region ToLongAsync + + /// + /// ²âÊԻñȡ64λÕûÐÍֵ + /// + [Fact] + public async Task TestToLongAsync() { + var result = await _sqlQuery.Select( "LongPrice" ).From( "Product" ).Where( "ProductId", TestConfig.Id ).ToLongAsync(); + Assert.Equal( TestConfig.LongValue, result ); + } + + #endregion + + #region ToLongOrNull + + /// + /// ²âÊԻñȡ64λ¿ɿÕÕûÐÍֵ - ÓÐֵ + /// + [Fact] + public void TestToLongOrNull_1() { + var result = _sqlQuery.Select( "LongPrice" ).From( "Product" ).Where( "ProductId", TestConfig.Id ).ToLongOrNull(); + Assert.Equal( TestConfig.LongValue, result ); + } + + /// + /// ²âÊԻñȡ64λ¿ɿÕÕûÐÍֵ - ¿Õֵ + /// + [Fact] + public void TestToLongOrNull_2() { + var result = _sqlQuery.Select( "Code" ).From( "Product" ).Where( "ProductId", TestConfig.Id ).ToLongOrNull(); + Assert.Null( result ); + } + + #endregion + + #region ToLongOrNullAsync + + /// + /// ²âÊԻñȡ64λ¿ɿÕÕûÐÍֵ - ÓÐֵ + /// + [Fact] + public async Task TestToLongOrNullAsync_1() { + var result = await _sqlQuery.Select( "LongPrice" ).From( "Product" ).Where( "ProductId", TestConfig.Id ).ToLongOrNullAsync(); + Assert.Equal( TestConfig.LongValue, result ); + } + + /// + /// ²âÊԻñȡ64λ¿ɿÕÕûÐÍֵ - ¿Õֵ + /// + [Fact] + public async Task TestToLongOrNullAsync_2() { + var result = await _sqlQuery.Select( "Code" ).From( "Product" ).Where( "ProductId", TestConfig.Id ).ToLongOrNullAsync(); + Assert.Null( result ); + } + + #endregion + + #region ToGuid + + /// + /// ²âÊԻñȡGuidֵ + /// + [Fact] + public void TestToGuid() { + var result = _sqlQuery.Select( "ProductId" ).From( "Product" ).Where( "ProductId", TestConfig.Id ).ToGuid(); + Assert.Equal( TestConfig.Id, result ); + } + + #endregion + + #region ToGuidAsync + + /// + /// ²âÊԻñȡGuidֵ + /// + [Fact] + public async Task TestToGuidAsync() { + var result = await _sqlQuery.Select( "ProductId" ).From( "Product" ).Where( "ProductId", TestConfig.Id ).ToGuidAsync(); + Assert.Equal( TestConfig.Id, result ); + } + + #endregion + + #region ToGuidOrNull + + /// + /// ²âÊԻñȡ¿ɿÕGuidֵ - ÓÐֵ + /// + [Fact] + public void TestToGuidOrNull_1() { + var result = _sqlQuery.Select( "ProductId" ).From( "Product" ).Where( "ProductId", TestConfig.Id ).ToGuidOrNull(); + Assert.Equal( TestConfig.Id, result ); + } + + /// + /// ²âÊԻñȡ¿ɿÕGuidֵ - ¿Õֵ + /// + [Fact] + public void TestToGuidOrNull_2() { + var result = _sqlQuery.Select( "Code" ).From( "Product" ).Where( "ProductId", TestConfig.Id ).ToGuidOrNull(); + Assert.Null( result ); + } + + #endregion + + #region ToGuidOrNullAsync + + /// + /// ²âÊԻñȡ¿ɿÕGuidֵ - ÓÐֵ + /// + [Fact] + public async Task TestToGuidOrNullAsync_1() { + var result = await _sqlQuery.Select( "ProductId" ).From( "Product" ).Where( "ProductId", TestConfig.Id ).ToGuidOrNullAsync(); + Assert.Equal( TestConfig.Id, result ); + } + + /// + /// ²âÊԻñȡ¿ɿÕGuidֵ - ¿Õֵ + /// + [Fact] + public async Task TestToGuidOrNullAsync_2() { + var result = await _sqlQuery.Select( "Code" ).From( "Product" ).Where( "ProductId", TestConfig.Id ).ToGuidOrNullAsync(); + Assert.Null( result ); + } + + #endregion + + #region ToBool + + /// + /// ²âÊԻñȡ²¼¶ûֵ + /// + [Fact] + public void TestToBool() { + var result = _sqlQuery.Select( "Enabled" ).From( "Product" ).Where( "ProductId", TestConfig.Id ).ToBool(); + Assert.Equal( TestConfig.BoolValue, result ); + } + + #endregion + + #region ToBoolAsync + + /// + /// ²âÊԻñȡ²¼¶ûֵ + /// + [Fact] + public async Task TestToBoolAsync() { + var result = await _sqlQuery.Select( "Enabled" ).From( "Product" ).Where( "ProductId", TestConfig.Id ).ToBoolAsync(); + Assert.Equal( TestConfig.BoolValue, result ); + } + + #endregion + + #region ToBoolOrNull + + /// + /// ²âÊԻñȡ¿ɿղ¼¶ûֵ - ÓÐֵ + /// + [Fact] + public void TestToBoolOrNull_1() { + var result = _sqlQuery.Select( "Enabled" ).From( "Product" ).Where( "ProductId", TestConfig.Id ).ToBoolOrNull(); + Assert.Equal( TestConfig.BoolValue, result ); + } + + /// + /// ²âÊԻñȡ¿ɿղ¼¶ûֵ - ¿Õֵ + /// + [Fact] + public void TestToBoolOrNull_2() { + var result = _sqlQuery.Select( "Code" ).From( "Product" ).Where( "ProductId", TestConfig.Id ).ToBoolOrNull(); + Assert.Null( result ); + } + + #endregion + + #region ToBoolOrNullAsync + + /// + /// ²âÊԻñȡ¿ɿղ¼¶ûֵ - ÓÐֵ + /// + [Fact] + public async Task TestToBoolOrNullAsync_1() { + var result = await _sqlQuery.Select( "Enabled" ).From( "Product" ).Where( "ProductId", TestConfig.Id ).ToBoolOrNullAsync(); + Assert.Equal( TestConfig.BoolValue, result ); + } + + /// + /// ²âÊԻñȡ¿ɿղ¼¶ûֵ - ¿Õֵ + /// + [Fact] + public async Task TestToBoolOrNullAsync_2() { + var result = await _sqlQuery.Select( "Code" ).From( "Product" ).Where( "ProductId", TestConfig.Id ).ToBoolOrNullAsync(); + Assert.Null( result ); + } + + #endregion + + #region ToFloat + + /// + /// ²âÊԻñȡFloatֵ + /// + [Fact] + public void TestToFloat() { + var result = _sqlQuery.Select( "FloatPrice" ).From( "Product" ).Where( "ProductId", TestConfig.Id ).ToFloat(); + Assert.Equal( TestConfig.FloatValue, result ); + } + + #endregion + + #region ToFloatAsync + + /// + /// ²âÊԻñȡFloatֵ + /// + [Fact] + public async Task TestToFloatAsync() { + var result = await _sqlQuery.Select( "FloatPrice" ).From( "Product" ).Where( "ProductId", TestConfig.Id ).ToFloatAsync(); + Assert.Equal( TestConfig.FloatValue, result ); + } + + #endregion + + #region ToFloatOrNull + + /// + /// ²âÊԻñȡ¿ɿÕFloatֵ - ÓÐֵ + /// + [Fact] + public void TestToFloatOrNull_1() { + var result = _sqlQuery.Select( "FloatPrice" ).From( "Product" ).Where( "ProductId", TestConfig.Id ).ToFloatOrNull(); + Assert.Equal( TestConfig.FloatValue, result ); + } + + /// + /// ²âÊԻñȡ¿ɿÕFloatֵ - ¿Õֵ + /// + [Fact] + public void TestToFloatOrNull_2() { + var result = _sqlQuery.Select( "Code" ).From( "Product" ).Where( "ProductId", TestConfig.Id ).ToFloatOrNull(); + Assert.Null( result ); + } + + #endregion + + #region ToFloatOrNullAsync + + /// + /// ²âÊԻñȡ¿ɿÕFloatֵ - ÓÐֵ + /// + [Fact] + public async Task TestToFloatOrNullAsync_1() { + var result = await _sqlQuery.Select( "FloatPrice" ).From( "Product" ).Where( "ProductId", TestConfig.Id ).ToFloatOrNullAsync(); + Assert.Equal( TestConfig.FloatValue, result ); + } + + /// + /// ²âÊԻñȡ¿ɿÕFloatֵ - ¿Õֵ + /// + [Fact] + public async Task TestToFloatOrNullAsync_2() { + var result = await _sqlQuery.Select( "Code" ).From( "Product" ).Where( "ProductId", TestConfig.Id ).ToFloatOrNullAsync(); + Assert.Null( result ); + } + + #endregion + + #region ToDouble + + /// + /// ²âÊԻñȡDoubleֵ + /// + [Fact] + public void TestToDouble() { + var result = _sqlQuery.Select( "Price" ).From( "Product" ).Where( "ProductId", TestConfig.Id ).ToDouble(); + Assert.Equal( TestConfig.DoubleValue, result ); + } + + #endregion + + #region ToDoubleAsync + + /// + /// ²âÊԻñȡDoubleֵ + /// + [Fact] + public async Task TestToDoubleAsync() { + var result = await _sqlQuery.Select( "Price" ).From( "Product" ).Where( "ProductId", TestConfig.Id ).ToDoubleAsync(); + Assert.Equal( TestConfig.DoubleValue, result ); + } + + #endregion + + #region ToDoubleOrNull + + /// + /// ²âÊԻñȡ¿ɿÕDoubleֵ - ÓÐֵ + /// + [Fact] + public void TestToDoubleOrNull_1() { + var result = _sqlQuery.Select( "Price" ).From( "Product" ).Where( "ProductId", TestConfig.Id ).ToDoubleOrNull(); + Assert.Equal( TestConfig.DoubleValue, result ); + } + + /// + /// ²âÊԻñȡ¿ɿÕDoubleֵ - ¿Õֵ + /// + [Fact] + public void TestToDoubleOrNull_2() { + var result = _sqlQuery.Select( "Code" ).From( "Product" ).Where( "ProductId", TestConfig.Id ).ToDoubleOrNull(); + Assert.Null( result ); + } + + #endregion + + #region ToDoubleOrNullAsync + + /// + /// ²âÊԻñȡ¿ɿÕDoubleֵ - ÓÐֵ + /// + [Fact] + public async Task TestToDoubleOrNullAsync_1() { + var result = await _sqlQuery.Select( "Price" ).From( "Product" ).Where( "ProductId", TestConfig.Id ).ToDoubleOrNullAsync(); + Assert.Equal( TestConfig.DoubleValue, result ); + } + + /// + /// ²âÊԻñȡ¿ɿÕDoubleֵ - ¿Õֵ + /// + [Fact] + public async Task TestToDoubleOrNullAsync_2() { + var result = await _sqlQuery.Select( "Code" ).From( "Product" ).Where( "ProductId", TestConfig.Id ).ToDoubleOrNullAsync(); + Assert.Null( result ); + } + + #endregion + + #region ToDecimal + + /// + /// ²âÊԻñȡDecimalֵ + /// + [Fact] + public void TestToDecimal() { + var result = _sqlQuery.Select( "Price" ).From( "Product" ).Where( "ProductId", TestConfig.Id ).ToDecimal(); + Assert.Equal( TestConfig.DecimalValue, result ); + } + + #endregion + + #region ToDecimalAsync + + /// + /// ²âÊԻñȡDecimalֵ + /// + [Fact] + public async Task TestToDecimalAsync() { + var result = await _sqlQuery.Select( "Price" ).From( "Product" ).Where( "ProductId", TestConfig.Id ).ToDecimalAsync(); + Assert.Equal( TestConfig.DecimalValue, result ); + } + + #endregion + + #region ToDecimalOrNull + + /// + /// ²âÊԻñȡDecimalֵ - ÓÐֵ + /// + [Fact] + public void TestToDecimalOrNull_1() { + var result = _sqlQuery.Select( "Price" ).From( "Product" ).Where( "ProductId", TestConfig.Id ).ToDecimalOrNull(); + Assert.Equal( TestConfig.DecimalValue, result ); + } + + /// + /// ²âÊԻñȡDecimalֵ - ¿Õֵ + /// + [Fact] + public void TestToDecimalOrNull_2() { + var result = _sqlQuery.Select( "Code" ).From( "Product" ).Where( "ProductId", TestConfig.Id ).ToDecimalOrNull(); + Assert.Null( result ); + } + + #endregion + + #region ToDecimalOrNullAsync + + /// + /// ²âÊԻñȡ¿ɿÕDecimalֵ - ÓÐֵ + /// + [Fact] + public async Task TestToDecimalOrNullAsync_1() { + var result = await _sqlQuery.Select( "Price" ).From( "Product" ).Where( "ProductId", TestConfig.Id ).ToDecimalOrNullAsync(); + Assert.Equal( TestConfig.DecimalValue, result ); + } + + /// + /// ²âÊԻñȡ¿ɿÕDecimalֵ - ¿Õֵ + /// + [Fact] + public async Task TestToDecimalOrNullAsync_2() { + var result = await _sqlQuery.Select( "Code" ).From( "Product" ).Where( "ProductId", TestConfig.Id ).ToDecimalOrNullAsync(); + Assert.Null( result ); + } + + #endregion + + #region ToDateTime + + /// + /// ²âÊԻñȡÈÕÆÚֵ + /// + [Fact] + public void TestToDateTime() { + var result = _sqlQuery.Select( "Birthday" ).From( "Customer" ).Where( "CustomerId", 1 ).ToDateTime(); + Assert.Equal( TestConfig.DateTimeValue, result ); + } + + #endregion + + #region ToDateTimeAsync + + /// + /// ²âÊԻñȡÈÕÆÚֵ + /// + [Fact] + public async Task TestToDateTimeAsync() { + var result = await _sqlQuery.Select( "Birthday" ).From( "Customer" ).Where( "CustomerId", 1 ).ToDateTimeAsync(); + Assert.Equal( TestConfig.DateTimeValue, result ); + } + + #endregion + + #region ToDateTimeOrNull + + /// + /// ²âÊԻñȡ¿ɿÕÈÕÆÚֵ - ÓÐֵ + /// + [Fact] + public void TestToDateTimeOrNull_1() { + var result = _sqlQuery.Select( "Birthday" ).From( "Customer" ).Where( "CustomerId", 1 ).ToDateTimeOrNull(); + Assert.Equal( TestConfig.DateTimeValue, result ); + } + + /// + /// ²âÊԻñȡ¿ɿÕÈÕÆÚֵ - ¿Õֵ + /// + [Fact] + public void TestToDateTimeOrNull_2() { + var result = _sqlQuery.Select( "Code" ).From( "Customer" ).Where( "CustomerId", 1 ).ToDateTimeOrNull(); + Assert.Null( result ); + } + + #endregion + + #region ToDateTimeOrNullAsync + + /// + /// ²âÊԻñȡ¿ɿÕÈÕÆÚֵ - ÓÐֵ + /// + [Fact] + public async Task TestToDateTimeOrNullAsync_1() { + var result = await _sqlQuery.Select( "Birthday" ).From( "Customer" ).Where( "CustomerId", 1 ).ToDateTimeOrNullAsync(); + Assert.Equal( TestConfig.DateTimeValue, result ); + } + + /// + /// ²âÊԻñȡ¿ɿÕÈÕÆÚֵ - ¿Õֵ + /// + [Fact] + public async Task TestToDateTimeOrNullAsync_2() { + var result = await _sqlQuery.Select( "Code" ).From( "Customer" ).Where( "CustomerId", 1 ).ToDateTimeOrNullAsync(); + Assert.Null( result ); + } + + #endregion + } +} diff --git a/test/Util.Data.Dapper.MySql.Tests.Integration/SqlQuery/MySqlQueryTest.Single.cs b/test/Util.Data.Dapper.MySql.Tests.Integration/SqlQuery/MySqlQueryTest.Single.cs new file mode 100644 index 00000000..088b132d --- /dev/null +++ b/test/Util.Data.Dapper.MySql.Tests.Integration/SqlQuery/MySqlQueryTest.Single.cs @@ -0,0 +1,52 @@ +using System.Threading.Tasks; +using Util.Data.Sql; +using Util.Tests.Configs; +using Util.Tests.Models; +using Xunit; + +namespace Util.Data.Dapper.Tests.SqlQuery { + /// + /// MySql Sql²éѯ¶ÔÏó²âÊÔ - »ñȡµ¥¸ö¶ÔÏó²âÊÔ + /// + public partial class MySqlQueryTest { + /// + /// ²âÊԻñȡµ¥¸öʵÌå + /// + [Fact] + public void TestExecuteSingle() { + var result = _sqlQuery.Select( "ProductId as Id,Code" ).From( "Product" ).Where( "ProductId", TestConfig.Id ).ExecuteSingle(); + Assert.Equal( TestConfig.Id, result.Id ); + Assert.Equal( TestConfig.Value, result.Code ); + } + + /// + /// ²âÊԻñȡµ¥¸öʵÌå + /// + [Fact] + public async Task TestExecuteSingleAsync() { + var result = await _sqlQuery.Select( "ProductId as Id,Code" ).From( "Product" ).Where( "ProductId", TestConfig.Id ).ExecuteSingleAsync(); + Assert.Equal( TestConfig.Id, result.Id ); + Assert.Equal( TestConfig.Value, result.Code ); + } + + /// + /// ²âÊԻñȡµ¥¸öʵÌå + /// + [Fact] + public void TestToEntity() { + var result = _sqlQuery.Select( "ProductId as Id,Code" ).From( "Product" ).Where( "ProductId", TestConfig.Id ).ToEntity(); + Assert.Equal( TestConfig.Id, result.Id ); + Assert.Equal( TestConfig.Value, result.Code ); + } + + /// + /// ²âÊԻñȡµ¥¸öʵÌå + /// + [Fact] + public async Task TestToEntityAsync() { + var result = await _sqlQuery.Select( "ProductId as Id,Code" ).From( "Product" ).Where( "ProductId", TestConfig.Id ).ToEntityAsync(); + Assert.Equal( TestConfig.Id, result.Id ); + Assert.Equal( TestConfig.Value, result.Code ); + } + } +} diff --git a/test/Util.Data.Dapper.MySql.Tests.Integration/SqlQuery/MySqlQueryTest.cs b/test/Util.Data.Dapper.MySql.Tests.Integration/SqlQuery/MySqlQueryTest.cs new file mode 100644 index 00000000..e560c015 --- /dev/null +++ b/test/Util.Data.Dapper.MySql.Tests.Integration/SqlQuery/MySqlQueryTest.cs @@ -0,0 +1,25 @@ +using Util.Data.Sql; + +namespace Util.Data.Dapper.Tests.SqlQuery { + /// + /// MySql Sql²éѯ¶ÔÏó²âÊÔ + /// + public partial class MySqlQueryTest { + /// + /// SqlִÐÐÆ÷ + /// + private readonly ISqlExecutor _sqlExecutor; + /// + /// Sql²éѯ¶ÔÏó + /// + private readonly ISqlQuery _sqlQuery; + + /// + /// ²âÊԳõʼ»¯ + /// + public MySqlQueryTest( ISqlExecutor sqlExecutor, ISqlQuery sqlQuery ) { + _sqlExecutor = sqlExecutor; + _sqlQuery = sqlQuery; + } + } +} diff --git a/test/Util.Data.Dapper.MySql.Tests.Integration/Startup.cs b/test/Util.Data.Dapper.MySql.Tests.Integration/Startup.cs new file mode 100644 index 00000000..e618153d --- /dev/null +++ b/test/Util.Data.Dapper.MySql.Tests.Integration/Startup.cs @@ -0,0 +1,63 @@ +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using Util.Aop; +using Util.Data.Dapper.Tests.Infrastructure; +using Util.Data.EntityFrameworkCore; +using Util.Data.Metadata; +using Util.Data.Sql; +using Util.Helpers; +using Util.Sessions; +using Util.Tests.Infrastructure; +using Util.Tests.UnitOfWorks; +using Xunit.DependencyInjection; +using Xunit.DependencyInjection.Logging; + +namespace Util.Data.Dapper.Tests { + /// + /// Æô¶¯ÅäÖà + /// + public class Startup { + /// + /// ÅäÖÃÖ÷»ú + /// + public void ConfigureHost( IHostBuilder hostBuilder ) { + hostBuilder.ConfigureDefaults( null ) + .ConfigureServices( ( context, services ) => { + services.AddTransient(); + } ) + .AddUtil( options => { + Environment.SetDevelopment(); + options.UseAop() + .UseMySqlQuery( Config.GetConnectionString( "connection" ) ) + .UseMySqlExecutor( Config.GetConnectionString( "connection" ) ) + .UseMySqlUnitOfWork( Config.GetConnectionString( "connection" ) ); + } ); + } + + /// + /// ÅäÖ÷þÎñ + /// + public void ConfigureServices( IServiceCollection services ) { + services.AddSingleton(); + InitDatabase( services ); + } + + /// + /// ³õʼ»¯Êý¾ݿâ + /// + private void InitDatabase( IServiceCollection services ) { + var unitOfWork = (MySqlUnitOfWork)services.BuildServiceProvider().GetService(); + unitOfWork.EnsureDeleted(); + unitOfWork.EnsureCreated(); + DatabaseScript.InitProcedures( unitOfWork?.Database ); + } + + /// + /// ÅäÖÃÈÕ־Ìṩ³ÌÐò + /// + public void Configure( ILoggerFactory loggerFactory, ITestOutputHelperAccessor accessor ) { + loggerFactory.AddProvider( new XunitTestOutputLoggerProvider( accessor, ( s, logLevel ) => logLevel >= LogLevel.Trace ) ); + } + } +} diff --git a/test/Util.Data.Dapper.MySql.Tests.Integration/Util.Data.Dapper.MySql.Tests.Integration.csproj b/test/Util.Data.Dapper.MySql.Tests.Integration/Util.Data.Dapper.MySql.Tests.Integration.csproj new file mode 100644 index 00000000..3edf8055 --- /dev/null +++ b/test/Util.Data.Dapper.MySql.Tests.Integration/Util.Data.Dapper.MySql.Tests.Integration.csproj @@ -0,0 +1,43 @@ + + + + $(NetTargetFramework) + false + Util.Data.Dapper.Tests + Util.Data.Dapper.Tests.Startup + + + + + Always + + + Always + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + + diff --git a/test/Util.Data.Dapper.MySql.Tests.Integration/appsettings.Development.json b/test/Util.Data.Dapper.MySql.Tests.Integration/appsettings.Development.json new file mode 100644 index 00000000..4e8eafe7 --- /dev/null +++ b/test/Util.Data.Dapper.MySql.Tests.Integration/appsettings.Development.json @@ -0,0 +1,11 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Trace", + "Microsoft": "Trace" + } + }, + "ConnectionStrings": { + "connection": "server=192.168.31.157;user=root;password=admin;database=Util.Data.Dapper.Test;port=3306;charset=utf8" + } +} \ No newline at end of file diff --git a/test/Util.Data.Dapper.MySql.Tests.Integration/appsettings.json b/test/Util.Data.Dapper.MySql.Tests.Integration/appsettings.json new file mode 100644 index 00000000..2f83569e --- /dev/null +++ b/test/Util.Data.Dapper.MySql.Tests.Integration/appsettings.json @@ -0,0 +1,11 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Error", + "Microsoft": "Error" + } + }, + "ConnectionStrings": { + "connection": "server=mysql.common;user=root;password=admin;database=Util.Data.Dapper.Test;port=3306;charset=utf8" + } +} \ No newline at end of file diff --git a/test/Util.Data.Dapper.PostgreSql.Tests.Integration/Infrastructure/DatabaseScript.cs b/test/Util.Data.Dapper.PostgreSql.Tests.Integration/Infrastructure/DatabaseScript.cs new file mode 100644 index 00000000..67d7e3e4 --- /dev/null +++ b/test/Util.Data.Dapper.PostgreSql.Tests.Integration/Infrastructure/DatabaseScript.cs @@ -0,0 +1,125 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; + +namespace Util.Data.Dapper.Tests.Infrastructure { + /// + /// 数据库初始化脚本 + /// + public class DatabaseScript { + /// + /// 初始化 + /// + public static void InitProcedures( DatabaseFacade database ) { + CreateGetProductCodeFunction( database ); + CreateGetProductFunction( database ); + CreateGetProductsFunction( database ); + CreateGetProductCodeOutputProcedure( database ); + CreateInsertProductProcedure( database ); + } + + /// + /// 创建Func_GetProductCode函数 + /// + private static void CreateGetProductCodeFunction( DatabaseFacade database ) { + var sql = @" + Create Or Replace Function ""Products"".""Func_GetProductCode""( + ""productId"" uuid + ) + Returns varchar + As $$ + Declare + code varchar; + Begin + Select ""Code"" Into code + From ""Products"".""Product"" + Where ""ProductId"" = ""productId""; + Return code; + End;$$ + Language plpgsql + "; + database.ExecuteSqlRaw( sql ); + } + + /// + /// 创建Func_GetProduct函数 + /// + private static void CreateGetProductFunction( DatabaseFacade database ) { + var sql = @" + Create Or Replace Function ""Products"".""Func_GetProduct""( + ""productId"" uuid + ) + Returns setof ""Products"".""Product"" + As $$ + Begin + Return Query + Select * + From ""Products"".""Product"" + Where ""ProductId"" = ""productId""; + End;$$ + Language plpgsql + "; + database.ExecuteSqlRaw( sql ); + } + + /// + /// 创建Func_GetProducts函数 + /// + private static void CreateGetProductsFunction( DatabaseFacade database ) { + var sql = @" + Create Or Replace Function ""Products"".""Func_GetProducts""( + ""productId"" uuid, + ""productId2"" uuid + ) + Returns Table( ""Id"" uuid,""Code"" varchar ) + As $$ + Begin + Return Query + Select p.""ProductId"" As ""Id"", p.""Code"" + From ""Products"".""Product"" As p + Where ""ProductId"" in ( ""productId"",""productId2""); + End;$$ + Language plpgsql + "; + database.ExecuteSqlRaw( sql ); + } + + /// + /// 创建Proc_GetProductCode_Output存储过程 + /// + private static void CreateGetProductCodeOutputProcedure( DatabaseFacade database ) { + var sql = @" + Create Or Replace Procedure ""Products"".""Proc_GetProductCode_Output""( + ""productId"" uuid, + ""code"" in out varchar + ) + As $$ + Begin + Select ""Code"" into code + From ""Products"".""Product"" + Where ""ProductId"" = ""productId""; + End;$$ + Language plpgsql + "; + database.ExecuteSqlRaw( sql ); + } + + /// + /// 创建Proc_InsertProduct存储过程 + /// + private static void CreateInsertProductProcedure( DatabaseFacade database ) { + var sql = @" + Create Or Replace Procedure ""Products"".""Proc_InsertProduct""( + ""productId"" uuid, + ""code"" varchar + ) + As $$ + Begin + Insert Into ""Products"".""Product""(""ProductId"",""Code"") + Values( ""productId"",code ); + End;$$ + Language plpgsql + "; + database.ExecuteSqlRaw( sql ); + } + } +} diff --git a/test/Util.Data.Dapper.PostgreSql.Tests.Integration/Metadata/PostgreSqlMetadataServiceTest.cs b/test/Util.Data.Dapper.PostgreSql.Tests.Integration/Metadata/PostgreSqlMetadataServiceTest.cs new file mode 100644 index 00000000..cf8bc1e1 --- /dev/null +++ b/test/Util.Data.Dapper.PostgreSql.Tests.Integration/Metadata/PostgreSqlMetadataServiceTest.cs @@ -0,0 +1,99 @@ +using System.Linq; +using Util.Data.Metadata; +using Xunit; + +namespace Util.Data.Dapper.Tests.Metadata { + /// + /// PostgreSql数据库元数据服务测试 + /// + public class PostgreSqlMetadataServiceTest { + /// + /// 数据库元信息 + /// + private readonly DatabaseInfo _databaseInfo; + + /// + /// 初始化 + /// + public PostgreSqlMetadataServiceTest( IMetadataService service ) { + _databaseInfo = service.GetDatabaseInfo(); + } + + /// + /// 测试获取数据库名称 + /// + [Fact] + public void TestDatabaseName() { + Assert.Equal( "Util.Data.Dapper.Test", _databaseInfo.Name ); + } + + /// + /// 测试获取表信息 + /// + [Fact] + public void TestTableInfo() { + var table = _databaseInfo.Tables.FirstOrDefault( t => t.Name == "Product" ); + Assert.NotNull( table ); + Assert.Equal( "Products", table.Schema ); + Assert.Equal( "产品", table.Comment ); + } + + /// + /// 测试获取主键信息 + /// + [Fact] + public void TestPrimaryKey() { + var table = _databaseInfo.Tables.First( t => t.Name == "OrderItem" ); + var pkColumn = table.Columns.FirstOrDefault( t => t.Name == "OrderItemId" ); + Assert.NotNull( pkColumn ); + Assert.True( pkColumn.IsPrimaryKey ); + var fkColumn = table.Columns.FirstOrDefault( t => t.Name == "OrderId" ); + Assert.NotNull( fkColumn ); + Assert.False( fkColumn.IsPrimaryKey ); + } + + /// + /// 测试获取自增信息 + /// + [Fact] + public void TestAutoIncrement() { + var table = _databaseInfo.Tables.FirstOrDefault( t => t.Name == "Customer" ); + Assert.NotNull( table ); + var column = table.Columns.FirstOrDefault( t => t.Name == "CustomerId" ); + Assert.NotNull( column ); + Assert.True( column.IsAutoIncrement ); + Assert.Equal( "int4", column.DataType ); + } + + /// + /// 测试获取数值精度信息 + /// + [Fact] + public void TestPrecision() { + var table = _databaseInfo.Tables.FirstOrDefault( t => t.Name == "Product" ); + Assert.NotNull( table ); + var column = table.Columns.FirstOrDefault( t => t.Name == "Price" ); + Assert.NotNull( column ); + Assert.Equal( 12, column.Precision ); + Assert.Equal( 2, column.Scale ); + } + + /// + /// 测试获取字符串列信息 + /// + [Fact] + public void TestStringInfo() { + var table = _databaseInfo.Tables.FirstOrDefault( t => t.Name == "Product" ); + Assert.NotNull( table ); + var count = table.Columns.Count( t => t.Name == "Code" ); + Assert.Equal( 1, count ); + var column = table.Columns.FirstOrDefault( t => t.Name == "Code" ); + Assert.NotNull( column ); + Assert.Equal( "产品编码", column.Comment ); + Assert.False( column.IsPrimaryKey ); + Assert.True( column.IsNullable ); + Assert.Equal( "varchar", column.DataType ); + Assert.Equal( 50, column.Length ); + } + } +} diff --git a/test/Util.Data.Dapper.PostgreSql.Tests.Integration/SqlBuilders/PostgreSqlExistsSqlBuilderTest.cs b/test/Util.Data.Dapper.PostgreSql.Tests.Integration/SqlBuilders/PostgreSqlExistsSqlBuilderTest.cs new file mode 100644 index 00000000..45e7f177 --- /dev/null +++ b/test/Util.Data.Dapper.PostgreSql.Tests.Integration/SqlBuilders/PostgreSqlExistsSqlBuilderTest.cs @@ -0,0 +1,48 @@ +using System.Text; +using Util.Data.Sql; +using Util.Data.Sql.Builders; +using Xunit; +using Xunit.Abstractions; + +namespace Util.Data.Dapper.Tests.SqlBuilders { + /// + /// 测试判断是否存在的Sql生成器 + /// + public class PostgreSqlExistsSqlBuilderTest { + /// + /// 输出工具 + /// + private readonly ITestOutputHelper _output; + + /// + /// 测试初始化 + /// + public PostgreSqlExistsSqlBuilderTest( ITestOutputHelper output ) { + _output = output; + } + + /// + /// 测试生成的Sql + /// + [Fact] + public void TestToSql() { + var sql = new StringBuilder(); + sql.AppendLine( "Select Case" ); + sql.AppendLine( " When Exists (" ); + sql.AppendLine( "Select 1 " ); + sql.Append( "From \"b\"" ); + sql.AppendLine( ")" ); + sql.AppendLine( " Then Cast(1 As Bit)" ); + sql.AppendLine( " Else Cast(0 As Bit) " ); + sql.Append( "End" ); + + var subQuery = new PostgreSqlBuilder() + .Select("a") + .From( "b" ); + var sqlBuilder = new PostgreSqlExistsSqlBuilder( subQuery ); + var result = sqlBuilder.GetSql(); + _output.WriteLine( result ); + Assert.Equal( sql.ToString(),result ); + } + } +} diff --git a/test/Util.Data.Dapper.PostgreSql.Tests.Integration/SqlExecutor/PostgreSqlExecutorTest.Execute.cs b/test/Util.Data.Dapper.PostgreSql.Tests.Integration/SqlExecutor/PostgreSqlExecutorTest.Execute.cs new file mode 100644 index 00000000..faeb751a --- /dev/null +++ b/test/Util.Data.Dapper.PostgreSql.Tests.Integration/SqlExecutor/PostgreSqlExecutorTest.Execute.cs @@ -0,0 +1,28 @@ +using System; +using System.Threading.Tasks; +using Util.Data.Sql; +using Util.Tests.Configs; +using Xunit; + +namespace Util.Data.Dapper.Tests.SqlExecutor { + /// + /// PostgreSql Sql执行器测试 - 执行Sql测试 + /// + public partial class PostgreSqlExecutorTest { + /// + /// 测试执行Sql增删改操作 + /// + [Fact] + public async Task TestExecuteAsync() { + var id = Guid.NewGuid(); + await _sqlExecutor + .AppendLine( "Insert Into \"Products\".\"Product\"(\"ProductId\",\"Code\") " ) + .Append( "Values(@ProductId,@Code)" ) + .AddParam( "@ProductId", id ) + .AddParam( "Code", TestConfig.Value ) + .ExecuteAsync(); + var result = await _sqlExecutor.Select( "Code" ).From( "Products.Product" ).Where( "ProductId", id ).ToStringAsync(); + Assert.Equal( TestConfig.Value, result ); + } + } +} diff --git a/test/Util.Data.Dapper.PostgreSql.Tests.Integration/SqlExecutor/PostgreSqlExecutorTest.Id.cs b/test/Util.Data.Dapper.PostgreSql.Tests.Integration/SqlExecutor/PostgreSqlExecutorTest.Id.cs new file mode 100644 index 00000000..232318a6 --- /dev/null +++ b/test/Util.Data.Dapper.PostgreSql.Tests.Integration/SqlExecutor/PostgreSqlExecutorTest.Id.cs @@ -0,0 +1,67 @@ +using System; +using System.Threading.Tasks; +using Util.Data.Sql; +using Util.Helpers; +using Util.Tests.Configs; +using Xunit; + +namespace Util.Data.Dapper.Tests.SqlExecutor { + /// + /// PostgreSql Sql执行器测试 - 标识列测试 + /// + public partial class PostgreSqlExecutorTest { + /// + /// 测试插入Guid主键 + /// + [Fact] + public async Task TestInsert_Guid() { + var id = Guid.NewGuid(); + await _sqlExecutor + .Insert( "ProductId,Code", "Products.Product" ) + .Values( id, TestConfig.Value ) + .ExecuteAsync(); + var result = await _sqlExecutor + .Select( "Code" ) + .From( "Products.Product" ) + .Where( "ProductId", id ) + .ToStringAsync(); + Assert.Equal( TestConfig.Value, result ); + } + + /// + /// 测试插入int自增长主键 + /// + [Fact] + public async Task TestInsert_Int() { + var value = Id.Create(); + await _sqlExecutor + .Insert( "Code", "Customers.Customer" ) + .Values( value ) + .ExecuteAsync(); + var result = await _sqlExecutor + .Select( "CustomerId" ) + .From( "Customers.Customer" ) + .Where( "Code", value ) + .ToIntAsync(); + Assert.True( result > 0 ); + } + + /// + /// 测试插入string主键 + /// + [Fact] + public async Task TestInsert_String() { + var id = Id.Create(); + await _sqlExecutor + .Insert( "OrderId,CustomerName", "Sales.Order" ) + .Values( id, TestConfig.Value ) + .ExecuteAsync(); + var result = await _sqlExecutor + .Select( "CustomerName" ) + .From( "Sales.Order" ) + .Where( "OrderId", id ) + .ToStringAsync(); + Assert.Equal( TestConfig.Value, result ); + } + } +} diff --git a/test/Util.Data.Dapper.PostgreSql.Tests.Integration/SqlExecutor/PostgreSqlExecutorTest.Insert.cs b/test/Util.Data.Dapper.PostgreSql.Tests.Integration/SqlExecutor/PostgreSqlExecutorTest.Insert.cs new file mode 100644 index 00000000..2130ba9a --- /dev/null +++ b/test/Util.Data.Dapper.PostgreSql.Tests.Integration/SqlExecutor/PostgreSqlExecutorTest.Insert.cs @@ -0,0 +1,83 @@ +using System; +using System.Threading.Tasks; +using Util.Data.Sql; +using Util.Tests.Configs; +using Xunit; + +namespace Util.Data.Dapper.Tests.SqlExecutor { + /// + /// PostgreSql Sql执行器测试 - 插入测试 + /// + public partial class PostgreSqlExecutorTest { + /// + /// 测试使用Insert Values语句插入一条数据 + /// + [Fact] + public async Task TestInsert_1() { + //插入一条数据 + var id = Guid.NewGuid(); + await _sqlExecutor + .Insert( "ProductId,Code", "Products.Product" ) + .Values( id, TestConfig.Value ) + .ExecuteAsync(); + + //获取值 + var result = await _sqlExecutor + .Select( "Code" ) + .From( "Products.Product" ) + .Where( "ProductId", id ) + .ToStringAsync(); + + //验证 + Assert.Equal( TestConfig.Value, result ); + } + + /// + /// 测试使用Insert Values语句插入2条数据 + /// + [Fact] + public async Task TestInsert_2() { + //插入一条数据 + var id = Guid.NewGuid(); + var id2 = Guid.NewGuid(); + await _sqlExecutor + .Insert( "ProductId,Code", "Products.Product" ) + .Values( id, TestConfig.Value ) + .Values( id2, TestConfig.Value ) + .ExecuteAsync(); + + //获取值 + var result = await _sqlExecutor + .AppendSelect( "Count(*)" ) + .From( "Products.Product" ) + .In( "ProductId", new[]{id,id2} ) + .ToIntAsync(); + + //验证 + Assert.Equal( 2, result ); + } + + /// + /// 测试使用Insert Select语句插入 + /// + [Fact] + public async Task TestInsert_3() { + //用Insert Select插入一条数据 + var id = Guid.NewGuid(); + await _sqlExecutor + .Insert( "ProductId,Code", "Products.Product" ) + .AppendSelect( $"'{id}','{TestConfig.Value}'" ) + .ExecuteAsync(); + + //获取值 + var result = await _sqlExecutor + .Select( "Code" ) + .From( "Products.Product" ) + .Where( "ProductId", id ) + .ToStringAsync(); + + //验证 + Assert.Equal( TestConfig.Value, result ); + } + } +} diff --git a/test/Util.Data.Dapper.PostgreSql.Tests.Integration/SqlExecutor/PostgreSqlExecutorTest.Param.cs b/test/Util.Data.Dapper.PostgreSql.Tests.Integration/SqlExecutor/PostgreSqlExecutorTest.Param.cs new file mode 100644 index 00000000..ed07c258 --- /dev/null +++ b/test/Util.Data.Dapper.PostgreSql.Tests.Integration/SqlExecutor/PostgreSqlExecutorTest.Param.cs @@ -0,0 +1,86 @@ +using System; +using System.Data; +using System.Threading.Tasks; +using Util.Data.Sql; +using Util.Tests.Configs; +using Xunit; + +namespace Util.Data.Dapper.Tests.SqlExecutor { + /// + /// PostgreSql Sql执行器测试 - 执行存储过程参数测试 + /// + public partial class PostgreSqlExecutorTest { + /// + /// 测试添加动态参数 + /// + [Fact] + public async Task TestAddParam_Dynamic() { + var id = Guid.NewGuid(); + await _sqlExecutor + .AppendLine( "Insert Into \"Products\".\"Product\"(\"ProductId\",\"Code\") " ) + .Append( "Values(@ProductId,@Code)" ) + .AddDynamicParams( new { ProductId=id, Code= TestConfig.Value } ) + .ExecuteAsync(); + var result = await _sqlExecutor.Select( "Code" ).From( "Products.Product" ).Where( "ProductId", id ).ToStringAsync(); + Assert.Equal( TestConfig.Value, result ); + } + + /// + /// 测试添加和获取输出参数 + /// 说明 + /// 1. PostgreSql数据库的存储过程需要使用call进行调用 + /// 2. 存储过程名称如果包含大写,需要使用转义符"",也可以使用[],会自动转换为"" + /// 3. 调用存储过程时,输出参数值传入null + /// 4. 定义存储过程的输出参数需要使用in out参数 + /// + [Fact] + public async Task TestAddParam_Output() { + //定义变量 + var id = Guid.NewGuid(); + + //插入数据 + await _sqlExecutor + .AppendLine( "Insert Into \"Products\".\"Product\"(\"ProductId\",\"Code\") " ) + .Append( "Values(@ProductId,@Code)" ) + .AddParam( "@ProductId", id ) + .AddParam( "Code", TestConfig.Value ) + .ExecuteAsync(); + + //执行存储过程 - 添加输出参数 + await _sqlExecutor + .AddParam( "productId", id ) + .AddParam( "code",DbType.String,ParameterDirection.InputOutput ) + .ExecuteProcedureAsync( "call [Products].[Proc_GetProductCode_Output](@productId,null)" ); + + //验证 - 使用GetParam获取输出参数 + Assert.Equal( TestConfig.Value, _sqlExecutor.GetParam( "code" ) ); + } + + /// + /// 测试添加参数 - 在执行前添加并获取参数 + /// + [Fact] + public async Task TestAddParam_1() { + var id = Guid.NewGuid(); + + //添加第一个参数 + _sqlExecutor + .AppendLine( "Insert Into \"Products\".\"Product\"(\"ProductId\",\"Code\") " ) + .Append( "Values(@ProductId,@Code)" ) + .AddParam( "@ProductId", id ); + + //获取参数 + var param = _sqlExecutor.GetParam( "ProductId" ); + Assert.Equal( id, param ); + + //添加第二个参数并执行 + await _sqlExecutor + .AddParam( "Code", TestConfig.Value ) + .ExecuteAsync(); + + //验证 + var result = await _sqlExecutor.Select( "Code" ).From( "Products.Product" ).Where( "ProductId", id ).ToStringAsync(); + Assert.Equal( TestConfig.Value, result ); + } + } +} diff --git a/test/Util.Data.Dapper.PostgreSql.Tests.Integration/SqlExecutor/PostgreSqlExecutorTest.Procedure.cs b/test/Util.Data.Dapper.PostgreSql.Tests.Integration/SqlExecutor/PostgreSqlExecutorTest.Procedure.cs new file mode 100644 index 00000000..d0df35aa --- /dev/null +++ b/test/Util.Data.Dapper.PostgreSql.Tests.Integration/SqlExecutor/PostgreSqlExecutorTest.Procedure.cs @@ -0,0 +1,35 @@ +using System; +using System.Threading.Tasks; +using Util.Data.Sql; +using Util.Tests.Configs; +using Xunit; + +namespace Util.Data.Dapper.Tests.SqlExecutor { + /// + /// PostgreSql Sql执行器测试 - 执行存储过程测试 + /// + public partial class PostgreSqlExecutorTest { + /// + /// 测试执行存储过程增删改操作 + /// + [Fact] + public async Task TestExecuteProcedureScalarAsync() { + //定义变量 + var id = Guid.NewGuid(); + + //插入数据,参数无论是否加@前缀均可 + await _sqlExecutor + .AddParam( "@productId", id ) + .AddParam( "code", TestConfig.Value ) + .ExecuteProcedureAsync( "call [Products].[Proc_InsertProduct](@productId,@code)" ); + + //获取IntValue值 + var result = await _sqlExecutor + .AddParam( "productId", id ) + .ExecuteProcedureScalarAsync( "Products.Func_GetProductCode" ); + + //验证 + Assert.Equal( TestConfig.Value, result ); + } + } +} diff --git a/test/Util.Data.Dapper.PostgreSql.Tests.Integration/SqlExecutor/PostgreSqlExecutorTest.cs b/test/Util.Data.Dapper.PostgreSql.Tests.Integration/SqlExecutor/PostgreSqlExecutorTest.cs new file mode 100644 index 00000000..c3a5e666 --- /dev/null +++ b/test/Util.Data.Dapper.PostgreSql.Tests.Integration/SqlExecutor/PostgreSqlExecutorTest.cs @@ -0,0 +1,31 @@ +using Util.Data.Sql; +using Xunit.Abstractions; + +namespace Util.Data.Dapper.Tests.SqlExecutor { + /// + /// PostgreSql Sql执行器测试 + /// + public partial class PostgreSqlExecutorTest { + /// + /// 测试输出工具 + /// + private readonly ITestOutputHelper _output; + /// + /// Sql执行器 + /// + private readonly ISqlExecutor _sqlExecutor; + /// + /// Sql执行器2 + /// + private readonly ISqlExecutor _sqlExecutor2; + + /// + /// 测试初始化 + /// + public PostgreSqlExecutorTest( ITestOutputHelper output, ISqlExecutor sqlExecutor, ISqlExecutor sqlExecutor2 ) { + _output = output; + _sqlExecutor = sqlExecutor; + _sqlExecutor2 = sqlExecutor2; + } + } +} diff --git a/test/Util.Data.Dapper.PostgreSql.Tests.Integration/SqlExecutor/SqlServerSqlExecutorTest.Transaction.cs b/test/Util.Data.Dapper.PostgreSql.Tests.Integration/SqlExecutor/SqlServerSqlExecutorTest.Transaction.cs new file mode 100644 index 00000000..39e62531 --- /dev/null +++ b/test/Util.Data.Dapper.PostgreSql.Tests.Integration/SqlExecutor/SqlServerSqlExecutorTest.Transaction.cs @@ -0,0 +1,206 @@ +using System; +using System.Threading.Tasks; +using Util.Data.Sql; +using Util.Tests.Configs; +using Xunit; + +namespace Util.Data.Dapper.Tests.SqlExecutor { + /// + /// PostgreSql Sql执行器测试 - 事务测试 + /// + public partial class PostgreSqlExecutorTest { + /// + /// 测试事务操作 - 不使用事务,第一次操作成功,第二次失败 + /// + [Fact] + public async Task TestTransaction_1() { + //创建两个Id + var id = Guid.NewGuid(); + var id2 = Guid.NewGuid(); + + try { + //插入Id成功 + await _sqlExecutor + .Insert( "ProductId,Code", "Products.Product" ) + .Values( id, TestConfig.Value ) + .ExecuteAsync(); + + //Code2列名错误,插入Id2失败 + await _sqlExecutor + .Insert( "ProductId,Code,Code2", "Products.Product" ) + .Values( id2, TestConfig.Value, TestConfig.Value ) + .ExecuteAsync(); + } + catch { + // ignored + } + + //断言 + var exists = await _sqlExecutor.From( "Products.Product" ).Where( "ProductId", id ).ExecuteExistsAsync(); + var exists2 = await _sqlExecutor.From( "Products.Product" ).Where( "ProductId", id2 ).ExecuteExistsAsync(); + Assert.True( exists ); + Assert.False( exists2 ); + } + + /// + /// 测试事务操作 - 调用BeginTransaction,CommitTransaction,RollbackTransaction + /// + [Fact] + public async Task TestTransaction_2() { + //开始事务 + _sqlExecutor.BeginTransaction(); + + //创建两个Id + var id = Guid.NewGuid(); + var id2 = Guid.NewGuid(); + + try { + //插入Id成功 + await _sqlExecutor + .Insert( "ProductId,Code", "Products.Product" ) + .Values( id, TestConfig.Value ) + .ExecuteAsync(); + + //Code2列名错误,插入Id2失败 + await _sqlExecutor + .Insert( "ProductId,Code,Code2", "Products.Product" ) + .Values( id2, TestConfig.Value, TestConfig.Value ) + .ExecuteAsync(); + + //提交事务 + _sqlExecutor.CommitTransaction(); + } + catch { + //回滚事务 + _sqlExecutor.RollbackTransaction(); + } + + //断言 + var exists = await _sqlExecutor.From( "Products.Product" ).Where( "ProductId", id ).ExecuteExistsAsync(); + var exists2 = await _sqlExecutor.From( "Products.Product" ).Where( "ProductId", id2 ).ExecuteExistsAsync(); + Assert.False( exists ); + Assert.False( exists2 ); + } + + /// + /// 测试事务操作 - 使用using调用BeginTransaction + /// + [Fact] + public async Task TestTransaction_3() { + //创建两个Id + var id = Guid.NewGuid(); + var id2 = Guid.NewGuid(); + + try { + using var transaction = _sqlExecutor.BeginTransaction(); + //插入Id成功 + await _sqlExecutor + .Insert( "ProductId,Code", "Products.Product" ) + .Values( id, TestConfig.Value ) + .ExecuteAsync(); + + //Code2列名错误,插入Id2失败 + await _sqlExecutor + .Insert( "ProductId,Code,Code2", "Products.Product" ) + .Values( id2, TestConfig.Value, TestConfig.Value ) + .ExecuteAsync(); + + //提交事务 + transaction.Commit(); + } + catch { + // ignored + } + + //断言 + var exists = await _sqlExecutor.From( "Products.Product" ).Where( "ProductId", id ).ExecuteExistsAsync(); + var exists2 = await _sqlExecutor.From( "Products.Product" ).Where( "ProductId", id2 ).ExecuteExistsAsync(); + Assert.False( exists ); + Assert.False( exists2 ); + } + + /// + /// 测试事务操作 - 外部传入事务 + /// + [Fact] + public async Task TestTransaction_4() { + //Sql执行器实例2开始事务 + _sqlExecutor2.BeginTransaction(); + var transaction = _sqlExecutor2.GetTransaction(); + + //设置Sql执行器实例1事务 + _sqlExecutor.SetTransaction( transaction ); + + //创建两个Id + var id = Guid.NewGuid(); + var id2 = Guid.NewGuid(); + + try { + //插入Id成功 + await _sqlExecutor + .Insert( "ProductId,Code", "Products.Product" ) + .Values( id, TestConfig.Value ) + .ExecuteAsync(); + + //Code2列名错误,插入Id2失败 + await _sqlExecutor2 + .Insert( "ProductId,Code,Code2", "Products.Product" ) + .Values( id2, TestConfig.Value, TestConfig.Value ) + .ExecuteAsync(); + + //提交事务 + _sqlExecutor.CommitTransaction(); + } + catch { + //回滚事务 + _sqlExecutor.RollbackTransaction(); + } + + //断言 + var exists = await _sqlExecutor.From( "Products.Product" ).Where( "ProductId", id ).ExecuteExistsAsync(); + var exists2 = await _sqlExecutor.From( "Products.Product" ).Where( "ProductId", id2 ).ExecuteExistsAsync(); + Assert.False( exists ); + Assert.False( exists2 ); + } + + /// + /// 测试事务操作 - 成功提交 + /// + [Fact] + public async Task TestTransaction_5() { + //开始事务 + _sqlExecutor.BeginTransaction(); + + //创建两个Id + var id = Guid.NewGuid(); + var id2 = Guid.NewGuid(); + + try { + //插入Id成功 + await _sqlExecutor + .Insert( "ProductId,Code", "Products.Product" ) + .Values( id, TestConfig.Value ) + .ExecuteAsync(); + + //插入Id2成功 + await _sqlExecutor + .Insert( "ProductId,Code", "Products.Product" ) + .Values( id2, TestConfig.Value ) + .ExecuteAsync(); + + //提交事务 + _sqlExecutor.CommitTransaction(); + } + catch { + //回滚事务 + _sqlExecutor.RollbackTransaction(); + } + + //断言 + var exists = await _sqlExecutor.From( "Products.Product" ).Where( "ProductId", id ).ExecuteExistsAsync(); + var exists2 = await _sqlExecutor.From( "Products.Product" ).Where( "ProductId", id2 ).ExecuteExistsAsync(); + Assert.True( exists ); + Assert.True( exists2 ); + } + } +} diff --git a/test/Util.Data.Dapper.PostgreSql.Tests.Integration/SqlQuery/PostgreSqlQueryTest.Exists.cs b/test/Util.Data.Dapper.PostgreSql.Tests.Integration/SqlQuery/PostgreSqlQueryTest.Exists.cs new file mode 100644 index 00000000..c33e3579 --- /dev/null +++ b/test/Util.Data.Dapper.PostgreSql.Tests.Integration/SqlQuery/PostgreSqlQueryTest.Exists.cs @@ -0,0 +1,48 @@ +using System; +using System.Threading.Tasks; +using Util.Data.Sql; +using Util.Tests.Configs; +using Xunit; + +namespace Util.Data.Dapper.Tests.SqlQuery { + /// + /// PostgreSql Sql²éѯ¶ÔÏó²âÊÔ - ÅжÏÊǷñ´æÔڲâÊÔ + /// + public partial class PostgreSqlQueryTest { + /// + /// ²âÊÔÅжÏÊǷñ´æÔÚ - ´æÔÚ + /// + [Fact] + public void TestExecuteExists_1() { + var result = _sqlQuery.From( "Products.Product" ).Where( "ProductId", TestConfig.Id ).ExecuteExists(); + Assert.True( result ); + } + + /// + /// ²âÊÔÅжÏÊǷñ´æÔÚ - ²»´æÔÚ + /// + [Fact] + public void TestExecuteExists_2() { + var result = _sqlQuery.From( "Products.Product" ).Where( "ProductId", Guid.NewGuid() ).ExecuteExists(); + Assert.False( result ); + } + + /// + /// ²âÊÔÅжÏÊǷñ´æÔÚ - ´æÔÚ + /// + [Fact] + public async Task TestExecuteExistsAsync_1() { + var result = await _sqlQuery.From( "Products.Product" ).Where( "ProductId", TestConfig.Id ).ExecuteExistsAsync(); + Assert.True( result ); + } + + /// + /// ²âÊÔÅжÏÊǷñ´æÔÚ - ²»´æÔÚ + /// + [Fact] + public async Task TestExecuteExistsAsync_2() { + var result = await _sqlQuery.From( "Products.Product" ).Where( "ProductId", Guid.NewGuid() ).ExecuteExistsAsync(); + Assert.False( result ); + } + } +} diff --git a/test/Util.Data.Dapper.PostgreSql.Tests.Integration/SqlQuery/PostgreSqlQueryTest.Procedure.cs b/test/Util.Data.Dapper.PostgreSql.Tests.Integration/SqlQuery/PostgreSqlQueryTest.Procedure.cs new file mode 100644 index 00000000..2597b41b --- /dev/null +++ b/test/Util.Data.Dapper.PostgreSql.Tests.Integration/SqlQuery/PostgreSqlQueryTest.Procedure.cs @@ -0,0 +1,233 @@ +using System; +using System.Threading.Tasks; +using Util.Data.Sql; +using Util.Tests.Configs; +using Util.Tests.Models; +using Xunit; + +namespace Util.Data.Dapper.Tests.SqlQuery { + /// + /// PostgreSql Sql²éѯ¶ÔÏó²âÊÔ - ִÐд洢¹ý³̲âÊÔ + /// ˵Ã÷: + /// 1. PostgreSqlµĴ洢¹ý³̲»Äܷµ»ØÊý¾Ý + /// 2. PostgreSqlµĺ¯Êý¿ÉÒԷµ»ØÊý¾Ý,Äܹ»ʹÓÃExecuteProcedureXXXX·½·¨µ÷Óú¯Êý + /// 3. ÐèҪÌرðעÒâPostgreSqlº¯Êýºʹ洢¹ý³ÌÖдóСдÎÊÌâ + /// + public partial class PostgreSqlQueryTest { + + #region ExecuteProcedureScalar + + /// + /// ²âÊÔִÐд洢¹ý³̻ñȡµ¥ֵ + /// + [Fact] + public void TestExecuteProcedureScalar_1() { + //ִÐд洢¹ý³Ì + var result = _sqlQuery + .AddParam( "productId", TestConfig.Id ) + .ExecuteProcedureScalar( "Products.Func_GetProductCode" ); + + //¶ÏÑÔ + Assert.Equal( TestConfig.Value, result ); + Assert.Equal( "\"Products\".\"Func_GetProductCode\"", _sqlQuery.PreviousSql.GetSql() ); + } + + /// + /// ²âÊÔִÐд洢¹ý³̻ñȡµ¥ֵ - ·ºÐͷ½·¨ + /// + [Fact] + public void TestExecuteProcedureScalar_2() { + //ִÐд洢¹ý³Ì + var result = _sqlQuery + .AddParam( "productId", TestConfig.Id ) + .ExecuteProcedureScalar( "Products.Func_GetProductCode" ); + + //¶ÏÑÔ + Assert.Equal( TestConfig.Value, result ); + Assert.Equal( "\"Products\".\"Func_GetProductCode\"", _sqlQuery.PreviousSql.GetSql() ); + } + + #endregion + + #region ExecuteProcedureScalarAsync + + /// + /// ²âÊÔִÐд洢¹ý³̻ñȡµ¥ֵ + /// + [Fact] + public async Task TestExecuteProcedureScalarAsync_1() { + //ִÐд洢¹ý³Ì + var result = await _sqlQuery + .AddParam( "productId", TestConfig.Id ) + .ExecuteProcedureScalarAsync( "Products.Func_GetProductCode" ); + + //¶ÏÑÔ + Assert.Equal( TestConfig.Value, result ); + Assert.Equal( "\"Products\".\"Func_GetProductCode\"", _sqlQuery.PreviousSql.GetSql() ); + } + + /// + /// ²âÊÔִÐд洢¹ý³̻ñȡµ¥ֵ - ·ºÐͷ½·¨ + /// + [Fact] + public async Task TestExecuteProcedureScalarAsync_2() { + //ִÐд洢¹ý³Ì + var result = await _sqlQuery + .AddParam( "productId", TestConfig.Id ) + .ExecuteProcedureScalarAsync( "Products.Func_GetProductCode" ); + + //¶ÏÑÔ + Assert.Equal( TestConfig.Value, result ); + Assert.Equal( "\"Products\".\"Func_GetProductCode\"", _sqlQuery.PreviousSql.GetSql() ); + } + + #endregion + + #region ExecuteProcedureSingle + + /// + /// ²âÊÔִÐд洢¹ý³̻ñȡµ¥¸öʵÌå + /// + [Fact] + public void TestExecuteProcedureSingle() { + //ִÐд洢¹ý³Ì + var result = _sqlQuery + .AddParam( "productId", TestConfig.Id ) + .ExecuteProcedureSingle( "Products.Func_GetProduct" ); + + //¶ÏÑÔ + Assert.Equal( TestConfig.Value, result.Code ); + Assert.Equal( "\"Products\".\"Func_GetProduct\"", _sqlQuery.PreviousSql.GetSql() ); + } + + #endregion + + #region ExecuteProcedureSingleAsync + + /// + /// ²âÊÔִÐд洢¹ý³̻ñȡµ¥¸öʵÌå + /// + [Fact] + public async Task TestExecuteProcedureSingleAsync() { + //ִÐд洢¹ý³Ì + var result = await _sqlQuery + .AddParam( "productId", TestConfig.Id ) + .ExecuteProcedureSingleAsync( "Products.Func_GetProduct" ); + + //¶ÏÑÔ + Assert.Equal( TestConfig.Value, result.Code ); + Assert.Equal( "\"Products\".\"Func_GetProduct\"", _sqlQuery.PreviousSql.GetSql() ); + } + + #endregion + + #region ExecuteProcedureQuery + + /// + /// ²âÊÔִÐд洢¹ý³̻ñȡʵÌ弯ºÏ + /// + [Fact] + public async Task TestExecuteProcedureQuery_1() { + //²åÈë2ÌõÊý¾Ý + var id = Guid.NewGuid(); + var id2 = Guid.NewGuid(); + await _sqlExecutor.Insert( "ProductId,Code", "Products.Product" ) + .Values( id, "a" ) + .Values( id2, "b" ) + .ExecuteAsync(); + + //ִÐд洢¹ý³Ì + var result = _sqlQuery + .AddParam( "productId", id ) + .AddParam( "productId2", id2 ) + .ExecuteProcedureQuery( "Products.Func_GetProducts" ); + + //¶ÏÑÔ + Assert.Equal( 2, result.Count ); + Assert.Contains( result, t => t.Id == id && t.Code == "a" ); + Assert.Contains( result, t => t.Id == id2 && t.Code == "b" ); + Assert.Equal( "\"Products\".\"Func_GetProducts\"", _sqlQuery.PreviousSql.GetSql() ); + } + + /// + /// ²âÊԻñȡʵÌ弯ºÏ - 1¸ö·ºÐͲÎÊý + /// + [Fact] + public async Task TestExecuteProcedureQuery_2() { + //²åÈë2ÌõÊý¾Ý + var id = Guid.NewGuid(); + var id2 = Guid.NewGuid(); + await _sqlExecutor.Insert( "ProductId,Code", "Products.Product" ) + .Values( id, "a" ) + .Values( id2, "b" ) + .ExecuteAsync(); + + //ִÐд洢¹ý³Ì + var result = _sqlQuery + .AddParam( "productId", id ) + .AddParam( "productId2", id2 ) + .ExecuteProcedureQuery( "Products.Func_GetProducts" ); + + //¶ÏÑÔ + Assert.Equal( 2, result.Count ); + Assert.Contains( result, t => t.Id == id && t.Code == "a" ); + Assert.Contains( result, t => t.Id == id2 && t.Code == "b" ); + Assert.Equal( "\"Products\".\"Func_GetProducts\"", _sqlQuery.PreviousSql.GetSql() ); + } + + #endregion + + #region ExecuteProcedureQueryAsync + + /// + /// ²âÊÔִÐд洢¹ý³̻ñȡʵÌ弯ºÏ + /// + [Fact] + public async Task TestExecuteProcedureQueryAsync_1() { + //²åÈë2ÌõÊý¾Ý + var id = Guid.NewGuid(); + var id2 = Guid.NewGuid(); + await _sqlExecutor.Insert( "ProductId,Code", "Products.Product" ) + .Values( id, "a" ) + .Values( id2, "b" ) + .ExecuteAsync(); + + //ִÐд洢¹ý³Ì + var result = await _sqlQuery + .AddDynamicParams( new{ productId=id, productId2=id2 } ) + .ExecuteProcedureQueryAsync( "Products.Func_GetProducts" ); + + //¶ÏÑÔ + Assert.Equal( 2, result.Count ); + Assert.Contains( result, t => t.Id == id && t.Code == "a" ); + Assert.Contains( result, t => t.Id == id2 && t.Code == "b" ); + } + + /// + /// ²âÊԻñȡʵÌ弯ºÏ - 1¸ö·ºÐͲÎÊý + /// + [Fact] + public async Task TestExecuteProcedureQueryAsync_2() { + //²åÈë2ÌõÊý¾Ý + var id = Guid.NewGuid(); + var id2 = Guid.NewGuid(); + await _sqlExecutor.Insert( "ProductId,Code", "Products.Product" ) + .Values( id, "a" ) + .Values( id2, "b" ) + .ExecuteAsync(); + + //ִÐд洢¹ý³Ì + var result = await _sqlQuery + .AddParam( "productId", id ) + .AddParam( "productId2", id2 ) + .ExecuteProcedureQueryAsync( "Products.Func_GetProducts" ); + + //¶ÏÑÔ + Assert.Equal( 2, result.Count ); + Assert.Contains( result, t => t.Id == id && t.Code == "a" ); + Assert.Contains( result, t => t.Id == id2 && t.Code == "b" ); + } + + #endregion + } +} diff --git a/test/Util.Data.Dapper.PostgreSql.Tests.Integration/SqlQuery/PostgreSqlQueryTest.Query.cs b/test/Util.Data.Dapper.PostgreSql.Tests.Integration/SqlQuery/PostgreSqlQueryTest.Query.cs new file mode 100644 index 00000000..05995d0a --- /dev/null +++ b/test/Util.Data.Dapper.PostgreSql.Tests.Integration/SqlQuery/PostgreSqlQueryTest.Query.cs @@ -0,0 +1,388 @@ +using System; +using System.Collections; +using System.Threading.Tasks; +using Util.Data.Sql; +using Util.Helpers; +using Util.Tests.Configs; +using Util.Tests.Models; +using Xunit; + +namespace Util.Data.Dapper.Tests.SqlQuery { + /// + /// PostgreSql Sql²éѯ¶ÔÏó²âÊÔ - ²éѯ²âÊÔ + /// + public partial class PostgreSqlQueryTest { + + #region ExecuteQuery + + /// + /// ²âÊԻñȡʵÌ弯ºÏ + /// + [Fact] + public async Task TestExecuteQuery_1() { + //²åÈë2ÌõÊý¾Ý + var id = Guid.NewGuid(); + var id2 = Guid.NewGuid(); + var code = "TestExecuteQuery_1"; + await _sqlExecutor.Insert( "ProductId,Code", "Products.Product" ) + .Values( id, code ) + .Values( id2, code ) + .ExecuteAsync(); + + //»ñȡ¶ÔÏó + var result = _sqlQuery.Select().From( "Products.Product" ).In( "ProductId", new[] { id, id2 } ).ExecuteQuery(); + + //¶ÏÑÔ + Assert.NotNull( result ); + Assert.Equal( 2, result.Count ); + Assert.Contains( result, t => t.ProductId == id ); + Assert.Contains( result, t => t.ProductId == id2 ); + Assert.Contains( result, t => t.Code == code ); + } + + /// + /// ²âÊԻñȡʵÌ弯ºÏ - 1¸ö·ºÐͲÎÊý + /// + [Fact] + public async Task TestExecuteQuery_2() { + //²åÈë2ÌõÊý¾Ý + var id = Guid.NewGuid(); + var id2 = Guid.NewGuid(); + var code = "TestExecuteQuery_2"; + await _sqlExecutor.Insert( "ProductId,Code", "Products.Product" ) + .Values( id, code ) + .Values( id2, code ) + .ExecuteAsync(); + + //»ñȡ¶ÔÏó + var result = _sqlQuery.Select("ProductId As Id,Code").From( "Products.Product" ).In( "ProductId", new[] { id, id2 } ).ExecuteQuery(); + + //¶ÏÑÔ + Assert.NotNull( result ); + Assert.Equal( 2, result.Count ); + Assert.Contains( result, t => t.Id == id ); + Assert.Contains( result, t => t.Id == id2 ); + Assert.Contains( result, t => t.Code == code ); + } + + /// + /// ²âÊԻñȡʵÌ弯ºÏ - 3¸ö·ºÐͲÎÊý - Ö÷´ӱí,ÉèÖùØÁªÊôÐÔ + /// + [Fact] + public async Task TestExecuteQuery_3() { + //²åÈ붩µ¥ + var orderId = Id.Create(); + var customerName = "customerName"; + await _sqlExecutor.Insert( "OrderId,CustomerName", "Sales.Order" ) + .Values( orderId, customerName ) + .ExecuteAsync(); + + //²åÈ붩µ¥Ã÷ϸ + var orderItemId = Id.CreateGuid(); + await _sqlExecutor.Insert( "OrderItemId,OrderId,Price", "Sales.OrderItem" ) + .Values( orderItemId, orderId,TestConfig.DecimalValue ) + .ExecuteAsync(); + + ////»ñȡ¶ÔÏó + var result = _sqlQuery + .Select( "i.OrderItemId As Id,i.*" ) //½«OrderItemIdӳÉäΪId,±ØÐëÔÚ֮ºó½ô¸úOrderItemÏà¹صÄÁÐ + .Select( "o.OrderId As Id,o.*" ) //½«OrderIdӳÉäΪId,½«¸î¶Ï֮ǰOrderItem±íÖеÄÐÅϢ,֮ºó¼ÌÐøÌí¼ÓOrder±íÖеÄÁÐ + .From( "Sales.OrderItem As i" ) + .LeftJoin( "Sales.Order As o" ).On( "o.OrderId", "i.OrderId" ) + .Where( "i.OrderItemId", orderItemId ) + .ExecuteQuery( ( item, order ) => { + item.Order = order; + return item; + } ); + + //¶ÏÑÔ + Assert.Single( (IEnumerable)result ); + Assert.Equal( orderItemId, result[0].Id ); + Assert.Equal( TestConfig.DecimalValue, result[0].Price ); + Assert.Equal( orderId, result[0].OrderId ); + Assert.Equal( orderId, result[0].Order.Id ); + Assert.Equal( customerName, result[0].Order.CustomerName ); + } + + #endregion + + #region ExecuteQueryAsync + + /// + /// ²âÊԻñȡʵÌ弯ºÏ + /// + [Fact] + public async Task TestExecuteQueryAsync_1() { + //²åÈë2ÌõÊý¾Ý + var id = Guid.NewGuid(); + var id2 = Guid.NewGuid(); + var code = "TestExecuteQueryAsync_1"; + await _sqlExecutor.Insert( "ProductId,Code", "Products.Product" ) + .Values( id, code ) + .Values( id2, code ) + .ExecuteAsync(); + + //»ñȡ¶ÔÏó + var result = await _sqlQuery.Select().From( "Products.Product" ).In( "ProductId", new[] { id, id2 } ).ExecuteQueryAsync(); + + //¶ÏÑÔ + Assert.NotNull( result ); + Assert.Equal( 2, result.Count ); + Assert.Contains( result, t => t.ProductId == id ); + Assert.Contains( result, t => t.ProductId == id2 ); + Assert.Contains( result, t => t.Code == code ); + } + + /// + /// ²âÊԻñȡʵÌ弯ºÏ + /// + [Fact] + public async Task TestExecuteQueryAsync_2() { + //²åÈë2ÌõÊý¾Ý + var id = Guid.NewGuid(); + var id2 = Guid.NewGuid(); + var code = "TestExecuteQueryAsync_2"; + await _sqlExecutor.Insert( "ProductId,Code", "Products.Product" ) + .Values( id, code ) + .Values( id2, code ) + .ExecuteAsync(); + + //»ñȡ¶ÔÏó + var result = await _sqlQuery.Select( "ProductId As Id,Code" ).From( "Products.Product" ).In( "ProductId", new[] { id, id2 } ).ExecuteQueryAsync(); + + //¶ÏÑÔ + Assert.NotNull( result ); + Assert.Equal( 2, result.Count ); + Assert.Contains( result, t => t.Id == id ); + Assert.Contains( result, t => t.Id == id2 ); + Assert.Contains( result, t => t.Code == code ); + } + + /// + /// ²âÊԻñȡʵÌ弯ºÏ - 3¸ö·ºÐͲÎÊý - Ö÷´ӱí,ÉèÖùØÁªÊôÐÔ + /// + [Fact] + public async Task TestExecuteQueryAsync_3() { + //²åÈ붩µ¥ + var orderId = Id.Create(); + var customerName = "customerName"; + await _sqlExecutor.Insert( "OrderId,CustomerName", "Sales.Order" ) + .Values( orderId, customerName ) + .ExecuteAsync(); + + //²åÈ붩µ¥Ã÷ϸ + var orderItemId = Id.CreateGuid(); + await _sqlExecutor.Insert( "OrderItemId,OrderId,Price", "Sales.OrderItem" ) + .Values( orderItemId, orderId, TestConfig.DecimalValue ) + .ExecuteAsync(); + + ////»ñȡ¶ÔÏó + var result = await _sqlQuery + .Select( "i.OrderItemId As Id,i.*" ) //½«OrderItemIdӳÉäΪId,±ØÐëÔÚ֮ºó½ô¸úOrderItemÏà¹صÄÁÐ + .Select( "o.OrderId As Id,o.*" ) //½«OrderIdӳÉäΪId,½«¸î¶Ï֮ǰOrderItem±íÖеÄÐÅϢ,֮ºó¼ÌÐøÌí¼ÓOrder±íÖеÄÁÐ + .From( "Sales.OrderItem As i" ) + .LeftJoin( "Sales.Order As o" ).On( "o.OrderId", "i.OrderId" ) + .Where( "i.OrderItemId", orderItemId ) + .ExecuteQueryAsync( ( item, order ) => { + item.Order = order; + return item; + } ); + + //¶ÏÑÔ + Assert.Single( (IEnumerable)result ); + Assert.Equal( orderItemId, result[0].Id ); + Assert.Equal( TestConfig.DecimalValue, result[0].Price ); + Assert.Equal( orderId, result[0].OrderId ); + Assert.Equal( orderId, result[0].Order.Id ); + Assert.Equal( customerName, result[0].Order.CustomerName ); + } + + #endregion + + #region ToList + + /// + /// ²âÊԻñȡʵÌ弯ºÏ + /// + [Fact] + public async Task TestToList_1() { + //²åÈë2ÌõÊý¾Ý + var id = Guid.NewGuid(); + var id2 = Guid.NewGuid(); + var code = "TestToList_1"; + await _sqlExecutor.Insert( "ProductId,Code", "Products.Product" ) + .Values( id, code ) + .Values( id2, code ) + .ExecuteAsync(); + + //»ñȡ¶ÔÏó + var result = _sqlQuery.Select().From( "Products.Product" ).In( "ProductId", new[] { id, id2 } ).ToList(); + + //¶ÏÑÔ + Assert.NotNull( result ); + Assert.Equal( 2, result.Count ); + Assert.Contains( result, t => t.ProductId == id ); + Assert.Contains( result, t => t.ProductId == id2 ); + Assert.Contains( result, t => t.Code == code ); + } + + /// + /// ²âÊԻñȡʵÌ弯ºÏ - 1¸ö·ºÐͲÎÊý + /// + [Fact] + public async Task TestToList_2() { + //²åÈë2ÌõÊý¾Ý + var id = Guid.NewGuid(); + var id2 = Guid.NewGuid(); + var code = "TestToList_2"; + await _sqlExecutor.Insert( "ProductId,Code", "Products.Product" ) + .Values( id, code ) + .Values( id2, code ) + .ExecuteAsync(); + + //»ñȡ¶ÔÏó + var result = _sqlQuery.Select( "ProductId As Id,Code" ).From( "Products.Product" ).In( "ProductId", new[] { id, id2 } ).ToList(); + + //¶ÏÑÔ + Assert.NotNull( result ); + Assert.Equal( 2, result.Count ); + Assert.Contains( result, t => t.Id == id ); + Assert.Contains( result, t => t.Id == id2 ); + Assert.Contains( result, t => t.Code == code ); + } + + /// + /// ²âÊԻñȡʵÌ弯ºÏ - 3¸ö·ºÐͲÎÊý - Ö÷´ӱí,ÉèÖùØÁªÊôÐÔ + /// + [Fact] + public async Task TestToList_3() { + //²åÈ붩µ¥ + var orderId = Id.Create(); + var customerName = "customerName"; + await _sqlExecutor.Insert( "OrderId,CustomerName", "Sales.Order" ) + .Values( orderId, customerName ) + .ExecuteAsync(); + + //²åÈ붩µ¥Ã÷ϸ + var orderItemId = Id.CreateGuid(); + await _sqlExecutor.Insert( "OrderItemId,OrderId,Price", "Sales.OrderItem" ) + .Values( orderItemId, orderId, TestConfig.DecimalValue ) + .ExecuteAsync(); + + ////»ñȡ¶ÔÏó + var result = _sqlQuery + .Select( "i.OrderItemId As Id,i.*" ) //½«OrderItemIdӳÉäΪId,±ØÐëÔÚ֮ºó½ô¸úOrderItemÏà¹صÄÁÐ + .Select( "o.OrderId As Id,o.*" ) //½«OrderIdӳÉäΪId,½«¸î¶Ï֮ǰOrderItem±íÖеÄÐÅϢ,֮ºó¼ÌÐøÌí¼ÓOrder±íÖеÄÁÐ + .From( "Sales.OrderItem As i" ) + .LeftJoin( "Sales.Order As o" ).On( "o.OrderId", "i.OrderId" ) + .Where( "i.OrderItemId", orderItemId ) + .ToList( ( item, order ) => { + item.Order = order; + return item; + } ); + + //¶ÏÑÔ + Assert.Single( (IEnumerable)result ); + Assert.Equal( orderItemId, result[0].Id ); + Assert.Equal( TestConfig.DecimalValue, result[0].Price ); + Assert.Equal( orderId, result[0].OrderId ); + Assert.Equal( orderId, result[0].Order.Id ); + Assert.Equal( customerName, result[0].Order.CustomerName ); + } + + #endregion + + #region ToListAsync + + /// + /// ²âÊԻñȡʵÌ弯ºÏ + /// + [Fact] + public async Task TestToListAsync_1() { + //²åÈë2ÌõÊý¾Ý + var id = Guid.NewGuid(); + var id2 = Guid.NewGuid(); + var code = "TestToListAsync_1"; + await _sqlExecutor.Insert( "ProductId,Code", "Products.Product" ) + .Values( id, code ) + .Values( id2, code ) + .ExecuteAsync(); + + //»ñȡ¶ÔÏó + var result = await _sqlQuery.Select().From( "Products.Product" ).In( "ProductId", new[] { id, id2 } ).ToListAsync(); + + //¶ÏÑÔ + Assert.NotNull( result ); + Assert.Equal( 2, result.Count ); + Assert.Contains( result, t => t.ProductId == id ); + Assert.Contains( result, t => t.ProductId == id2 ); + Assert.Contains( result, t => t.Code == code ); + } + + /// + /// ²âÊԻñȡʵÌ弯ºÏ + /// + [Fact] + public async Task TestToListAsync_2() { + //²åÈë2ÌõÊý¾Ý + var id = Guid.NewGuid(); + var id2 = Guid.NewGuid(); + var code = "TestToListAsync_2"; + await _sqlExecutor.Insert( "ProductId,Code", "Products.Product" ) + .Values( id, code ) + .Values( id2, code ) + .ExecuteAsync(); + + //»ñȡ¶ÔÏó + var result = await _sqlQuery.Select( "ProductId As Id,Code" ).From( "Products.Product" ).In( "ProductId", new[] { id, id2 } ).ToListAsync(); + + //¶ÏÑÔ + Assert.NotNull( result ); + Assert.Equal( 2, result.Count ); + Assert.Contains( result, t => t.Id == id ); + Assert.Contains( result, t => t.Id == id2 ); + Assert.Contains( result, t => t.Code == code ); + } + + /// + /// ²âÊԻñȡʵÌ弯ºÏ - 3¸ö·ºÐͲÎÊý - Ö÷´ӱí,ÉèÖùØÁªÊôÐÔ + /// + [Fact] + public async Task TestToListAsync_3() { + //²åÈ붩µ¥ + var orderId = Id.Create(); + var customerName = "customerName"; + await _sqlExecutor.Insert( "OrderId,CustomerName", "Sales.Order" ) + .Values( orderId, customerName ) + .ExecuteAsync(); + + //²åÈ붩µ¥Ã÷ϸ + var orderItemId = Id.CreateGuid(); + await _sqlExecutor.Insert( "OrderItemId,OrderId,Price", "Sales.OrderItem" ) + .Values( orderItemId, orderId, TestConfig.DecimalValue ) + .ExecuteAsync(); + + ////»ñȡ¶ÔÏó + var result = await _sqlQuery + .Select( "i.OrderItemId As Id,i.*" ) //½«OrderItemIdӳÉäΪId,±ØÐëÔÚ֮ºó½ô¸úOrderItemÏà¹صÄÁÐ + .Select( "o.OrderId As Id,o.*" ) //½«OrderIdӳÉäΪId,½«¸î¶Ï֮ǰOrderItem±íÖеÄÐÅϢ,֮ºó¼ÌÐøÌí¼ÓOrder±íÖеÄÁÐ + .From( "Sales.OrderItem As i" ) + .LeftJoin( "Sales.Order As o" ).On( "o.OrderId", "i.OrderId" ) + .Where( "i.OrderItemId", orderItemId ) + .ToListAsync( ( item, order ) => { + item.Order = order; + return item; + } ); + + //¶ÏÑÔ + Assert.Single( (IEnumerable)result ); + Assert.Equal( orderItemId, result[0].Id ); + Assert.Equal( TestConfig.DecimalValue, result[0].Price ); + Assert.Equal( orderId, result[0].OrderId ); + Assert.Equal( orderId, result[0].Order.Id ); + Assert.Equal( customerName, result[0].Order.CustomerName ); + } + + #endregion + } +} diff --git a/test/Util.Data.Dapper.PostgreSql.Tests.Integration/SqlQuery/PostgreSqlQueryTest.Scalar.cs b/test/Util.Data.Dapper.PostgreSql.Tests.Integration/SqlQuery/PostgreSqlQueryTest.Scalar.cs new file mode 100644 index 00000000..fcf4312c --- /dev/null +++ b/test/Util.Data.Dapper.PostgreSql.Tests.Integration/SqlQuery/PostgreSqlQueryTest.Scalar.cs @@ -0,0 +1,629 @@ +using System.Threading.Tasks; +using Util.Data.Sql; +using Util.Tests.Configs; +using Xunit; + +namespace Util.Data.Dapper.Tests.SqlQuery { + /// + /// PostgreSql Sql²éѯ¶ÔÏó²âÊÔ - µ¥ֵ²âÊÔ + /// + public partial class PostgreSqlQueryTest { + + #region ExecuteScalar + + /// + /// ²âÊԻñȡµ¥ֵ + /// + [Fact] + public void TestExecuteScalar_1() { + var result = _sqlQuery.Select( "Code" ).From( "Products.Product" ).Where( "ProductId", TestConfig.Id ).ExecuteScalar(); + Assert.Equal( TestConfig.Value, result.SafeString() ); + } + + /// + /// ²âÊԻñȡµ¥ֵ - ·ºÐÍ + /// + [Fact] + public void TestExecuteScalar_2() { + var result = _sqlQuery.Select( "Code" ).From( "Products.Product" ).Where( "ProductId", TestConfig.Id ).ExecuteScalar(); + Assert.Equal( TestConfig.Value, result ); + } + + #endregion + + #region ExecuteScalarAsync + + /// + /// ²âÊԻñȡµ¥ֵ + /// + [Fact] + public async Task TestExecuteScalarAsync_1() { + var result = await _sqlQuery.Select( "Code" ).From( "Products.Product" ).Where( "ProductId", TestConfig.Id ).ExecuteScalarAsync(); + Assert.Equal( TestConfig.Value, result.SafeString() ); + } + + /// + /// ²âÊԻñȡµ¥ֵ - ·ºÐÍ + /// + [Fact] + public async Task TestExecuteScalarAsync_2() { + var result = await _sqlQuery.Select( "Code" ).From( "Products.Product" ).Where( "ProductId", TestConfig.Id ).ExecuteScalarAsync(); + Assert.Equal( TestConfig.Value, result ); + } + + #endregion + + #region ToStringAsync + + /// + /// ²âÊԻñȡ×ַû´®ֵ + /// + [Fact] + public async Task TestToStringAsync() { + var result = await _sqlQuery.Select( "Code" ).From( "Products.Product" ).Where( "ProductId", TestConfig.Id ).ToStringAsync(); + Assert.Equal( TestConfig.Value, result ); + } + + #endregion + + #region ToInt + + /// + /// ²âÊԻñȡ32λÕûÐÍֵ + /// + [Fact] + public void TestToInt() { + var result = _sqlQuery.Select( "IntPrice" ).From( "Products.Product" ).Where( "ProductId", TestConfig.Id ).ToInt(); + Assert.Equal( TestConfig.IntValue, result ); + } + + #endregion + + #region ToIntAsync + + /// + /// ²âÊԻñȡ32λÕûÐÍֵ + /// + [Fact] + public async Task TestToIntAsync() { + var result = await _sqlQuery.Select( "IntPrice" ).From( "Products.Product" ).Where( "ProductId", TestConfig.Id ).ToIntAsync(); + Assert.Equal( TestConfig.IntValue, result ); + } + + #endregion + + #region ToIntOrNull + + /// + /// ²âÊԻñȡ32λÕûÐÍֵ - ÓÐֵ + /// + [Fact] + public void TestToIntOrNull_1() { + var result = _sqlQuery.Select( "IntPrice" ).From( "Products.Product" ).Where( "ProductId", TestConfig.Id ).ToIntOrNull(); + Assert.Equal( TestConfig.IntValue, result ); + } + + /// + /// ²âÊԻñȡ32λ¿ɿÕÕûÐÍֵ - ¿Õֵ + /// + [Fact] + public void TestToIntOrNull_2() { + var result = _sqlQuery.Select( "Code" ).From( "Products.Product" ).Where( "ProductId", TestConfig.Id ).ToIntOrNull(); + Assert.Null( result ); + } + + #endregion + + #region ToIntOrNullAsync + + /// + /// ²âÊԻñȡ32λ¿ɿÕÕûÐÍֵ - ÓÐֵ + /// + [Fact] + public async Task TestToIntOrNullAsync_1() { + var result = await _sqlQuery.Select( "IntPrice" ).From( "Products.Product" ).Where( "ProductId", TestConfig.Id ).ToIntOrNullAsync(); + Assert.Equal( TestConfig.IntValue, result ); + } + + /// + /// ²âÊԻñȡ32λ¿ɿÕÕûÐÍֵ - ¿Õֵ + /// + [Fact] + public async Task TestToIntOrNullAsync_2() { + var result = await _sqlQuery.Select( "Code" ).From( "Products.Product" ).Where( "ProductId", TestConfig.Id ).ToIntOrNullAsync(); + Assert.Null( result ); + } + + #endregion + + #region ToLong + + /// + /// ²âÊԻñȡ64λÕûÐÍֵ + /// + [Fact] + public void TestToLong() { + var result = _sqlQuery.Select( "LongPrice" ).From( "Products.Product" ).Where( "ProductId", TestConfig.Id ).ToLong(); + Assert.Equal( TestConfig.LongValue, result ); + } + + #endregion + + #region ToLongAsync + + /// + /// ²âÊԻñȡ64λÕûÐÍֵ + /// + [Fact] + public async Task TestToLongAsync() { + var result = await _sqlQuery.Select( "LongPrice" ).From( "Products.Product" ).Where( "ProductId", TestConfig.Id ).ToLongAsync(); + Assert.Equal( TestConfig.LongValue, result ); + } + + #endregion + + #region ToLongOrNull + + /// + /// ²âÊԻñȡ64λ¿ɿÕÕûÐÍֵ - ÓÐֵ + /// + [Fact] + public void TestToLongOrNull_1() { + var result = _sqlQuery.Select( "LongPrice" ).From( "Products.Product" ).Where( "ProductId", TestConfig.Id ).ToLongOrNull(); + Assert.Equal( TestConfig.LongValue, result ); + } + + /// + /// ²âÊԻñȡ64λ¿ɿÕÕûÐÍֵ - ¿Õֵ + /// + [Fact] + public void TestToLongOrNull_2() { + var result = _sqlQuery.Select( "Code" ).From( "Products.Product" ).Where( "ProductId", TestConfig.Id ).ToLongOrNull(); + Assert.Null( result ); + } + + #endregion + + #region ToLongOrNullAsync + + /// + /// ²âÊԻñȡ64λ¿ɿÕÕûÐÍֵ - ÓÐֵ + /// + [Fact] + public async Task TestToLongOrNullAsync_1() { + var result = await _sqlQuery.Select( "LongPrice" ).From( "Products.Product" ).Where( "ProductId", TestConfig.Id ).ToLongOrNullAsync(); + Assert.Equal( TestConfig.LongValue, result ); + } + + /// + /// ²âÊԻñȡ64λ¿ɿÕÕûÐÍֵ - ¿Õֵ + /// + [Fact] + public async Task TestToLongOrNullAsync_2() { + var result = await _sqlQuery.Select( "Code" ).From( "Products.Product" ).Where( "ProductId", TestConfig.Id ).ToLongOrNullAsync(); + Assert.Null( result ); + } + + #endregion + + #region ToGuid + + /// + /// ²âÊԻñȡGuidֵ + /// + [Fact] + public void TestToGuid() { + var result = _sqlQuery.Select( "ProductId" ).From( "Products.Product" ).Where( "ProductId", TestConfig.Id ).ToGuid(); + Assert.Equal( TestConfig.Id, result ); + } + + #endregion + + #region ToGuidAsync + + /// + /// ²âÊԻñȡGuidֵ + /// + [Fact] + public async Task TestToGuidAsync() { + var result = await _sqlQuery.Select( "ProductId" ).From( "Products.Product" ).Where( "ProductId", TestConfig.Id ).ToGuidAsync(); + Assert.Equal( TestConfig.Id, result ); + } + + #endregion + + #region ToGuidOrNull + + /// + /// ²âÊԻñȡ¿ɿÕGuidֵ - ÓÐֵ + /// + [Fact] + public void TestToGuidOrNull_1() { + var result = _sqlQuery.Select( "ProductId" ).From( "Products.Product" ).Where( "ProductId", TestConfig.Id ).ToGuidOrNull(); + Assert.Equal( TestConfig.Id, result ); + } + + /// + /// ²âÊԻñȡ¿ɿÕGuidֵ - ¿Õֵ + /// + [Fact] + public void TestToGuidOrNull_2() { + var result = _sqlQuery.Select( "Code" ).From( "Products.Product" ).Where( "ProductId", TestConfig.Id ).ToGuidOrNull(); + Assert.Null( result ); + } + + #endregion + + #region ToGuidOrNullAsync + + /// + /// ²âÊԻñȡ¿ɿÕGuidֵ - ÓÐֵ + /// + [Fact] + public async Task TestToGuidOrNullAsync_1() { + var result = await _sqlQuery.Select( "ProductId" ).From( "Products.Product" ).Where( "ProductId", TestConfig.Id ).ToGuidOrNullAsync(); + Assert.Equal( TestConfig.Id, result ); + } + + /// + /// ²âÊԻñȡ¿ɿÕGuidֵ - ¿Õֵ + /// + [Fact] + public async Task TestToGuidOrNullAsync_2() { + var result = await _sqlQuery.Select( "Code" ).From( "Products.Product" ).Where( "ProductId", TestConfig.Id ).ToGuidOrNullAsync(); + Assert.Null( result ); + } + + #endregion + + #region ToBool + + /// + /// ²âÊԻñȡ²¼¶ûֵ + /// + [Fact] + public void TestToBool() { + var result = _sqlQuery.Select( "Enabled" ).From( "Products.Product" ).Where( "ProductId", TestConfig.Id ).ToBool(); + Assert.Equal( TestConfig.BoolValue, result ); + } + + #endregion + + #region ToBoolAsync + + /// + /// ²âÊԻñȡ²¼¶ûֵ + /// + [Fact] + public async Task TestToBoolAsync() { + var result = await _sqlQuery.Select( "Enabled" ).From( "Products.Product" ).Where( "ProductId", TestConfig.Id ).ToBoolAsync(); + Assert.Equal( TestConfig.BoolValue, result ); + } + + #endregion + + #region ToBoolOrNull + + /// + /// ²âÊԻñȡ¿ɿղ¼¶ûֵ - ÓÐֵ + /// + [Fact] + public void TestToBoolOrNull_1() { + var result = _sqlQuery.Select( "Enabled" ).From( "Products.Product" ).Where( "ProductId", TestConfig.Id ).ToBoolOrNull(); + Assert.Equal( TestConfig.BoolValue, result ); + } + + /// + /// ²âÊԻñȡ¿ɿղ¼¶ûֵ - ¿Õֵ + /// + [Fact] + public void TestToBoolOrNull_2() { + var result = _sqlQuery.Select( "Code" ).From( "Products.Product" ).Where( "ProductId", TestConfig.Id ).ToBoolOrNull(); + Assert.Null( result ); + } + + #endregion + + #region ToBoolOrNullAsync + + /// + /// ²âÊԻñȡ¿ɿղ¼¶ûֵ - ÓÐֵ + /// + [Fact] + public async Task TestToBoolOrNullAsync_1() { + var result = await _sqlQuery.Select( "Enabled" ).From( "Products.Product" ).Where( "ProductId", TestConfig.Id ).ToBoolOrNullAsync(); + Assert.Equal( TestConfig.BoolValue, result ); + } + + /// + /// ²âÊԻñȡ¿ɿղ¼¶ûֵ - ¿Õֵ + /// + [Fact] + public async Task TestToBoolOrNullAsync_2() { + var result = await _sqlQuery.Select( "Code" ).From( "Products.Product" ).Where( "ProductId", TestConfig.Id ).ToBoolOrNullAsync(); + Assert.Null( result ); + } + + #endregion + + #region ToFloat + + /// + /// ²âÊԻñȡFloatֵ + /// + [Fact] + public void TestToFloat() { + var result = _sqlQuery.Select( "FloatPrice" ).From( "Products.Product" ).Where( "ProductId", TestConfig.Id ).ToFloat(); + Assert.Equal( TestConfig.FloatValue, result ); + } + + #endregion + + #region ToFloatAsync + + /// + /// ²âÊԻñȡFloatֵ + /// + [Fact] + public async Task TestToFloatAsync() { + var result = await _sqlQuery.Select( "FloatPrice" ).From( "Products.Product" ).Where( "ProductId", TestConfig.Id ).ToFloatAsync(); + Assert.Equal( TestConfig.FloatValue, result ); + } + + #endregion + + #region ToFloatOrNull + + /// + /// ²âÊԻñȡ¿ɿÕFloatֵ - ÓÐֵ + /// + [Fact] + public void TestToFloatOrNull_1() { + var result = _sqlQuery.Select( "FloatPrice" ).From( "Products.Product" ).Where( "ProductId", TestConfig.Id ).ToFloatOrNull(); + Assert.Equal( TestConfig.FloatValue, result ); + } + + /// + /// ²âÊԻñȡ¿ɿÕFloatֵ - ¿Õֵ + /// + [Fact] + public void TestToFloatOrNull_2() { + var result = _sqlQuery.Select( "Code" ).From( "Products.Product" ).Where( "ProductId", TestConfig.Id ).ToFloatOrNull(); + Assert.Null( result ); + } + + #endregion + + #region ToFloatOrNullAsync + + /// + /// ²âÊԻñȡ¿ɿÕFloatֵ - ÓÐֵ + /// + [Fact] + public async Task TestToFloatOrNullAsync_1() { + var result = await _sqlQuery.Select( "FloatPrice" ).From( "Products.Product" ).Where( "ProductId", TestConfig.Id ).ToFloatOrNullAsync(); + Assert.Equal( TestConfig.FloatValue, result ); + } + + /// + /// ²âÊԻñȡ¿ɿÕFloatֵ - ¿Õֵ + /// + [Fact] + public async Task TestToFloatOrNullAsync_2() { + var result = await _sqlQuery.Select( "Code" ).From( "Products.Product" ).Where( "ProductId", TestConfig.Id ).ToFloatOrNullAsync(); + Assert.Null( result ); + } + + #endregion + + #region ToDouble + + /// + /// ²âÊԻñȡDoubleֵ + /// + [Fact] + public void TestToDouble() { + var result = _sqlQuery.Select( "Price" ).From( "Products.Product" ).Where( "ProductId", TestConfig.Id ).ToDouble(); + Assert.Equal( TestConfig.DoubleValue, result ); + } + + #endregion + + #region ToDoubleAsync + + /// + /// ²âÊԻñȡDoubleֵ + /// + [Fact] + public async Task TestToDoubleAsync() { + var result = await _sqlQuery.Select( "Price" ).From( "Products.Product" ).Where( "ProductId", TestConfig.Id ).ToDoubleAsync(); + Assert.Equal( TestConfig.DoubleValue, result ); + } + + #endregion + + #region ToDoubleOrNull + + /// + /// ²âÊԻñȡ¿ɿÕDoubleֵ - ÓÐֵ + /// + [Fact] + public void TestToDoubleOrNull_1() { + var result = _sqlQuery.Select( "Price" ).From( "Products.Product" ).Where( "ProductId", TestConfig.Id ).ToDoubleOrNull(); + Assert.Equal( TestConfig.DoubleValue, result ); + } + + /// + /// ²âÊԻñȡ¿ɿÕDoubleֵ - ¿Õֵ + /// + [Fact] + public void TestToDoubleOrNull_2() { + var result = _sqlQuery.Select( "Code" ).From( "Products.Product" ).Where( "ProductId", TestConfig.Id ).ToDoubleOrNull(); + Assert.Null( result ); + } + + #endregion + + #region ToDoubleOrNullAsync + + /// + /// ²âÊԻñȡ¿ɿÕDoubleֵ - ÓÐֵ + /// + [Fact] + public async Task TestToDoubleOrNullAsync_1() { + var result = await _sqlQuery.Select( "Price" ).From( "Products.Product" ).Where( "ProductId", TestConfig.Id ).ToDoubleOrNullAsync(); + Assert.Equal( TestConfig.DoubleValue, result ); + } + + /// + /// ²âÊԻñȡ¿ɿÕDoubleֵ - ¿Õֵ + /// + [Fact] + public async Task TestToDoubleOrNullAsync_2() { + var result = await _sqlQuery.Select( "Code" ).From( "Products.Product" ).Where( "ProductId", TestConfig.Id ).ToDoubleOrNullAsync(); + Assert.Null( result ); + } + + #endregion + + #region ToDecimal + + /// + /// ²âÊԻñȡDecimalֵ + /// + [Fact] + public void TestToDecimal() { + var result = _sqlQuery.Select( "Price" ).From( "Products.Product" ).Where( "ProductId", TestConfig.Id ).ToDecimal(); + Assert.Equal( TestConfig.DecimalValue, result ); + } + + #endregion + + #region ToDecimalAsync + + /// + /// ²âÊԻñȡDecimalֵ + /// + [Fact] + public async Task TestToDecimalAsync() { + var result = await _sqlQuery.Select( "Price" ).From( "Products.Product" ).Where( "ProductId", TestConfig.Id ).ToDecimalAsync(); + Assert.Equal( TestConfig.DecimalValue, result ); + } + + #endregion + + #region ToDecimalOrNull + + /// + /// ²âÊԻñȡDecimalֵ - ÓÐֵ + /// + [Fact] + public void TestToDecimalOrNull_1() { + var result = _sqlQuery.Select( "Price" ).From( "Products.Product" ).Where( "ProductId", TestConfig.Id ).ToDecimalOrNull(); + Assert.Equal( TestConfig.DecimalValue, result ); + } + + /// + /// ²âÊԻñȡDecimalֵ - ¿Õֵ + /// + [Fact] + public void TestToDecimalOrNull_2() { + var result = _sqlQuery.Select( "Code" ).From( "Products.Product" ).Where( "ProductId", TestConfig.Id ).ToDecimalOrNull(); + Assert.Null( result ); + } + + #endregion + + #region ToDecimalOrNullAsync + + /// + /// ²âÊԻñȡ¿ɿÕDecimalֵ - ÓÐֵ + /// + [Fact] + public async Task TestToDecimalOrNullAsync_1() { + var result = await _sqlQuery.Select( "Price" ).From( "Products.Product" ).Where( "ProductId", TestConfig.Id ).ToDecimalOrNullAsync(); + Assert.Equal( TestConfig.DecimalValue, result ); + } + + /// + /// ²âÊԻñȡ¿ɿÕDecimalֵ - ¿Õֵ + /// + [Fact] + public async Task TestToDecimalOrNullAsync_2() { + var result = await _sqlQuery.Select( "Code" ).From( "Products.Product" ).Where( "ProductId", TestConfig.Id ).ToDecimalOrNullAsync(); + Assert.Null( result ); + } + + #endregion + + #region ToDateTime + + /// + /// ²âÊԻñȡÈÕÆÚֵ + /// + [Fact] + public void TestToDateTime() { + var result = _sqlQuery.Select( "Birthday" ).From( "Customers.Customer" ).Where( "CustomerId", 1 ).ToDateTime(); + Assert.Equal( TestConfig.DateTimeValue, result ); + } + + #endregion + + #region ToDateTimeAsync + + /// + /// ²âÊԻñȡÈÕÆÚֵ + /// + [Fact] + public async Task TestToDateTimeAsync() { + var result = await _sqlQuery.Select( "Birthday" ).From( "Customers.Customer" ).Where( "CustomerId", 1 ).ToDateTimeAsync(); + Assert.Equal( TestConfig.DateTimeValue, result ); + } + + #endregion + + #region ToDateTimeOrNull + + /// + /// ²âÊԻñȡ¿ɿÕÈÕÆÚֵ - ÓÐֵ + /// + [Fact] + public void TestToDateTimeOrNull_1() { + var result = _sqlQuery.Select( "Birthday" ).From( "Customers.Customer" ).Where( "CustomerId", 1 ).ToDateTimeOrNull(); + Assert.Equal( TestConfig.DateTimeValue, result ); + } + + /// + /// ²âÊԻñȡ¿ɿÕÈÕÆÚֵ - ¿Õֵ + /// + [Fact] + public void TestToDateTimeOrNull_2() { + var result = _sqlQuery.Select( "Code" ).From( "Customers.Customer" ).Where( "CustomerId", 1 ).ToDateTimeOrNull(); + Assert.Null( result ); + } + + #endregion + + #region ToDateTimeOrNullAsync + + /// + /// ²âÊԻñȡ¿ɿÕÈÕÆÚֵ - ÓÐֵ + /// + [Fact] + public async Task TestToDateTimeOrNullAsync_1() { + var result = await _sqlQuery.Select( "Birthday" ).From( "Customers.Customer" ).Where( "CustomerId", 1 ).ToDateTimeOrNullAsync(); + Assert.Equal( TestConfig.DateTimeValue, result ); + } + + /// + /// ²âÊԻñȡ¿ɿÕÈÕÆÚֵ - ¿Õֵ + /// + [Fact] + public async Task TestToDateTimeOrNullAsync_2() { + var result = await _sqlQuery.Select( "Code" ).From( "Customers.Customer" ).Where( "CustomerId", 1 ).ToDateTimeOrNullAsync(); + Assert.Null( result ); + } + + #endregion + } +} diff --git a/test/Util.Data.Dapper.PostgreSql.Tests.Integration/SqlQuery/PostgreSqlQueryTest.Single.cs b/test/Util.Data.Dapper.PostgreSql.Tests.Integration/SqlQuery/PostgreSqlQueryTest.Single.cs new file mode 100644 index 00000000..48e5de93 --- /dev/null +++ b/test/Util.Data.Dapper.PostgreSql.Tests.Integration/SqlQuery/PostgreSqlQueryTest.Single.cs @@ -0,0 +1,52 @@ +using System.Threading.Tasks; +using Util.Data.Sql; +using Util.Tests.Configs; +using Util.Tests.Models; +using Xunit; + +namespace Util.Data.Dapper.Tests.SqlQuery { + /// + /// PostgreSql Sql²éѯ¶ÔÏó²âÊÔ - »ñȡµ¥¸ö¶ÔÏó²âÊÔ + /// + public partial class PostgreSqlQueryTest { + /// + /// ²âÊԻñȡµ¥¸öʵÌå + /// + [Fact] + public void TestExecuteSingle() { + var result = _sqlQuery.Select( "ProductId as Id,Code" ).From( "Products.Product" ).Where( "ProductId", TestConfig.Id ).ExecuteSingle(); + Assert.Equal( TestConfig.Id, result.Id ); + Assert.Equal( TestConfig.Value, result.Code ); + } + + /// + /// ²âÊԻñȡµ¥¸öʵÌå + /// + [Fact] + public async Task TestExecuteSingleAsync() { + var result = await _sqlQuery.Select( "ProductId as Id,Code" ).From( "Products.Product" ).Where( "ProductId", TestConfig.Id ).ExecuteSingleAsync(); + Assert.Equal( TestConfig.Id, result.Id ); + Assert.Equal( TestConfig.Value, result.Code ); + } + + /// + /// ²âÊԻñȡµ¥¸öʵÌå + /// + [Fact] + public void TestToEntity() { + var result = _sqlQuery.Select( "ProductId as Id,Code" ).From( "Products.Product" ).Where( "ProductId", TestConfig.Id ).ToEntity(); + Assert.Equal( TestConfig.Id, result.Id ); + Assert.Equal( TestConfig.Value, result.Code ); + } + + /// + /// ²âÊԻñȡµ¥¸öʵÌå + /// + [Fact] + public async Task TestToEntityAsync() { + var result = await _sqlQuery.Select( "ProductId as Id,Code" ).From( "Products.Product" ).Where( "ProductId", TestConfig.Id ).ToEntityAsync(); + Assert.Equal( TestConfig.Id, result.Id ); + Assert.Equal( TestConfig.Value, result.Code ); + } + } +} diff --git a/test/Util.Data.Dapper.PostgreSql.Tests.Integration/SqlQuery/PostgreSqlQueryTest.cs b/test/Util.Data.Dapper.PostgreSql.Tests.Integration/SqlQuery/PostgreSqlQueryTest.cs new file mode 100644 index 00000000..226d0012 --- /dev/null +++ b/test/Util.Data.Dapper.PostgreSql.Tests.Integration/SqlQuery/PostgreSqlQueryTest.cs @@ -0,0 +1,25 @@ +using Util.Data.Sql; + +namespace Util.Data.Dapper.Tests.SqlQuery { + /// + /// PostgreSql Sql²éѯ¶ÔÏó²âÊÔ + /// + public partial class PostgreSqlQueryTest { + /// + /// SqlִÐÐÆ÷ + /// + private readonly ISqlExecutor _sqlExecutor; + /// + /// Sql²éѯ¶ÔÏó + /// + private readonly ISqlQuery _sqlQuery; + + /// + /// ²âÊԳõʼ»¯ + /// + public PostgreSqlQueryTest( ISqlExecutor sqlExecutor, ISqlQuery sqlQuery ) { + _sqlExecutor = sqlExecutor; + _sqlQuery = sqlQuery; + } + } +} diff --git a/test/Util.Data.Dapper.PostgreSql.Tests.Integration/Startup.cs b/test/Util.Data.Dapper.PostgreSql.Tests.Integration/Startup.cs new file mode 100644 index 00000000..0419a87a --- /dev/null +++ b/test/Util.Data.Dapper.PostgreSql.Tests.Integration/Startup.cs @@ -0,0 +1,65 @@ +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using Util.Aop; +using Util.Data.Dapper.Tests.Infrastructure; +using Util.Data.EntityFrameworkCore; +using Util.Data.Metadata; +using Util.Data.Sql; +using Util.Dates; +using Util.Helpers; +using Util.Sessions; +using Util.Tests.Infrastructure; +using Util.Tests.UnitOfWorks; +using Xunit.DependencyInjection; +using Xunit.DependencyInjection.Logging; + +namespace Util.Data.Dapper.Tests { + /// + /// Æô¶¯ÅäÖà + /// + public class Startup { + /// + /// ÅäÖÃÖ÷»ú + /// + public void ConfigureHost( IHostBuilder hostBuilder ) { + hostBuilder.ConfigureDefaults( null ) + .ConfigureServices( ( context, services ) => { + services.AddTransient(); + } ) + .AddUtil( options => { + Environment.SetDevelopment(); + options.UseAop() + .UseUtc() + .UsePgSqlQuery( Config.GetConnectionString( "connection" ) ) + .UsePgSqlExecutor( Config.GetConnectionString( "connection" ) ) + .UsePgSqlUnitOfWork( Config.GetConnectionString( "connection" ) ); + } ); + } + + /// + /// ÅäÖ÷þÎñ + /// + public void ConfigureServices( IServiceCollection services ) { + services.AddSingleton(); + InitDatabase( services ); + } + + /// + /// ³õʼ»¯Êý¾ݿâ + /// + private void InitDatabase( IServiceCollection services ) { + var unitOfWork = (PgSqlUnitOfWork)services.BuildServiceProvider().GetService(); + unitOfWork.EnsureDeleted(); + unitOfWork.EnsureCreated(); + DatabaseScript.InitProcedures( unitOfWork?.Database ); + } + + /// + /// ÅäÖÃÈÕ־Ìṩ³ÌÐò + /// + public void Configure( ILoggerFactory loggerFactory, ITestOutputHelperAccessor accessor ) { + loggerFactory.AddProvider( new XunitTestOutputLoggerProvider( accessor, ( s, logLevel ) => logLevel >= LogLevel.Trace ) ); + } + } +} diff --git a/test/Util.Data.Dapper.PostgreSql.Tests.Integration/Util.Data.Dapper.PostgreSql.Tests.Integration.csproj b/test/Util.Data.Dapper.PostgreSql.Tests.Integration/Util.Data.Dapper.PostgreSql.Tests.Integration.csproj new file mode 100644 index 00000000..6fd2b070 --- /dev/null +++ b/test/Util.Data.Dapper.PostgreSql.Tests.Integration/Util.Data.Dapper.PostgreSql.Tests.Integration.csproj @@ -0,0 +1,43 @@ + + + + $(NetTargetFramework) + false + Util.Data.Dapper.Tests + Util.Data.Dapper.Tests.Startup + + + + + Always + + + Always + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + + \ No newline at end of file diff --git a/test/Util.Data.Dapper.PostgreSql.Tests.Integration/appsettings.Development.json b/test/Util.Data.Dapper.PostgreSql.Tests.Integration/appsettings.Development.json new file mode 100644 index 00000000..ddcdab0f --- /dev/null +++ b/test/Util.Data.Dapper.PostgreSql.Tests.Integration/appsettings.Development.json @@ -0,0 +1,11 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Trace", + "Microsoft": "Trace" + } + }, + "ConnectionStrings": { + "connection": "server=192.168.31.158;User Id=admin;password=admin;database=Util.Data.Dapper.Test" + } +} \ No newline at end of file diff --git a/test/Util.Data.Dapper.PostgreSql.Tests.Integration/appsettings.json b/test/Util.Data.Dapper.PostgreSql.Tests.Integration/appsettings.json new file mode 100644 index 00000000..0c879c0f --- /dev/null +++ b/test/Util.Data.Dapper.PostgreSql.Tests.Integration/appsettings.json @@ -0,0 +1,11 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Error", + "Microsoft": "Error" + } + }, + "ConnectionStrings": { + "connection": "server=postgresql.common;User Id=admin;password=admin;database=Util.Data.Dapper.Test" + } +} \ No newline at end of file diff --git a/test/Util.Data.Dapper.SqlServer.Tests.Integration/Infrastructure/DatabaseScript.cs b/test/Util.Data.Dapper.SqlServer.Tests.Integration/Infrastructure/DatabaseScript.cs new file mode 100644 index 00000000..f28977b4 --- /dev/null +++ b/test/Util.Data.Dapper.SqlServer.Tests.Integration/Infrastructure/DatabaseScript.cs @@ -0,0 +1,138 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; + +namespace Util.Data.Dapper.Tests.Infrastructure { + /// + /// 数据库初始化脚本 + /// + public class DatabaseScript { + /// + /// 初始化 + /// + public static void InitProcedures( DatabaseFacade database ) { + CreateGetProductCodeProcedure( database ); + CreateGetProductProcedure( database ); + CreateGetProductsProcedure( database ); + CreateGetOrderItemProcedure( database ); + CreateGetProductCodeOutputProcedure( database ); + CreateReturnProcedure( database ); + CreateInsertProductProcedure( database ); + } + + /// + /// 创建Proc_GetProductCode存储过程 + /// + private static void CreateGetProductCodeProcedure( DatabaseFacade database ) { + var sql = @" + Create Procedure [Products].[Proc_GetProductCode] ( + @productId uniqueidentifier + ) + As + Select [Code] + From [Products].[Product] + Where [ProductId] = @productId + "; + database.ExecuteSqlRaw( sql ); + } + + /// + /// 创建Proc_GetProduct存储过程 + /// + private static void CreateGetProductProcedure( DatabaseFacade database ) { + var sql = @" + Create Procedure [Products].[Proc_GetProduct] ( + @productId uniqueidentifier + ) + As + Select * + From [Products].[Product] + Where [ProductId] = @productId + "; + database.ExecuteSqlRaw( sql ); + } + + /// + /// 创建Proc_GetProducts存储过程 + /// + private static void CreateGetProductsProcedure( DatabaseFacade database ) { + var sql = @" + Create Procedure [Products].[Proc_GetProducts] ( + @productId uniqueidentifier, + @productId2 uniqueidentifier + ) + As + Select p.ProductId As Id,p.* + From [Products].[Product] As p + Where [ProductId] in ( @productId,@productId2 ) + "; + database.ExecuteSqlRaw( sql ); + } + + /// + /// 创建Proc_GetOrderItem存储过程 + /// + private static void CreateGetOrderItemProcedure( DatabaseFacade database ) { + var sql = @" + Create Procedure [Sales].[Proc_GetOrderItem] ( + @orderItemId uniqueidentifier + ) + As + Select i.OrderItemId As Id,i.*,o.OrderId As Id,o.* + From [Sales].[OrderItem] As i + Left Join [Sales].[Order] As o On o.OrderId=i.OrderId + Where i.OrderItemId=@orderItemId + "; + database.ExecuteSqlRaw( sql ); + } + + /// + /// 创建Proc_GetProductCode_Output存储过程 + /// + private static void CreateGetProductCodeOutputProcedure( DatabaseFacade database ) { + var sql = @" + Create Procedure [Products].[Proc_GetProductCode_Output] ( + @productId uniqueidentifier, + @code nvarchar(50) output + ) + As + Select @code=[Code] + From [Products].[Product] + Where [ProductId] = @productId + "; + database.ExecuteSqlRaw( sql ); + } + + /// + /// 创建Proc_Return存储过程 + /// + private static void CreateReturnProcedure( DatabaseFacade database ) { + var sql = @" + Create Procedure [Products].[Proc_Return] ( + @productId uniqueidentifier + ) + As + If Exists(Select * From [Products].[Product] Where [ProductId] = @productId) + Return 1; + Else + Return -1; + "; + database.ExecuteSqlRaw( sql ); + } + + /// + /// 创建Proc_InsertProduct存储过程 + /// + private static void CreateInsertProductProcedure( DatabaseFacade database ) { + var sql = @" + Create Procedure [Products].[Proc_InsertProduct] ( + @productId uniqueidentifier, + @code nvarchar(50) + ) + As + Insert [Products].[Product](ProductId,Code) + Values( @productId,@code ) + "; + database.ExecuteSqlRaw( sql ); + } + } +} diff --git a/test/Util.Data.Dapper.SqlServer.Tests.Integration/Metadata/SqlServerMetadataServiceTest.cs b/test/Util.Data.Dapper.SqlServer.Tests.Integration/Metadata/SqlServerMetadataServiceTest.cs new file mode 100644 index 00000000..16a91af8 --- /dev/null +++ b/test/Util.Data.Dapper.SqlServer.Tests.Integration/Metadata/SqlServerMetadataServiceTest.cs @@ -0,0 +1,99 @@ +using System.Linq; +using Util.Data.Metadata; +using Xunit; + +namespace Util.Data.Dapper.Tests.Metadata { + /// + /// Sql Server数据库元数据服务测试 + /// + public class SqlServerMetadataServiceTest { + /// + /// 数据库元信息 + /// + private readonly DatabaseInfo _databaseInfo; + + /// + /// 初始化 + /// + public SqlServerMetadataServiceTest( IMetadataService service ) { + _databaseInfo = service.GetDatabaseInfo(); + } + + /// + /// 测试获取数据库名称 + /// + [Fact] + public void TestDatabaseName() { + Assert.Equal( "Util.Data.Dapper.Test", _databaseInfo.Name ); + } + + /// + /// 测试获取表信息 + /// + [Fact] + public void TestTableInfo() { + var table = _databaseInfo.Tables.FirstOrDefault( t => t.Name == "Product" ); + Assert.NotNull( table ); + Assert.Equal( "Products", table.Schema ); + Assert.Equal( "产品", table.Comment ); + } + + /// + /// 测试获取主键信息 + /// + [Fact] + public void TestPrimaryKey() { + var table = _databaseInfo.Tables.First( t => t.Name == "OrderItem" ); + var pkColumn = table.Columns.FirstOrDefault( t => t.Name == "OrderItemId" ); + Assert.NotNull( pkColumn ); + Assert.True( pkColumn.IsPrimaryKey ); + var fkColumn = table.Columns.FirstOrDefault( t => t.Name == "OrderId" ); + Assert.NotNull( fkColumn ); + Assert.False( fkColumn.IsPrimaryKey ); + } + + /// + /// 测试获取自增信息 + /// + [Fact] + public void TestAutoIncrement() { + var table = _databaseInfo.Tables.FirstOrDefault( t => t.Name == "Customer" ); + Assert.NotNull( table ); + var column = table.Columns.FirstOrDefault( t => t.Name == "CustomerId" ); + Assert.NotNull( column ); + Assert.True( column.IsAutoIncrement ); + Assert.Equal( "int", column.DataType ); + } + + /// + /// 测试获取数值精度信息 + /// + [Fact] + public void TestPrecision() { + var table = _databaseInfo.Tables.FirstOrDefault( t => t.Name == "Product" ); + Assert.NotNull( table ); + var column = table.Columns.FirstOrDefault( t => t.Name == "Price" ); + Assert.NotNull( column ); + Assert.Equal( 12, column.Precision ); + Assert.Equal( 2, column.Scale ); + } + + /// + /// 测试获取字符串列信息 + /// + [Fact] + public void TestStringInfo() { + var table = _databaseInfo.Tables.FirstOrDefault( t => t.Name == "Product" ); + Assert.NotNull( table ); + var count = table.Columns.Count( t => t.Name == "Code" ); + Assert.Equal( 1, count ); + var column = table.Columns.FirstOrDefault( t => t.Name == "Code" ); + Assert.NotNull( column ); + Assert.Equal( "产品编码", column.Comment ); + Assert.False( column.IsPrimaryKey ); + Assert.True( column.IsNullable ); + Assert.Equal( "nvarchar", column.DataType ); + Assert.Equal( 100, column.Length ); + } + } +} diff --git a/test/Util.Data.Dapper.SqlServer.Tests.Integration/SqlBuilders/SqlServerExistsSqlBuilderTest.cs b/test/Util.Data.Dapper.SqlServer.Tests.Integration/SqlBuilders/SqlServerExistsSqlBuilderTest.cs new file mode 100644 index 00000000..8228402d --- /dev/null +++ b/test/Util.Data.Dapper.SqlServer.Tests.Integration/SqlBuilders/SqlServerExistsSqlBuilderTest.cs @@ -0,0 +1,48 @@ +using System.Text; +using Util.Data.Sql; +using Util.Data.Sql.Builders; +using Xunit; +using Xunit.Abstractions; + +namespace Util.Data.Dapper.Tests.SqlBuilders { + /// + /// 测试判断是否存在的Sql生成器 + /// + public class SqlServerExistsSqlBuilderTest { + /// + /// 输出工具 + /// + private readonly ITestOutputHelper _output; + + /// + /// 测试初始化 + /// + public SqlServerExistsSqlBuilderTest( ITestOutputHelper output ) { + _output = output; + } + + /// + /// 测试生成的Sql + /// + [Fact] + public void TestToSql() { + var sql = new StringBuilder(); + sql.AppendLine( "Select Case" ); + sql.AppendLine( " When Exists (" ); + sql.AppendLine( "Select 1 " ); + sql.Append( "From [b]" ); + sql.AppendLine( ")" ); + sql.AppendLine( " Then Cast(1 As Bit)" ); + sql.AppendLine( " Else Cast(0 As Bit) " ); + sql.Append( "End" ); + + var subQuery = new SqlServerBuilder() + .Select("a") + .From( "b" ); + var sqlBuilder = new SqlServerExistsSqlBuilder( subQuery ); + var result = sqlBuilder.GetSql(); + _output.WriteLine( result ); + Assert.Equal( sql.ToString(),result ); + } + } +} diff --git a/test/Util.Data.Dapper.SqlServer.Tests.Integration/SqlExecutor/SqlServerSqlExecutorTest.Execute.cs b/test/Util.Data.Dapper.SqlServer.Tests.Integration/SqlExecutor/SqlServerSqlExecutorTest.Execute.cs new file mode 100644 index 00000000..2f606589 --- /dev/null +++ b/test/Util.Data.Dapper.SqlServer.Tests.Integration/SqlExecutor/SqlServerSqlExecutorTest.Execute.cs @@ -0,0 +1,28 @@ +using System; +using System.Threading.Tasks; +using Util.Data.Sql; +using Util.Tests.Configs; +using Xunit; + +namespace Util.Data.Dapper.Tests.SqlExecutor { + /// + /// Sql Server Sql执行器测试 - 执行Sql测试 + /// + public partial class SqlServerSqlExecutorTest { + /// + /// 测试执行Sql增删改操作 + /// + [Fact] + public async Task TestExecuteAsync() { + var id = Guid.NewGuid(); + await _sqlExecutor + .AppendLine( "Insert Products.Product(ProductId,Code) " ) + .Append( "Values(@ProductId,@Code)" ) + .AddParam( "@ProductId", id ) + .AddParam( "Code", TestConfig.Value ) + .ExecuteAsync(); + var result = await _sqlExecutor.Select( "Code" ).From( "Products.Product" ).Where( "ProductId", id ).ToStringAsync(); + Assert.Equal( TestConfig.Value, result ); + } + } +} diff --git a/test/Util.Data.Dapper.SqlServer.Tests.Integration/SqlExecutor/SqlServerSqlExecutorTest.Id.cs b/test/Util.Data.Dapper.SqlServer.Tests.Integration/SqlExecutor/SqlServerSqlExecutorTest.Id.cs new file mode 100644 index 00000000..5adbcd4e --- /dev/null +++ b/test/Util.Data.Dapper.SqlServer.Tests.Integration/SqlExecutor/SqlServerSqlExecutorTest.Id.cs @@ -0,0 +1,67 @@ +using System; +using System.Threading.Tasks; +using Util.Data.Sql; +using Util.Helpers; +using Util.Tests.Configs; +using Xunit; + +namespace Util.Data.Dapper.Tests.SqlExecutor { + /// + /// Sql Server Sql执行器测试 - 标识列测试 + /// + public partial class SqlServerSqlExecutorTest { + /// + /// 测试插入Guid主键 + /// + [Fact] + public async Task TestInsert_Guid() { + var id = Guid.NewGuid(); + await _sqlExecutor + .Insert( "ProductId,Code", "Products.Product" ) + .Values( id, TestConfig.Value ) + .ExecuteAsync(); + var result = await _sqlExecutor + .Select( "Code" ) + .From( "Products.Product" ) + .Where( "ProductId", id ) + .ToStringAsync(); + Assert.Equal( TestConfig.Value, result ); + } + + /// + /// 测试插入int自增长主键 + /// + [Fact] + public async Task TestInsert_Int() { + var value = Id.Create(); + await _sqlExecutor + .Insert( "Code", "Customers.Customer" ) + .Values( value ) + .ExecuteAsync(); + var result = await _sqlExecutor + .Select( "CustomerId" ) + .From( "Customers.Customer" ) + .Where( "Code", value ) + .ToIntAsync(); + Assert.True( result > 0 ); + } + + /// + /// 测试插入string主键 + /// + [Fact] + public async Task TestInsert_String() { + var id = Id.Create(); + await _sqlExecutor + .Insert( "OrderId,CustomerName", "Sales.Order" ) + .Values( id, TestConfig.Value ) + .ExecuteAsync(); + var result = await _sqlExecutor + .Select( "CustomerName" ) + .From( "Sales.Order" ) + .Where( "OrderId", id ) + .ToStringAsync(); + Assert.Equal( TestConfig.Value, result ); + } + } +} diff --git a/test/Util.Data.Dapper.SqlServer.Tests.Integration/SqlExecutor/SqlServerSqlExecutorTest.Insert.cs b/test/Util.Data.Dapper.SqlServer.Tests.Integration/SqlExecutor/SqlServerSqlExecutorTest.Insert.cs new file mode 100644 index 00000000..fe6fd757 --- /dev/null +++ b/test/Util.Data.Dapper.SqlServer.Tests.Integration/SqlExecutor/SqlServerSqlExecutorTest.Insert.cs @@ -0,0 +1,83 @@ +using System; +using System.Threading.Tasks; +using Util.Data.Sql; +using Util.Tests.Configs; +using Xunit; + +namespace Util.Data.Dapper.Tests.SqlExecutor { + /// + /// Sql Server Sql执行器测试 - 插入测试 + /// + public partial class SqlServerSqlExecutorTest { + /// + /// 测试使用Insert Values语句插入一条数据 + /// + [Fact] + public async Task TestInsert_1() { + //插入一条数据 + var id = Guid.NewGuid(); + await _sqlExecutor + .Insert( "ProductId,Code", "Products.Product" ) + .Values( id, TestConfig.Value ) + .ExecuteAsync(); + + //获取值 + var result = await _sqlExecutor + .Select( "Code" ) + .From( "Products.Product" ) + .Where( "ProductId", id ) + .ToStringAsync(); + + //验证 + Assert.Equal( TestConfig.Value, result ); + } + + /// + /// 测试使用Insert Values语句插入2条数据 + /// + [Fact] + public async Task TestInsert_2() { + //插入一条数据 + var id = Guid.NewGuid(); + var id2 = Guid.NewGuid(); + await _sqlExecutor + .Insert( "ProductId,Code", "Products.Product" ) + .Values( id, TestConfig.Value ) + .Values( id2, TestConfig.Value ) + .ExecuteAsync(); + + //获取值 + var result = await _sqlExecutor + .AppendSelect( "Count(*)" ) + .From( "Products.Product" ) + .In( "ProductId", new[]{id,id2} ) + .ToIntAsync(); + + //验证 + Assert.Equal( 2, result ); + } + + /// + /// 测试使用Insert Select语句插入 + /// + [Fact] + public async Task TestInsert_3() { + //用Insert Select插入一条数据 + var id = Guid.NewGuid(); + await _sqlExecutor + .Insert( "ProductId,Code", "Products.Product" ) + .AppendSelect( $"'{id}','{TestConfig.Value}'" ) + .ExecuteAsync(); + + //获取值 + var result = await _sqlExecutor + .Select( "Code" ) + .From( "Products.Product" ) + .Where( "ProductId", id ) + .ToStringAsync(); + + //验证 + Assert.Equal( TestConfig.Value, result ); + } + } +} diff --git a/test/Util.Data.Dapper.SqlServer.Tests.Integration/SqlExecutor/SqlServerSqlExecutorTest.Param.cs b/test/Util.Data.Dapper.SqlServer.Tests.Integration/SqlExecutor/SqlServerSqlExecutorTest.Param.cs new file mode 100644 index 00000000..90af7ffa --- /dev/null +++ b/test/Util.Data.Dapper.SqlServer.Tests.Integration/SqlExecutor/SqlServerSqlExecutorTest.Param.cs @@ -0,0 +1,102 @@ +using System; +using System.Data; +using System.Threading.Tasks; +using Util.Data.Sql; +using Util.Tests.Configs; +using Xunit; + +namespace Util.Data.Dapper.Tests.SqlExecutor { + /// + /// Sql Server Sql执行器测试 - 执行存储过程参数测试 + /// + public partial class SqlServerSqlExecutorTest { + /// + /// 测试添加动态参数 + /// + [Fact] + public async Task TestAddParam_Dynamic() { + var id = Guid.NewGuid(); + await _sqlExecutor + .AppendLine( "Insert Products.Product(ProductId,Code) " ) + .Append( "Values(@ProductId,@Code)" ) + .AddDynamicParams( new { ProductId=id, Code= TestConfig.Value } ) + .ExecuteAsync(); + var result = await _sqlExecutor.Select( "Code" ).From( "Products.Product" ).Where( "ProductId", id ).ToStringAsync(); + Assert.Equal( TestConfig.Value, result ); + } + + /// + /// 测试添加和获取输出参数 + /// + [Fact] + public async Task TestAddParam_Output() { + //定义变量 + var id = Guid.NewGuid(); + + //插入数据 + await _sqlExecutor + .AppendLine( "Insert Products.Product(ProductId,Code) " ) + .Append( "Values(@ProductId,@Code)" ) + .AddParam( "@ProductId", id ) + .AddParam( "Code", TestConfig.Value ) + .ExecuteAsync(); + + //执行存储过程 - 添加输出参数 + await _sqlExecutor + .AddParam( "productId", id ) + .AddParam( "code",dbType: DbType.String,direction: ParameterDirection.Output,size:50 ) + .ExecuteProcedureAsync( "Products.Proc_GetProductCode_Output" ); + + //验证 - 使用GetParam获取输出参数 + Assert.Equal( TestConfig.Value, _sqlExecutor.GetParam( "code" ) ); + } + + /// + /// 测试添加和获取返回参数 + /// + [Fact] + public async Task TestAddParam_Return() { + //执行存储过程 - 添加返回参数,注意:返回参数名任意设置均可 + await _sqlExecutor + .AddParam( "productId", TestConfig.Id ) + .AddParam( "value", DbType.Int32, ParameterDirection.ReturnValue ) + .ExecuteProcedureAsync( "Products.Proc_Return" ); + //使用GetParam获取返回参数,参数名与之前设置的保持一致 + Assert.Equal( 1, _sqlExecutor.GetParam( "value" ) ); + + //执行存储过程 - 传入无效Id + await _sqlExecutor + .AddParam( "productId", Guid.NewGuid() ) + .AddParam( "value", DbType.Int32, ParameterDirection.ReturnValue ) + .ExecuteProcedureAsync( "Products.Proc_Return" ); + Assert.Equal( -1, _sqlExecutor.GetParam( "value" ) ); + } + + /// + /// 测试添加参数 - 在执行前添加并获取参数 + /// + [Fact] + public async Task TestAddParam_1() { + var id = Guid.NewGuid(); + + //添加第一个参数 + _sqlExecutor + .AppendLine( "Insert Products.Product(ProductId,Code) " ) + .Append( "Values(@ProductId,@Code)" ) + .AddParam( "@ProductId", id ); + + //获取参数 + var param = _sqlExecutor.GetParam( "ProductId" ); + Assert.Equal( id, param ); + + //添加第二个参数并执行 + await _sqlExecutor + .AddParam( "Code", TestConfig.Value ) + .ExecuteAsync(); + + //验证 + var result = await _sqlExecutor.Select( "Code" ).From( "Products.Product" ).Where( "ProductId", id ).ToStringAsync(); + Assert.Equal( TestConfig.Value, result ); + } + } +} diff --git a/test/Util.Data.Dapper.SqlServer.Tests.Integration/SqlExecutor/SqlServerSqlExecutorTest.Procedure.cs b/test/Util.Data.Dapper.SqlServer.Tests.Integration/SqlExecutor/SqlServerSqlExecutorTest.Procedure.cs new file mode 100644 index 00000000..d230dc81 --- /dev/null +++ b/test/Util.Data.Dapper.SqlServer.Tests.Integration/SqlExecutor/SqlServerSqlExecutorTest.Procedure.cs @@ -0,0 +1,35 @@ +using System; +using System.Threading.Tasks; +using Util.Data.Sql; +using Util.Tests.Configs; +using Xunit; + +namespace Util.Data.Dapper.Tests.SqlExecutor { + /// + /// Sql Server Sql执行器测试 - 执行存储过程测试 + /// + public partial class SqlServerSqlExecutorTest { + /// + /// 测试执行存储过程增删改操作 + /// + [Fact] + public async Task TestExecuteProcedureScalarAsync() { + //定义变量 + var id = Guid.NewGuid(); + + //插入数据,参数无论是否加@前缀均可 + await _sqlExecutor + .AddParam( "@productId", id ) + .AddParam( "code", TestConfig.Value ) + .ExecuteProcedureAsync( "Products.Proc_InsertProduct" ); + + //获取IntValue值 + var result = await _sqlExecutor + .AddParam( "productId", id ) + .ExecuteProcedureScalarAsync( "Products.Proc_GetProductCode" ); + + //验证 + Assert.Equal( TestConfig.Value, result ); + } + } +} diff --git a/test/Util.Data.Dapper.SqlServer.Tests.Integration/SqlExecutor/SqlServerSqlExecutorTest.Transaction.cs b/test/Util.Data.Dapper.SqlServer.Tests.Integration/SqlExecutor/SqlServerSqlExecutorTest.Transaction.cs new file mode 100644 index 00000000..ade0f285 --- /dev/null +++ b/test/Util.Data.Dapper.SqlServer.Tests.Integration/SqlExecutor/SqlServerSqlExecutorTest.Transaction.cs @@ -0,0 +1,206 @@ +using System; +using System.Threading.Tasks; +using Util.Data.Sql; +using Util.Tests.Configs; +using Xunit; + +namespace Util.Data.Dapper.Tests.SqlExecutor { + /// + /// Sql Server Sql执行器测试 - 事务测试 + /// + public partial class SqlServerSqlExecutorTest { + /// + /// 测试事务操作 - 不使用事务,第一次操作成功,第二次失败 + /// + [Fact] + public async Task TestTransaction_1() { + //创建两个Id + var id = Guid.NewGuid(); + var id2 = Guid.NewGuid(); + + try { + //插入Id成功 + await _sqlExecutor + .Insert( "ProductId,Code", "Products.Product" ) + .Values( id, TestConfig.Value ) + .ExecuteAsync(); + + //Code2列名错误,插入Id2失败 + await _sqlExecutor + .Insert( "ProductId,Code,Code2", "Products.Product" ) + .Values( id2, TestConfig.Value, TestConfig.Value ) + .ExecuteAsync(); + } + catch { + // ignored + } + + //断言 + var exists = await _sqlExecutor.From( "Products.Product" ).Where( "ProductId", id ).ExecuteExistsAsync(); + var exists2 = await _sqlExecutor.From( "Products.Product" ).Where( "ProductId", id2 ).ExecuteExistsAsync(); + Assert.True( exists ); + Assert.False( exists2 ); + } + + /// + /// 测试事务操作 - 调用BeginTransaction,CommitTransaction,RollbackTransaction + /// + [Fact] + public async Task TestTransaction_2() { + //开始事务 + _sqlExecutor.BeginTransaction(); + + //创建两个Id + var id = Guid.NewGuid(); + var id2 = Guid.NewGuid(); + + try { + //插入Id成功 + await _sqlExecutor + .Insert( "ProductId,Code", "Products.Product" ) + .Values( id, TestConfig.Value ) + .ExecuteAsync(); + + //Code2列名错误,插入Id2失败 + await _sqlExecutor + .Insert( "ProductId,Code,Code2", "Products.Product" ) + .Values( id2, TestConfig.Value, TestConfig.Value ) + .ExecuteAsync(); + + //提交事务 + _sqlExecutor.CommitTransaction(); + } + catch { + //回滚事务 + _sqlExecutor.RollbackTransaction(); + } + + //断言 + var exists = await _sqlExecutor.From( "Products.Product" ).Where( "ProductId", id ).ExecuteExistsAsync(); + var exists2 = await _sqlExecutor.From( "Products.Product" ).Where( "ProductId", id2 ).ExecuteExistsAsync(); + Assert.False( exists ); + Assert.False( exists2 ); + } + + /// + /// 测试事务操作 - 使用using调用BeginTransaction + /// + [Fact] + public async Task TestTransaction_3() { + //创建两个Id + var id = Guid.NewGuid(); + var id2 = Guid.NewGuid(); + + try { + using var transaction = _sqlExecutor.BeginTransaction(); + //插入Id成功 + await _sqlExecutor + .Insert( "ProductId,Code", "Products.Product" ) + .Values( id, TestConfig.Value ) + .ExecuteAsync(); + + //Code2列名错误,插入Id2失败 + await _sqlExecutor + .Insert( "ProductId,Code,Code2", "Products.Product" ) + .Values( id2, TestConfig.Value, TestConfig.Value ) + .ExecuteAsync(); + + //提交事务 + transaction.Commit(); + } + catch { + // ignored + } + + //断言 + var exists = await _sqlExecutor.From( "Products.Product" ).Where( "ProductId", id ).ExecuteExistsAsync(); + var exists2 = await _sqlExecutor.From( "Products.Product" ).Where( "ProductId", id2 ).ExecuteExistsAsync(); + Assert.False( exists ); + Assert.False( exists2 ); + } + + /// + /// 测试事务操作 - 外部传入事务 + /// + [Fact] + public async Task TestTransaction_4() { + //Sql执行器实例2开始事务 + _sqlExecutor2.BeginTransaction(); + var transaction = _sqlExecutor2.GetTransaction(); + + //设置Sql执行器实例1事务 + _sqlExecutor.SetTransaction( transaction ); + + //创建两个Id + var id = Guid.NewGuid(); + var id2 = Guid.NewGuid(); + + try { + //插入Id成功 + await _sqlExecutor + .Insert( "ProductId,Code", "Products.Product" ) + .Values( id, TestConfig.Value ) + .ExecuteAsync(); + + //Code2列名错误,插入Id2失败 + await _sqlExecutor2 + .Insert( "ProductId,Code,Code2", "Products.Product" ) + .Values( id2, TestConfig.Value, TestConfig.Value ) + .ExecuteAsync(); + + //提交事务 + _sqlExecutor.CommitTransaction(); + } + catch { + //回滚事务 + _sqlExecutor.RollbackTransaction(); + } + + //断言 + var exists = await _sqlExecutor.From( "Products.Product" ).Where( "ProductId", id ).ExecuteExistsAsync(); + var exists2 = await _sqlExecutor.From( "Products.Product" ).Where( "ProductId", id2 ).ExecuteExistsAsync(); + Assert.False( exists ); + Assert.False( exists2 ); + } + + /// + /// 测试事务操作 - 成功提交 + /// + [Fact] + public async Task TestTransaction_5() { + //开始事务 + _sqlExecutor.BeginTransaction(); + + //创建两个Id + var id = Guid.NewGuid(); + var id2 = Guid.NewGuid(); + + try { + //插入Id成功 + await _sqlExecutor + .Insert( "ProductId,Code", "Products.Product" ) + .Values( id, TestConfig.Value ) + .ExecuteAsync(); + + //插入Id2成功 + await _sqlExecutor + .Insert( "ProductId,Code", "Products.Product" ) + .Values( id2, TestConfig.Value ) + .ExecuteAsync(); + + //提交事务 + _sqlExecutor.CommitTransaction(); + } + catch { + //回滚事务 + _sqlExecutor.RollbackTransaction(); + } + + //断言 + var exists = await _sqlExecutor.From( "Products.Product" ).Where( "ProductId", id ).ExecuteExistsAsync(); + var exists2 = await _sqlExecutor.From( "Products.Product" ).Where( "ProductId", id2 ).ExecuteExistsAsync(); + Assert.True( exists ); + Assert.True( exists2 ); + } + } +} diff --git a/test/Util.Data.Dapper.SqlServer.Tests.Integration/SqlExecutor/SqlServerSqlExecutorTest.cs b/test/Util.Data.Dapper.SqlServer.Tests.Integration/SqlExecutor/SqlServerSqlExecutorTest.cs new file mode 100644 index 00000000..30c50d66 --- /dev/null +++ b/test/Util.Data.Dapper.SqlServer.Tests.Integration/SqlExecutor/SqlServerSqlExecutorTest.cs @@ -0,0 +1,31 @@ +using Util.Data.Sql; +using Xunit.Abstractions; + +namespace Util.Data.Dapper.Tests.SqlExecutor { + /// + /// Sql Server Sql执行器测试 + /// + public partial class SqlServerSqlExecutorTest { + /// + /// 测试输出工具 + /// + private readonly ITestOutputHelper _output; + /// + /// Sql执行器 + /// + private readonly ISqlExecutor _sqlExecutor; + /// + /// Sql执行器2 + /// + private readonly ISqlExecutor _sqlExecutor2; + + /// + /// 测试初始化 + /// + public SqlServerSqlExecutorTest( ITestOutputHelper output, ISqlExecutor sqlExecutor, ISqlExecutor sqlExecutor2 ) { + _output = output; + _sqlExecutor = sqlExecutor; + _sqlExecutor2 = sqlExecutor2; + } + } +} diff --git a/test/Util.Data.Dapper.SqlServer.Tests.Integration/SqlQuery/SqlServerSqlQueryTest.Exists.cs b/test/Util.Data.Dapper.SqlServer.Tests.Integration/SqlQuery/SqlServerSqlQueryTest.Exists.cs new file mode 100644 index 00000000..303e6697 --- /dev/null +++ b/test/Util.Data.Dapper.SqlServer.Tests.Integration/SqlQuery/SqlServerSqlQueryTest.Exists.cs @@ -0,0 +1,48 @@ +using System; +using System.Threading.Tasks; +using Util.Data.Sql; +using Util.Tests.Configs; +using Xunit; + +namespace Util.Data.Dapper.Tests.SqlQuery { + /// + /// Sql Server Sql²éѯ¶ÔÏó²âÊÔ - ÅжÏÊǷñ´æÔڲâÊÔ + /// + public partial class SqlServerSqlQueryTest { + /// + /// ²âÊÔÅжÏÊǷñ´æÔÚ - ´æÔÚ + /// + [Fact] + public void TestExecuteExists_1() { + var result = _sqlQuery.From( "Products.Product" ).Where( "ProductId", TestConfig.Id ).ExecuteExists(); + Assert.True( result ); + } + + /// + /// ²âÊÔÅжÏÊǷñ´æÔÚ - ²»´æÔÚ + /// + [Fact] + public void TestExecuteExists_2() { + var result = _sqlQuery.From( "Products.Product" ).Where( "ProductId", Guid.NewGuid() ).ExecuteExists(); + Assert.False( result ); + } + + /// + /// ²âÊÔÅжÏÊǷñ´æÔÚ - ´æÔÚ + /// + [Fact] + public async Task TestExecuteExistsAsync_1() { + var result = await _sqlQuery.From( "Products.Product" ).Where( "ProductId", TestConfig.Id ).ExecuteExistsAsync(); + Assert.True( result ); + } + + /// + /// ²âÊÔÅжÏÊǷñ´æÔÚ - ²»´æÔÚ + /// + [Fact] + public async Task TestExecuteExistsAsync_2() { + var result = await _sqlQuery.From( "Products.Product" ).Where( "ProductId", Guid.NewGuid() ).ExecuteExistsAsync(); + Assert.False( result ); + } + } +} diff --git a/test/Util.Data.Dapper.SqlServer.Tests.Integration/SqlQuery/SqlServerSqlQueryTest.Procedure.cs b/test/Util.Data.Dapper.SqlServer.Tests.Integration/SqlQuery/SqlServerSqlQueryTest.Procedure.cs new file mode 100644 index 00000000..e4a17f9c --- /dev/null +++ b/test/Util.Data.Dapper.SqlServer.Tests.Integration/SqlQuery/SqlServerSqlQueryTest.Procedure.cs @@ -0,0 +1,303 @@ +using System; +using System.Collections; +using System.Threading.Tasks; +using Util.Data.Sql; +using Util.Helpers; +using Util.Tests.Configs; +using Util.Tests.Models; +using Xunit; + +namespace Util.Data.Dapper.Tests.SqlQuery { + /// + /// Sql Server Sql²éѯ¶ÔÏó²âÊÔ - ִÐд洢¹ý³̲âÊÔ + /// + public partial class SqlServerSqlQueryTest { + + #region ExecuteProcedureScalar + + /// + /// ²âÊÔִÐд洢¹ý³̻ñȡµ¥ֵ + /// + [Fact] + public void TestExecuteProcedureScalar_1() { + //ִÐд洢¹ý³Ì + var result = _sqlQuery + .AddParam( "productId", TestConfig.Id ) + .ExecuteProcedureScalar( "Products.Proc_GetProductCode" ); + + //¶ÏÑÔ + Assert.Equal( TestConfig.Value, result ); + Assert.Equal( "[Products].[Proc_GetProductCode]", _sqlQuery.PreviousSql.GetSql() ); + } + + /// + /// ²âÊÔִÐд洢¹ý³̻ñȡµ¥ֵ - ·ºÐͷ½·¨ + /// + [Fact] + public void TestExecuteProcedureScalar_2() { + //ִÐд洢¹ý³Ì + var result = _sqlQuery + .AddParam( "productId", TestConfig.Id ) + .ExecuteProcedureScalar( "Products.Proc_GetProductCode" ); + + //¶ÏÑÔ + Assert.Equal( TestConfig.Value, result ); + Assert.Equal( "[Products].[Proc_GetProductCode]", _sqlQuery.PreviousSql.GetSql() ); + } + + #endregion + + #region ExecuteProcedureScalarAsync + + /// + /// ²âÊÔִÐд洢¹ý³̻ñȡµ¥ֵ + /// + [Fact] + public async Task TestExecuteProcedureScalarAsync_1() { + //ִÐд洢¹ý³Ì + var result = await _sqlQuery + .AddParam( "productId", TestConfig.Id ) + .ExecuteProcedureScalarAsync( "Products.Proc_GetProductCode" ); + + //¶ÏÑÔ + Assert.Equal( TestConfig.Value, result ); + Assert.Equal( "[Products].[Proc_GetProductCode]", _sqlQuery.PreviousSql.GetSql() ); + } + + /// + /// ²âÊÔִÐд洢¹ý³̻ñȡµ¥ֵ - ·ºÐͷ½·¨ + /// + [Fact] + public async Task TestExecuteProcedureScalarAsync_2() { + //ִÐд洢¹ý³Ì + var result = await _sqlQuery + .AddParam( "productId", TestConfig.Id ) + .ExecuteProcedureScalarAsync( "Products.Proc_GetProductCode" ); + + //¶ÏÑÔ + Assert.Equal( TestConfig.Value, result ); + Assert.Equal( "[Products].[Proc_GetProductCode]", _sqlQuery.PreviousSql.GetSql() ); + } + + #endregion + + #region ExecuteProcedureSingle + + /// + /// ²âÊÔִÐд洢¹ý³̻ñȡµ¥¸öʵÌå + /// + [Fact] + public void TestExecuteProcedureSingle() { + //ִÐд洢¹ý³Ì + var result = _sqlQuery + .AddParam( "productId", TestConfig.Id ) + .ExecuteProcedureSingle( "Products.Proc_GetProduct" ); + + //¶ÏÑÔ + Assert.Equal( TestConfig.Value, result.Code ); + Assert.Equal( "[Products].[Proc_GetProduct]", _sqlQuery.PreviousSql.GetSql() ); + } + + #endregion + + #region ExecuteProcedureSingleAsync + + /// + /// ²âÊÔִÐд洢¹ý³̻ñȡµ¥¸öʵÌå + /// + [Fact] + public async Task TestExecuteProcedureSingleAsync() { + //ִÐд洢¹ý³Ì + var result = await _sqlQuery + .AddParam( "productId", TestConfig.Id ) + .ExecuteProcedureSingleAsync( "Products.Proc_GetProduct" ); + + //¶ÏÑÔ + Assert.Equal( TestConfig.Value, result.Code ); + Assert.Equal( "[Products].[Proc_GetProduct]", _sqlQuery.PreviousSql.GetSql() ); + } + + #endregion + + #region ExecuteProcedureQuery + + /// + /// ²âÊÔִÐд洢¹ý³̻ñȡʵÌ弯ºÏ + /// + [Fact] + public async Task TestExecuteProcedureQuery_1() { + //²åÈë2ÌõÊý¾Ý + var id = Guid.NewGuid(); + var id2 = Guid.NewGuid(); + await _sqlExecutor.Insert( "ProductId,Code", "Products.Product" ) + .Values( id, "a" ) + .Values( id2, "b" ) + .ExecuteAsync(); + + //ִÐд洢¹ý³Ì + var result = _sqlQuery + .AddParam( "productId", id ) + .AddParam( "productId2", id2 ) + .ExecuteProcedureQuery( "Products.Proc_GetProducts" ); + + //¶ÏÑÔ + Assert.Equal( 2, result.Count ); + Assert.Contains( result, t => t.Id == id && t.Code == "a" ); + Assert.Contains( result, t => t.Id == id2 && t.Code == "b" ); + Assert.Equal( "[Products].[Proc_GetProducts]", _sqlQuery.PreviousSql.GetSql() ); + } + + /// + /// ²âÊԻñȡʵÌ弯ºÏ - 1¸ö·ºÐͲÎÊý + /// + [Fact] + public async Task TestExecuteProcedureQuery_2() { + //²åÈë2ÌõÊý¾Ý + var id = Guid.NewGuid(); + var id2 = Guid.NewGuid(); + await _sqlExecutor.Insert( "ProductId,Code", "Products.Product" ) + .Values( id, "a" ) + .Values( id2, "b" ) + .ExecuteAsync(); + + //ִÐд洢¹ý³Ì + var result = _sqlQuery + .AddParam( "productId", id ) + .AddParam( "productId2", id2 ) + .ExecuteProcedureQuery( "Products.Proc_GetProducts" ); + + //¶ÏÑÔ + Assert.Equal( 2, result.Count ); + Assert.Contains( result, t => t.Id == id && t.Code == "a" ); + Assert.Contains( result, t => t.Id == id2 && t.Code == "b" ); + Assert.Equal( "[Products].[Proc_GetProducts]", _sqlQuery.PreviousSql.GetSql() ); + } + + /// + /// ²âÊԻñȡʵÌ弯ºÏ - 3¸ö·ºÐͲÎÊý - Ö÷´ӱí,ÉèÖùØÁªÊôÐÔ + /// + [Fact] + public async Task TestExecuteProcedureQuery_3() { + //²åÈ붩µ¥ + var orderId = Id.Create(); + var customerName = "customerName"; + await _sqlExecutor.Insert( "OrderId,CustomerName", "Sales.Order" ) + .Values( orderId, customerName ) + .ExecuteAsync(); + + //²åÈ붩µ¥Ã÷ϸ + var orderItemId = Id.CreateGuid(); + await _sqlExecutor.Insert( "OrderItemId,OrderId,Price", "Sales.OrderItem" ) + .Values( orderItemId, orderId, TestConfig.DecimalValue ) + .ExecuteAsync(); + + //»ñȡ¶ÔÏó + var result = _sqlQuery + .AddParam( "orderItemId", orderItemId ) + .ExecuteProcedureQuery( "Sales.Proc_GetOrderItem", ( item, order ) => { + item.Order = order; + return item; + } ); + + //¶ÏÑÔ + Assert.Single( (IEnumerable)result ); + Assert.Equal( orderItemId, result[0].Id ); + Assert.Equal( TestConfig.DecimalValue, result[0].Price ); + Assert.Equal( orderId, result[0].OrderId ); + Assert.Equal( orderId, result[0].Order.Id ); + Assert.Equal( customerName, result[0].Order.CustomerName ); + } + + #endregion + + #region ExecuteProcedureQueryAsync + + /// + /// ²âÊÔִÐд洢¹ý³̻ñȡʵÌ弯ºÏ + /// + [Fact] + public async Task TestExecuteProcedureQueryAsync_1() { + //²åÈë2ÌõÊý¾Ý + var id = Guid.NewGuid(); + var id2 = Guid.NewGuid(); + await _sqlExecutor.Insert( "ProductId,Code", "Products.Product" ) + .Values( id, "a" ) + .Values( id2, "b" ) + .ExecuteAsync(); + + //ִÐд洢¹ý³Ì + var result = await _sqlQuery + .AddDynamicParams( new{ productId=id, productId2=id2 } ) + .ExecuteProcedureQueryAsync( "Products.Proc_GetProducts" ); + + //¶ÏÑÔ + Assert.Equal( 2, result.Count ); + Assert.Contains( result, t => t.Id == id && t.Code == "a" ); + Assert.Contains( result, t => t.Id == id2 && t.Code == "b" ); + Assert.Equal( "[Products].[Proc_GetProducts]", _sqlQuery.PreviousSql.GetSql() ); + } + + /// + /// ²âÊԻñȡʵÌ弯ºÏ - 1¸ö·ºÐͲÎÊý + /// + [Fact] + public async Task TestExecuteProcedureQueryAsync_2() { + //²åÈë2ÌõÊý¾Ý + var id = Guid.NewGuid(); + var id2 = Guid.NewGuid(); + await _sqlExecutor.Insert( "ProductId,Code", "Products.Product" ) + .Values( id, "a" ) + .Values( id2, "b" ) + .ExecuteAsync(); + + //ִÐд洢¹ý³Ì + var result = await _sqlQuery + .AddParam( "productId", id ) + .AddParam( "productId2", id2 ) + .ExecuteProcedureQueryAsync( "Products.Proc_GetProducts" ); + + //¶ÏÑÔ + Assert.Equal( 2, result.Count ); + Assert.Contains( result, t => t.Id == id && t.Code == "a" ); + Assert.Contains( result, t => t.Id == id2 && t.Code == "b" ); + Assert.Equal( "[Products].[Proc_GetProducts]", _sqlQuery.PreviousSql.GetSql() ); + } + + /// + /// ²âÊԻñȡʵÌ弯ºÏ - 3¸ö·ºÐͲÎÊý - Ö÷´ӱí,ÉèÖùØÁªÊôÐÔ + /// + [Fact] + public async Task TestExecuteProcedureQueryAsync_3() { + //²åÈ붩µ¥ + var orderId = Id.Create(); + var customerName = "customerName"; + await _sqlExecutor.Insert( "OrderId,CustomerName", "Sales.Order" ) + .Values( orderId, customerName ) + .ExecuteAsync(); + + //²åÈ붩µ¥Ã÷ϸ + var orderItemId = Id.CreateGuid(); + await _sqlExecutor.Insert( "OrderItemId,OrderId,Price", "Sales.OrderItem" ) + .Values( orderItemId, orderId, TestConfig.DecimalValue ) + .ExecuteAsync(); + + //»ñȡ¶ÔÏó + var result = await _sqlQuery + .AddParam( "orderItemId", orderItemId ) + .ExecuteProcedureQueryAsync( "Sales.Proc_GetOrderItem", ( item, order ) => { + item.Order = order; + return item; + } ); + + //¶ÏÑÔ + Assert.Single( (IEnumerable)result ); + Assert.Equal( orderItemId, result[0].Id ); + Assert.Equal( TestConfig.DecimalValue, result[0].Price ); + Assert.Equal( orderId, result[0].OrderId ); + Assert.Equal( orderId, result[0].Order.Id ); + Assert.Equal( customerName, result[0].Order.CustomerName ); + } + + #endregion + } +} diff --git a/test/Util.Data.Dapper.SqlServer.Tests.Integration/SqlQuery/SqlServerSqlQueryTest.Query.cs b/test/Util.Data.Dapper.SqlServer.Tests.Integration/SqlQuery/SqlServerSqlQueryTest.Query.cs new file mode 100644 index 00000000..63e5b10e --- /dev/null +++ b/test/Util.Data.Dapper.SqlServer.Tests.Integration/SqlQuery/SqlServerSqlQueryTest.Query.cs @@ -0,0 +1,388 @@ +using System; +using System.Collections; +using System.Threading.Tasks; +using Util.Data.Sql; +using Util.Helpers; +using Util.Tests.Configs; +using Util.Tests.Models; +using Xunit; + +namespace Util.Data.Dapper.Tests.SqlQuery { + /// + /// Sql Server Sql²éѯ¶ÔÏó²âÊÔ - ²éѯ²âÊÔ + /// + public partial class SqlServerSqlQueryTest { + + #region ExecuteQuery + + /// + /// ²âÊԻñȡʵÌ弯ºÏ + /// + [Fact] + public async Task TestExecuteQuery_1() { + //²åÈë2ÌõÊý¾Ý + var id = Guid.NewGuid(); + var id2 = Guid.NewGuid(); + var code = "TestExecuteQuery_1"; + await _sqlExecutor.Insert( "ProductId,Code", "Products.Product" ) + .Values( id, code ) + .Values( id2, code ) + .ExecuteAsync(); + + //»ñȡ¶ÔÏó + var result = _sqlQuery.Select().From( "Products.Product" ).In( "ProductId", new[] { id, id2 } ).ExecuteQuery(); + + //¶ÏÑÔ + Assert.NotNull( result ); + Assert.Equal( 2, result.Count ); + Assert.Contains( result, t => t.ProductId == id ); + Assert.Contains( result, t => t.ProductId == id2 ); + Assert.Contains( result, t => t.Code == code ); + } + + /// + /// ²âÊԻñȡʵÌ弯ºÏ - 1¸ö·ºÐͲÎÊý + /// + [Fact] + public async Task TestExecuteQuery_2() { + //²åÈë2ÌõÊý¾Ý + var id = Guid.NewGuid(); + var id2 = Guid.NewGuid(); + var code = "TestExecuteQuery_2"; + await _sqlExecutor.Insert( "ProductId,Code", "Products.Product" ) + .Values( id, code ) + .Values( id2, code ) + .ExecuteAsync(); + + //»ñȡ¶ÔÏó + var result = _sqlQuery.Select("ProductId As Id,Code").From( "Products.Product" ).In( "ProductId", new[] { id, id2 } ).ExecuteQuery(); + + //¶ÏÑÔ + Assert.NotNull( result ); + Assert.Equal( 2, result.Count ); + Assert.Contains( result, t => t.Id == id ); + Assert.Contains( result, t => t.Id == id2 ); + Assert.Contains( result, t => t.Code == code ); + } + + /// + /// ²âÊԻñȡʵÌ弯ºÏ - 3¸ö·ºÐͲÎÊý - Ö÷´ӱí,ÉèÖùØÁªÊôÐÔ + /// + [Fact] + public async Task TestExecuteQuery_3() { + //²åÈ붩µ¥ + var orderId = Id.Create(); + var customerName = "customerName"; + await _sqlExecutor.Insert( "OrderId,CustomerName", "Sales.Order" ) + .Values( orderId, customerName ) + .ExecuteAsync(); + + //²åÈ붩µ¥Ã÷ϸ + var orderItemId = Id.CreateGuid(); + await _sqlExecutor.Insert( "OrderItemId,OrderId,Price", "Sales.OrderItem" ) + .Values( orderItemId, orderId,TestConfig.DecimalValue ) + .ExecuteAsync(); + + ////»ñȡ¶ÔÏó + var result = _sqlQuery + .Select( "i.OrderItemId As Id,i.*" ) //½«OrderItemIdӳÉäΪId,±ØÐëÔÚ֮ºó½ô¸úOrderItemÏà¹صÄÁÐ + .Select( "o.OrderId As Id,o.*" ) //½«OrderIdӳÉäΪId,½«¸î¶Ï֮ǰOrderItem±íÖеÄÐÅϢ,֮ºó¼ÌÐøÌí¼ÓOrder±íÖеÄÁÐ + .From( "Sales.OrderItem As i" ) + .LeftJoin( "Sales.Order As o" ).On( "o.OrderId", "i.OrderId" ) + .Where( "i.OrderItemId", orderItemId ) + .ExecuteQuery( ( item, order ) => { + item.Order = order; + return item; + } ); + + //¶ÏÑÔ + Assert.Single( (IEnumerable)result ); + Assert.Equal( orderItemId, result[0].Id ); + Assert.Equal( TestConfig.DecimalValue, result[0].Price ); + Assert.Equal( orderId, result[0].OrderId ); + Assert.Equal( orderId, result[0].Order.Id ); + Assert.Equal( customerName, result[0].Order.CustomerName ); + } + + #endregion + + #region ExecuteQueryAsync + + /// + /// ²âÊԻñȡʵÌ弯ºÏ + /// + [Fact] + public async Task TestExecuteQueryAsync_1() { + //²åÈë2ÌõÊý¾Ý + var id = Guid.NewGuid(); + var id2 = Guid.NewGuid(); + var code = "TestExecuteQueryAsync_1"; + await _sqlExecutor.Insert( "ProductId,Code", "Products.Product" ) + .Values( id, code ) + .Values( id2, code ) + .ExecuteAsync(); + + //»ñȡ¶ÔÏó + var result = await _sqlQuery.Select().From( "Products.Product" ).In( "ProductId", new[] { id, id2 } ).ExecuteQueryAsync(); + + //¶ÏÑÔ + Assert.NotNull( result ); + Assert.Equal( 2, result.Count ); + Assert.Contains( result, t => t.ProductId == id ); + Assert.Contains( result, t => t.ProductId == id2 ); + Assert.Contains( result, t => t.Code == code ); + } + + /// + /// ²âÊԻñȡʵÌ弯ºÏ + /// + [Fact] + public async Task TestExecuteQueryAsync_2() { + //²åÈë2ÌõÊý¾Ý + var id = Guid.NewGuid(); + var id2 = Guid.NewGuid(); + var code = "TestExecuteQueryAsync_2"; + await _sqlExecutor.Insert( "ProductId,Code", "Products.Product" ) + .Values( id, code ) + .Values( id2, code ) + .ExecuteAsync(); + + //»ñȡ¶ÔÏó + var result = await _sqlQuery.Select( "ProductId As Id,Code" ).From( "Products.Product" ).In( "ProductId", new[] { id, id2 } ).ExecuteQueryAsync(); + + //¶ÏÑÔ + Assert.NotNull( result ); + Assert.Equal( 2, result.Count ); + Assert.Contains( result, t => t.Id == id ); + Assert.Contains( result, t => t.Id == id2 ); + Assert.Contains( result, t => t.Code == code ); + } + + /// + /// ²âÊԻñȡʵÌ弯ºÏ - 3¸ö·ºÐͲÎÊý - Ö÷´ӱí,ÉèÖùØÁªÊôÐÔ + /// + [Fact] + public async Task TestExecuteQueryAsync_3() { + //²åÈ붩µ¥ + var orderId = Id.Create(); + var customerName = "customerName"; + await _sqlExecutor.Insert( "OrderId,CustomerName", "Sales.Order" ) + .Values( orderId, customerName ) + .ExecuteAsync(); + + //²åÈ붩µ¥Ã÷ϸ + var orderItemId = Id.CreateGuid(); + await _sqlExecutor.Insert( "OrderItemId,OrderId,Price", "Sales.OrderItem" ) + .Values( orderItemId, orderId, TestConfig.DecimalValue ) + .ExecuteAsync(); + + ////»ñȡ¶ÔÏó + var result = await _sqlQuery + .Select( "i.OrderItemId As Id,i.*" ) //½«OrderItemIdӳÉäΪId,±ØÐëÔÚ֮ºó½ô¸úOrderItemÏà¹صÄÁÐ + .Select( "o.OrderId As Id,o.*" ) //½«OrderIdӳÉäΪId,½«¸î¶Ï֮ǰOrderItem±íÖеÄÐÅϢ,֮ºó¼ÌÐøÌí¼ÓOrder±íÖеÄÁÐ + .From( "Sales.OrderItem As i" ) + .LeftJoin( "Sales.Order As o" ).On( "o.OrderId", "i.OrderId" ) + .Where( "i.OrderItemId", orderItemId ) + .ExecuteQueryAsync( ( item, order ) => { + item.Order = order; + return item; + } ); + + //¶ÏÑÔ + Assert.Single( (IEnumerable)result ); + Assert.Equal( orderItemId, result[0].Id ); + Assert.Equal( TestConfig.DecimalValue, result[0].Price ); + Assert.Equal( orderId, result[0].OrderId ); + Assert.Equal( orderId, result[0].Order.Id ); + Assert.Equal( customerName, result[0].Order.CustomerName ); + } + + #endregion + + #region ToList + + /// + /// ²âÊԻñȡʵÌ弯ºÏ + /// + [Fact] + public async Task TestToList_1() { + //²åÈë2ÌõÊý¾Ý + var id = Guid.NewGuid(); + var id2 = Guid.NewGuid(); + var code = "TestToList_1"; + await _sqlExecutor.Insert( "ProductId,Code", "Products.Product" ) + .Values( id, code ) + .Values( id2, code ) + .ExecuteAsync(); + + //»ñȡ¶ÔÏó + var result = _sqlQuery.Select().From( "Products.Product" ).In( "ProductId", new[] { id, id2 } ).ToList(); + + //¶ÏÑÔ + Assert.NotNull( result ); + Assert.Equal( 2, result.Count ); + Assert.Contains( result, t => t.ProductId == id ); + Assert.Contains( result, t => t.ProductId == id2 ); + Assert.Contains( result, t => t.Code == code ); + } + + /// + /// ²âÊԻñȡʵÌ弯ºÏ - 1¸ö·ºÐͲÎÊý + /// + [Fact] + public async Task TestToList_2() { + //²åÈë2ÌõÊý¾Ý + var id = Guid.NewGuid(); + var id2 = Guid.NewGuid(); + var code = "TestToList_2"; + await _sqlExecutor.Insert( "ProductId,Code", "Products.Product" ) + .Values( id, code ) + .Values( id2, code ) + .ExecuteAsync(); + + //»ñȡ¶ÔÏó + var result = _sqlQuery.Select( "ProductId As Id,Code" ).From( "Products.Product" ).In( "ProductId", new[] { id, id2 } ).ToList(); + + //¶ÏÑÔ + Assert.NotNull( result ); + Assert.Equal( 2, result.Count ); + Assert.Contains( result, t => t.Id == id ); + Assert.Contains( result, t => t.Id == id2 ); + Assert.Contains( result, t => t.Code == code ); + } + + /// + /// ²âÊԻñȡʵÌ弯ºÏ - 3¸ö·ºÐͲÎÊý - Ö÷´ӱí,ÉèÖùØÁªÊôÐÔ + /// + [Fact] + public async Task TestToList_3() { + //²åÈ붩µ¥ + var orderId = Id.Create(); + var customerName = "customerName"; + await _sqlExecutor.Insert( "OrderId,CustomerName", "Sales.Order" ) + .Values( orderId, customerName ) + .ExecuteAsync(); + + //²åÈ붩µ¥Ã÷ϸ + var orderItemId = Id.CreateGuid(); + await _sqlExecutor.Insert( "OrderItemId,OrderId,Price", "Sales.OrderItem" ) + .Values( orderItemId, orderId, TestConfig.DecimalValue ) + .ExecuteAsync(); + + ////»ñȡ¶ÔÏó + var result = _sqlQuery + .Select( "i.OrderItemId As Id,i.*" ) //½«OrderItemIdӳÉäΪId,±ØÐëÔÚ֮ºó½ô¸úOrderItemÏà¹صÄÁÐ + .Select( "o.OrderId As Id,o.*" ) //½«OrderIdӳÉäΪId,½«¸î¶Ï֮ǰOrderItem±íÖеÄÐÅϢ,֮ºó¼ÌÐøÌí¼ÓOrder±íÖеÄÁÐ + .From( "Sales.OrderItem As i" ) + .LeftJoin( "Sales.Order As o" ).On( "o.OrderId", "i.OrderId" ) + .Where( "i.OrderItemId", orderItemId ) + .ToList( ( item, order ) => { + item.Order = order; + return item; + } ); + + //¶ÏÑÔ + Assert.Single( (IEnumerable)result ); + Assert.Equal( orderItemId, result[0].Id ); + Assert.Equal( TestConfig.DecimalValue, result[0].Price ); + Assert.Equal( orderId, result[0].OrderId ); + Assert.Equal( orderId, result[0].Order.Id ); + Assert.Equal( customerName, result[0].Order.CustomerName ); + } + + #endregion + + #region ToListAsync + + /// + /// ²âÊԻñȡʵÌ弯ºÏ + /// + [Fact] + public async Task TestToListAsync_1() { + //²åÈë2ÌõÊý¾Ý + var id = Guid.NewGuid(); + var id2 = Guid.NewGuid(); + var code = "TestToListAsync_1"; + await _sqlExecutor.Insert( "ProductId,Code", "Products.Product" ) + .Values( id, code ) + .Values( id2, code ) + .ExecuteAsync(); + + //»ñȡ¶ÔÏó + var result = await _sqlQuery.Select().From( "Products.Product" ).In( "ProductId", new[] { id, id2 } ).ToListAsync(); + + //¶ÏÑÔ + Assert.NotNull( result ); + Assert.Equal( 2, result.Count ); + Assert.Contains( result, t => t.ProductId == id ); + Assert.Contains( result, t => t.ProductId == id2 ); + Assert.Contains( result, t => t.Code == code ); + } + + /// + /// ²âÊԻñȡʵÌ弯ºÏ + /// + [Fact] + public async Task TestToListAsync_2() { + //²åÈë2ÌõÊý¾Ý + var id = Guid.NewGuid(); + var id2 = Guid.NewGuid(); + var code = "TestToListAsync_2"; + await _sqlExecutor.Insert( "ProductId,Code", "Products.Product" ) + .Values( id, code ) + .Values( id2, code ) + .ExecuteAsync(); + + //»ñȡ¶ÔÏó + var result = await _sqlQuery.Select( "ProductId As Id,Code" ).From( "Products.Product" ).In( "ProductId", new[] { id, id2 } ).ToListAsync(); + + //¶ÏÑÔ + Assert.NotNull( result ); + Assert.Equal( 2, result.Count ); + Assert.Contains( result, t => t.Id == id ); + Assert.Contains( result, t => t.Id == id2 ); + Assert.Contains( result, t => t.Code == code ); + } + + /// + /// ²âÊԻñȡʵÌ弯ºÏ - 3¸ö·ºÐͲÎÊý - Ö÷´ӱí,ÉèÖùØÁªÊôÐÔ + /// + [Fact] + public async Task TestToListAsync_3() { + //²åÈ붩µ¥ + var orderId = Id.Create(); + var customerName = "customerName"; + await _sqlExecutor.Insert( "OrderId,CustomerName", "Sales.Order" ) + .Values( orderId, customerName ) + .ExecuteAsync(); + + //²åÈ붩µ¥Ã÷ϸ + var orderItemId = Id.CreateGuid(); + await _sqlExecutor.Insert( "OrderItemId,OrderId,Price", "Sales.OrderItem" ) + .Values( orderItemId, orderId, TestConfig.DecimalValue ) + .ExecuteAsync(); + + ////»ñȡ¶ÔÏó + var result = await _sqlQuery + .Select( "i.OrderItemId As Id,i.*" ) //½«OrderItemIdӳÉäΪId,±ØÐëÔÚ֮ºó½ô¸úOrderItemÏà¹صÄÁÐ + .Select( "o.OrderId As Id,o.*" ) //½«OrderIdӳÉäΪId,½«¸î¶Ï֮ǰOrderItem±íÖеÄÐÅϢ,֮ºó¼ÌÐøÌí¼ÓOrder±íÖеÄÁÐ + .From( "Sales.OrderItem As i" ) + .LeftJoin( "Sales.Order As o" ).On( "o.OrderId", "i.OrderId" ) + .Where( "i.OrderItemId", orderItemId ) + .ToListAsync( ( item, order ) => { + item.Order = order; + return item; + } ); + + //¶ÏÑÔ + Assert.Single( (IEnumerable)result ); + Assert.Equal( orderItemId, result[0].Id ); + Assert.Equal( TestConfig.DecimalValue, result[0].Price ); + Assert.Equal( orderId, result[0].OrderId ); + Assert.Equal( orderId, result[0].Order.Id ); + Assert.Equal( customerName, result[0].Order.CustomerName ); + } + + #endregion + } +} diff --git a/test/Util.Data.Dapper.SqlServer.Tests.Integration/SqlQuery/SqlServerSqlQueryTest.Scalar.cs b/test/Util.Data.Dapper.SqlServer.Tests.Integration/SqlQuery/SqlServerSqlQueryTest.Scalar.cs new file mode 100644 index 00000000..b215e861 --- /dev/null +++ b/test/Util.Data.Dapper.SqlServer.Tests.Integration/SqlQuery/SqlServerSqlQueryTest.Scalar.cs @@ -0,0 +1,629 @@ +using System.Threading.Tasks; +using Util.Data.Sql; +using Util.Tests.Configs; +using Xunit; + +namespace Util.Data.Dapper.Tests.SqlQuery { + /// + /// Sql Server Sql²éѯ¶ÔÏó²âÊÔ - µ¥ֵ²âÊÔ + /// + public partial class SqlServerSqlQueryTest { + + #region ExecuteScalar + + /// + /// ²âÊԻñȡµ¥ֵ + /// + [Fact] + public void TestExecuteScalar_1() { + var result = _sqlQuery.Select( "Code" ).From( "Products.Product" ).Where( "ProductId", TestConfig.Id ).ExecuteScalar(); + Assert.Equal( TestConfig.Value, result.SafeString() ); + } + + /// + /// ²âÊԻñȡµ¥ֵ - ·ºÐÍ + /// + [Fact] + public void TestExecuteScalar_2() { + var result = _sqlQuery.Select( "Code" ).From( "Products.Product" ).Where( "ProductId", TestConfig.Id ).ExecuteScalar(); + Assert.Equal( TestConfig.Value, result ); + } + + #endregion + + #region ExecuteScalarAsync + + /// + /// ²âÊԻñȡµ¥ֵ + /// + [Fact] + public async Task TestExecuteScalarAsync_1() { + var result = await _sqlQuery.Select( "Code" ).From( "Products.Product" ).Where( "ProductId", TestConfig.Id ).ExecuteScalarAsync(); + Assert.Equal( TestConfig.Value, result.SafeString() ); + } + + /// + /// ²âÊԻñȡµ¥ֵ - ·ºÐÍ + /// + [Fact] + public async Task TestExecuteScalarAsync_2() { + var result = await _sqlQuery.Select( "Code" ).From( "Products.Product" ).Where( "ProductId", TestConfig.Id ).ExecuteScalarAsync(); + Assert.Equal( TestConfig.Value, result ); + } + + #endregion + + #region ToStringAsync + + /// + /// ²âÊԻñȡ×ַû´®ֵ + /// + [Fact] + public async Task TestToStringAsync() { + var result = await _sqlQuery.Select( "Code" ).From( "Products.Product" ).Where( "ProductId", TestConfig.Id ).ToStringAsync(); + Assert.Equal( TestConfig.Value, result ); + } + + #endregion + + #region ToInt + + /// + /// ²âÊԻñȡ32λÕûÐÍֵ + /// + [Fact] + public void TestToInt() { + var result = _sqlQuery.Select( "IntPrice" ).From( "Products.Product" ).Where( "ProductId", TestConfig.Id ).ToInt(); + Assert.Equal( TestConfig.IntValue, result ); + } + + #endregion + + #region ToIntAsync + + /// + /// ²âÊԻñȡ32λÕûÐÍֵ + /// + [Fact] + public async Task TestToIntAsync() { + var result = await _sqlQuery.Select( "IntPrice" ).From( "Products.Product" ).Where( "ProductId", TestConfig.Id ).ToIntAsync(); + Assert.Equal( TestConfig.IntValue, result ); + } + + #endregion + + #region ToIntOrNull + + /// + /// ²âÊԻñȡ32λÕûÐÍֵ - ÓÐֵ + /// + [Fact] + public void TestToIntOrNull_1() { + var result = _sqlQuery.Select( "IntPrice" ).From( "Products.Product" ).Where( "ProductId", TestConfig.Id ).ToIntOrNull(); + Assert.Equal( TestConfig.IntValue, result ); + } + + /// + /// ²âÊԻñȡ32λ¿ɿÕÕûÐÍֵ - ¿Õֵ + /// + [Fact] + public void TestToIntOrNull_2() { + var result = _sqlQuery.Select( "Code" ).From( "Products.Product" ).Where( "ProductId", TestConfig.Id ).ToIntOrNull(); + Assert.Null( result ); + } + + #endregion + + #region ToIntOrNullAsync + + /// + /// ²âÊԻñȡ32λ¿ɿÕÕûÐÍֵ - ÓÐֵ + /// + [Fact] + public async Task TestToIntOrNullAsync_1() { + var result = await _sqlQuery.Select( "IntPrice" ).From( "Products.Product" ).Where( "ProductId", TestConfig.Id ).ToIntOrNullAsync(); + Assert.Equal( TestConfig.IntValue, result ); + } + + /// + /// ²âÊԻñȡ32λ¿ɿÕÕûÐÍֵ - ¿Õֵ + /// + [Fact] + public async Task TestToIntOrNullAsync_2() { + var result = await _sqlQuery.Select( "Code" ).From( "Products.Product" ).Where( "ProductId", TestConfig.Id ).ToIntOrNullAsync(); + Assert.Null( result ); + } + + #endregion + + #region ToLong + + /// + /// ²âÊԻñȡ64λÕûÐÍֵ + /// + [Fact] + public void TestToLong() { + var result = _sqlQuery.Select( "LongPrice" ).From( "Products.Product" ).Where( "ProductId", TestConfig.Id ).ToLong(); + Assert.Equal( TestConfig.LongValue, result ); + } + + #endregion + + #region ToLongAsync + + /// + /// ²âÊԻñȡ64λÕûÐÍֵ + /// + [Fact] + public async Task TestToLongAsync() { + var result = await _sqlQuery.Select( "LongPrice" ).From( "Products.Product" ).Where( "ProductId", TestConfig.Id ).ToLongAsync(); + Assert.Equal( TestConfig.LongValue, result ); + } + + #endregion + + #region ToLongOrNull + + /// + /// ²âÊԻñȡ64λ¿ɿÕÕûÐÍֵ - ÓÐֵ + /// + [Fact] + public void TestToLongOrNull_1() { + var result = _sqlQuery.Select( "LongPrice" ).From( "Products.Product" ).Where( "ProductId", TestConfig.Id ).ToLongOrNull(); + Assert.Equal( TestConfig.LongValue, result ); + } + + /// + /// ²âÊԻñȡ64λ¿ɿÕÕûÐÍֵ - ¿Õֵ + /// + [Fact] + public void TestToLongOrNull_2() { + var result = _sqlQuery.Select( "Code" ).From( "Products.Product" ).Where( "ProductId", TestConfig.Id ).ToLongOrNull(); + Assert.Null( result ); + } + + #endregion + + #region ToLongOrNullAsync + + /// + /// ²âÊԻñȡ64λ¿ɿÕÕûÐÍֵ - ÓÐֵ + /// + [Fact] + public async Task TestToLongOrNullAsync_1() { + var result = await _sqlQuery.Select( "LongPrice" ).From( "Products.Product" ).Where( "ProductId", TestConfig.Id ).ToLongOrNullAsync(); + Assert.Equal( TestConfig.LongValue, result ); + } + + /// + /// ²âÊԻñȡ64λ¿ɿÕÕûÐÍֵ - ¿Õֵ + /// + [Fact] + public async Task TestToLongOrNullAsync_2() { + var result = await _sqlQuery.Select( "Code" ).From( "Products.Product" ).Where( "ProductId", TestConfig.Id ).ToLongOrNullAsync(); + Assert.Null( result ); + } + + #endregion + + #region ToGuid + + /// + /// ²âÊԻñȡGuidֵ + /// + [Fact] + public void TestToGuid() { + var result = _sqlQuery.Select( "ProductId" ).From( "Products.Product" ).Where( "ProductId", TestConfig.Id ).ToGuid(); + Assert.Equal( TestConfig.Id, result ); + } + + #endregion + + #region ToGuidAsync + + /// + /// ²âÊԻñȡGuidֵ + /// + [Fact] + public async Task TestToGuidAsync() { + var result = await _sqlQuery.Select( "ProductId" ).From( "Products.Product" ).Where( "ProductId", TestConfig.Id ).ToGuidAsync(); + Assert.Equal( TestConfig.Id, result ); + } + + #endregion + + #region ToGuidOrNull + + /// + /// ²âÊԻñȡ¿ɿÕGuidֵ - ÓÐֵ + /// + [Fact] + public void TestToGuidOrNull_1() { + var result = _sqlQuery.Select( "ProductId" ).From( "Products.Product" ).Where( "ProductId", TestConfig.Id ).ToGuidOrNull(); + Assert.Equal( TestConfig.Id, result ); + } + + /// + /// ²âÊԻñȡ¿ɿÕGuidֵ - ¿Õֵ + /// + [Fact] + public void TestToGuidOrNull_2() { + var result = _sqlQuery.Select( "Code" ).From( "Products.Product" ).Where( "ProductId", TestConfig.Id ).ToGuidOrNull(); + Assert.Null( result ); + } + + #endregion + + #region ToGuidOrNullAsync + + /// + /// ²âÊԻñȡ¿ɿÕGuidֵ - ÓÐֵ + /// + [Fact] + public async Task TestToGuidOrNullAsync_1() { + var result = await _sqlQuery.Select( "ProductId" ).From( "Products.Product" ).Where( "ProductId", TestConfig.Id ).ToGuidOrNullAsync(); + Assert.Equal( TestConfig.Id, result ); + } + + /// + /// ²âÊԻñȡ¿ɿÕGuidֵ - ¿Õֵ + /// + [Fact] + public async Task TestToGuidOrNullAsync_2() { + var result = await _sqlQuery.Select( "Code" ).From( "Products.Product" ).Where( "ProductId", TestConfig.Id ).ToGuidOrNullAsync(); + Assert.Null( result ); + } + + #endregion + + #region ToBool + + /// + /// ²âÊԻñȡ²¼¶ûֵ + /// + [Fact] + public void TestToBool() { + var result = _sqlQuery.Select( "Enabled" ).From( "Products.Product" ).Where( "ProductId", TestConfig.Id ).ToBool(); + Assert.Equal( TestConfig.BoolValue, result ); + } + + #endregion + + #region ToBoolAsync + + /// + /// ²âÊԻñȡ²¼¶ûֵ + /// + [Fact] + public async Task TestToBoolAsync() { + var result = await _sqlQuery.Select( "Enabled" ).From( "Products.Product" ).Where( "ProductId", TestConfig.Id ).ToBoolAsync(); + Assert.Equal( TestConfig.BoolValue, result ); + } + + #endregion + + #region ToBoolOrNull + + /// + /// ²âÊԻñȡ¿ɿղ¼¶ûֵ - ÓÐֵ + /// + [Fact] + public void TestToBoolOrNull_1() { + var result = _sqlQuery.Select( "Enabled" ).From( "Products.Product" ).Where( "ProductId", TestConfig.Id ).ToBoolOrNull(); + Assert.Equal( TestConfig.BoolValue, result ); + } + + /// + /// ²âÊԻñȡ¿ɿղ¼¶ûֵ - ¿Õֵ + /// + [Fact] + public void TestToBoolOrNull_2() { + var result = _sqlQuery.Select( "Code" ).From( "Products.Product" ).Where( "ProductId", TestConfig.Id ).ToBoolOrNull(); + Assert.Null( result ); + } + + #endregion + + #region ToBoolOrNullAsync + + /// + /// ²âÊԻñȡ¿ɿղ¼¶ûֵ - ÓÐֵ + /// + [Fact] + public async Task TestToBoolOrNullAsync_1() { + var result = await _sqlQuery.Select( "Enabled" ).From( "Products.Product" ).Where( "ProductId", TestConfig.Id ).ToBoolOrNullAsync(); + Assert.Equal( TestConfig.BoolValue, result ); + } + + /// + /// ²âÊԻñȡ¿ɿղ¼¶ûֵ - ¿Õֵ + /// + [Fact] + public async Task TestToBoolOrNullAsync_2() { + var result = await _sqlQuery.Select( "Code" ).From( "Products.Product" ).Where( "ProductId", TestConfig.Id ).ToBoolOrNullAsync(); + Assert.Null( result ); + } + + #endregion + + #region ToFloat + + /// + /// ²âÊԻñȡFloatֵ + /// + [Fact] + public void TestToFloat() { + var result = _sqlQuery.Select( "FloatPrice" ).From( "Products.Product" ).Where( "ProductId", TestConfig.Id ).ToFloat(); + Assert.Equal( TestConfig.FloatValue, result ); + } + + #endregion + + #region ToFloatAsync + + /// + /// ²âÊԻñȡFloatֵ + /// + [Fact] + public async Task TestToFloatAsync() { + var result = await _sqlQuery.Select( "FloatPrice" ).From( "Products.Product" ).Where( "ProductId", TestConfig.Id ).ToFloatAsync(); + Assert.Equal( TestConfig.FloatValue, result ); + } + + #endregion + + #region ToFloatOrNull + + /// + /// ²âÊԻñȡ¿ɿÕFloatֵ - ÓÐֵ + /// + [Fact] + public void TestToFloatOrNull_1() { + var result = _sqlQuery.Select( "FloatPrice" ).From( "Products.Product" ).Where( "ProductId", TestConfig.Id ).ToFloatOrNull(); + Assert.Equal( TestConfig.FloatValue, result ); + } + + /// + /// ²âÊԻñȡ¿ɿÕFloatֵ - ¿Õֵ + /// + [Fact] + public void TestToFloatOrNull_2() { + var result = _sqlQuery.Select( "Code" ).From( "Products.Product" ).Where( "ProductId", TestConfig.Id ).ToFloatOrNull(); + Assert.Null( result ); + } + + #endregion + + #region ToFloatOrNullAsync + + /// + /// ²âÊԻñȡ¿ɿÕFloatֵ - ÓÐֵ + /// + [Fact] + public async Task TestToFloatOrNullAsync_1() { + var result = await _sqlQuery.Select( "FloatPrice" ).From( "Products.Product" ).Where( "ProductId", TestConfig.Id ).ToFloatOrNullAsync(); + Assert.Equal( TestConfig.FloatValue, result ); + } + + /// + /// ²âÊԻñȡ¿ɿÕFloatֵ - ¿Õֵ + /// + [Fact] + public async Task TestToFloatOrNullAsync_2() { + var result = await _sqlQuery.Select( "Code" ).From( "Products.Product" ).Where( "ProductId", TestConfig.Id ).ToFloatOrNullAsync(); + Assert.Null( result ); + } + + #endregion + + #region ToDouble + + /// + /// ²âÊԻñȡDoubleֵ + /// + [Fact] + public void TestToDouble() { + var result = _sqlQuery.Select( "Price" ).From( "Products.Product" ).Where( "ProductId", TestConfig.Id ).ToDouble(); + Assert.Equal( TestConfig.DoubleValue, result ); + } + + #endregion + + #region ToDoubleAsync + + /// + /// ²âÊԻñȡDoubleֵ + /// + [Fact] + public async Task TestToDoubleAsync() { + var result = await _sqlQuery.Select( "Price" ).From( "Products.Product" ).Where( "ProductId", TestConfig.Id ).ToDoubleAsync(); + Assert.Equal( TestConfig.DoubleValue, result ); + } + + #endregion + + #region ToDoubleOrNull + + /// + /// ²âÊԻñȡ¿ɿÕDoubleֵ - ÓÐֵ + /// + [Fact] + public void TestToDoubleOrNull_1() { + var result = _sqlQuery.Select( "Price" ).From( "Products.Product" ).Where( "ProductId", TestConfig.Id ).ToDoubleOrNull(); + Assert.Equal( TestConfig.DoubleValue, result ); + } + + /// + /// ²âÊԻñȡ¿ɿÕDoubleֵ - ¿Õֵ + /// + [Fact] + public void TestToDoubleOrNull_2() { + var result = _sqlQuery.Select( "Code" ).From( "Products.Product" ).Where( "ProductId", TestConfig.Id ).ToDoubleOrNull(); + Assert.Null( result ); + } + + #endregion + + #region ToDoubleOrNullAsync + + /// + /// ²âÊԻñȡ¿ɿÕDoubleֵ - ÓÐֵ + /// + [Fact] + public async Task TestToDoubleOrNullAsync_1() { + var result = await _sqlQuery.Select( "Price" ).From( "Products.Product" ).Where( "ProductId", TestConfig.Id ).ToDoubleOrNullAsync(); + Assert.Equal( TestConfig.DoubleValue, result ); + } + + /// + /// ²âÊԻñȡ¿ɿÕDoubleֵ - ¿Õֵ + /// + [Fact] + public async Task TestToDoubleOrNullAsync_2() { + var result = await _sqlQuery.Select( "Code" ).From( "Products.Product" ).Where( "ProductId", TestConfig.Id ).ToDoubleOrNullAsync(); + Assert.Null( result ); + } + + #endregion + + #region ToDecimal + + /// + /// ²âÊԻñȡDecimalֵ + /// + [Fact] + public void TestToDecimal() { + var result = _sqlQuery.Select( "Price" ).From( "Products.Product" ).Where( "ProductId", TestConfig.Id ).ToDecimal(); + Assert.Equal( TestConfig.DecimalValue, result ); + } + + #endregion + + #region ToDecimalAsync + + /// + /// ²âÊԻñȡDecimalֵ + /// + [Fact] + public async Task TestToDecimalAsync() { + var result = await _sqlQuery.Select( "Price" ).From( "Products.Product" ).Where( "ProductId", TestConfig.Id ).ToDecimalAsync(); + Assert.Equal( TestConfig.DecimalValue, result ); + } + + #endregion + + #region ToDecimalOrNull + + /// + /// ²âÊԻñȡDecimalֵ - ÓÐֵ + /// + [Fact] + public void TestToDecimalOrNull_1() { + var result = _sqlQuery.Select( "Price" ).From( "Products.Product" ).Where( "ProductId", TestConfig.Id ).ToDecimalOrNull(); + Assert.Equal( TestConfig.DecimalValue, result ); + } + + /// + /// ²âÊԻñȡDecimalֵ - ¿Õֵ + /// + [Fact] + public void TestToDecimalOrNull_2() { + var result = _sqlQuery.Select( "Code" ).From( "Products.Product" ).Where( "ProductId", TestConfig.Id ).ToDecimalOrNull(); + Assert.Null( result ); + } + + #endregion + + #region ToDecimalOrNullAsync + + /// + /// ²âÊԻñȡ¿ɿÕDecimalֵ - ÓÐֵ + /// + [Fact] + public async Task TestToDecimalOrNullAsync_1() { + var result = await _sqlQuery.Select( "Price" ).From( "Products.Product" ).Where( "ProductId", TestConfig.Id ).ToDecimalOrNullAsync(); + Assert.Equal( TestConfig.DecimalValue, result ); + } + + /// + /// ²âÊԻñȡ¿ɿÕDecimalֵ - ¿Õֵ + /// + [Fact] + public async Task TestToDecimalOrNullAsync_2() { + var result = await _sqlQuery.Select( "Code" ).From( "Products.Product" ).Where( "ProductId", TestConfig.Id ).ToDecimalOrNullAsync(); + Assert.Null( result ); + } + + #endregion + + #region ToDateTime + + /// + /// ²âÊԻñȡÈÕÆÚֵ + /// + [Fact] + public void TestToDateTime() { + var result = _sqlQuery.Select( "Birthday" ).From( "Customers.Customer" ).Where( "CustomerId", 1 ).ToDateTime(); + Assert.Equal( TestConfig.DateTimeValue, result ); + } + + #endregion + + #region ToDateTimeAsync + + /// + /// ²âÊԻñȡÈÕÆÚֵ + /// + [Fact] + public async Task TestToDateTimeAsync() { + var result = await _sqlQuery.Select( "Birthday" ).From( "Customers.Customer" ).Where( "CustomerId", 1 ).ToDateTimeAsync(); + Assert.Equal( TestConfig.DateTimeValue, result ); + } + + #endregion + + #region ToDateTimeOrNull + + /// + /// ²âÊԻñȡ¿ɿÕÈÕÆÚֵ - ÓÐֵ + /// + [Fact] + public void TestToDateTimeOrNull_1() { + var result = _sqlQuery.Select( "Birthday" ).From( "Customers.Customer" ).Where( "CustomerId", 1 ).ToDateTimeOrNull(); + Assert.Equal( TestConfig.DateTimeValue, result ); + } + + /// + /// ²âÊԻñȡ¿ɿÕÈÕÆÚֵ - ¿Õֵ + /// + [Fact] + public void TestToDateTimeOrNull_2() { + var result = _sqlQuery.Select( "Code" ).From( "Customers.Customer" ).Where( "CustomerId", 1 ).ToDateTimeOrNull(); + Assert.Null( result ); + } + + #endregion + + #region ToDateTimeOrNullAsync + + /// + /// ²âÊԻñȡ¿ɿÕÈÕÆÚֵ - ÓÐֵ + /// + [Fact] + public async Task TestToDateTimeOrNullAsync_1() { + var result = await _sqlQuery.Select( "Birthday" ).From( "Customers.Customer" ).Where( "CustomerId", 1 ).ToDateTimeOrNullAsync(); + Assert.Equal( TestConfig.DateTimeValue, result ); + } + + /// + /// ²âÊԻñȡ¿ɿÕÈÕÆÚֵ - ¿Õֵ + /// + [Fact] + public async Task TestToDateTimeOrNullAsync_2() { + var result = await _sqlQuery.Select( "Code" ).From( "Customers.Customer" ).Where( "CustomerId", 1 ).ToDateTimeOrNullAsync(); + Assert.Null( result ); + } + + #endregion + } +} diff --git a/test/Util.Data.Dapper.SqlServer.Tests.Integration/SqlQuery/SqlServerSqlQueryTest.Single.cs b/test/Util.Data.Dapper.SqlServer.Tests.Integration/SqlQuery/SqlServerSqlQueryTest.Single.cs new file mode 100644 index 00000000..3ea9c56a --- /dev/null +++ b/test/Util.Data.Dapper.SqlServer.Tests.Integration/SqlQuery/SqlServerSqlQueryTest.Single.cs @@ -0,0 +1,52 @@ +using System.Threading.Tasks; +using Util.Data.Sql; +using Util.Tests.Configs; +using Util.Tests.Models; +using Xunit; + +namespace Util.Data.Dapper.Tests.SqlQuery { + /// + /// Sql Server Sql²éѯ¶ÔÏó²âÊÔ - »ñȡµ¥¸ö¶ÔÏó²âÊÔ + /// + public partial class SqlServerSqlQueryTest { + /// + /// ²âÊԻñȡµ¥¸öʵÌå + /// + [Fact] + public void TestExecuteSingle() { + var result = _sqlQuery.Select( "ProductId as Id,Code" ).From( "Products.Product" ).Where( "ProductId", TestConfig.Id ).ExecuteSingle(); + Assert.Equal( TestConfig.Id, result.Id ); + Assert.Equal( TestConfig.Value, result.Code ); + } + + /// + /// ²âÊԻñȡµ¥¸öʵÌå + /// + [Fact] + public async Task TestExecuteSingleAsync() { + var result = await _sqlQuery.Select( "ProductId as Id,Code" ).From( "Products.Product" ).Where( "ProductId", TestConfig.Id ).ExecuteSingleAsync(); + Assert.Equal( TestConfig.Id, result.Id ); + Assert.Equal( TestConfig.Value, result.Code ); + } + + /// + /// ²âÊԻñȡµ¥¸öʵÌå + /// + [Fact] + public void TestToEntity() { + var result = _sqlQuery.Select( "ProductId as Id,Code" ).From( "Products.Product" ).Where( "ProductId", TestConfig.Id ).ToEntity(); + Assert.Equal( TestConfig.Id, result.Id ); + Assert.Equal( TestConfig.Value, result.Code ); + } + + /// + /// ²âÊԻñȡµ¥¸öʵÌå + /// + [Fact] + public async Task TestToEntityAsync() { + var result = await _sqlQuery.Select( "ProductId as Id,Code" ).From( "Products.Product" ).Where( "ProductId", TestConfig.Id ).ToEntityAsync(); + Assert.Equal( TestConfig.Id, result.Id ); + Assert.Equal( TestConfig.Value, result.Code ); + } + } +} diff --git a/test/Util.Data.Dapper.SqlServer.Tests.Integration/SqlQuery/SqlServerSqlQueryTest.cs b/test/Util.Data.Dapper.SqlServer.Tests.Integration/SqlQuery/SqlServerSqlQueryTest.cs new file mode 100644 index 00000000..5b5c947f --- /dev/null +++ b/test/Util.Data.Dapper.SqlServer.Tests.Integration/SqlQuery/SqlServerSqlQueryTest.cs @@ -0,0 +1,25 @@ +using Util.Data.Sql; + +namespace Util.Data.Dapper.Tests.SqlQuery { + /// + /// Sql Server Sql²éѯ¶ÔÏó²âÊÔ + /// + public partial class SqlServerSqlQueryTest { + /// + /// SqlִÐÐÆ÷ + /// + private readonly ISqlExecutor _sqlExecutor; + /// + /// Sql²éѯ¶ÔÏó + /// + private readonly ISqlQuery _sqlQuery; + + /// + /// ²âÊԳõʼ»¯ + /// + public SqlServerSqlQueryTest( ISqlExecutor sqlExecutor, ISqlQuery sqlQuery ) { + _sqlExecutor = sqlExecutor; + _sqlQuery = sqlQuery; + } + } +} diff --git a/test/Util.Data.Dapper.SqlServer.Tests.Integration/Startup.cs b/test/Util.Data.Dapper.SqlServer.Tests.Integration/Startup.cs new file mode 100644 index 00000000..031fdcbf --- /dev/null +++ b/test/Util.Data.Dapper.SqlServer.Tests.Integration/Startup.cs @@ -0,0 +1,63 @@ +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using Util.Aop; +using Util.Data.Dapper.Tests.Infrastructure; +using Util.Data.EntityFrameworkCore; +using Util.Data.Metadata; +using Util.Data.Sql; +using Util.Helpers; +using Util.Sessions; +using Util.Tests.Infrastructure; +using Util.Tests.UnitOfWorks; +using Xunit.DependencyInjection; +using Xunit.DependencyInjection.Logging; + +namespace Util.Data.Dapper.Tests { + /// + /// Æô¶¯ÅäÖà + /// + public class Startup { + /// + /// ÅäÖÃÖ÷»ú + /// + public void ConfigureHost( IHostBuilder hostBuilder ) { + hostBuilder.ConfigureDefaults( null ) + .ConfigureServices( ( context, services ) => { + services.AddTransient(); + } ) + .AddUtil( options => { + Environment.SetDevelopment(); + options.UseAop() + .UseSqlServerSqlQuery( Config.GetConnectionString( "connection" ) ) + .UseSqlServerSqlExecutor( Config.GetConnectionString( "connection" ) ) + .UseSqlServerUnitOfWork( Config.GetConnectionString( "connection" ) ); + } ); + } + + /// + /// ÅäÖ÷þÎñ + /// + public void ConfigureServices( IServiceCollection services ) { + services.AddSingleton(); + InitDatabase( services ); + } + + /// + /// ³õʼ»¯Êý¾ݿâ + /// + private void InitDatabase( IServiceCollection services ) { + var unitOfWork = (SqlServerUnitOfWork)services.BuildServiceProvider().GetService(); + unitOfWork.EnsureDeleted(); + unitOfWork.EnsureCreated(); + DatabaseScript.InitProcedures( unitOfWork?.Database ); + } + + /// + /// ÅäÖÃÈÕ־Ìṩ³ÌÐò + /// + public void Configure( ILoggerFactory loggerFactory, ITestOutputHelperAccessor accessor ) { + loggerFactory.AddProvider( new XunitTestOutputLoggerProvider( accessor, ( s, logLevel ) => logLevel >= LogLevel.Trace ) ); + } + } +} diff --git a/test/Util.Data.Dapper.SqlServer.Tests.Integration/Util.Data.Dapper.SqlServer.Tests.Integration.csproj b/test/Util.Data.Dapper.SqlServer.Tests.Integration/Util.Data.Dapper.SqlServer.Tests.Integration.csproj new file mode 100644 index 00000000..ca707d4e --- /dev/null +++ b/test/Util.Data.Dapper.SqlServer.Tests.Integration/Util.Data.Dapper.SqlServer.Tests.Integration.csproj @@ -0,0 +1,43 @@ + + + + $(NetTargetFramework) + false + Util.Data.Dapper.Tests + Util.Data.Dapper.Tests.Startup + + + + + Always + + + Always + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + + diff --git a/test/Util.Data.Dapper.SqlServer.Tests.Integration/appsettings.Development.json b/test/Util.Data.Dapper.SqlServer.Tests.Integration/appsettings.Development.json new file mode 100644 index 00000000..957a9733 --- /dev/null +++ b/test/Util.Data.Dapper.SqlServer.Tests.Integration/appsettings.Development.json @@ -0,0 +1,11 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Trace", + "Microsoft": "Trace" + } + }, + "ConnectionStrings": { + "connection": "Server=.\\sql2014;Database=Util.Data.Dapper.Test;uid=sa;pwd=sa;MultipleActiveResultSets=true" + } +} \ No newline at end of file diff --git a/test/Util.Data.Dapper.SqlServer.Tests.Integration/appsettings.json b/test/Util.Data.Dapper.SqlServer.Tests.Integration/appsettings.json new file mode 100644 index 00000000..3db92989 --- /dev/null +++ b/test/Util.Data.Dapper.SqlServer.Tests.Integration/appsettings.json @@ -0,0 +1,11 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Error", + "Microsoft": "Error" + } + }, + "ConnectionStrings": { + "connection": "Server=192.168.31.123\\sql2014;Database=Util.Data.Dapper.Test;uid=sa;pwd=sa;MultipleActiveResultSets=true;" + } +} \ No newline at end of file diff --git a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Filters/DeleteFilterTest.cs b/test/Util.Data.EntityFrameworkCore.MySql.Tests.Integration/Filters/DeleteFilterTest.cs similarity index 97% rename from test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Filters/DeleteFilterTest.cs rename to test/Util.Data.EntityFrameworkCore.MySql.Tests.Integration/Filters/DeleteFilterTest.cs index 0b085697..e589e106 100644 --- a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Filters/DeleteFilterTest.cs +++ b/test/Util.Data.EntityFrameworkCore.MySql.Tests.Integration/Filters/DeleteFilterTest.cs @@ -1,4 +1,4 @@ -using Util.Data.EntityFrameworkCore.Models; +using Util.Tests.Models; using Xunit; using Xunit.Abstractions; diff --git a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Filters/FilterManagerTest.cs b/test/Util.Data.EntityFrameworkCore.MySql.Tests.Integration/Filters/FilterManagerTest.cs similarity index 97% rename from test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Filters/FilterManagerTest.cs rename to test/Util.Data.EntityFrameworkCore.MySql.Tests.Integration/Filters/FilterManagerTest.cs index 6cd331a2..4ac4609d 100644 --- a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Filters/FilterManagerTest.cs +++ b/test/Util.Data.EntityFrameworkCore.MySql.Tests.Integration/Filters/FilterManagerTest.cs @@ -1,6 +1,6 @@ -using Util.Data.EntityFrameworkCore.Models; -using Util.Data.Filters; +using Util.Data.Filters; using Util.Domain; +using Util.Tests.Models; using Xunit; namespace Util.Data.EntityFrameworkCore.Filters { diff --git a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Startup.cs b/test/Util.Data.EntityFrameworkCore.MySql.Tests.Integration/Startup.cs similarity index 80% rename from test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Startup.cs rename to test/Util.Data.EntityFrameworkCore.MySql.Tests.Integration/Startup.cs index e76e4871..56e9fa5c 100644 --- a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Startup.cs +++ b/test/Util.Data.EntityFrameworkCore.MySql.Tests.Integration/Startup.cs @@ -2,10 +2,10 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using Util.Aop; -using Util.Data.EntityFrameworkCore.Infrastructure; -using Util.Data.EntityFrameworkCore.UnitOfWorks; using Util.Helpers; using Util.Sessions; +using Util.Tests.Infrastructure; +using Util.Tests.UnitOfWorks; using Xunit.DependencyInjection; using Xunit.DependencyInjection.Logging; @@ -18,7 +18,12 @@ namespace Util.Data.EntityFrameworkCore { /// ÅäÖÃÖ÷»ú /// public void ConfigureHost( IHostBuilder hostBuilder ) { - hostBuilder.ConfigureDefaults( null ).UseEnvironment( "Development" ).EnableAop(); + hostBuilder.ConfigureDefaults( null ) + .AddUtil( options => { + Environment.SetDevelopment(); + options.UseAop() + .UseMySqlUnitOfWork( Config.GetConnectionString( "connection" ) ); + } ); } /// @@ -26,9 +31,6 @@ namespace Util.Data.EntityFrameworkCore { /// public void ConfigureServices( IServiceCollection services ) { services.AddSingleton(); - services.AddUtil( options => { - options.UsePgSqlUnitOfWork( Config.GetConnectionString( "connection" ) ); - } ); InitDatabase( services ); } @@ -36,7 +38,7 @@ namespace Util.Data.EntityFrameworkCore { /// ³õʼ»¯Êý¾ݿâ /// private void InitDatabase( IServiceCollection services ) { - var unitOfWork = services.BuildServiceProvider().GetService(); + var unitOfWork = services.BuildServiceProvider().GetService(); unitOfWork.EnsureDeleted(); unitOfWork.EnsureCreated(); } diff --git a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Tests/CustomerRepositoryTest.cs b/test/Util.Data.EntityFrameworkCore.MySql.Tests.Integration/Tests/CustomerRepositoryTest.cs similarity index 78% rename from test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Tests/CustomerRepositoryTest.cs rename to test/Util.Data.EntityFrameworkCore.MySql.Tests.Integration/Tests/CustomerRepositoryTest.cs index 5d1f82a6..2f43c378 100644 --- a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Tests/CustomerRepositoryTest.cs +++ b/test/Util.Data.EntityFrameworkCore.MySql.Tests.Integration/Tests/CustomerRepositoryTest.cs @@ -1,12 +1,13 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; -using Util.Data.EntityFrameworkCore.Fakes; -using Util.Data.EntityFrameworkCore.Infrastructure; -using Util.Data.EntityFrameworkCore.Models; -using Util.Data.EntityFrameworkCore.Repositories; -using Util.Data.EntityFrameworkCore.UnitOfWorks; +using Microsoft.EntityFrameworkCore; using Util.Data.Queries; +using Util.Tests.Fakes; +using Util.Tests.Infrastructure; +using Util.Tests.Models; +using Util.Tests.Repositories; +using Util.Tests.UnitOfWorks; using Xunit; namespace Util.Data.EntityFrameworkCore.Tests { @@ -16,6 +17,7 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 1. 测试自增长int类型标识 /// 2. 测试日期范围查询 /// 3. 测试分页查询 + /// 4. 测试Utc日期 /// public class CustomerRepositoryTest : TestBase { @@ -29,7 +31,7 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// /// 测试初始化 /// - public CustomerRepositoryTest( ICustomerRepository repository,ISqlServerUnitOfWork unitOfWork ) :base( unitOfWork ) { + public CustomerRepositoryTest( ICustomerRepository repository, ITestUnitOfWork unitOfWork ) : base( unitOfWork ) { _repository = repository; } @@ -37,23 +39,6 @@ namespace Util.Data.EntityFrameworkCore.Tests { #region 辅助操作 - /// - /// 添加实体列表 - /// - /// 添加数量 - /// 客户名称 - private List AddCustomers( int count = 2, string name = null ) { - var customers = CustomerFakeService.GetCustomers( count ); - customers.ForEach( customer => { - if( name != null ) - customer.Name = name; - } ); - _repository.Add( customers ); - UnitOfWork.Commit(); - UnitOfWork.ClearCache(); - return customers.OrderBy( t => t.Code ).ToList(); - } - /// /// 添加实体列表 /// @@ -62,8 +47,9 @@ namespace Util.Data.EntityFrameworkCore.Tests { private async Task> AddCustomersAsync( int count = 2, string name = null ) { var customers = CustomerFakeService.GetCustomers( count ); customers.ForEach( customer => { - if( name != null ) + if ( name != null ) customer.Name = name; + customer.CreationTime = null; } ); await _repository.AddAsync( customers ); await UnitOfWork.CommitAsync(); @@ -79,7 +65,7 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试添加范围查询条件 - 日期带时间 /// [Fact] - public void TestBetween_DateTime_1() { + public async Task TestBetween_DateTime_1() { //常量 var name = "TestBetween_DateTime_1"; var birthday = "2005-5-5 05:05:05".ToDateTime(); @@ -87,19 +73,19 @@ namespace Util.Data.EntityFrameworkCore.Tests { var maxBirthday = "2005-5-8 06:05:05".ToDateTime(); //添加实体列表 - AddCustomers(); + await AddCustomersAsync(); var customers = CustomerFakeService.GetCustomers( 5 ); customers.ForEach( customer => { customer.Name = name; customer.Birthday = birthday; birthday = birthday.AddDays( 1 ); } ); - _repository.Add( customers ); - UnitOfWork.Commit(); + await _repository.AddAsync( customers ); + await UnitOfWork.CommitAsync(); UnitOfWork.ClearCache(); //查询 - var result = _repository.Find().Where( t => t.Name == name ).Between( t => t.Birthday, minBirthday, maxBirthday ).ToList(); + var result = await _repository.Find().Where( t => t.Name == name ).Between( t => t.Birthday, minBirthday, maxBirthday ).ToListAsync(); //验证 Assert.Equal( 2, result.Count ); @@ -109,7 +95,7 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试添加范围查询条件 - 日期带时间 - 包含左边界 /// [Fact] - public void TestBetween_DateTime_2() { + public async Task TestBetween_DateTime_2() { //常量 var name = "TestBetween_DateTime_2"; var birthday = "2005-5-5 05:05:05".ToDateTime(); @@ -117,19 +103,19 @@ namespace Util.Data.EntityFrameworkCore.Tests { var maxBirthday = "2005-5-8 05:05:05".ToDateTime(); //添加实体列表 - AddCustomers(); + await AddCustomersAsync(); var customers = CustomerFakeService.GetCustomers( 5 ); customers.ForEach( customer => { customer.Name = name; customer.Birthday = birthday; birthday = birthday.AddDays( 1 ); } ); - _repository.Add( customers ); - UnitOfWork.Commit(); + await _repository.AddAsync( customers ); + await UnitOfWork.CommitAsync(); UnitOfWork.ClearCache(); //查询 - var result = _repository.Find().Where( t => t.Name == name ).Between( t => t.Birthday, minBirthday, maxBirthday, boundary: Boundary.Left ).ToList(); + var result = await _repository.Find().Where( t => t.Name == name ).Between( t => t.Birthday, minBirthday, maxBirthday, boundary: Boundary.Left ).ToListAsync(); //验证 Assert.Equal( 2, result.Count ); @@ -139,7 +125,7 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试添加范围查询条件 - 日期带时间 - 包含右边界 /// [Fact] - public void TestBetween_DateTime_3() { + public async Task TestBetween_DateTime_3() { //常量 var name = "TestBetween_DateTime_3"; var birthday = "2005-5-5 05:05:05".ToDateTime(); @@ -147,19 +133,19 @@ namespace Util.Data.EntityFrameworkCore.Tests { var maxBirthday = "2005-5-8 05:05:05".ToDateTime(); //添加实体列表 - AddCustomers(); + await AddCustomersAsync(); var customers = CustomerFakeService.GetCustomers( 5 ); customers.ForEach( customer => { customer.Name = name; customer.Birthday = birthday; birthday = birthday.AddDays( 1 ); } ); - _repository.Add( customers ); - UnitOfWork.Commit(); + await _repository.AddAsync( customers ); + await UnitOfWork.CommitAsync(); UnitOfWork.ClearCache(); //查询 - var result = _repository.Find().Where( t => t.Name == name ).Between( t => t.Birthday, minBirthday, maxBirthday, boundary: Boundary.Right ).ToList(); + var result = await _repository.Find().Where( t => t.Name == name ).Between( t => t.Birthday, minBirthday, maxBirthday, boundary: Boundary.Right ).ToListAsync(); //验证 Assert.Equal( 2, result.Count ); @@ -169,7 +155,7 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试添加范围查询条件 - 日期带时间 - 包含两边 /// [Fact] - public void TestBetween_DateTime_4() { + public async Task TestBetween_DateTime_4() { //常量 var name = "TestBetween_DateTime_4"; var birthday = "2005-5-5 05:05:05".ToDateTime(); @@ -177,19 +163,19 @@ namespace Util.Data.EntityFrameworkCore.Tests { var maxBirthday = "2005-5-8 05:05:05".ToDateTime(); //添加实体列表 - AddCustomers(); + await AddCustomersAsync(); var customers = CustomerFakeService.GetCustomers( 5 ); customers.ForEach( customer => { customer.Name = name; customer.Birthday = birthday; birthday = birthday.AddDays( 1 ); } ); - _repository.Add( customers ); - UnitOfWork.Commit(); + await _repository.AddAsync( customers ); + await UnitOfWork.CommitAsync(); UnitOfWork.ClearCache(); //查询 - var result = _repository.Find().Where( t => t.Name == name ).Between( t => t.Birthday, minBirthday, maxBirthday, boundary: Boundary.Both ).ToList(); + var result = await _repository.Find().Where( t => t.Name == name ).Between( t => t.Birthday, minBirthday, maxBirthday, boundary: Boundary.Both ).ToListAsync(); //验证 Assert.Equal( 3, result.Count ); @@ -199,7 +185,7 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试添加范围查询条件 - 日期带时间 - 不包含边界 /// [Fact] - public void TestBetween_DateTime_5() { + public async Task TestBetween_DateTime_5() { //常量 var name = "TestBetween_DateTime_5"; var birthday = "2005-5-5 05:05:05".ToDateTime(); @@ -207,19 +193,19 @@ namespace Util.Data.EntityFrameworkCore.Tests { var maxBirthday = "2005-5-8 05:05:05".ToDateTime(); //添加实体列表 - AddCustomers(); + await AddCustomersAsync(); var customers = CustomerFakeService.GetCustomers( 5 ); customers.ForEach( customer => { customer.Name = name; customer.Birthday = birthday; birthday = birthday.AddDays( 1 ); } ); - _repository.Add( customers ); - UnitOfWork.Commit(); + await _repository.AddAsync( customers ); + await UnitOfWork.CommitAsync(); UnitOfWork.ClearCache(); //查询 - var result = _repository.Find().Where( t => t.Name == name ).Between( t => t.Birthday, minBirthday, maxBirthday, boundary: Boundary.Neither ).ToList(); + var result = await _repository.Find().Where( t => t.Name == name ).Between( t => t.Birthday, minBirthday, maxBirthday, boundary: Boundary.Neither ).ToListAsync(); //验证 Assert.Single( result ); @@ -229,26 +215,26 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试添加范围查询条件 - 日期带时间 - 最大值为空 /// [Fact] - public void TestBetween_DateTime_6() { + public async Task TestBetween_DateTime_6() { //常量 var name = "TestBetween_DateTime_6"; var birthday = "2005-5-5 05:05:05".ToDateTime(); var minBirthday = "2005-5-6 05:05:05".ToDateTime(); //添加实体列表 - AddCustomers(); + await AddCustomersAsync(); var customers = CustomerFakeService.GetCustomers( 5 ); customers.ForEach( customer => { customer.Name = name; customer.Birthday = birthday; birthday = birthday.AddDays( 1 ); } ); - _repository.Add( customers ); - UnitOfWork.Commit(); + await _repository.AddAsync( customers ); + await UnitOfWork.CommitAsync(); UnitOfWork.ClearCache(); //查询 - var result = _repository.Find().Where( t => t.Name == name ).Between( t => t.Birthday, minBirthday, null, boundary: Boundary.Both ).ToList(); + var result = await _repository.Find().Where( t => t.Name == name ).Between( t => t.Birthday, minBirthday, null, boundary: Boundary.Both ).ToListAsync(); //验证 Assert.Equal( 4, result.Count ); @@ -258,26 +244,26 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试添加范围查询条件 - 日期带时间 - 最小值为空 /// [Fact] - public void TestBetween_DateTime_7() { + public async Task TestBetween_DateTime_7() { //常量 var name = "TestBetween_DateTime_7"; var birthday = "2005-5-5 05:05:05".ToDateTime(); var maxBirthday = "2005-5-8 05:05:05".ToDateTime(); //添加实体列表 - AddCustomers(); + await AddCustomersAsync(); var customers = CustomerFakeService.GetCustomers( 5 ); customers.ForEach( customer => { customer.Name = name; customer.Birthday = birthday; birthday = birthday.AddDays( 1 ); } ); - _repository.Add( customers ); - UnitOfWork.Commit(); + await _repository.AddAsync( customers ); + await UnitOfWork.CommitAsync(); UnitOfWork.ClearCache(); //查询 - var result = _repository.Find().Where( t => t.Name == name ).Between( t => t.Birthday, null, maxBirthday, boundary: Boundary.Both ).ToList(); + var result = await _repository.Find().Where( t => t.Name == name ).Between( t => t.Birthday, null, maxBirthday, boundary: Boundary.Both ).ToListAsync(); //验证 Assert.Equal( 4, result.Count ); @@ -287,7 +273,7 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试添加范围查询条件 - 日期不带时间 - 包含左边界 /// [Fact] - public void TestBetween_Date_1() { + public async Task TestBetween_Date_1() { //常量 var name = "TestBetween_Date_1"; var birthday = "2005-5-5 05:05:05".ToDateTime(); @@ -295,23 +281,23 @@ namespace Util.Data.EntityFrameworkCore.Tests { var maxBirthday = "2005-5-8".ToDateTime(); //添加实体列表 - AddCustomers(); + await AddCustomersAsync(); var customers = CustomerFakeService.GetCustomers( 5 ); customers.ForEach( customer => { customer.Name = name; customer.Birthday = birthday; birthday = birthday.AddDays( 1 ); } ); - _repository.Add( customers ); - UnitOfWork.Commit(); + await _repository.AddAsync( customers ); + await UnitOfWork.CommitAsync(); UnitOfWork.ClearCache(); //查询 - var result = _repository.Find() + var result = await _repository.Find() .Where( t => t.Name == name ) .Between( t => t.Birthday, minBirthday, maxBirthday, false, Boundary.Left ) .OrderBy( t => t.Birthday ) - .ToList(); + .ToListAsync(); //验证 Assert.Equal( 2, result.Count ); @@ -323,7 +309,7 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试添加范围查询条件 - 日期不带时间 - 包含右边界 /// [Fact] - public void TestBetween_Date_2() { + public async Task TestBetween_Date_2() { //常量 var name = "TestBetween_Date_2"; var birthday = "2005-5-5 05:05:05".ToDateTime(); @@ -331,23 +317,23 @@ namespace Util.Data.EntityFrameworkCore.Tests { var maxBirthday = "2005-5-8".ToDateTime(); //添加实体列表 - AddCustomers(); + await AddCustomersAsync(); var customers = CustomerFakeService.GetCustomers( 5 ); customers.ForEach( customer => { customer.Name = name; customer.Birthday = birthday; birthday = birthday.AddDays( 1 ); } ); - _repository.Add( customers ); - UnitOfWork.Commit(); + await _repository.AddAsync( customers ); + await UnitOfWork.CommitAsync(); UnitOfWork.ClearCache(); //查询 - var result = _repository.Find() + var result = await _repository.Find() .Where( t => t.Name == name ) .Between( t => t.Birthday, minBirthday, maxBirthday, false, Boundary.Right ) .OrderBy( t => t.Birthday ) - .ToList(); + .ToListAsync(); //验证 Assert.Equal( 2, result.Count ); @@ -359,7 +345,7 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试添加范围查询条件 - 日期不带时间 - 包含两边 /// [Fact] - public void TestBetween_Date_3() { + public async Task TestBetween_Date_3() { //常量 var name = "TestBetween_Date_3"; var birthday = "2005-5-5 05:05:05".ToDateTime(); @@ -367,23 +353,23 @@ namespace Util.Data.EntityFrameworkCore.Tests { var maxBirthday = "2005-5-8".ToDateTime(); //添加实体列表 - AddCustomers(); + await AddCustomersAsync(); var customers = CustomerFakeService.GetCustomers( 5 ); customers.ForEach( customer => { customer.Name = name; customer.Birthday = birthday; birthday = birthday.AddDays( 1 ); } ); - _repository.Add( customers ); - UnitOfWork.Commit(); + await _repository.AddAsync( customers ); + await UnitOfWork.CommitAsync(); UnitOfWork.ClearCache(); //查询 - var result = _repository.Find() + var result = await _repository.Find() .Where( t => t.Name == name ) .Between( t => t.Birthday, minBirthday, maxBirthday, false, Boundary.Both ) .OrderBy( t => t.Birthday ) - .ToList(); + .ToListAsync(); //验证 Assert.Equal( 3, result.Count ); @@ -396,7 +382,7 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试添加范围查询条件 - 日期不带时间 - 不包含边界 /// [Fact] - public void TestBetween_Date_4() { + public async Task TestBetween_Date_4() { //常量 var name = "TestBetween_Date_4"; var birthday = "2005-5-5 05:05:05".ToDateTime(); @@ -404,22 +390,22 @@ namespace Util.Data.EntityFrameworkCore.Tests { var maxBirthday = "2005-5-8".ToDateTime(); //添加实体列表 - AddCustomers(); + await AddCustomersAsync(); var customers = CustomerFakeService.GetCustomers( 5 ); customers.ForEach( customer => { customer.Name = name; customer.Birthday = birthday; birthday = birthday.AddDays( 1 ); } ); - _repository.Add( customers ); - UnitOfWork.Commit(); + await _repository.AddAsync( customers ); + await UnitOfWork.CommitAsync(); UnitOfWork.ClearCache(); //查询 - var result = _repository.Find() + var result = await _repository.Find() .Where( t => t.Name == name ) .Between( t => t.Birthday, minBirthday, maxBirthday, false, Boundary.Neither ) - .ToList(); + .ToListAsync(); //验证 Assert.Single( result ); @@ -430,14 +416,14 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试添加范围查询条件 - 日期不带时间 - 最大值为空 /// [Fact] - public void TestBetween_Date_5() { + public async Task TestBetween_Date_5() { //常量 var name = "TestBetween_Date_5"; var birthday = "2005-5-5 05:05:05".ToDateTime(); var minBirthday = "2005-5-6".ToDateTime(); //添加实体列表 - AddCustomers(); + await AddCustomersAsync(); var customers = CustomerFakeService.GetCustomers( 5 ); customers.ForEach( customer => { customer.Nickname = name; @@ -445,16 +431,16 @@ namespace Util.Data.EntityFrameworkCore.Tests { customer.Birthday = birthday; birthday = birthday.AddDays( 1 ); } ); - _repository.Add( customers ); - UnitOfWork.Commit(); + await _repository.AddAsync( customers ); + await UnitOfWork.CommitAsync(); UnitOfWork.ClearCache(); //查询 - var result = _repository.Find() + var result = await _repository.Find() .Where( t => t.Name == name ) .Between( t => t.Birthday, minBirthday, null, false ) .OrderBy( t => t.Birthday ) - .ToList(); + .ToListAsync(); //验证 Assert.Equal( 4, result.Count ); @@ -465,29 +451,29 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试添加范围查询条件 - 日期不带时间 - 最小值为空 /// [Fact] - public void TestBetween_Date_6() { + public async Task TestBetween_Date_6() { //常量 var name = "TestBetween_Date_6"; var birthday = "2005-5-5 05:05:05".ToDateTime(); var maxBirthday = "2005-5-8".ToDateTime(); //添加实体列表 - AddCustomers(); + await AddCustomersAsync(); var customers = CustomerFakeService.GetCustomers( 5 ); customers.ForEach( customer => { customer.Name = name; customer.Birthday = birthday; birthday = birthday.AddDays( 1 ); } ); - _repository.Add( customers ); - UnitOfWork.Commit(); + await _repository.AddAsync( customers ); + await UnitOfWork.CommitAsync(); UnitOfWork.ClearCache(); //查询 - var result = _repository.Find() + var result = await _repository.Find() .Where( t => t.Name == name ) .Between( t => t.Birthday, null, maxBirthday, false ) - .ToList(); + .ToListAsync(); //验证 Assert.Equal( 4, result.Count ); @@ -501,15 +487,15 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试获取分页列表 /// [Fact] - public void TestToPageList_1() { + public async Task TestToPageList_1() { //常量 var name = "TestToPageList_1"; //添加实体列表 - var customers = AddCustomers( 10, name ); + var customers = await AddCustomersAsync( 10, name ); //创建查询参数 - var parameter = new QueryParameter { PageSize = 3, Page = 1,Order = "Code" }; + var parameter = new QueryParameter { PageSize = 3, Page = 1, Order = "Code" }; //查询 var result = _repository.Find().Where( t => t.Name == name ).ToPageList( parameter ); @@ -529,12 +515,12 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试获取分页列表 - 第二页 /// [Fact] - public void TestToPageList_2() { + public async Task TestToPageList_2() { //常量 var name = "TestToPageList_2"; //添加实体列表 - var customers = AddCustomers( 10, name ); + var customers = await AddCustomersAsync( 10, name ); //创建查询参数 var parameter = new QueryParameter { PageSize = 3, Page = 2, Order = "Code" }; @@ -557,12 +543,12 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试获取分页列表 - Queryable设置排序 /// [Fact] - public void TestToPageList_3() { + public async Task TestToPageList_3() { //常量 var name = "TestToPageList_3"; //添加实体列表 - var customers = AddCustomers( 10, name ); + var customers = await AddCustomersAsync( 10, name ); //创建查询参数 var parameter = new QueryParameter { PageSize = 3, Page = 2 }; diff --git a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Tests/EntityEventsTest.cs b/test/Util.Data.EntityFrameworkCore.MySql.Tests.Integration/Tests/EntityEventsTest.cs similarity index 51% rename from test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Tests/EntityEventsTest.cs rename to test/Util.Data.EntityFrameworkCore.MySql.Tests.Integration/Tests/EntityEventsTest.cs index aa33e98c..b4e62e8c 100644 --- a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Tests/EntityEventsTest.cs +++ b/test/Util.Data.EntityFrameworkCore.MySql.Tests.Integration/Tests/EntityEventsTest.cs @@ -1,8 +1,9 @@ -using Util.Data.EntityFrameworkCore.EventHandlers; -using Util.Data.EntityFrameworkCore.Fakes; -using Util.Data.EntityFrameworkCore.Infrastructure; -using Util.Data.EntityFrameworkCore.Repositories; -using Util.Data.EntityFrameworkCore.UnitOfWorks; +using System.Threading.Tasks; +using Util.Tests.EventHandlers; +using Util.Tests.Fakes; +using Util.Tests.Infrastructure; +using Util.Tests.Repositories; +using Util.Tests.UnitOfWorks; using Xunit; using Xunit.Abstractions; @@ -31,7 +32,7 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试初始化 /// public EntityEventsTest( ITestOutputHelper testOutputHelper, IProductRepository productRepository, - IOperationLogRepository operationLogRepository,ISqlServerUnitOfWork unitOfWork ) :base(unitOfWork){ + IOperationLogRepository operationLogRepository, ITestUnitOfWork unitOfWork ) :base(unitOfWork){ _testOutputHelper = testOutputHelper; _productRepository = productRepository; _operationLogRepository = operationLogRepository; @@ -45,32 +46,32 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试实体创建事件 /// [Fact] - public void TestEntityCreatedEvent() { + public async Task TestEntityCreatedEvent() { //添加实体 var entity = ProductFakeService.GetProduct(); entity.Init(); entity.Name = "EntityCreatedEvent"; - _productRepository.Add( entity ); - UnitOfWork.Commit(); + await _productRepository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); //验证 - Assert.True( _operationLogRepository.Exists( t => t.Caption == "EntityCreatedEvent" && t.LogName == nameof( ProductCreatedEventHandler ) ) ); + Assert.True( await _operationLogRepository.ExistsAsync( t => t.Caption == "EntityCreatedEvent" && t.LogName == nameof( ProductCreatedEventHandler ) ) ); } /// /// 测试实体变更事件 - 创建 /// [Fact] - public void TestEntityChangedEvent_Created() { + public async Task TestEntityChangedEvent_Created() { //添加实体 var entity = ProductFakeService.GetProduct(); entity.Init(); entity.Name = "EntityChangedEvent_Created"; - _productRepository.Add( entity ); - UnitOfWork.Commit(); + await _productRepository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); //验证 - Assert.True( _operationLogRepository.Exists( t => t.Caption == "EntityChangedEvent_Created" && t.LogName == nameof( ProductChangedEventHandler ) ) ); + Assert.True( await _operationLogRepository.ExistsAsync( t => t.Caption == "EntityChangedEvent_Created" && t.LogName == nameof( ProductChangedEventHandler ) ) ); } #endregion @@ -81,44 +82,44 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试实体修改事件 /// [Fact] - public void TestEntityUpdatedEvent() { + public async Task TestEntityUpdatedEvent() { //添加实体 var entity = ProductFakeService.GetProduct(); entity.Init(); - _productRepository.Add( entity ); - UnitOfWork.Commit(); + await _productRepository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); UnitOfWork.ClearCache(); //修改实体 - var product = _productRepository.FindById( entity.Id ); + var product = await _productRepository.FindByIdAsync( entity.Id ); product.Name = "EntityUpdatedEvent"; - _productRepository.Update( product ); - UnitOfWork.Commit(); + await _productRepository.UpdateAsync( product ); + await UnitOfWork.CommitAsync(); //验证 - Assert.True( _operationLogRepository.Exists( t => t.Caption == "EntityUpdatedEvent" && t.LogName == nameof( ProductUpdatedEventHandler ) ) ); + Assert.True( await _operationLogRepository.ExistsAsync( t => t.Caption == "EntityUpdatedEvent" && t.LogName == nameof( ProductUpdatedEventHandler ) ) ); } /// /// 测试实体变更事件 - 修改 /// [Fact] - public void TestEntityChangedEvent_Updated() { + public async Task TestEntityChangedEvent_Updated() { //添加实体 var entity = ProductFakeService.GetProduct(); entity.Init(); - _productRepository.Add( entity ); - UnitOfWork.Commit(); + await _productRepository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); UnitOfWork.ClearCache(); //修改实体 var product = _productRepository.FindById( entity.Id ); product.Name = "EntityChangedEvent_Updated"; - _productRepository.Update( product ); - UnitOfWork.Commit(); + await _productRepository.UpdateAsync( product ); + await UnitOfWork.CommitAsync(); //验证 - Assert.True( _operationLogRepository.Exists( t => t.Caption == "EntityChangedEvent_Updated" && t.LogName == nameof( ProductChangedEventHandler ) ) ); + Assert.True( await _operationLogRepository.ExistsAsync( t => t.Caption == "EntityChangedEvent_Updated" && t.LogName == nameof( ProductChangedEventHandler ) ) ); } #endregion @@ -129,80 +130,80 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试实体删除事件 - 逻辑删除 /// [Fact] - public void TestEntityDeletedEvent_1() { + public async Task TestEntityDeletedEvent_1() { //添加实体 var entity = ProductFakeService.GetProduct(); entity.Init(); entity.Name = "EntityDeletedEvent"; - _productRepository.Add( entity ); - UnitOfWork.Commit(); + await _productRepository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); //删除实体 - _productRepository.Remove( entity ); - UnitOfWork.Commit(); + await _productRepository.RemoveAsync( entity ); + await UnitOfWork.CommitAsync(); //验证 - Assert.True( _operationLogRepository.Exists( t => t.Caption == "EntityDeletedEvent" && t.LogName == nameof( ProductDeletedEventHandler ) ) ); + Assert.True( await _operationLogRepository.ExistsAsync( t => t.Caption == "EntityDeletedEvent" && t.LogName == nameof( ProductDeletedEventHandler ) ) ); } /// /// 测试实体删除事件 - 物理删除 /// [Fact] - public void TestEntityDeletedEvent_2() { + public async Task TestEntityDeletedEvent_2() { //添加实体 var entity = OperationLogFakeService.GetOperationLog(); entity.Init(); entity.LogName = "EntityDeletedEvent"; - _operationLogRepository.Add( entity ); - UnitOfWork.Commit(); + await _operationLogRepository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); //删除实体 - _operationLogRepository.Remove( entity ); - UnitOfWork.Commit(); + await _operationLogRepository.RemoveAsync( entity ); + await UnitOfWork.CommitAsync(); //验证 - Assert.True( _operationLogRepository.Exists( t => t.LogName == "Test" && t.Caption == nameof( OperationLogDeletedEventHandler ) && t.Content == "EntityDeletedEvent" ) ); + Assert.True( await _operationLogRepository.ExistsAsync( t => t.LogName == "Test" && t.Caption == nameof( OperationLogDeletedEventHandler ) && t.Content == "EntityDeletedEvent" ) ); } /// /// 测试实体变更事件 - 逻辑删除 /// [Fact] - public void TestEntityChangedEvent_Deleted_1() { + public async Task TestEntityChangedEvent_Deleted_1() { //添加实体 var entity = ProductFakeService.GetProduct(); entity.Init(); entity.Name = "EntityChangedEvent_Deleted"; - _productRepository.Add( entity ); - UnitOfWork.Commit(); + await _productRepository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); //删除实体 - _productRepository.Remove( entity ); - UnitOfWork.Commit(); + await _productRepository.RemoveAsync( entity ); + await UnitOfWork.CommitAsync(); //验证 - Assert.True( _operationLogRepository.Exists( t => t.Caption == "EntityChangedEvent_Deleted" && t.LogName == nameof( ProductChangedEventHandler ) ) ); + Assert.True( await _operationLogRepository.ExistsAsync( t => t.Caption == "EntityChangedEvent_Deleted" && t.LogName == nameof( ProductChangedEventHandler ) ) ); } /// /// 测试实体变更事件 - 物理删除 /// [Fact] - public void TestEntityChangedEvent_Deleted_2() { + public async Task TestEntityChangedEvent_Deleted_2() { //添加实体 var entity = OperationLogFakeService.GetOperationLog(); entity.Init(); entity.LogName = "EntityChangedEvent_Deleted"; - _operationLogRepository.Add( entity ); - UnitOfWork.Commit(); + await _operationLogRepository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); //删除实体 - _operationLogRepository.Remove( entity ); - UnitOfWork.Commit(); + await _operationLogRepository.RemoveAsync( entity ); + await UnitOfWork.CommitAsync(); //验证 - Assert.True( _operationLogRepository.Exists( t => t.LogName == "Test" && t.Caption == nameof( OperationLogChangedEventHandler ) && t.Content == "EntityChangedEvent_Deleted" ) ); + Assert.True( await _operationLogRepository.ExistsAsync( t => t.LogName == "Test" && t.Caption == nameof( OperationLogChangedEventHandler ) && t.Content == "EntityChangedEvent_Deleted" ) ); } #endregion diff --git a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Tests/OperationLogRepositoryTest.cs b/test/Util.Data.EntityFrameworkCore.MySql.Tests.Integration/Tests/OperationLogRepositoryTest.cs similarity index 65% rename from test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Tests/OperationLogRepositoryTest.cs rename to test/Util.Data.EntityFrameworkCore.MySql.Tests.Integration/Tests/OperationLogRepositoryTest.cs index 093602fa..fecbccb7 100644 --- a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Tests/OperationLogRepositoryTest.cs +++ b/test/Util.Data.EntityFrameworkCore.MySql.Tests.Integration/Tests/OperationLogRepositoryTest.cs @@ -1,7 +1,8 @@ -using Util.Data.EntityFrameworkCore.Fakes; -using Util.Data.EntityFrameworkCore.Infrastructure; -using Util.Data.EntityFrameworkCore.Repositories; -using Util.Data.EntityFrameworkCore.UnitOfWorks; +using System.Threading.Tasks; +using Util.Tests.Fakes; +using Util.Tests.Infrastructure; +using Util.Tests.Repositories; +using Util.Tests.UnitOfWorks; using Xunit; namespace Util.Data.EntityFrameworkCore.Tests { @@ -19,7 +20,7 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// /// 测试初始化 /// - public OperationLogRepositoryTest( IOperationLogRepository operationLogRepository, ISqlServerUnitOfWork unitOfWork ) : base( unitOfWork ) { + public OperationLogRepositoryTest( IOperationLogRepository operationLogRepository, ITestUnitOfWork unitOfWork ) : base( unitOfWork ) { _repository = operationLogRepository; } @@ -27,11 +28,11 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试添加实体 /// [Fact] - public void TestAdd() { + public async Task TestAdd() { //添加实体 var entity = OperationLogFakeService.GetOperationLog(); - _repository.Add( entity ); - UnitOfWork.Commit(); + await _repository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); //验证 Assert.True( entity.Id > 0 ); @@ -42,20 +43,20 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试通过标识移除实体 - 物理删除 /// [Fact] - public void TestRemove_Id() { + public async Task TestRemove_Id() { //添加实体 var entity = OperationLogFakeService.GetOperationLog(); - _repository.Add( entity ); - UnitOfWork.Commit(); + await _repository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); UnitOfWork.ClearCache(); //移除实体 - _repository.Remove( entity.Id ); - UnitOfWork.Commit(); + await _repository.RemoveAsync( entity.Id ); + await UnitOfWork.CommitAsync(); UnitOfWork.ClearCache(); //验证 - var result = _repository.FindById( entity.Id ); + var result = await _repository.FindByIdAsync( entity.Id ); Assert.Null( result ); } } diff --git a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Tests/OrderRepositoryTest.cs b/test/Util.Data.EntityFrameworkCore.MySql.Tests.Integration/Tests/OrderRepositoryTest.cs similarity index 73% rename from test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Tests/OrderRepositoryTest.cs rename to test/Util.Data.EntityFrameworkCore.MySql.Tests.Integration/Tests/OrderRepositoryTest.cs index 8cf5daa7..076b5bd1 100644 --- a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Tests/OrderRepositoryTest.cs +++ b/test/Util.Data.EntityFrameworkCore.MySql.Tests.Integration/Tests/OrderRepositoryTest.cs @@ -1,10 +1,10 @@ using System.Threading.Tasks; using Microsoft.EntityFrameworkCore; -using Util.Data.EntityFrameworkCore.Fakes; -using Util.Data.EntityFrameworkCore.Infrastructure; -using Util.Data.EntityFrameworkCore.Models; -using Util.Data.EntityFrameworkCore.Repositories; -using Util.Data.EntityFrameworkCore.UnitOfWorks; +using Util.Tests.Fakes; +using Util.Tests.Infrastructure; +using Util.Tests.Models; +using Util.Tests.Repositories; +using Util.Tests.UnitOfWorks; using Xunit; namespace Util.Data.EntityFrameworkCore.Tests { @@ -26,7 +26,7 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// /// 测试初始化 /// - public OrderRepositoryTest( IOrderRepository repository,ISqlServerUnitOfWork unitOfWork ) : base( unitOfWork ) { + public OrderRepositoryTest( IOrderRepository repository, ITestUnitOfWork unitOfWork ) : base( unitOfWork ) { _repository = repository; } @@ -34,29 +34,6 @@ namespace Util.Data.EntityFrameworkCore.Tests { #region 辅助方法 - /// - /// 添加订单 - /// - private Order AddOrder() { - var order = OrderFakeService.GetOrder(); - order.Init(); - order.OrderItems.Add( CreateOrderItem() ); - order.OrderItems.Add( CreateOrderItem() ); - _repository.Add( order ); - UnitOfWork.Commit(); - UnitOfWork.ClearCache(); - return order; - } - - /// - /// 创建订单项 - /// - private OrderItem CreateOrderItem() { - var item = OrderItemFakeService.GetOrderItem(); - item.Init(); - return item; - } - /// /// 添加订单 /// @@ -71,6 +48,15 @@ namespace Util.Data.EntityFrameworkCore.Tests { return order; } + /// + /// 创建订单项 + /// + private OrderItem CreateOrderItem() { + var item = OrderItemFakeService.GetOrderItem(); + item.Init(); + return item; + } + #endregion #region Single @@ -79,12 +65,12 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试查找单个实体 /// [Fact] - public void TestSingle_1() { + public async Task TestSingle_1() { //添加实体 - var entity = AddOrder(); + var entity = await AddOrderAsync(); //查找单个实体 - var result = _repository.Single( t => t.Id == entity.Id ); + var result = await _repository.SingleAsync( t => t.Id == entity.Id ); //验证 Assert.Empty( result.OrderItems ); @@ -94,12 +80,12 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试查找单个实体 - 使用Include包含子实体集合 /// [Fact] - public void TestSingle_2() { + public async Task TestSingle_2() { //添加实体 - var entity = AddOrder(); + var entity = await AddOrderAsync(); //查找单个实体 - var result = _repository.Single( t => t.Id == entity.Id, queryable => queryable.Include( t => t.OrderItems ) ); + var result = await _repository.SingleAsync( t => t.Id == entity.Id, queryable => queryable.Include( t => t.OrderItems ) ); //验证 Assert.Equal( 2, result.OrderItems.Count ); diff --git a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Tests/PostRepositoryTest.cs b/test/Util.Data.EntityFrameworkCore.MySql.Tests.Integration/Tests/PostRepositoryTest.cs similarity index 81% rename from test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Tests/PostRepositoryTest.cs rename to test/Util.Data.EntityFrameworkCore.MySql.Tests.Integration/Tests/PostRepositoryTest.cs index 6c4e8c20..c238dde1 100644 --- a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Tests/PostRepositoryTest.cs +++ b/test/Util.Data.EntityFrameworkCore.MySql.Tests.Integration/Tests/PostRepositoryTest.cs @@ -1,9 +1,9 @@ using System.Threading.Tasks; using Microsoft.EntityFrameworkCore; -using Util.Data.EntityFrameworkCore.Fakes; -using Util.Data.EntityFrameworkCore.Infrastructure; -using Util.Data.EntityFrameworkCore.Repositories; -using Util.Data.EntityFrameworkCore.UnitOfWorks; +using Util.Tests.Fakes; +using Util.Tests.Infrastructure; +using Util.Tests.Repositories; +using Util.Tests.UnitOfWorks; using Xunit; namespace Util.Data.EntityFrameworkCore.Tests { @@ -21,7 +21,7 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// /// 测试初始化 /// - public PostRepositoryTest(IPostRepository repository, IPgSqlUnitOfWork unitOfWork ) : base(unitOfWork){ + public PostRepositoryTest(IPostRepository repository, ITestUnitOfWork unitOfWork ) : base(unitOfWork){ _repository = repository; } diff --git a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Tests/ProductRepositoryTest.Queryable.cs b/test/Util.Data.EntityFrameworkCore.MySql.Tests.Integration/Tests/ProductRepositoryTest.Queryable.cs similarity index 78% rename from test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Tests/ProductRepositoryTest.Queryable.cs rename to test/Util.Data.EntityFrameworkCore.MySql.Tests.Integration/Tests/ProductRepositoryTest.Queryable.cs index bbd31de8..e03ea9c5 100644 --- a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Tests/ProductRepositoryTest.Queryable.cs +++ b/test/Util.Data.EntityFrameworkCore.MySql.Tests.Integration/Tests/ProductRepositoryTest.Queryable.cs @@ -1,8 +1,9 @@ using System; using System.Linq; -using Util.Data.EntityFrameworkCore.Conditions; -using Util.Data.EntityFrameworkCore.Fakes; +using System.Threading.Tasks; using Util.Data.Queries; +using Util.Tests.Conditions; +using Util.Tests.Fakes; using Xunit; namespace Util.Data.EntityFrameworkCore.Tests { @@ -17,13 +18,13 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试设置查询条件 - 添加查询条件对象 /// [Fact] - public void TestWhere() { + public async Task TestWhere() { //常量 var name = "TestWhere"; //添加实体列表 - AddProducts(); - var products = AddProducts( name: name ); + await AddProductsAsync(); + var products = await AddProductsAsync( name: name ); //创建查询条件 var condition = new ProductNameCondition( name ); @@ -44,13 +45,13 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试设置查询条件 - IQueryable添加WhereIf扩展 - true /// [Fact] - public void TestWhereIf_True() { + public async Task TestWhereIf_True() { //常量 var name = "TestWhereIf_True"; //添加实体列表 - AddProducts(); - var products = AddProducts( name: name ); + await AddProductsAsync(); + var products = await AddProductsAsync( name: name ); //查询 var result = _repository.Find().WhereIf( t => t.Name == name, true ).ToList(); @@ -63,13 +64,13 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试设置查询条件 - IQueryable添加WhereIf扩展 - false /// [Fact] - public void TestWhereIf_False() { + public async Task TestWhereIf_False() { //常量 var name = "TestWhereIf_False"; //添加实体列表 - AddProducts(); - var products = AddProducts( name: name ); + await AddProductsAsync(); + var products = await AddProductsAsync( name: name ); //查询 var result = _repository.Find().WhereIf( t => t.Name == name, false ).ToList(); @@ -86,13 +87,13 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试设置查询条件 - IQueryable添加WhereIfNotEmpty扩展 - 有效条件 /// [Fact] - public void TestWhereIfNotEmpty_Valid() { + public async Task TestWhereIfNotEmpty_Valid() { //常量 var name = "TestWhereIfNotEmpty_Valid"; //添加实体列表 - AddProducts(); - var products = AddProducts( name: name ); + await AddProductsAsync(); + var products = await AddProductsAsync( name: name ); //查询 var result = _repository.Find().WhereIfNotEmpty( t => t.Name == name ).ToList(); @@ -105,13 +106,13 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试设置查询条件 - IQueryable添加WhereIfNotEmpty扩展 - 忽略条件 /// [Fact] - public void TestWhereIfNotEmpty_Ignore() { + public async Task TestWhereIfNotEmpty_Ignore() { //常量 var name = "TestWhereIfNotEmpty_Ignore"; //添加实体列表 - AddProducts(); - var products = AddProducts( name: name ); + await AddProductsAsync(); + var products = await AddProductsAsync( name: name ); //查询 var result = _repository.Find().Where( t => t.Name == name ).WhereIfNotEmpty( t => t.Code == "" ).ToList(); @@ -124,9 +125,9 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试设置查询条件 - IQueryable添加WhereIfNotEmpty扩展 - 无效条件,抛出异常 /// [Fact] - public void TestWhereIfNotEmpty_Invalid() { + public async Task TestWhereIfNotEmpty_Invalid() { //添加实体列表 - AddProducts(); + await AddProductsAsync(); //查询 Assert.Throws( () => { @@ -142,17 +143,17 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试设置查询条件 - IQueryable添加OrIfNotEmpty扩展 - 有效条件 /// [Fact] - public void TestOrIfNotEmpty_Valid() { + public async Task TestOrIfNotEmpty_Valid() { //常量 var name1 = "TestOrIfNotEmpty_Valid_1"; var name2 = "TestOrIfNotEmpty_Valid_2"; var name3 = "TestOrIfNotEmpty_Valid_3"; //添加实体列表 - AddProducts(); - AddProducts( 2, name1 ); - AddProducts( 3, name2 ); - AddProducts( 4, name3 ); + await AddProductsAsync(); + await AddProductsAsync( 2, name1 ); + await AddProductsAsync( 3, name2 ); + await AddProductsAsync( 4, name3 ); //查询 var result = _repository.Find().OrIfNotEmpty( t => t.Name == name1,t => t.Name == name2, t => t.Name == name3 ).ToList(); @@ -165,17 +166,17 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试设置查询条件 - IQueryable添加OrIfNotEmpty扩展 - 忽略条件 /// [Fact] - public void TestOrIfNotEmpty_Ignore() { + public async Task TestOrIfNotEmpty_Ignore() { //常量 var name1 = "TestOrIfNotEmpty_Ignore_1"; var name2 = "TestOrIfNotEmpty_Ignore_2"; var name3 = "TestOrIfNotEmpty_Ignore_3"; //添加实体列表 - AddProducts(); - AddProducts( 2, name1 ); - AddProducts( 3, name2 ); - AddProducts( 4, name3 ); + await AddProductsAsync(); + await AddProductsAsync( 2, name1 ); + await AddProductsAsync( 3, name2 ); + await AddProductsAsync( 4, name3 ); //查询 var result = _repository.Find().OrIfNotEmpty( t => t.Name == name1, t => t.Name == name2, t => t.Name == "" ).ToList(); @@ -192,21 +193,21 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试添加范围查询条件 /// [Fact] - public void TestBetween_1() { + public async Task TestBetween_1() { //常量 var name = "TestBetween_1"; var price = 10.1M; //添加实体列表 - AddProducts(); + await AddProductsAsync(); var products = ProductFakeService.GetProducts( 5 ); products.ForEach( product => { product.Init(); product.Name = name; product.Price = price++; } ); - _repository.Add( products ); - UnitOfWork.Commit(); + await _repository.AddAsync( products ); + await UnitOfWork.CommitAsync(); UnitOfWork.ClearCache(); //查询 @@ -220,21 +221,21 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试添加范围查询条件 - 包含左边界 /// [Fact] - public void TestBetween_2() { + public async Task TestBetween_2() { //常量 var name = "TestBetween_2"; var price = 10.1M; //添加实体列表 - AddProducts(); + await AddProductsAsync(); var products = ProductFakeService.GetProducts( 5 ); products.ForEach( product => { product.Init(); product.Name = name; product.Price = price++; } ); - _repository.Add( products ); - UnitOfWork.Commit(); + await _repository.AddAsync( products ); + await UnitOfWork.CommitAsync(); UnitOfWork.ClearCache(); //查询 @@ -248,21 +249,21 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试添加范围查询条件 - 包含右边界 /// [Fact] - public void TestBetween_3() { + public async Task TestBetween_3() { //常量 var name = "TestBetween_3"; var price = 10.1M; //添加实体列表 - AddProducts(); + await AddProductsAsync(); var products = ProductFakeService.GetProducts( 5 ); products.ForEach( product => { product.Init(); product.Name = name; product.Price = price++; } ); - _repository.Add( products ); - UnitOfWork.Commit(); + await _repository.AddAsync( products ); + await UnitOfWork.CommitAsync(); UnitOfWork.ClearCache(); //查询 @@ -276,21 +277,21 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试添加范围查询条件 - 包含两边 /// [Fact] - public void TestBetween_4() { + public async Task TestBetween_4() { //常量 var name = "TestBetween_4"; var price = 10.1M; //添加实体列表 - AddProducts(); + await AddProductsAsync(); var products = ProductFakeService.GetProducts( 5 ); products.ForEach( product => { product.Init(); product.Name = name; product.Price = price++; } ); - _repository.Add( products ); - UnitOfWork.Commit(); + await _repository.AddAsync( products ); + await UnitOfWork.CommitAsync(); UnitOfWork.ClearCache(); //查询 @@ -304,21 +305,21 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试添加范围查询条件 - 不包含边界 /// [Fact] - public void TestBetween_5() { + public async Task TestBetween_5() { //常量 var name = "TestBetween_5"; var price = 10.1M; //添加实体列表 - AddProducts(); + await AddProductsAsync(); var products = ProductFakeService.GetProducts( 5 ); products.ForEach( product => { product.Init(); product.Name = name; product.Price = price++; } ); - _repository.Add( products ); - UnitOfWork.Commit(); + await _repository.AddAsync( products ); + await UnitOfWork.CommitAsync(); UnitOfWork.ClearCache(); //查询 @@ -332,21 +333,21 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试添加范围查询条件 - 最大值为空 /// [Fact] - public void TestBetween_6() { + public async Task TestBetween_6() { //常量 var name = "TestBetween_6"; var price = 10.1M; //添加实体列表 - AddProducts(); + await AddProductsAsync(); var products = ProductFakeService.GetProducts( 5 ); products.ForEach( product => { product.Init(); product.Name = name; product.Price = price++; } ); - _repository.Add( products ); - UnitOfWork.Commit(); + await _repository.AddAsync( products ); + await UnitOfWork.CommitAsync(); UnitOfWork.ClearCache(); //查询 @@ -360,21 +361,21 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试添加范围查询条件 - 最小值为空 /// [Fact] - public void TestBetween_7() { + public async Task TestBetween_7() { //常量 var name = "TestBetween_7"; var price = 10.1M; //添加实体列表 - AddProducts(); + await AddProductsAsync(); var products = ProductFakeService.GetProducts( 5 ); products.ForEach( product => { product.Init(); product.Name = name; product.Price = price++; } ); - _repository.Add( products ); - UnitOfWork.Commit(); + await _repository.AddAsync( products ); + await UnitOfWork.CommitAsync(); UnitOfWork.ClearCache(); //查询 diff --git a/test/Util.Data.EntityFrameworkCore.MySql.Tests.Integration/Tests/ProductRepositoryTest.cs b/test/Util.Data.EntityFrameworkCore.MySql.Tests.Integration/Tests/ProductRepositoryTest.cs new file mode 100644 index 00000000..c7a31428 --- /dev/null +++ b/test/Util.Data.EntityFrameworkCore.MySql.Tests.Integration/Tests/ProductRepositoryTest.cs @@ -0,0 +1,1408 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Util.Exceptions; +using Util.Tests.Fakes; +using Util.Tests.Infrastructure; +using Util.Tests.Models; +using Util.Tests.Repositories; +using Util.Tests.UnitOfWorks; +using Xunit; +using Xunit.Abstractions; +using Xunit.DependencyInjection; + +namespace Util.Data.EntityFrameworkCore.Tests { + /// + /// 产品仓储测试 + /// 说明: + /// 1. 测试Guid类型标识 + /// 2. 测试仓储基础方法 + /// 3. 测试扩展属性 + /// + public partial class ProductRepositoryTest : TestBase { + + #region 测试初始化 + + /// + /// 日志消息 + /// + private readonly ITestOutputHelper _log; + /// + /// 仓储 + /// + private readonly IProductRepository _repository; + + /// + /// 测试初始化 + /// + public ProductRepositoryTest( ITestOutputHelperAccessor accessor, IProductRepository repository, ITestUnitOfWork unitOfWork ) :base(unitOfWork) { + _log = accessor.Output; + _repository = repository; + } + + #endregion + + #region 辅助方法 + + /// + /// 添加产品 + /// + private async Task AddProductAsync( string name = null ) { + var entity = ProductFakeService.GetProduct(); + entity.Init(); + if( name != null ) + entity.Name = name; + await _repository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); + return entity; + } + + /// + /// 添加实体列表 + /// + /// 添加数量 + /// 产品名称 + private async Task> AddProductsAsync( int count = 2, string name = null ) { + var products = ProductFakeService.GetProducts( count ); + products.ForEach( product => { + product.Init(); + if( name != null ) + product.Name = name; + } ); + await _repository.AddAsync( products ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + return products.OrderBy( t => t.Id ).ToList(); + } + + /// + /// 打印更改跟踪调试信息 + /// + private void WriteTrackerDebug() { + _log.WriteLine( UnitOfWork.GetChangeTrackerDebugView() ); + } + + #endregion + + #region FindById + + /// + /// 测试通过标识查找实体 - 跟踪实体 + /// + [Fact] + public async Task TestFindById_Tracking_1() { + //添加实体 + var entity = await AddProductAsync(); + UnitOfWork.ClearCache(); + + //验证 + var result = _repository.FindById( entity.Id ); + WriteTrackerDebug(); + Assert.Equal( entity.Code, result.Code ); + } + + /// + /// 测试通过标识查找实体 - 跟踪实体 - 字符串标识 + /// + [Fact] + public async Task TestFindById_Tracking_2() { + //添加实体 + var entity = await AddProductAsync(); + UnitOfWork.ClearCache(); + + //验证 + var result = _repository.FindById( entity.Id.ToString() ); + WriteTrackerDebug(); + Assert.Equal( entity.Code, result.Code ); + } + + /// + /// 测试通过标识查找实体 - 不跟踪实体 + /// + [Fact] + public async Task TestFindById_NoTracking() { + //添加实体 + var entity = await AddProductAsync(); + UnitOfWork.ClearCache(); + + //验证 + var result = _repository.NoTracking().FindById( entity.Id ); + WriteTrackerDebug(); + Assert.Equal( entity.Code, result.Code ); + } + + #endregion + + #region FindByIdAsync + + /// + /// 测试通过标识查找实体 - 跟踪 - 异步 + /// + [Fact] + public async Task TestFindByIdAsync_Tracking_1() { + //添加实体 + var entity = await AddProductAsync(); + UnitOfWork.ClearCache(); + + //验证 + var result = await _repository.FindByIdAsync( entity.Id ); + WriteTrackerDebug(); + Assert.Equal( entity.Code, result.Code ); + } + + /// + /// 测试通过标识查找实体 - 跟踪 - 异步 - 字符串标识 + /// + [Fact] + public async Task TestFindByIdAsync_Tracking_2() { + //添加实体 + var entity = await AddProductAsync(); + UnitOfWork.ClearCache(); + + //验证 + var result = await _repository.FindByIdAsync( entity.Id.ToString() ); + WriteTrackerDebug(); + Assert.Equal( entity.Code, result.Code ); + } + + /// + /// 测试通过标识查找实体 - 不跟踪 - 异步 + /// + [Fact] + public async Task TestFindByIdAsync_NoTracking() { + //添加实体 + var entity = await AddProductAsync(); + UnitOfWork.ClearCache(); + + //验证 + var result = await _repository.NoTracking().FindByIdAsync( entity.Id ); + WriteTrackerDebug(); + Assert.Equal( entity.Code, result.Code ); + } + + #endregion + + #region FindByIds + + /// + /// 测试通过标识列表查找实体列表 - 传入逗号分隔的标识列表 + /// + [Fact] + public async Task TestFindByIds_1() { + //常量 + var count = 3; + + //添加实体列表 + var products = ProductFakeService.GetProducts( count ).OrderBy( t => t.Code ).ToList(); + products.ForEach( product => { + product.Init(); + } ); + await _repository.AddAsync( products ); + await UnitOfWork.CommitAsync(); + + //验证 + var result = _repository.FindByIds( products[0].Id, products[1].Id, products[2].Id ).OrderBy( t => t.Code ).ToList(); + Assert.Equal( products[0].Description, result[0].Description ); + Assert.Equal( products[1].Description, result[1].Description ); + Assert.Equal( products[2].Description, result[2].Description ); + } + + /// + /// 测试通过标识列表查找实体列表 - 传入集合 + /// + [Fact] + public async Task TestFindByIds_2() { + //常量 + var count = 3; + + //添加实体列表 + var products = ProductFakeService.GetProducts( count ).OrderBy( t => t.Code ).ToList(); + products.ForEach( product => { + product.Init(); + } ); + await _repository.AddAsync( products ); + await UnitOfWork.CommitAsync(); + + //验证 + var result = _repository.FindByIds( products.Select( t => t.Id ) ).OrderBy( t => t.Code ).ToList(); + Assert.Equal( products[0].Description, result[0].Description ); + Assert.Equal( products[1].Description, result[1].Description ); + Assert.Equal( products[2].Description, result[2].Description ); + } + + /// + /// 测试通过标识列表查找实体列表 - 传入标识列表字符串 + /// + [Fact] + public async Task TestFindByIds_3() { + //常量 + var count = 3; + + //添加实体列表 + var products = ProductFakeService.GetProducts( count ).OrderBy( t => t.Code ).ToList(); + products.ForEach( product => { + product.Init(); + } ); + await _repository.AddAsync( products ); + await UnitOfWork.CommitAsync(); + + //验证 + var result = _repository.FindByIds( products.Select( t => t.Id ).Join() ).OrderBy( t => t.Code ).ToList(); + Assert.Equal( products[0].Description, result[0].Description ); + Assert.Equal( products[1].Description, result[1].Description ); + Assert.Equal( products[2].Description, result[2].Description ); + } + + #endregion + + #region FindByIdsAsync + + /// + /// 测试通过标识列表查找实体列表 - 传入逗号分隔的标识列表 - 异步 + /// + [Fact] + public async Task TestFindByIdsAsync_1() { + //常量 + var count = 3; + + //添加实体列表 + var products = ProductFakeService.GetProducts( count ).OrderBy( t => t.Code ).ToList(); + products.ForEach( product => { + product.Init(); + } ); + await _repository.AddAsync( products ); + await UnitOfWork.CommitAsync(); + + //验证 + var result = ( await _repository.FindByIdsAsync( products[0].Id, products[1].Id, products[2].Id ) ).OrderBy( t => t.Code ).ToList(); + Assert.Equal( products[0].Description, result[0].Description ); + Assert.Equal( products[1].Description, result[1].Description ); + Assert.Equal( products[2].Description, result[2].Description ); + } + + /// + /// 测试通过标识列表查找实体列表 - 传入集合 - 异步 + /// + [Fact] + public async Task TestFindByIdsAsync_2() { + //常量 + var count = 3; + + //添加实体列表 + var products = ProductFakeService.GetProducts( count ).OrderBy( t => t.Code ).ToList(); + products.ForEach( product => { + product.Init(); + } ); + await _repository.AddAsync( products ); + await UnitOfWork.CommitAsync(); + + //验证 + var result = ( await _repository.FindByIdsAsync( products.Select( t => t.Id ) ) ).OrderBy( t => t.Code ).ToList(); + Assert.Equal( products[0].Description, result[0].Description ); + Assert.Equal( products[1].Description, result[1].Description ); + Assert.Equal( products[2].Description, result[2].Description ); + } + + /// + /// 测试通过标识列表查找实体列表 - 传入标识列表字符串 - 异步 + /// + [Fact] + public async Task TestFindByIdsAsync_3() { + //常量 + var count = 3; + + //添加实体列表 + var products = ProductFakeService.GetProducts( count ).OrderBy( t => t.Code ).ToList(); + products.ForEach( product => { + product.Init(); + } ); + await _repository.AddAsync( products ); + await UnitOfWork.CommitAsync(); + + //验证 + var result = ( await _repository.FindByIdsAsync( products.Select( t => t.Id ).Join() ) ).OrderBy( t => t.Code ).ToList(); + Assert.Equal( products[0].Description, result[0].Description ); + Assert.Equal( products[1].Description, result[1].Description ); + Assert.Equal( products[2].Description, result[2].Description ); + } + + #endregion + + #region Single + + /// + /// 测试查找单个实体 + /// + [Fact] + public async Task TestSingle_1() { + //常量 + var name = "TestSingle"; + + //添加实体 + var entity = await AddProductAsync( name ); + UnitOfWork.ClearCache(); + + //验证 + var result = _repository.Single( t => t.Name == name ); + Assert.Equal( entity.Code, result.Code ); + } + + #endregion + + #region SingleAsync + + /// + /// 测试查找单个实体 - 异步 + /// + [Fact] + public async Task TestSingleAsync() { + //常量 + var name = "TestSingleAsync"; + + //添加实体 + var entity = await AddProductAsync( name ); + UnitOfWork.ClearCache(); + + //验证 + var result = await _repository.SingleAsync( t => t.Name == name ); + Assert.Equal( entity.Code, result.Code ); + } + + #endregion + + #region Exists + + /// + /// 测试判断是否存在 + /// + [Fact] + public async Task TestExists() { + //添加实体 + var entity = await AddProductAsync(); + UnitOfWork.ClearCache(); + + //验证 + Assert.True( _repository.Exists( t => t.Id == entity.Id ) ); + } + + #endregion + + #region ExistsAsync + + /// + /// 测试判断是否存在 - 异步 + /// + [Fact] + public async Task TestExistsAsync() { + //添加实体 + var entity = await AddProductAsync(); + UnitOfWork.ClearCache(); + + //验证 + Assert.True( await _repository.ExistsAsync( t => t.Id == entity.Id ) ); + } + + #endregion + + #region Count + + /// + /// 测试查找数量 + /// + [Fact] + public async Task TestCount() { + //常量 + var name = "TestCount"; + var count = 3; + + //添加实体列表 + var products = ProductFakeService.GetProducts( count ); + products.ForEach( product => { + product.Init(); + product.Name = name; + } ); + await _repository.AddAsync( products ); + await UnitOfWork.CommitAsync(); + + //验证 + var result = _repository.Count( t => t.Name == name ); + Assert.Equal( count, result ); + } + + #endregion + + #region CountAsync + + /// + /// 测试查找数量 - 异步 + /// + [Fact] + public async Task TestCountAsync() { + //常量 + var name = "TestCountAsync"; + var count = 3; + + //添加实体列表 + var products = ProductFakeService.GetProducts( count ); + products.ForEach( product => { + product.Init(); + product.Name = name; + } ); + await _repository.AddAsync( products ); + await UnitOfWork.CommitAsync(); + + //验证 + var result = await _repository.CountAsync( t => t.Name == name ); + Assert.Equal( count, result ); + } + + #endregion + + #region Update + + /// + /// 测试更新方法1 - 查找并修改实体,直接提交工作单元 + /// + [Fact] + public async Task TestUpdate_1() { + //常量 + var code = "TestUpdate_1_Code"; + + //添加实体 + var entity = await AddProductAsync(); + UnitOfWork.ClearCache(); + + //查找实体并修改 + var product = await _repository.FindByIdAsync( entity.Id ); + product.Code = code; + + //直接提交工作单元 + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //验证 + var result = await _repository.FindByIdAsync( entity.Id ); + Assert.Equal( code, result.Code ); + } + + /// + /// 测试更新并发 - 使用更新方法1 + /// 更新方法1的缺陷: 通过赋值的方式更新查找实体的版本号,无法触发乐观锁 + /// + [Fact] + public async Task TestUpdate_1_Concurrency() { + //常量 + var code = "TestUpdate_1_Concurrency_Code"; + var description = "TestUpdate_1_Concurrency_Description"; + + //添加实体 + var entity = await AddProductAsync(); + UnitOfWork.ClearCache(); + + //此处模拟用户1打开表单并修改,但尚未提交,这将保存旧实体 + var product = await _repository.FindByIdAsync( entity.Id ); + product.Code = code; + UnitOfWork.ClearCache(); + + //此处模拟用户2更新该实体,这将导致版本号变化 + var product2 = await _repository.FindByIdAsync( entity.Id ); + product2.Description = description; + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //此处模拟用户1提交表单,查找实体,并进行赋值 + var result = _repository.FindById( entity.Id ); + result.Code = product.Code; + result.Description = product.Description; + result.Version = product.Version; + //提交工作单元,由于版本号变化,预期应触发乐观锁,但实际未触发 + await UnitOfWork.CommitAsync(); + + //结果:用户1覆盖了用户2设置的Description属性 + Assert.Equal( code, result.Code ); + Assert.NotEqual( description, result.Description ); + } + + /// + /// 测试更新方法2 - 创建未跟踪实体,调用dbcontext.Update方法 + /// + [Fact] + public async Task TestUpdate_2() { + //常量 + var code = "TestUpdate_2_Code"; + + //添加实体 + var entity = await AddProductAsync(); + UnitOfWork.ClearCache(); + + //创建未跟踪实体 + var product = entity.MapTo(); + product.Code = code; + //调用dbcontext.Update方法更新实体 + _repository.UpdateProduct( product ); + //提交工作单元 + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //验证 + var result = await _repository.FindByIdAsync( entity.Id ); + Assert.Equal( code, result.Code ); + } + + /// + /// 测试更新方法2的陷阱 + /// 如果在创建未跟踪实体并调用dbcontext.Update方法之前,从dbcontext中已查找出该实体,将发生异常 + /// + [Fact] + public async Task TestUpdate_2_InvalidOperation() { + //常量 + var code = "TestUpdate_2_InvalidOperation_Code"; + + //添加实体 + var entity = await AddProductAsync(); + UnitOfWork.ClearCache(); + + //模拟更新之前无意中已查找出该实体 + await _repository.FindByIdAsync( entity.Id ); + + //创建未跟踪实体 + var product = entity.MapTo(); + product.Code = code; + + //由于实体已被跟踪,调用dbcontext.Update方法更新实体将触发异常 + Assert.Throws( () => { + _repository.UpdateProduct( product ); + } ); + } + + /// + /// 测试更新并发 - 使用更新方法2 + /// + [Fact] + public async Task TestUpdate_2_Concurrency() { + //常量 + var code = "TestUpdate_2_Concurrency_Code"; + var description = "TestUpdate_2_Concurrency_Description"; + + //添加实体 + var entity = await AddProductAsync(); + UnitOfWork.ClearCache(); + + //此处模拟用户1打开表单并修改,但尚未提交,这将保存旧实体 + var product = await _repository.FindByIdAsync( entity.Id ); + product.Code = code; + UnitOfWork.ClearCache(); + + //此处模拟用户2更新该实体,这将导致版本号变化 + var product2 = await _repository.FindByIdAsync( entity.Id ); + product2.Description = description; + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //此处模拟用户1提交表单,创建一个新的实体,并赋值 + var result = product.MapTo(); + + //调用dbcontext.Update方法更新实体 + _repository.UpdateProduct( result ); + + //提交工作单元,由于版本号变化,触发乐观锁 + await Assert.ThrowsAsync( async () => { + await UnitOfWork.CommitAsync(); + } ); + } + + /// + /// 测试Util Update更新方法 - 查找并修改实体,提交工作单元 + /// + [Fact] + public async Task TestUpdate_3_1() { + //常量 + var code = "TestUpdate_3_1_Code"; + + //添加实体 + var entity = await AddProductAsync(); + UnitOfWork.ClearCache(); + + //查找实体并修改 + var product = await _repository.FindByIdAsync( entity.Id ); + product.Code = code; + + //调用Update方法 + await _repository.UpdateAsync( product ); + + //提交工作单元 + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //验证 + var result = _repository.FindById( entity.Id ); + Assert.Equal( code, result.Code ); + } + + /// + /// 测试Util Update更新方法 - 创建未跟踪实体,调用Update方法 + /// + [Fact] + public async Task TestUpdate_3_2() { + //常量 + var code = "TestUpdate_3_2_Code"; + + //添加实体 + var entity = await AddProductAsync(); + UnitOfWork.ClearCache(); + + //创建未跟踪实体 + var product = entity.MapTo(); + product.Code = code; + + //调用Update方法更新实体 + await _repository.UpdateAsync( product ); + + //提交工作单元 + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //验证 + var result = await _repository.FindByIdAsync( entity.Id ); + Assert.Equal( code, result.Code ); + } + + /// + /// 测试Util Update更新方法 - 允许在创建未跟踪实体并调用Update方法之前查找实体,不会发生异常 + /// + [Fact] + public async Task TestUpdate_3_3() { + //常量 + var code = "TestUpdate_3_3_InvalidOperation_Code"; + + //添加实体 + var entity = await AddProductAsync(); + UnitOfWork.ClearCache(); + + //模拟更新之前无意中已查找出该实体 + await _repository.FindByIdAsync( entity.Id ); + + //创建未跟踪实体 + var product = entity.MapTo(); + product.Code = code; + + //调用Update方法更新实体 + await _repository.UpdateAsync( product ); + + //提交工作单元 + _log.WriteLine( UnitOfWork.GetChangeTrackerDebugView() ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //验证 + var result = _repository.FindById( entity.Id ); + Assert.Equal( code, result.Code ); + } + + /// + /// 测试更新并发 - 使用Util Update更新方法 + /// 通过赋值的方式更新查找实体的版本号,触发乐观锁 + /// + [Fact] + public async Task TestUpdate_3_Concurrency_1() { + //常量 + var code = "TestUpdate_3_Concurrency_1_Code"; + var description = "TestUpdate_3_Concurrency_1_Description"; + + //添加实体 + var entity = await AddProductAsync(); + UnitOfWork.ClearCache(); + + //此处模拟用户1打开表单并修改,但尚未提交,这将保存旧实体 + var product = await _repository.FindByIdAsync( entity.Id ); + product.Code = code; + UnitOfWork.ClearCache(); + + //此处模拟用户2更新该实体,这将导致版本号变化 + var product2 = await _repository.FindByIdAsync( entity.Id ); + product2.Description = description; + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //此处模拟用户1提交表单,查找实体,并进行赋值 + var result = await _repository.FindByIdAsync( entity.Id ); + result.Code = product.Code; + result.Description = product.Description; + result.Version = product.Version; + + //调用Update方法更新实体时触发乐观锁 + await Assert.ThrowsAsync( async () => { + await _repository.UpdateAsync( result ); + } ); + } + + /// + /// 测试更新并发 - 使用Util Update更新方法 + /// 更新未跟踪实体触发乐观锁 + /// + [Fact] + public async Task TestUpdate_3_Concurrency_2() { + //常量 + var code = "TestUpdate_3_Concurrency_2_Code"; + var description = "TestUpdate_3_Concurrency_2_Description"; + + //添加实体 + var entity = await AddProductAsync(); + UnitOfWork.ClearCache(); + + //此处模拟用户1打开表单并修改,但尚未提交,这将保存旧实体 + var product = await _repository.FindByIdAsync( entity.Id ); + product.Code = code; + UnitOfWork.ClearCache(); + + //此处模拟用户2更新该实体,这将导致版本号变化 + var product2 = await _repository.FindByIdAsync( entity.Id ); + product2.Description = description; + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //此处模拟用户1提交表单,创建一个新的实体,并赋值 + var result = product.MapTo(); + + //调用Update方法更新实体 + await _repository.UpdateAsync( result ); + + //提交工作单元,由于版本号变化,触发乐观锁 + await Assert.ThrowsAsync( async () => { + await UnitOfWork.CommitAsync(); + } ); + } + + /// + /// 测试更新集合 + /// + [Fact] + public async Task TestUpdate_4() { + //常量 + var count = 3; + var code = "TestUpdate_4_Code"; + + //添加实体列表 + var entities = ProductFakeService.GetProducts( count ); + entities.ForEach( product => { + product.Init(); + } ); + await _repository.AddAsync( entities ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //查找实体,赋值,调用Update方法,提交工作单元 + var products = await _repository.FindByIdsAsync( entities.Select( t => t.Id ) ); + products.ForEach( product => product.Code = code ); + await _repository.UpdateAsync( products ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //验证 + var result = await _repository.FindByIdsAsync( entities.Select( t => t.Id ) ); + Assert.Equal( code, result[0].Code ); + Assert.Equal( code, result[1].Code ); + Assert.Equal( code, result[2].Code ); + } + + #endregion + + #region Remove + + /// + /// 测试通过标识移除实体 - 逻辑删除 + /// + [Fact] + public async Task TestRemoveAsync_Id_1() { + //添加实体 + var entity = await AddProductAsync(); + UnitOfWork.ClearCache(); + + //移除实体 + await _repository.RemoveAsync( entity.Id ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //验证 + var result = await _repository.FindByIdAsync( entity.Id ); + Assert.Null( result ); + } + + /// + /// 测试通过标识移除实体 - 逻辑删除 - 使用工作单元禁用逻辑删除过滤器 + /// + [Fact] + public async Task TestRemoveAsync_Id_2() { + //添加实体 + var entity = await AddProductAsync(); + UnitOfWork.ClearCache(); + + //移除实体 + await _repository.RemoveAsync( entity.Id ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //使用工作单元禁用逻辑删除过滤器,可以查出 + using( UnitOfWork.DisableDeleteFilter() ) { + var product = await _repository.FindByIdAsync( entity.Id ); + Assert.True( product.IsDeleted ); + Assert.Equal( entity.Code, product.Code ); + } + UnitOfWork.ClearCache(); + + //逻辑删除过滤器已启用,无法查出 + var result = await _repository.FindByIdAsync( entity.Id ); + Assert.Null( result ); + } + + /// + /// 测试通过标识移除实体 - 逻辑删除 - 使用仓储禁用逻辑删除过滤器 + /// + [Fact] + public async Task TestRemoveAsync_Id_3() { + //添加实体 + var entity = await AddProductAsync(); + UnitOfWork.ClearCache(); + + //移除实体 + await _repository.RemoveAsync( entity.Id ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //使用仓储禁用逻辑删除过滤器,可以查出 + using( _repository.DisableDeleteFilter() ) { + var product = await _repository.FindByIdAsync( entity.Id ); + Assert.True( product.IsDeleted ); + Assert.Equal( entity.Code, product.Code ); + } + UnitOfWork.ClearCache(); + + //逻辑删除过滤器已启用,无法查出 + var result = await _repository.FindByIdAsync( entity.Id ); + Assert.Null( result ); + } + + /// + /// 测试移除实体 - 逻辑删除 + /// + [Fact] + public async Task TestRemoveAsync_Entity() { + //添加实体 + var entity = await AddProductAsync(); + UnitOfWork.ClearCache(); + + //移除实体 + await _repository.RemoveAsync( entity ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //验证 + var result = await _repository.FindByIdAsync( entity.Id ); + Assert.Null( result ); + } + + /// + /// 测试移除实体集合 - 逻辑删除 - 通过标识列表 + /// + [Fact] + public async Task TestRemoveAsync_Entities_1() { + //常量 + var count = 3; + + //添加实体列表 + var products = ProductFakeService.GetProducts( count ).ToList(); + products.ForEach( product => { + product.Init(); + } ); + await _repository.AddAsync( products ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //移除实体集合 + var ids = products.Select( t => t.Id ).ToList(); + await _repository.RemoveAsync( ids ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //验证 + using( _repository.DisableDeleteFilter() ) { + var result = await _repository.FindByIdsAsync( ids ); + Assert.Equal( count, result.Count ); + result.ForEach( t => Assert.True( t.IsDeleted ) ); + } + } + + /// + /// 测试移除实体集合 - 逻辑删除 - 通过实体列表 + /// + [Fact] + public async Task TestRemoveAsync_Entities_2() { + //常量 + var count = 3; + + //添加实体列表 + var products = ProductFakeService.GetProducts( count ).ToList(); + products.ForEach( product => { + product.Init(); + } ); + await _repository.AddAsync( products ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //移除实体集合 + await _repository.RemoveAsync( products ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //验证 + using( _repository.DisableDeleteFilter() ) { + var result = await _repository.FindByIdsAsync( products.Select( t => t.Id ) ); + Assert.Equal( count, result.Count ); + result.ForEach( t => Assert.True( t.IsDeleted ) ); + } + } + + #endregion + + #region Audit + + /// + /// 测试设置创建审计属性 + /// + [Fact] + public async Task TestCreationAudit() { + var entity = ProductFakeService.GetProduct(); + entity.Init(); + await _repository.AddAsync( entity ); + Assert.NotEqual( TestSession.TestUserId, entity.CreatorId ); + await UnitOfWork.CommitAsync(); + Assert.Equal( TestSession.TestUserId, entity.CreatorId ); + Assert.Equal( TestSession.TestUserId, entity.LastModifierId ); + } + + /// + /// 测试设置修改审计属性 + /// + [Fact] + public async Task TestModificationAudit() { + //工作单元 + var unitOfWork = (MySqlUnitOfWork)UnitOfWork; + + //常量 + var code = "TestModificationAudit"; + + //添加实体 + var entity = await AddProductAsync(); + unitOfWork.ClearCache(); + + //修改 + var product = entity.MapTo(); + product.Code = code; + await _repository.UpdateAsync( product ); + unitOfWork.SetSession( new TestSession { UserId = TestSession.TestUserId2.ToString() } ); + + //验证修改前审计属性 + Assert.Equal( TestSession.TestUserId, product.CreatorId ); + Assert.Equal( TestSession.TestUserId, product.LastModifierId ); + + //提交 + await unitOfWork.CommitAsync(); + + //验证修改后审计属性 + Assert.Equal( TestSession.TestUserId, product.CreatorId ); + Assert.Equal( TestSession.TestUserId2, product.LastModifierId ); + } + + #endregion + + #region ExtraProperties + + /// + /// 测试扩展属性 - 添加简单扩展属性 + /// + [Fact] + public async Task TestExtraProperties_1() { + //常量 + var value = "TestExtraProperties_1"; + + //添加实体 + var entity = new Product(); + entity.Init(); + entity.TestProperty1 = value; + await _repository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //验证 + var result = await _repository.FindByIdAsync( entity.Id ); + Assert.Equal( value, result.TestProperty1 ); + } + + /// + /// 测试扩展属性 - 修改简单扩展属性 + /// + [Fact] + public async Task TestExtraProperties_2() { + //常量 + var oldValue = "TestExtraProperties_2_1"; + var newValue = "TestExtraProperties_2_2"; + + //添加实体 + var entity = new Product(); + entity.Init(); + entity.TestProperty1 = oldValue; + await _repository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //验证 + var oldEntity = await _repository.FindByIdAsync( entity.Id ); + Assert.Equal( oldValue, oldEntity.TestProperty1 ); + + //修改实体 + oldEntity.TestProperty1 = newValue; + await _repository.UpdateAsync( oldEntity ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //验证 + var result = await _repository.FindByIdAsync( entity.Id ); + Assert.Equal( newValue, result.TestProperty1 ); + } + + /// + /// 测试扩展属性 - 添加对象扩展属性 + /// + [Fact] + public async Task TestExtraProperties_3() { + //常量 + var code = 2; + var name = "TestExtraProperties_3"; + var enumValue = ProductEnum.World; + + //添加实体 + var entity = new Product(); + entity.Init(); + entity.TestProperty2.Code = code; + entity.TestProperty2.Name = name; + entity.TestProperty2.EnumValue = enumValue; + await _repository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //验证 + var result = _repository.FindById( entity.Id ); + Assert.Equal( code, result.TestProperty2.Code ); + Assert.Equal( name, result.TestProperty2.Name ); + Assert.Equal( enumValue, result.TestProperty2.EnumValue ); + } + + /// + /// 测试扩展属性 - 修改对象扩展属性 + /// + [Fact] + public async Task TestExtraProperties_4() { + //常量 + var code = 2; + var oldName = "TestExtraProperties_4_1"; + var newName = "TestExtraProperties_4_2"; + var oldEnumValue = ProductEnum.Hello; + var newEnumValue = ProductEnum.World; + + //添加实体 + var entity = new Product(); + entity.Init(); + entity.TestProperty2.Code = code; + entity.TestProperty2.Name = oldName; + entity.TestProperty2.EnumValue = oldEnumValue; + await _repository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //验证 + var oldEntity = await _repository.FindByIdAsync( entity.Id ); + Assert.Equal( code, oldEntity.TestProperty2.Code ); + Assert.Equal( oldName, oldEntity.TestProperty2.Name ); + Assert.Equal( oldEnumValue, oldEntity.TestProperty2.EnumValue ); + + //修改实体 + oldEntity.TestProperty2.Name = newName; + oldEntity.TestProperty2.EnumValue = newEnumValue; + WriteTrackerDebug(); + await _repository.UpdateAsync( oldEntity ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //验证 + var result = await _repository.FindByIdAsync( entity.Id ); + Assert.Equal( newName, result.TestProperty2.Name ); + Assert.Equal( newEnumValue, result.TestProperty2.EnumValue ); + } + + /// + /// 测试扩展属性 - 添加对象集合扩展属性 + /// + [Fact] + public async Task TestExtraProperties_5() { + //常量 + var code = 1; + var name1 = "TestExtraProperties_5_1"; + var name2 = "TestExtraProperties_5_2"; + + //添加实体 + var entity = new Product(); + entity.Init(); + entity.TestProperties.Add( new ProductItem { Code = code, Name = name1 } ); + entity.TestProperties.Add( new ProductItem { Code = code, Name = name2 } ); + await _repository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //验证 + var result = await _repository.FindByIdAsync( entity.Id ); + Assert.Equal( 2, result.TestProperties.Count ); + Assert.Equal( code, result.TestProperties[0].Code ); + Assert.Equal( name1, result.TestProperties[0].Name ); + Assert.Equal( code, result.TestProperties[1].Code ); + Assert.Equal( name2, result.TestProperties[1].Name ); + } + + /// + /// 测试扩展属性 - 修改对象集合扩展属性 + /// + [Fact] + public async Task TestExtraProperties_6() { + //常量 + var code = 1; + var oldName = "TestExtraProperties_6_1"; + var newName = "TestExtraProperties_6_2"; + var name3 = "TestExtraProperties_6_3"; + + //添加实体 + var entity = new Product(); + entity.Init(); + entity.TestProperties.Add( new ProductItem { Code = code, Name = oldName } ); + entity.TestProperties.Add( new ProductItem { Code = code, Name = oldName } ); + await _repository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //验证 + var oldEntity = await _repository.FindByIdAsync( entity.Id ); + Assert.Equal( 2, oldEntity.TestProperties.Count ); + + //修改实体 + oldEntity.TestProperties[0].Name = newName; + oldEntity.TestProperties[1].Name = newName; + oldEntity.TestProperties.Add( new ProductItem { Code = code, Name = name3 } ); + await _repository.UpdateAsync( oldEntity ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //验证 + var result = await _repository.FindByIdAsync( entity.Id ); + Assert.Equal( 3, result.TestProperties.Count ); + Assert.Equal( code, result.TestProperties[0].Code ); + Assert.Equal( newName, result.TestProperties[0].Name ); + Assert.Equal( code, result.TestProperties[1].Code ); + Assert.Equal( newName, result.TestProperties[1].Name ); + Assert.Equal( code, result.TestProperties[2].Code ); + Assert.Equal( name3, result.TestProperties[2].Name ); + } + + /// + /// 测试扩展属性 - 添加多个扩展属性 + /// + [Fact] + public async Task TestExtraProperties_7() { + //常量 + var code = 2; + var name = "TestExtraProperties_7"; + + //添加实体 + var entity = new Product(); + entity.Init(); + entity.TestProperty1 = name; + entity.TestProperty2.Code = code; + entity.TestProperty2.Name = name; + entity.TestProperties.Add( new ProductItem { Code = code, Name = name } ); + entity.TestProperties.Add( new ProductItem { Code = code, Name = name } ); + await _repository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //验证 + var result = await _repository.FindByIdAsync( entity.Id ); + Assert.Equal( name, result.TestProperty1 ); + Assert.Equal( code, result.TestProperty2.Code ); + Assert.Equal( name, result.TestProperty2.Name ); + Assert.Equal( code, result.TestProperties[0].Code ); + Assert.Equal( name, result.TestProperties[0].Name ); + Assert.Equal( code, result.TestProperties[1].Code ); + Assert.Equal( name, result.TestProperties[1].Name ); + } + + /// + /// 测试扩展属性 - 修改多个扩展属性 + /// + [Fact] + public async Task TestExtraProperties_8() { + //常量 + var code = 2; + var oldName = "TestExtraProperties_8_1"; + var newName = "TestExtraProperties_8_2"; + + //添加实体 + var entity = new Product(); + entity.Init(); + entity.TestProperty1 = oldName; + entity.TestProperty2.Code = code; + entity.TestProperty2.Name = oldName; + entity.TestProperties.Add( new ProductItem { Code = code, Name = oldName } ); + entity.TestProperties.Add( new ProductItem { Code = code, Name = oldName } ); + await _repository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //验证 + var oldEntity = await _repository.FindByIdAsync( entity.Id ); + Assert.Equal( oldName, oldEntity.TestProperty1 ); + Assert.Equal( code, oldEntity.TestProperty2.Code ); + Assert.Equal( oldName, oldEntity.TestProperty2.Name ); + Assert.Equal( 2, oldEntity.TestProperties.Count ); + + //修改实体 + oldEntity.TestProperty1 = newName; + oldEntity.TestProperty2.Name = newName; + oldEntity.TestProperties[0].Name = newName; + oldEntity.TestProperties[1].Name = newName; + oldEntity.TestProperties.Add( new ProductItem{ Code = code, Name = newName } ); + await _repository.UpdateAsync( oldEntity ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //验证 + var result = await _repository.FindByIdAsync( entity.Id ); + Assert.Equal( newName, result.TestProperty1 ); + Assert.Equal( newName, result.TestProperty2.Name ); + Assert.Equal( 3, result.TestProperties.Count ); + Assert.Equal( newName, result.TestProperties[0].Name ); + Assert.Equal( newName, result.TestProperties[1].Name ); + Assert.Equal( newName, result.TestProperties[2].Name ); + } + + /// + /// 测试扩展属性 - 添加枚举扩展属性 + /// + [Fact] + public async Task TestExtraProperties_9() { + //常量 + ProductEnum value = ProductEnum.World; + + //添加实体 + var entity = new Product(); + entity.Init(); + entity.TestProperty3 = value; + await _repository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //验证 + var result = await _repository.FindByIdAsync( entity.Id ); + Assert.Equal( value, result.TestProperty3 ); + } + + /// + /// 测试扩展属性 - 修改枚举扩展属性 + /// + [Fact] + public async Task TestExtraProperties_10() { + //常量 + ProductEnum oldValue = ProductEnum.Hello; + ProductEnum newValue = ProductEnum.World; + + //添加实体 + var entity = new Product(); + entity.Init(); + entity.TestProperty3 = oldValue; + await _repository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //验证 + var oldEntity = await _repository.FindByIdAsync( entity.Id ); + Assert.Equal( oldValue, oldEntity.TestProperty3 ); + + //修改实体 + oldEntity.TestProperty3 = newValue; + await _repository.UpdateAsync( oldEntity ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //验证 + var result = await _repository.FindByIdAsync( entity.Id ); + Assert.Equal( newValue, result.TestProperty3 ); + } + + /// + /// 测试扩展属性 - 添加不可变对象扩展属性 + /// + [Fact] + public async Task TestExtraProperties_11() { + //常量 + var code = 2; + var name = "TestExtraProperties_11"; + + //添加实体 + var entity = new Product(); + entity.Init(); + entity.TestProperty4 = new ProductItem2( code, name ); + await _repository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //验证 + var result = await _repository.FindByIdAsync( entity.Id ); + Assert.Equal( code, result.TestProperty4.Code ); + Assert.Equal( name, result.TestProperty4.Name ); + } + + /// + /// 测试扩展属性 - 修改对象扩展属性 + /// + [Fact] + public async Task TestExtraProperties_12() { + //常量 + var code = 2; + var oldName = "TestExtraProperties_12_1"; + var newName = "TestExtraProperties_12_2"; + + //添加实体 + var entity = new Product(); + entity.Init(); + entity.TestProperty4 = new ProductItem2( code, oldName ); + await _repository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //验证 + var oldEntity = await _repository.FindByIdAsync( entity.Id ); + Assert.Equal( code, oldEntity.TestProperty4.Code ); + Assert.Equal( oldName, oldEntity.TestProperty4.Name ); + + //修改实体 + oldEntity.TestProperty4 = new ProductItem2( code, newName ); + WriteTrackerDebug(); + await _repository.UpdateAsync( oldEntity ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //验证 + var result = await _repository.FindByIdAsync( entity.Id ); + Assert.Equal( newName, result.TestProperty4.Name ); + } + + #endregion + } +} \ No newline at end of file diff --git a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Tests/TagRepositoryTest.cs b/test/Util.Data.EntityFrameworkCore.MySql.Tests.Integration/Tests/TagRepositoryTest.cs similarity index 75% rename from test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Tests/TagRepositoryTest.cs rename to test/Util.Data.EntityFrameworkCore.MySql.Tests.Integration/Tests/TagRepositoryTest.cs index e0b924bc..3819f129 100644 --- a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Tests/TagRepositoryTest.cs +++ b/test/Util.Data.EntityFrameworkCore.MySql.Tests.Integration/Tests/TagRepositoryTest.cs @@ -1,8 +1,8 @@ using System.Threading.Tasks; -using Util.Data.EntityFrameworkCore.Fakes; -using Util.Data.EntityFrameworkCore.Infrastructure; -using Util.Data.EntityFrameworkCore.Repositories; -using Util.Data.EntityFrameworkCore.UnitOfWorks; +using Util.Tests.Fakes; +using Util.Tests.Infrastructure; +using Util.Tests.Repositories; +using Util.Tests.UnitOfWorks; using Xunit; namespace Util.Data.EntityFrameworkCore.Tests { @@ -18,7 +18,7 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// /// 测试初始化 /// - public TagRepositoryTest( ITagRepository repository, IPgSqlUnitOfWork unitOfWork ) : base( unitOfWork ) { + public TagRepositoryTest( ITagRepository repository, ITestUnitOfWork unitOfWork ) : base( unitOfWork ) { _repository = repository; } diff --git a/test/Util.Data.EntityFrameworkCore.MySql.Tests.Integration/Util.Data.EntityFrameworkCore.MySql.Tests.Integration.csproj b/test/Util.Data.EntityFrameworkCore.MySql.Tests.Integration/Util.Data.EntityFrameworkCore.MySql.Tests.Integration.csproj new file mode 100644 index 00000000..1516a49b --- /dev/null +++ b/test/Util.Data.EntityFrameworkCore.MySql.Tests.Integration/Util.Data.EntityFrameworkCore.MySql.Tests.Integration.csproj @@ -0,0 +1,39 @@ + + + + $(NetTargetFramework) + false + Util.Data.EntityFrameworkCore + Util.Data.EntityFrameworkCore.Startup + + + + + Always + + + Always + + + + + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + \ No newline at end of file diff --git a/test/Util.Data.EntityFrameworkCore.MySql.Tests.Integration/appsettings.Development.json b/test/Util.Data.EntityFrameworkCore.MySql.Tests.Integration/appsettings.Development.json new file mode 100644 index 00000000..eb63570e --- /dev/null +++ b/test/Util.Data.EntityFrameworkCore.MySql.Tests.Integration/appsettings.Development.json @@ -0,0 +1,11 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Trace", + "Microsoft": "Trace" + } + }, + "ConnectionStrings": { + "connection": "server=192.168.31.157;user=root;password=admin;database=Util.Data.EntityFrameworkCore.Test;port=3306;charset=utf8" + } +} \ No newline at end of file diff --git a/test/Util.Data.EntityFrameworkCore.MySql.Tests.Integration/appsettings.json b/test/Util.Data.EntityFrameworkCore.MySql.Tests.Integration/appsettings.json new file mode 100644 index 00000000..323453eb --- /dev/null +++ b/test/Util.Data.EntityFrameworkCore.MySql.Tests.Integration/appsettings.json @@ -0,0 +1,11 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Error", + "Microsoft": "Error" + } + }, + "ConnectionStrings": { + "connection": "server=mysql.common;user=root;password=admin;database=Util.Data.EntityFrameworkCore.Test;port=3306;charset=utf8" + } +} \ No newline at end of file diff --git a/test/Util.Data.EntityFrameworkCore.Oracle.Tests.Integration/Filters/DeleteFilterTest.cs b/test/Util.Data.EntityFrameworkCore.Oracle.Tests.Integration/Filters/DeleteFilterTest.cs new file mode 100644 index 00000000..e589e106 --- /dev/null +++ b/test/Util.Data.EntityFrameworkCore.Oracle.Tests.Integration/Filters/DeleteFilterTest.cs @@ -0,0 +1,81 @@ +using Util.Tests.Models; +using Xunit; +using Xunit.Abstractions; + +namespace Util.Data.EntityFrameworkCore.Filters { + /// + /// 逻辑删除过滤器测试 + /// + public class DeleteFilterTest { + /// + /// 测试消息输出 + /// + private readonly ITestOutputHelper _testOutputHelper; + /// + /// 逻辑删除过滤器 + /// + private readonly DeleteFilter _filter; + + /// + /// 测试初始化 + /// + public DeleteFilterTest( ITestOutputHelper testOutputHelper ) { + _testOutputHelper = testOutputHelper; + _filter = new DeleteFilter(); + } + + /// + /// 测试是否启用 + /// + [Fact] + public void TestIsEnabled() { + //默认值为启用 + Assert.True( _filter.IsEnabled ); + + //禁用过滤器 + _filter.Disable(); + Assert.False( _filter.IsEnabled ); + + //启用过滤器 + _filter.Enable(); + Assert.True( _filter.IsEnabled ); + } + + /// + /// 测试禁用 + /// + [Fact] + public void TestDisable() { + //默认值为启用 + Assert.True( _filter.IsEnabled ); + + //禁用过滤器 + using( _filter.Disable() ) { + Assert.False( _filter.IsEnabled ); + } + + //恢复启用状态 + Assert.True( _filter.IsEnabled ); + } + + /// + /// 测试实体是否启用过滤器 + /// + [Fact] + public void TestIsEntityEnabled() { + Assert.False( _filter.IsEntityEnabled() ); + Assert.True( _filter.IsEntityEnabled() ); + } + + /// + /// 测试获取表达式 + /// + [Fact] + public void TestGetExpression() { + var expression = _filter.GetExpression(); + var result = "entity => Not(Property(entity, \"IsDeleted\"))"; + _testOutputHelper.WriteLine( expression.ToString() ); + Assert.Equal( result,expression.ToString() ); + } + } +} diff --git a/test/Util.Data.EntityFrameworkCore.Oracle.Tests.Integration/Filters/FilterManagerTest.cs b/test/Util.Data.EntityFrameworkCore.Oracle.Tests.Integration/Filters/FilterManagerTest.cs new file mode 100644 index 00000000..4ac4609d --- /dev/null +++ b/test/Util.Data.EntityFrameworkCore.Oracle.Tests.Integration/Filters/FilterManagerTest.cs @@ -0,0 +1,101 @@ +using Util.Data.Filters; +using Util.Domain; +using Util.Tests.Models; +using Xunit; + +namespace Util.Data.EntityFrameworkCore.Filters { + /// + /// 数据过滤器管理器测试 + /// + public class FilterManagerTest { + /// + /// 数据过滤器管理器 + /// + private readonly IFilterManager _filterManager; + + /// + /// 测试初始化 + /// + public FilterManagerTest( IFilterManager filterManager ) { + _filterManager = filterManager; + } + + /// + /// 测试获取过滤器 - 泛型 + /// + [Fact] + public void TestGetFilter_1() { + //逻辑删除过滤器已默认加载 + var filter = _filterManager.GetFilter(); + Assert.NotNull( filter ); + Assert.True( filter.IsEnabled ); + } + + /// + /// 测试获取过滤器 - 非泛型 + /// + [Fact] + public void TestGetFilter_2() { + //逻辑删除过滤器已默认加载 + var filter = _filterManager.GetFilter(typeof( IDelete ) ); + Assert.NotNull( filter ); + } + + /// + /// 测试禁用过滤器 + /// + [Fact] + public void TestDisableFilter_1() { + _filterManager.DisableFilter(); + var filter = _filterManager.GetFilter(); + Assert.False( filter.IsEnabled ); + } + + /// + /// 测试禁用过滤器 - 使用using + /// + [Fact] + public void TestDisableFilter_2() { + var filter = _filterManager.GetFilter(); + using ( _filterManager.DisableFilter() ) { + Assert.False( filter.IsEnabled ); + } + Assert.True( filter.IsEnabled ); + } + + /// + /// 测试启用过滤器 + /// + [Fact] + public void TestEnableFilter() { + var filter = _filterManager.GetFilter(); + + //禁用 + _filterManager.DisableFilter(); + Assert.False( filter.IsEnabled ); + + //启用 + _filterManager.EnableFilter(); + Assert.True( filter.IsEnabled ); + } + + /// + /// 测试实体是否启用过滤器 + /// + [Fact] + public void TestIsEntityEnabled() { + Assert.False( _filterManager.IsEntityEnabled() ); + Assert.True( _filterManager.IsEntityEnabled() ); + } + + /// + /// 测试过滤器是否启用 + /// + [Fact] + public void TestIsEnabled() { + Assert.True( _filterManager.IsEnabled() ); + Assert.False( _filterManager.IsEnabled() ); + } + } +} + diff --git a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Startup.cs b/test/Util.Data.EntityFrameworkCore.Oracle.Tests.Integration/Startup.cs similarity index 76% rename from test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Startup.cs rename to test/Util.Data.EntityFrameworkCore.Oracle.Tests.Integration/Startup.cs index 9b88c453..9ccce7c6 100644 --- a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Startup.cs +++ b/test/Util.Data.EntityFrameworkCore.Oracle.Tests.Integration/Startup.cs @@ -2,10 +2,10 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using Util.Aop; -using Util.Data.EntityFrameworkCore.Infrastructure; -using Util.Data.EntityFrameworkCore.UnitOfWorks; using Util.Helpers; using Util.Sessions; +using Util.Tests.Infrastructure; +using Util.Tests.UnitOfWorks; using Xunit.DependencyInjection; using Xunit.DependencyInjection.Logging; @@ -18,7 +18,12 @@ namespace Util.Data.EntityFrameworkCore { /// ÅäÖÃÖ÷»ú /// public void ConfigureHost( IHostBuilder hostBuilder ) { - hostBuilder.ConfigureDefaults( null ).UseEnvironment( "Development" ).EnableAop(); + hostBuilder.ConfigureDefaults( null ) + .AddUtil( options => { + Environment.SetDevelopment(); + options.UseAop() + .UseOracleUnitOfWork( Config.GetConnectionString( "connection" ) ); + } ); } /// @@ -26,9 +31,6 @@ namespace Util.Data.EntityFrameworkCore { /// public void ConfigureServices( IServiceCollection services ) { services.AddSingleton(); - services.AddUtil( options => { - options.UseSqlServerUnitOfWork( Config.GetConnectionString( "connection" ) ); - } ); InitDatabase( services ); } @@ -36,7 +38,7 @@ namespace Util.Data.EntityFrameworkCore { /// ³õʼ»¯Êý¾ݿâ /// private void InitDatabase( IServiceCollection services ) { - var unitOfWork = services.BuildServiceProvider().GetService(); + var unitOfWork = services.BuildServiceProvider().GetService(); unitOfWork.EnsureDeleted(); unitOfWork.EnsureCreated(); } diff --git a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Tests/CustomerRepositoryTest.cs b/test/Util.Data.EntityFrameworkCore.Oracle.Tests.Integration/Tests/CustomerRepositoryTest.cs similarity index 77% rename from test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Tests/CustomerRepositoryTest.cs rename to test/Util.Data.EntityFrameworkCore.Oracle.Tests.Integration/Tests/CustomerRepositoryTest.cs index 38fe8178..2f43c378 100644 --- a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Tests/CustomerRepositoryTest.cs +++ b/test/Util.Data.EntityFrameworkCore.Oracle.Tests.Integration/Tests/CustomerRepositoryTest.cs @@ -1,12 +1,13 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; -using Util.Data.EntityFrameworkCore.Fakes; -using Util.Data.EntityFrameworkCore.Infrastructure; -using Util.Data.EntityFrameworkCore.Models; -using Util.Data.EntityFrameworkCore.Repositories; -using Util.Data.EntityFrameworkCore.UnitOfWorks; +using Microsoft.EntityFrameworkCore; using Util.Data.Queries; +using Util.Tests.Fakes; +using Util.Tests.Infrastructure; +using Util.Tests.Models; +using Util.Tests.Repositories; +using Util.Tests.UnitOfWorks; using Xunit; namespace Util.Data.EntityFrameworkCore.Tests { @@ -16,6 +17,7 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 1. 测试自增长int类型标识 /// 2. 测试日期范围查询 /// 3. 测试分页查询 + /// 4. 测试Utc日期 /// public class CustomerRepositoryTest : TestBase { @@ -29,7 +31,7 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// /// 测试初始化 /// - public CustomerRepositoryTest( ICustomerRepository repository, IPgSqlUnitOfWork unitOfWork ) : base( unitOfWork ) { + public CustomerRepositoryTest( ICustomerRepository repository, ITestUnitOfWork unitOfWork ) : base( unitOfWork ) { _repository = repository; } @@ -37,23 +39,6 @@ namespace Util.Data.EntityFrameworkCore.Tests { #region 辅助操作 - /// - /// 添加实体列表 - /// - /// 添加数量 - /// 客户名称 - private List AddCustomers( int count = 2, string name = null ) { - var customers = CustomerFakeService.GetCustomers( count ); - customers.ForEach( customer => { - if ( name != null ) - customer.Name = name; - } ); - _repository.Add( customers ); - UnitOfWork.Commit(); - UnitOfWork.ClearCache(); - return customers.OrderBy( t => t.Id ).ToList(); - } - /// /// 添加实体列表 /// @@ -64,11 +49,12 @@ namespace Util.Data.EntityFrameworkCore.Tests { customers.ForEach( customer => { if ( name != null ) customer.Name = name; + customer.CreationTime = null; } ); await _repository.AddAsync( customers ); await UnitOfWork.CommitAsync(); UnitOfWork.ClearCache(); - return customers.OrderBy( t => t.Id ).ToList(); + return customers.OrderBy( t => t.Code ).ToList(); } #endregion @@ -79,7 +65,7 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试添加范围查询条件 - 日期带时间 /// [Fact] - public void TestBetween_DateTime_1() { + public async Task TestBetween_DateTime_1() { //常量 var name = "TestBetween_DateTime_1"; var birthday = "2005-5-5 05:05:05".ToDateTime(); @@ -87,19 +73,19 @@ namespace Util.Data.EntityFrameworkCore.Tests { var maxBirthday = "2005-5-8 06:05:05".ToDateTime(); //添加实体列表 - AddCustomers(); + await AddCustomersAsync(); var customers = CustomerFakeService.GetCustomers( 5 ); customers.ForEach( customer => { customer.Name = name; customer.Birthday = birthday; birthday = birthday.AddDays( 1 ); } ); - _repository.Add( customers ); - UnitOfWork.Commit(); + await _repository.AddAsync( customers ); + await UnitOfWork.CommitAsync(); UnitOfWork.ClearCache(); //查询 - var result = _repository.Find().Where( t => t.Name == name ).Between( t => t.Birthday, minBirthday, maxBirthday ).ToList(); + var result = await _repository.Find().Where( t => t.Name == name ).Between( t => t.Birthday, minBirthday, maxBirthday ).ToListAsync(); //验证 Assert.Equal( 2, result.Count ); @@ -109,7 +95,7 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试添加范围查询条件 - 日期带时间 - 包含左边界 /// [Fact] - public void TestBetween_DateTime_2() { + public async Task TestBetween_DateTime_2() { //常量 var name = "TestBetween_DateTime_2"; var birthday = "2005-5-5 05:05:05".ToDateTime(); @@ -117,19 +103,19 @@ namespace Util.Data.EntityFrameworkCore.Tests { var maxBirthday = "2005-5-8 05:05:05".ToDateTime(); //添加实体列表 - AddCustomers(); + await AddCustomersAsync(); var customers = CustomerFakeService.GetCustomers( 5 ); customers.ForEach( customer => { customer.Name = name; customer.Birthday = birthday; birthday = birthday.AddDays( 1 ); } ); - _repository.Add( customers ); - UnitOfWork.Commit(); + await _repository.AddAsync( customers ); + await UnitOfWork.CommitAsync(); UnitOfWork.ClearCache(); //查询 - var result = _repository.Find().Where( t => t.Name == name ).Between( t => t.Birthday, minBirthday, maxBirthday, boundary: Boundary.Left ).ToList(); + var result = await _repository.Find().Where( t => t.Name == name ).Between( t => t.Birthday, minBirthday, maxBirthday, boundary: Boundary.Left ).ToListAsync(); //验证 Assert.Equal( 2, result.Count ); @@ -139,7 +125,7 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试添加范围查询条件 - 日期带时间 - 包含右边界 /// [Fact] - public void TestBetween_DateTime_3() { + public async Task TestBetween_DateTime_3() { //常量 var name = "TestBetween_DateTime_3"; var birthday = "2005-5-5 05:05:05".ToDateTime(); @@ -147,19 +133,19 @@ namespace Util.Data.EntityFrameworkCore.Tests { var maxBirthday = "2005-5-8 05:05:05".ToDateTime(); //添加实体列表 - AddCustomers(); + await AddCustomersAsync(); var customers = CustomerFakeService.GetCustomers( 5 ); customers.ForEach( customer => { customer.Name = name; customer.Birthday = birthday; birthday = birthday.AddDays( 1 ); } ); - _repository.Add( customers ); - UnitOfWork.Commit(); + await _repository.AddAsync( customers ); + await UnitOfWork.CommitAsync(); UnitOfWork.ClearCache(); //查询 - var result = _repository.Find().Where( t => t.Name == name ).Between( t => t.Birthday, minBirthday, maxBirthday, boundary: Boundary.Right ).ToList(); + var result = await _repository.Find().Where( t => t.Name == name ).Between( t => t.Birthday, minBirthday, maxBirthday, boundary: Boundary.Right ).ToListAsync(); //验证 Assert.Equal( 2, result.Count ); @@ -169,7 +155,7 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试添加范围查询条件 - 日期带时间 - 包含两边 /// [Fact] - public void TestBetween_DateTime_4() { + public async Task TestBetween_DateTime_4() { //常量 var name = "TestBetween_DateTime_4"; var birthday = "2005-5-5 05:05:05".ToDateTime(); @@ -177,19 +163,19 @@ namespace Util.Data.EntityFrameworkCore.Tests { var maxBirthday = "2005-5-8 05:05:05".ToDateTime(); //添加实体列表 - AddCustomers(); + await AddCustomersAsync(); var customers = CustomerFakeService.GetCustomers( 5 ); customers.ForEach( customer => { customer.Name = name; customer.Birthday = birthday; birthday = birthday.AddDays( 1 ); } ); - _repository.Add( customers ); - UnitOfWork.Commit(); + await _repository.AddAsync( customers ); + await UnitOfWork.CommitAsync(); UnitOfWork.ClearCache(); //查询 - var result = _repository.Find().Where( t => t.Name == name ).Between( t => t.Birthday, minBirthday, maxBirthday, boundary: Boundary.Both ).ToList(); + var result = await _repository.Find().Where( t => t.Name == name ).Between( t => t.Birthday, minBirthday, maxBirthday, boundary: Boundary.Both ).ToListAsync(); //验证 Assert.Equal( 3, result.Count ); @@ -199,7 +185,7 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试添加范围查询条件 - 日期带时间 - 不包含边界 /// [Fact] - public void TestBetween_DateTime_5() { + public async Task TestBetween_DateTime_5() { //常量 var name = "TestBetween_DateTime_5"; var birthday = "2005-5-5 05:05:05".ToDateTime(); @@ -207,19 +193,19 @@ namespace Util.Data.EntityFrameworkCore.Tests { var maxBirthday = "2005-5-8 05:05:05".ToDateTime(); //添加实体列表 - AddCustomers(); + await AddCustomersAsync(); var customers = CustomerFakeService.GetCustomers( 5 ); customers.ForEach( customer => { customer.Name = name; customer.Birthday = birthday; birthday = birthday.AddDays( 1 ); } ); - _repository.Add( customers ); - UnitOfWork.Commit(); + await _repository.AddAsync( customers ); + await UnitOfWork.CommitAsync(); UnitOfWork.ClearCache(); //查询 - var result = _repository.Find().Where( t => t.Name == name ).Between( t => t.Birthday, minBirthday, maxBirthday, boundary: Boundary.Neither ).ToList(); + var result = await _repository.Find().Where( t => t.Name == name ).Between( t => t.Birthday, minBirthday, maxBirthday, boundary: Boundary.Neither ).ToListAsync(); //验证 Assert.Single( result ); @@ -229,26 +215,26 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试添加范围查询条件 - 日期带时间 - 最大值为空 /// [Fact] - public void TestBetween_DateTime_6() { + public async Task TestBetween_DateTime_6() { //常量 var name = "TestBetween_DateTime_6"; var birthday = "2005-5-5 05:05:05".ToDateTime(); var minBirthday = "2005-5-6 05:05:05".ToDateTime(); //添加实体列表 - AddCustomers(); + await AddCustomersAsync(); var customers = CustomerFakeService.GetCustomers( 5 ); customers.ForEach( customer => { customer.Name = name; customer.Birthday = birthday; birthday = birthday.AddDays( 1 ); } ); - _repository.Add( customers ); - UnitOfWork.Commit(); + await _repository.AddAsync( customers ); + await UnitOfWork.CommitAsync(); UnitOfWork.ClearCache(); //查询 - var result = _repository.Find().Where( t => t.Name == name ).Between( t => t.Birthday, minBirthday, null, boundary: Boundary.Both ).ToList(); + var result = await _repository.Find().Where( t => t.Name == name ).Between( t => t.Birthday, minBirthday, null, boundary: Boundary.Both ).ToListAsync(); //验证 Assert.Equal( 4, result.Count ); @@ -258,26 +244,26 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试添加范围查询条件 - 日期带时间 - 最小值为空 /// [Fact] - public void TestBetween_DateTime_7() { + public async Task TestBetween_DateTime_7() { //常量 var name = "TestBetween_DateTime_7"; var birthday = "2005-5-5 05:05:05".ToDateTime(); var maxBirthday = "2005-5-8 05:05:05".ToDateTime(); //添加实体列表 - AddCustomers(); + await AddCustomersAsync(); var customers = CustomerFakeService.GetCustomers( 5 ); customers.ForEach( customer => { customer.Name = name; customer.Birthday = birthday; birthday = birthday.AddDays( 1 ); } ); - _repository.Add( customers ); - UnitOfWork.Commit(); + await _repository.AddAsync( customers ); + await UnitOfWork.CommitAsync(); UnitOfWork.ClearCache(); //查询 - var result = _repository.Find().Where( t => t.Name == name ).Between( t => t.Birthday, null, maxBirthday, boundary: Boundary.Both ).ToList(); + var result = await _repository.Find().Where( t => t.Name == name ).Between( t => t.Birthday, null, maxBirthday, boundary: Boundary.Both ).ToListAsync(); //验证 Assert.Equal( 4, result.Count ); @@ -287,7 +273,7 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试添加范围查询条件 - 日期不带时间 - 包含左边界 /// [Fact] - public void TestBetween_Date_1() { + public async Task TestBetween_Date_1() { //常量 var name = "TestBetween_Date_1"; var birthday = "2005-5-5 05:05:05".ToDateTime(); @@ -295,23 +281,23 @@ namespace Util.Data.EntityFrameworkCore.Tests { var maxBirthday = "2005-5-8".ToDateTime(); //添加实体列表 - AddCustomers(); + await AddCustomersAsync(); var customers = CustomerFakeService.GetCustomers( 5 ); customers.ForEach( customer => { customer.Name = name; customer.Birthday = birthday; birthday = birthday.AddDays( 1 ); } ); - _repository.Add( customers ); - UnitOfWork.Commit(); + await _repository.AddAsync( customers ); + await UnitOfWork.CommitAsync(); UnitOfWork.ClearCache(); //查询 - var result = _repository.Find() + var result = await _repository.Find() .Where( t => t.Name == name ) .Between( t => t.Birthday, minBirthday, maxBirthday, false, Boundary.Left ) .OrderBy( t => t.Birthday ) - .ToList(); + .ToListAsync(); //验证 Assert.Equal( 2, result.Count ); @@ -323,7 +309,7 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试添加范围查询条件 - 日期不带时间 - 包含右边界 /// [Fact] - public void TestBetween_Date_2() { + public async Task TestBetween_Date_2() { //常量 var name = "TestBetween_Date_2"; var birthday = "2005-5-5 05:05:05".ToDateTime(); @@ -331,23 +317,23 @@ namespace Util.Data.EntityFrameworkCore.Tests { var maxBirthday = "2005-5-8".ToDateTime(); //添加实体列表 - AddCustomers(); + await AddCustomersAsync(); var customers = CustomerFakeService.GetCustomers( 5 ); customers.ForEach( customer => { customer.Name = name; customer.Birthday = birthday; birthday = birthday.AddDays( 1 ); } ); - _repository.Add( customers ); - UnitOfWork.Commit(); + await _repository.AddAsync( customers ); + await UnitOfWork.CommitAsync(); UnitOfWork.ClearCache(); //查询 - var result = _repository.Find() + var result = await _repository.Find() .Where( t => t.Name == name ) .Between( t => t.Birthday, minBirthday, maxBirthday, false, Boundary.Right ) .OrderBy( t => t.Birthday ) - .ToList(); + .ToListAsync(); //验证 Assert.Equal( 2, result.Count ); @@ -359,7 +345,7 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试添加范围查询条件 - 日期不带时间 - 包含两边 /// [Fact] - public void TestBetween_Date_3() { + public async Task TestBetween_Date_3() { //常量 var name = "TestBetween_Date_3"; var birthday = "2005-5-5 05:05:05".ToDateTime(); @@ -367,23 +353,23 @@ namespace Util.Data.EntityFrameworkCore.Tests { var maxBirthday = "2005-5-8".ToDateTime(); //添加实体列表 - AddCustomers(); + await AddCustomersAsync(); var customers = CustomerFakeService.GetCustomers( 5 ); customers.ForEach( customer => { customer.Name = name; customer.Birthday = birthday; birthday = birthday.AddDays( 1 ); } ); - _repository.Add( customers ); - UnitOfWork.Commit(); + await _repository.AddAsync( customers ); + await UnitOfWork.CommitAsync(); UnitOfWork.ClearCache(); //查询 - var result = _repository.Find() + var result = await _repository.Find() .Where( t => t.Name == name ) .Between( t => t.Birthday, minBirthday, maxBirthday, false, Boundary.Both ) .OrderBy( t => t.Birthday ) - .ToList(); + .ToListAsync(); //验证 Assert.Equal( 3, result.Count ); @@ -396,7 +382,7 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试添加范围查询条件 - 日期不带时间 - 不包含边界 /// [Fact] - public void TestBetween_Date_4() { + public async Task TestBetween_Date_4() { //常量 var name = "TestBetween_Date_4"; var birthday = "2005-5-5 05:05:05".ToDateTime(); @@ -404,22 +390,22 @@ namespace Util.Data.EntityFrameworkCore.Tests { var maxBirthday = "2005-5-8".ToDateTime(); //添加实体列表 - AddCustomers(); + await AddCustomersAsync(); var customers = CustomerFakeService.GetCustomers( 5 ); customers.ForEach( customer => { customer.Name = name; customer.Birthday = birthday; birthday = birthday.AddDays( 1 ); } ); - _repository.Add( customers ); - UnitOfWork.Commit(); + await _repository.AddAsync( customers ); + await UnitOfWork.CommitAsync(); UnitOfWork.ClearCache(); //查询 - var result = _repository.Find() + var result = await _repository.Find() .Where( t => t.Name == name ) .Between( t => t.Birthday, minBirthday, maxBirthday, false, Boundary.Neither ) - .ToList(); + .ToListAsync(); //验证 Assert.Single( result ); @@ -430,14 +416,14 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试添加范围查询条件 - 日期不带时间 - 最大值为空 /// [Fact] - public void TestBetween_Date_5() { + public async Task TestBetween_Date_5() { //常量 var name = "TestBetween_Date_5"; var birthday = "2005-5-5 05:05:05".ToDateTime(); var minBirthday = "2005-5-6".ToDateTime(); //添加实体列表 - AddCustomers(); + await AddCustomersAsync(); var customers = CustomerFakeService.GetCustomers( 5 ); customers.ForEach( customer => { customer.Nickname = name; @@ -445,16 +431,16 @@ namespace Util.Data.EntityFrameworkCore.Tests { customer.Birthday = birthday; birthday = birthday.AddDays( 1 ); } ); - _repository.Add( customers ); - UnitOfWork.Commit(); + await _repository.AddAsync( customers ); + await UnitOfWork.CommitAsync(); UnitOfWork.ClearCache(); //查询 - var result = _repository.Find() + var result = await _repository.Find() .Where( t => t.Name == name ) .Between( t => t.Birthday, minBirthday, null, false ) .OrderBy( t => t.Birthday ) - .ToList(); + .ToListAsync(); //验证 Assert.Equal( 4, result.Count ); @@ -465,29 +451,29 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试添加范围查询条件 - 日期不带时间 - 最小值为空 /// [Fact] - public void TestBetween_Date_6() { + public async Task TestBetween_Date_6() { //常量 var name = "TestBetween_Date_6"; var birthday = "2005-5-5 05:05:05".ToDateTime(); var maxBirthday = "2005-5-8".ToDateTime(); //添加实体列表 - AddCustomers(); + await AddCustomersAsync(); var customers = CustomerFakeService.GetCustomers( 5 ); customers.ForEach( customer => { customer.Name = name; customer.Birthday = birthday; birthday = birthday.AddDays( 1 ); } ); - _repository.Add( customers ); - UnitOfWork.Commit(); + await _repository.AddAsync( customers ); + await UnitOfWork.CommitAsync(); UnitOfWork.ClearCache(); //查询 - var result = _repository.Find() + var result = await _repository.Find() .Where( t => t.Name == name ) .Between( t => t.Birthday, null, maxBirthday, false ) - .ToList(); + .ToListAsync(); //验证 Assert.Equal( 4, result.Count ); @@ -501,15 +487,15 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试获取分页列表 /// [Fact] - public void TestToPageList_1() { + public async Task TestToPageList_1() { //常量 var name = "TestToPageList_1"; //添加实体列表 - var customers = AddCustomers( 10, name ); + var customers = await AddCustomersAsync( 10, name ); //创建查询参数 - var parameter = new QueryParameter { PageSize = 3, Page = 1, Order = "Id" }; + var parameter = new QueryParameter { PageSize = 3, Page = 1, Order = "Code" }; //查询 var result = _repository.Find().Where( t => t.Name == name ).ToPageList( parameter ); @@ -529,15 +515,15 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试获取分页列表 - 第二页 /// [Fact] - public void TestToPageList_2() { + public async Task TestToPageList_2() { //常量 var name = "TestToPageList_2"; //添加实体列表 - var customers = AddCustomers( 10, name ); + var customers = await AddCustomersAsync( 10, name ); //创建查询参数 - var parameter = new QueryParameter { PageSize = 3, Page = 2, Order = "Id" }; + var parameter = new QueryParameter { PageSize = 3, Page = 2, Order = "Code" }; //查询 var result = _repository.Find().Where( t => t.Name == name ).ToPageList( parameter ); @@ -557,18 +543,18 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试获取分页列表 - Queryable设置排序 /// [Fact] - public void TestToPageList_3() { + public async Task TestToPageList_3() { //常量 var name = "TestToPageList_3"; //添加实体列表 - var customers = AddCustomers( 10, name ); + var customers = await AddCustomersAsync( 10, name ); //创建查询参数 var parameter = new QueryParameter { PageSize = 3, Page = 2 }; //查询 - var result = _repository.Find().Where( t => t.Name == name ).OrderBy( t => t.Id ).ToPageList( parameter ); + var result = _repository.Find().Where( t => t.Name == name ).OrderBy( t => t.Code ).ToPageList( parameter ); //验证 Assert.Equal( 4, result.PageCount ); @@ -597,7 +583,7 @@ namespace Util.Data.EntityFrameworkCore.Tests { var customers = await AddCustomersAsync( 10, name ); //创建查询参数 - var parameter = new QueryParameter { PageSize = 3, Page = 2, Order = "Id" }; + var parameter = new QueryParameter { PageSize = 3, Page = 2, Order = "Code" }; //查询 var result = await _repository.Find().Where( t => t.Name == name ).ToPageListAsync( parameter ); diff --git a/test/Util.Data.EntityFrameworkCore.Oracle.Tests.Integration/Tests/EntityEventsTest.cs b/test/Util.Data.EntityFrameworkCore.Oracle.Tests.Integration/Tests/EntityEventsTest.cs new file mode 100644 index 00000000..b4e62e8c --- /dev/null +++ b/test/Util.Data.EntityFrameworkCore.Oracle.Tests.Integration/Tests/EntityEventsTest.cs @@ -0,0 +1,211 @@ +using System.Threading.Tasks; +using Util.Tests.EventHandlers; +using Util.Tests.Fakes; +using Util.Tests.Infrastructure; +using Util.Tests.Repositories; +using Util.Tests.UnitOfWorks; +using Xunit; +using Xunit.Abstractions; + +namespace Util.Data.EntityFrameworkCore.Tests { + /// + /// 实体事件测试 + /// + public class EntityEventsTest : TestBase { + + #region 测试初始化 + + /// + /// 测试输出 + /// + private readonly ITestOutputHelper _testOutputHelper; + /// + /// 产品仓储 + /// + private readonly IProductRepository _productRepository; + /// + /// 操作日志仓储 + /// + private readonly IOperationLogRepository _operationLogRepository; + + /// + /// 测试初始化 + /// + public EntityEventsTest( ITestOutputHelper testOutputHelper, IProductRepository productRepository, + IOperationLogRepository operationLogRepository, ITestUnitOfWork unitOfWork ) :base(unitOfWork){ + _testOutputHelper = testOutputHelper; + _productRepository = productRepository; + _operationLogRepository = operationLogRepository; + } + + #endregion + + #region 实体创建事件 + + /// + /// 测试实体创建事件 + /// + [Fact] + public async Task TestEntityCreatedEvent() { + //添加实体 + var entity = ProductFakeService.GetProduct(); + entity.Init(); + entity.Name = "EntityCreatedEvent"; + await _productRepository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); + + //验证 + Assert.True( await _operationLogRepository.ExistsAsync( t => t.Caption == "EntityCreatedEvent" && t.LogName == nameof( ProductCreatedEventHandler ) ) ); + } + + /// + /// 测试实体变更事件 - 创建 + /// + [Fact] + public async Task TestEntityChangedEvent_Created() { + //添加实体 + var entity = ProductFakeService.GetProduct(); + entity.Init(); + entity.Name = "EntityChangedEvent_Created"; + await _productRepository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); + + //验证 + Assert.True( await _operationLogRepository.ExistsAsync( t => t.Caption == "EntityChangedEvent_Created" && t.LogName == nameof( ProductChangedEventHandler ) ) ); + } + + #endregion + + #region 实体修改事件 + + /// + /// 测试实体修改事件 + /// + [Fact] + public async Task TestEntityUpdatedEvent() { + //添加实体 + var entity = ProductFakeService.GetProduct(); + entity.Init(); + await _productRepository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //修改实体 + var product = await _productRepository.FindByIdAsync( entity.Id ); + product.Name = "EntityUpdatedEvent"; + await _productRepository.UpdateAsync( product ); + await UnitOfWork.CommitAsync(); + + //验证 + Assert.True( await _operationLogRepository.ExistsAsync( t => t.Caption == "EntityUpdatedEvent" && t.LogName == nameof( ProductUpdatedEventHandler ) ) ); + } + + /// + /// 测试实体变更事件 - 修改 + /// + [Fact] + public async Task TestEntityChangedEvent_Updated() { + //添加实体 + var entity = ProductFakeService.GetProduct(); + entity.Init(); + await _productRepository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //修改实体 + var product = _productRepository.FindById( entity.Id ); + product.Name = "EntityChangedEvent_Updated"; + await _productRepository.UpdateAsync( product ); + await UnitOfWork.CommitAsync(); + + //验证 + Assert.True( await _operationLogRepository.ExistsAsync( t => t.Caption == "EntityChangedEvent_Updated" && t.LogName == nameof( ProductChangedEventHandler ) ) ); + } + + #endregion + + #region 实体删除事件 + + /// + /// 测试实体删除事件 - 逻辑删除 + /// + [Fact] + public async Task TestEntityDeletedEvent_1() { + //添加实体 + var entity = ProductFakeService.GetProduct(); + entity.Init(); + entity.Name = "EntityDeletedEvent"; + await _productRepository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); + + //删除实体 + await _productRepository.RemoveAsync( entity ); + await UnitOfWork.CommitAsync(); + + //验证 + Assert.True( await _operationLogRepository.ExistsAsync( t => t.Caption == "EntityDeletedEvent" && t.LogName == nameof( ProductDeletedEventHandler ) ) ); + } + + /// + /// 测试实体删除事件 - 物理删除 + /// + [Fact] + public async Task TestEntityDeletedEvent_2() { + //添加实体 + var entity = OperationLogFakeService.GetOperationLog(); + entity.Init(); + entity.LogName = "EntityDeletedEvent"; + await _operationLogRepository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); + + //删除实体 + await _operationLogRepository.RemoveAsync( entity ); + await UnitOfWork.CommitAsync(); + + //验证 + Assert.True( await _operationLogRepository.ExistsAsync( t => t.LogName == "Test" && t.Caption == nameof( OperationLogDeletedEventHandler ) && t.Content == "EntityDeletedEvent" ) ); + } + + /// + /// 测试实体变更事件 - 逻辑删除 + /// + [Fact] + public async Task TestEntityChangedEvent_Deleted_1() { + //添加实体 + var entity = ProductFakeService.GetProduct(); + entity.Init(); + entity.Name = "EntityChangedEvent_Deleted"; + await _productRepository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); + + //删除实体 + await _productRepository.RemoveAsync( entity ); + await UnitOfWork.CommitAsync(); + + //验证 + Assert.True( await _operationLogRepository.ExistsAsync( t => t.Caption == "EntityChangedEvent_Deleted" && t.LogName == nameof( ProductChangedEventHandler ) ) ); + } + + /// + /// 测试实体变更事件 - 物理删除 + /// + [Fact] + public async Task TestEntityChangedEvent_Deleted_2() { + //添加实体 + var entity = OperationLogFakeService.GetOperationLog(); + entity.Init(); + entity.LogName = "EntityChangedEvent_Deleted"; + await _operationLogRepository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); + + //删除实体 + await _operationLogRepository.RemoveAsync( entity ); + await UnitOfWork.CommitAsync(); + + //验证 + Assert.True( await _operationLogRepository.ExistsAsync( t => t.LogName == "Test" && t.Caption == nameof( OperationLogChangedEventHandler ) && t.Content == "EntityChangedEvent_Deleted" ) ); + } + + #endregion + } +} diff --git a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Tests/OperationLogRepositoryTest.cs b/test/Util.Data.EntityFrameworkCore.Oracle.Tests.Integration/Tests/OperationLogRepositoryTest.cs similarity index 63% rename from test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Tests/OperationLogRepositoryTest.cs rename to test/Util.Data.EntityFrameworkCore.Oracle.Tests.Integration/Tests/OperationLogRepositoryTest.cs index 669eb17a..fecbccb7 100644 --- a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Tests/OperationLogRepositoryTest.cs +++ b/test/Util.Data.EntityFrameworkCore.Oracle.Tests.Integration/Tests/OperationLogRepositoryTest.cs @@ -1,7 +1,8 @@ -using Util.Data.EntityFrameworkCore.Fakes; -using Util.Data.EntityFrameworkCore.Infrastructure; -using Util.Data.EntityFrameworkCore.Repositories; -using Util.Data.EntityFrameworkCore.UnitOfWorks; +using System.Threading.Tasks; +using Util.Tests.Fakes; +using Util.Tests.Infrastructure; +using Util.Tests.Repositories; +using Util.Tests.UnitOfWorks; using Xunit; namespace Util.Data.EntityFrameworkCore.Tests { @@ -19,19 +20,19 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// /// 测试初始化 /// - public OperationLogRepositoryTest( IOperationLogRepository repository, IPgSqlUnitOfWork unitOfWork ) :base(unitOfWork) { - _repository = repository; + public OperationLogRepositoryTest( IOperationLogRepository operationLogRepository, ITestUnitOfWork unitOfWork ) : base( unitOfWork ) { + _repository = operationLogRepository; } /// /// 测试添加实体 /// [Fact] - public void TestAdd() { + public async Task TestAdd() { //添加实体 var entity = OperationLogFakeService.GetOperationLog(); - _repository.Add( entity ); - UnitOfWork.Commit(); + await _repository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); //验证 Assert.True( entity.Id > 0 ); @@ -42,20 +43,20 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试通过标识移除实体 - 物理删除 /// [Fact] - public void TestRemove_Id() { + public async Task TestRemove_Id() { //添加实体 var entity = OperationLogFakeService.GetOperationLog(); - _repository.Add( entity ); - UnitOfWork.Commit(); + await _repository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); UnitOfWork.ClearCache(); //移除实体 - _repository.Remove( entity.Id ); - UnitOfWork.Commit(); + await _repository.RemoveAsync( entity.Id ); + await UnitOfWork.CommitAsync(); UnitOfWork.ClearCache(); //验证 - var result = _repository.FindById( entity.Id ); + var result = await _repository.FindByIdAsync( entity.Id ); Assert.Null( result ); } } diff --git a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Tests/OrderRepositoryTest.cs b/test/Util.Data.EntityFrameworkCore.Oracle.Tests.Integration/Tests/OrderRepositoryTest.cs similarity index 72% rename from test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Tests/OrderRepositoryTest.cs rename to test/Util.Data.EntityFrameworkCore.Oracle.Tests.Integration/Tests/OrderRepositoryTest.cs index d2bdfd36..076b5bd1 100644 --- a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Tests/OrderRepositoryTest.cs +++ b/test/Util.Data.EntityFrameworkCore.Oracle.Tests.Integration/Tests/OrderRepositoryTest.cs @@ -1,10 +1,10 @@ using System.Threading.Tasks; using Microsoft.EntityFrameworkCore; -using Util.Data.EntityFrameworkCore.Fakes; -using Util.Data.EntityFrameworkCore.Infrastructure; -using Util.Data.EntityFrameworkCore.Models; -using Util.Data.EntityFrameworkCore.Repositories; -using Util.Data.EntityFrameworkCore.UnitOfWorks; +using Util.Tests.Fakes; +using Util.Tests.Infrastructure; +using Util.Tests.Models; +using Util.Tests.Repositories; +using Util.Tests.UnitOfWorks; using Xunit; namespace Util.Data.EntityFrameworkCore.Tests { @@ -26,7 +26,7 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// /// 测试初始化 /// - public OrderRepositoryTest(IOrderRepository repository, IPgSqlUnitOfWork unitOfWork ) : base(unitOfWork){ + public OrderRepositoryTest( IOrderRepository repository, ITestUnitOfWork unitOfWork ) : base( unitOfWork ) { _repository = repository; } @@ -34,29 +34,6 @@ namespace Util.Data.EntityFrameworkCore.Tests { #region 辅助方法 - /// - /// 添加订单 - /// - private Order AddOrder() { - var order = OrderFakeService.GetOrder(); - order.Init(); - order.OrderItems.Add( CreateOrderItem() ); - order.OrderItems.Add( CreateOrderItem() ); - _repository.Add( order ); - UnitOfWork.Commit(); - UnitOfWork.ClearCache(); - return order; - } - - /// - /// 创建订单项 - /// - private OrderItem CreateOrderItem() { - var item = OrderItemFakeService.GetOrderItem(); - item.Init(); - return item; - } - /// /// 添加订单 /// @@ -71,6 +48,15 @@ namespace Util.Data.EntityFrameworkCore.Tests { return order; } + /// + /// 创建订单项 + /// + private OrderItem CreateOrderItem() { + var item = OrderItemFakeService.GetOrderItem(); + item.Init(); + return item; + } + #endregion #region Single @@ -79,12 +65,12 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试查找单个实体 /// [Fact] - public void TestSingle_1() { + public async Task TestSingle_1() { //添加实体 - var entity = AddOrder(); + var entity = await AddOrderAsync(); //查找单个实体 - var result = _repository.Single( t => t.Id == entity.Id ); + var result = await _repository.SingleAsync( t => t.Id == entity.Id ); //验证 Assert.Empty( result.OrderItems ); @@ -94,12 +80,12 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试查找单个实体 - 使用Include包含子实体集合 /// [Fact] - public void TestSingle_2() { + public async Task TestSingle_2() { //添加实体 - var entity = AddOrder(); + var entity = await AddOrderAsync(); //查找单个实体 - var result = _repository.Single( t => t.Id == entity.Id, queryable => queryable.Include( t => t.OrderItems ) ); + var result = await _repository.SingleAsync( t => t.Id == entity.Id, queryable => queryable.Include( t => t.OrderItems ) ); //验证 Assert.Equal( 2, result.OrderItems.Count ); diff --git a/test/Util.Data.EntityFrameworkCore.Oracle.Tests.Integration/Tests/PostRepositoryTest.cs b/test/Util.Data.EntityFrameworkCore.Oracle.Tests.Integration/Tests/PostRepositoryTest.cs new file mode 100644 index 00000000..c238dde1 --- /dev/null +++ b/test/Util.Data.EntityFrameworkCore.Oracle.Tests.Integration/Tests/PostRepositoryTest.cs @@ -0,0 +1,54 @@ +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore; +using Util.Tests.Fakes; +using Util.Tests.Infrastructure; +using Util.Tests.Repositories; +using Util.Tests.UnitOfWorks; +using Xunit; + +namespace Util.Data.EntityFrameworkCore.Tests { + /// + /// 贴子仓储测试 + /// 说明: + /// 1. 测试多对多 + /// + public class PostRepositoryTest : TestBase { + /// + /// 仓储 + /// + private readonly IPostRepository _repository; + + /// + /// 测试初始化 + /// + public PostRepositoryTest(IPostRepository repository, ITestUnitOfWork unitOfWork ) : base(unitOfWork){ + _repository = repository; + } + + /// + /// 测试添加实体 + /// + [Fact] + public async Task TestAddAsync() { + //添加实体 + var post = PostFakeService.GetPost(); + post.Init(); + var tag1 = TagFakeService.GetTag(); + tag1.Init(); + post.Tags.Add( tag1 ); + + var tag2 = TagFakeService.GetTag(); + tag2.Init(); + post.Tags.Add( tag2 ); + + await _repository.AddAsync( post ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //验证 + var result = await _repository.SingleAsync( t => t.Id == post.Id, queryable => queryable.Include( t => t.Tags ) ); + Assert.NotNull( result ); + Assert.Equal( 2,result.Tags.Count ); + } + } +} \ No newline at end of file diff --git a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Tests/ProductRepositoryTest.Queryable.cs b/test/Util.Data.EntityFrameworkCore.Oracle.Tests.Integration/Tests/ProductRepositoryTest.Queryable.cs similarity index 77% rename from test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Tests/ProductRepositoryTest.Queryable.cs rename to test/Util.Data.EntityFrameworkCore.Oracle.Tests.Integration/Tests/ProductRepositoryTest.Queryable.cs index d0272dfd..e03ea9c5 100644 --- a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Tests/ProductRepositoryTest.Queryable.cs +++ b/test/Util.Data.EntityFrameworkCore.Oracle.Tests.Integration/Tests/ProductRepositoryTest.Queryable.cs @@ -1,8 +1,9 @@ using System; using System.Linq; -using Util.Data.EntityFrameworkCore.Conditions; -using Util.Data.EntityFrameworkCore.Fakes; +using System.Threading.Tasks; using Util.Data.Queries; +using Util.Tests.Conditions; +using Util.Tests.Fakes; using Xunit; namespace Util.Data.EntityFrameworkCore.Tests { @@ -17,24 +18,23 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试设置查询条件 - 添加查询条件对象 /// [Fact] - public void TestWhere() { + public async Task TestWhere() { //常量 var name = "TestWhere"; //添加实体列表 - AddProducts(); - var products = AddProducts( name: name ); + await AddProductsAsync(); + var products = await AddProductsAsync( name: name ); //创建查询条件 var condition = new ProductNameCondition( name ); //查询 - var result = _repository.Find().Where( condition ).OrderBy( t => t.Code ).ToList(); + var result = _repository.Find().Where( condition ).ToList(); //验证 Assert.Equal( products.Count, result.Count ); - Assert.Equal( products[0].Code, result[0].Code ); - Assert.Equal( products[1].Code, result[1].Code ); + Assert.True( result.TrueForAll( t => products.Any( p => p.Id == t.Id ) ) ); } #endregion @@ -45,13 +45,13 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试设置查询条件 - IQueryable添加WhereIf扩展 - true /// [Fact] - public void TestWhereIf_True() { + public async Task TestWhereIf_True() { //常量 var name = "TestWhereIf_True"; //添加实体列表 - AddProducts(); - var products = AddProducts( name: name ); + await AddProductsAsync(); + var products = await AddProductsAsync( name: name ); //查询 var result = _repository.Find().WhereIf( t => t.Name == name, true ).ToList(); @@ -64,13 +64,13 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试设置查询条件 - IQueryable添加WhereIf扩展 - false /// [Fact] - public void TestWhereIf_False() { + public async Task TestWhereIf_False() { //常量 var name = "TestWhereIf_False"; //添加实体列表 - AddProducts(); - var products = AddProducts( name: name ); + await AddProductsAsync(); + var products = await AddProductsAsync( name: name ); //查询 var result = _repository.Find().WhereIf( t => t.Name == name, false ).ToList(); @@ -87,13 +87,13 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试设置查询条件 - IQueryable添加WhereIfNotEmpty扩展 - 有效条件 /// [Fact] - public void TestWhereIfNotEmpty_Valid() { + public async Task TestWhereIfNotEmpty_Valid() { //常量 var name = "TestWhereIfNotEmpty_Valid"; //添加实体列表 - AddProducts(); - var products = AddProducts( name: name ); + await AddProductsAsync(); + var products = await AddProductsAsync( name: name ); //查询 var result = _repository.Find().WhereIfNotEmpty( t => t.Name == name ).ToList(); @@ -106,13 +106,13 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试设置查询条件 - IQueryable添加WhereIfNotEmpty扩展 - 忽略条件 /// [Fact] - public void TestWhereIfNotEmpty_Ignore() { + public async Task TestWhereIfNotEmpty_Ignore() { //常量 var name = "TestWhereIfNotEmpty_Ignore"; //添加实体列表 - AddProducts(); - var products = AddProducts( name: name ); + await AddProductsAsync(); + var products = await AddProductsAsync( name: name ); //查询 var result = _repository.Find().Where( t => t.Name == name ).WhereIfNotEmpty( t => t.Code == "" ).ToList(); @@ -125,9 +125,9 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试设置查询条件 - IQueryable添加WhereIfNotEmpty扩展 - 无效条件,抛出异常 /// [Fact] - public void TestWhereIfNotEmpty_Invalid() { + public async Task TestWhereIfNotEmpty_Invalid() { //添加实体列表 - AddProducts(); + await AddProductsAsync(); //查询 Assert.Throws( () => { @@ -143,17 +143,17 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试设置查询条件 - IQueryable添加OrIfNotEmpty扩展 - 有效条件 /// [Fact] - public void TestOrIfNotEmpty_Valid() { + public async Task TestOrIfNotEmpty_Valid() { //常量 var name1 = "TestOrIfNotEmpty_Valid_1"; var name2 = "TestOrIfNotEmpty_Valid_2"; var name3 = "TestOrIfNotEmpty_Valid_3"; //添加实体列表 - AddProducts(); - AddProducts( 2, name1 ); - AddProducts( 3, name2 ); - AddProducts( 4, name3 ); + await AddProductsAsync(); + await AddProductsAsync( 2, name1 ); + await AddProductsAsync( 3, name2 ); + await AddProductsAsync( 4, name3 ); //查询 var result = _repository.Find().OrIfNotEmpty( t => t.Name == name1,t => t.Name == name2, t => t.Name == name3 ).ToList(); @@ -166,17 +166,17 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试设置查询条件 - IQueryable添加OrIfNotEmpty扩展 - 忽略条件 /// [Fact] - public void TestOrIfNotEmpty_Ignore() { + public async Task TestOrIfNotEmpty_Ignore() { //常量 var name1 = "TestOrIfNotEmpty_Ignore_1"; var name2 = "TestOrIfNotEmpty_Ignore_2"; var name3 = "TestOrIfNotEmpty_Ignore_3"; //添加实体列表 - AddProducts(); - AddProducts( 2, name1 ); - AddProducts( 3, name2 ); - AddProducts( 4, name3 ); + await AddProductsAsync(); + await AddProductsAsync( 2, name1 ); + await AddProductsAsync( 3, name2 ); + await AddProductsAsync( 4, name3 ); //查询 var result = _repository.Find().OrIfNotEmpty( t => t.Name == name1, t => t.Name == name2, t => t.Name == "" ).ToList(); @@ -193,21 +193,21 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试添加范围查询条件 /// [Fact] - public void TestBetween_1() { + public async Task TestBetween_1() { //常量 var name = "TestBetween_1"; var price = 10.1M; //添加实体列表 - AddProducts(); + await AddProductsAsync(); var products = ProductFakeService.GetProducts( 5 ); products.ForEach( product => { product.Init(); product.Name = name; product.Price = price++; } ); - _repository.Add( products ); - UnitOfWork.Commit(); + await _repository.AddAsync( products ); + await UnitOfWork.CommitAsync(); UnitOfWork.ClearCache(); //查询 @@ -221,21 +221,21 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试添加范围查询条件 - 包含左边界 /// [Fact] - public void TestBetween_2() { + public async Task TestBetween_2() { //常量 var name = "TestBetween_2"; var price = 10.1M; //添加实体列表 - AddProducts(); + await AddProductsAsync(); var products = ProductFakeService.GetProducts( 5 ); products.ForEach( product => { product.Init(); product.Name = name; product.Price = price++; } ); - _repository.Add( products ); - UnitOfWork.Commit(); + await _repository.AddAsync( products ); + await UnitOfWork.CommitAsync(); UnitOfWork.ClearCache(); //查询 @@ -249,21 +249,21 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试添加范围查询条件 - 包含右边界 /// [Fact] - public void TestBetween_3() { + public async Task TestBetween_3() { //常量 var name = "TestBetween_3"; var price = 10.1M; //添加实体列表 - AddProducts(); + await AddProductsAsync(); var products = ProductFakeService.GetProducts( 5 ); products.ForEach( product => { product.Init(); product.Name = name; product.Price = price++; } ); - _repository.Add( products ); - UnitOfWork.Commit(); + await _repository.AddAsync( products ); + await UnitOfWork.CommitAsync(); UnitOfWork.ClearCache(); //查询 @@ -277,21 +277,21 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试添加范围查询条件 - 包含两边 /// [Fact] - public void TestBetween_4() { + public async Task TestBetween_4() { //常量 var name = "TestBetween_4"; var price = 10.1M; //添加实体列表 - AddProducts(); + await AddProductsAsync(); var products = ProductFakeService.GetProducts( 5 ); products.ForEach( product => { product.Init(); product.Name = name; product.Price = price++; } ); - _repository.Add( products ); - UnitOfWork.Commit(); + await _repository.AddAsync( products ); + await UnitOfWork.CommitAsync(); UnitOfWork.ClearCache(); //查询 @@ -305,21 +305,21 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试添加范围查询条件 - 不包含边界 /// [Fact] - public void TestBetween_5() { + public async Task TestBetween_5() { //常量 var name = "TestBetween_5"; var price = 10.1M; //添加实体列表 - AddProducts(); + await AddProductsAsync(); var products = ProductFakeService.GetProducts( 5 ); products.ForEach( product => { product.Init(); product.Name = name; product.Price = price++; } ); - _repository.Add( products ); - UnitOfWork.Commit(); + await _repository.AddAsync( products ); + await UnitOfWork.CommitAsync(); UnitOfWork.ClearCache(); //查询 @@ -333,21 +333,21 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试添加范围查询条件 - 最大值为空 /// [Fact] - public void TestBetween_6() { + public async Task TestBetween_6() { //常量 var name = "TestBetween_6"; var price = 10.1M; //添加实体列表 - AddProducts(); + await AddProductsAsync(); var products = ProductFakeService.GetProducts( 5 ); products.ForEach( product => { product.Init(); product.Name = name; product.Price = price++; } ); - _repository.Add( products ); - UnitOfWork.Commit(); + await _repository.AddAsync( products ); + await UnitOfWork.CommitAsync(); UnitOfWork.ClearCache(); //查询 @@ -361,21 +361,21 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试添加范围查询条件 - 最小值为空 /// [Fact] - public void TestBetween_7() { + public async Task TestBetween_7() { //常量 var name = "TestBetween_7"; var price = 10.1M; //添加实体列表 - AddProducts(); + await AddProductsAsync(); var products = ProductFakeService.GetProducts( 5 ); products.ForEach( product => { product.Init(); product.Name = name; product.Price = price++; } ); - _repository.Add( products ); - UnitOfWork.Commit(); + await _repository.AddAsync( products ); + await UnitOfWork.CommitAsync(); UnitOfWork.ClearCache(); //查询 diff --git a/test/Util.Data.EntityFrameworkCore.Oracle.Tests.Integration/Tests/ProductRepositoryTest.cs b/test/Util.Data.EntityFrameworkCore.Oracle.Tests.Integration/Tests/ProductRepositoryTest.cs new file mode 100644 index 00000000..c9710351 --- /dev/null +++ b/test/Util.Data.EntityFrameworkCore.Oracle.Tests.Integration/Tests/ProductRepositoryTest.cs @@ -0,0 +1,1408 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Util.Exceptions; +using Util.Tests.Fakes; +using Util.Tests.Infrastructure; +using Util.Tests.Models; +using Util.Tests.Repositories; +using Util.Tests.UnitOfWorks; +using Xunit; +using Xunit.Abstractions; +using Xunit.DependencyInjection; + +namespace Util.Data.EntityFrameworkCore.Tests { + /// + /// 产品仓储测试 + /// 说明: + /// 1. 测试Guid类型标识 + /// 2. 测试仓储基础方法 + /// 3. 测试扩展属性 + /// + public partial class ProductRepositoryTest : TestBase { + + #region 测试初始化 + + /// + /// 日志消息 + /// + private readonly ITestOutputHelper _log; + /// + /// 仓储 + /// + private readonly IProductRepository _repository; + + /// + /// 测试初始化 + /// + public ProductRepositoryTest( ITestOutputHelperAccessor accessor, IProductRepository repository, ITestUnitOfWork unitOfWork ) :base(unitOfWork) { + _log = accessor.Output; + _repository = repository; + } + + #endregion + + #region 辅助方法 + + /// + /// 添加产品 + /// + private async Task AddProductAsync( string name = null ) { + var entity = ProductFakeService.GetProduct(); + entity.Init(); + if( name != null ) + entity.Name = name; + await _repository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); + return entity; + } + + /// + /// 添加实体列表 + /// + /// 添加数量 + /// 产品名称 + private async Task> AddProductsAsync( int count = 2, string name = null ) { + var products = ProductFakeService.GetProducts( count ); + products.ForEach( product => { + product.Init(); + if( name != null ) + product.Name = name; + } ); + await _repository.AddAsync( products ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + return products.OrderBy( t => t.Id ).ToList(); + } + + /// + /// 打印更改跟踪调试信息 + /// + private void WriteTrackerDebug() { + _log.WriteLine( UnitOfWork.GetChangeTrackerDebugView() ); + } + + #endregion + + #region FindById + + /// + /// 测试通过标识查找实体 - 跟踪实体 + /// + [Fact] + public async Task TestFindById_Tracking_1() { + //添加实体 + var entity = await AddProductAsync(); + UnitOfWork.ClearCache(); + + //验证 + var result = _repository.FindById( entity.Id ); + WriteTrackerDebug(); + Assert.Equal( entity.Code, result.Code ); + } + + /// + /// 测试通过标识查找实体 - 跟踪实体 - 字符串标识 + /// + [Fact] + public async Task TestFindById_Tracking_2() { + //添加实体 + var entity = await AddProductAsync(); + UnitOfWork.ClearCache(); + + //验证 + var result = _repository.FindById( entity.Id.ToString() ); + WriteTrackerDebug(); + Assert.Equal( entity.Code, result.Code ); + } + + /// + /// 测试通过标识查找实体 - 不跟踪实体 + /// + [Fact] + public async Task TestFindById_NoTracking() { + //添加实体 + var entity = await AddProductAsync(); + UnitOfWork.ClearCache(); + + //验证 + var result = _repository.NoTracking().FindById( entity.Id ); + WriteTrackerDebug(); + Assert.Equal( entity.Code, result.Code ); + } + + #endregion + + #region FindByIdAsync + + /// + /// 测试通过标识查找实体 - 跟踪 - 异步 + /// + [Fact] + public async Task TestFindByIdAsync_Tracking_1() { + //添加实体 + var entity = await AddProductAsync(); + UnitOfWork.ClearCache(); + + //验证 + var result = await _repository.FindByIdAsync( entity.Id ); + WriteTrackerDebug(); + Assert.Equal( entity.Code, result.Code ); + } + + /// + /// 测试通过标识查找实体 - 跟踪 - 异步 - 字符串标识 + /// + [Fact] + public async Task TestFindByIdAsync_Tracking_2() { + //添加实体 + var entity = await AddProductAsync(); + UnitOfWork.ClearCache(); + + //验证 + var result = await _repository.FindByIdAsync( entity.Id.ToString() ); + WriteTrackerDebug(); + Assert.Equal( entity.Code, result.Code ); + } + + /// + /// 测试通过标识查找实体 - 不跟踪 - 异步 + /// + [Fact] + public async Task TestFindByIdAsync_NoTracking() { + //添加实体 + var entity = await AddProductAsync(); + UnitOfWork.ClearCache(); + + //验证 + var result = await _repository.NoTracking().FindByIdAsync( entity.Id ); + WriteTrackerDebug(); + Assert.Equal( entity.Code, result.Code ); + } + + #endregion + + #region FindByIds + + /// + /// 测试通过标识列表查找实体列表 - 传入逗号分隔的标识列表 + /// + [Fact] + public async Task TestFindByIds_1() { + //常量 + var count = 3; + + //添加实体列表 + var products = ProductFakeService.GetProducts( count ).OrderBy( t => t.Code ).ToList(); + products.ForEach( product => { + product.Init(); + } ); + await _repository.AddAsync( products ); + await UnitOfWork.CommitAsync(); + + //验证 + var result = _repository.FindByIds( products[0].Id, products[1].Id, products[2].Id ).OrderBy( t => t.Code ).ToList(); + Assert.Equal( products[0].Description, result[0].Description ); + Assert.Equal( products[1].Description, result[1].Description ); + Assert.Equal( products[2].Description, result[2].Description ); + } + + /// + /// 测试通过标识列表查找实体列表 - 传入集合 + /// + [Fact] + public async Task TestFindByIds_2() { + //常量 + var count = 3; + + //添加实体列表 + var products = ProductFakeService.GetProducts( count ).OrderBy( t => t.Code ).ToList(); + products.ForEach( product => { + product.Init(); + } ); + await _repository.AddAsync( products ); + await UnitOfWork.CommitAsync(); + + //验证 + var result = _repository.FindByIds( products.Select( t => t.Id ) ).OrderBy( t => t.Code ).ToList(); + Assert.Equal( products[0].Description, result[0].Description ); + Assert.Equal( products[1].Description, result[1].Description ); + Assert.Equal( products[2].Description, result[2].Description ); + } + + /// + /// 测试通过标识列表查找实体列表 - 传入标识列表字符串 + /// + [Fact] + public async Task TestFindByIds_3() { + //常量 + var count = 3; + + //添加实体列表 + var products = ProductFakeService.GetProducts( count ).OrderBy( t => t.Code ).ToList(); + products.ForEach( product => { + product.Init(); + } ); + await _repository.AddAsync( products ); + await UnitOfWork.CommitAsync(); + + //验证 + var result = _repository.FindByIds( products.Select( t => t.Id ).Join() ).OrderBy( t => t.Code ).ToList(); + Assert.Equal( products[0].Description, result[0].Description ); + Assert.Equal( products[1].Description, result[1].Description ); + Assert.Equal( products[2].Description, result[2].Description ); + } + + #endregion + + #region FindByIdsAsync + + /// + /// 测试通过标识列表查找实体列表 - 传入逗号分隔的标识列表 - 异步 + /// + [Fact] + public async Task TestFindByIdsAsync_1() { + //常量 + var count = 3; + + //添加实体列表 + var products = ProductFakeService.GetProducts( count ).OrderBy( t => t.Code ).ToList(); + products.ForEach( product => { + product.Init(); + } ); + await _repository.AddAsync( products ); + await UnitOfWork.CommitAsync(); + + //验证 + var result = ( await _repository.FindByIdsAsync( products[0].Id, products[1].Id, products[2].Id ) ).OrderBy( t => t.Code ).ToList(); + Assert.Equal( products[0].Description, result[0].Description ); + Assert.Equal( products[1].Description, result[1].Description ); + Assert.Equal( products[2].Description, result[2].Description ); + } + + /// + /// 测试通过标识列表查找实体列表 - 传入集合 - 异步 + /// + [Fact] + public async Task TestFindByIdsAsync_2() { + //常量 + var count = 3; + + //添加实体列表 + var products = ProductFakeService.GetProducts( count ).OrderBy( t => t.Code ).ToList(); + products.ForEach( product => { + product.Init(); + } ); + await _repository.AddAsync( products ); + await UnitOfWork.CommitAsync(); + + //验证 + var result = ( await _repository.FindByIdsAsync( products.Select( t => t.Id ) ) ).OrderBy( t => t.Code ).ToList(); + Assert.Equal( products[0].Description, result[0].Description ); + Assert.Equal( products[1].Description, result[1].Description ); + Assert.Equal( products[2].Description, result[2].Description ); + } + + /// + /// 测试通过标识列表查找实体列表 - 传入标识列表字符串 - 异步 + /// + [Fact] + public async Task TestFindByIdsAsync_3() { + //常量 + var count = 3; + + //添加实体列表 + var products = ProductFakeService.GetProducts( count ).OrderBy( t => t.Code ).ToList(); + products.ForEach( product => { + product.Init(); + } ); + await _repository.AddAsync( products ); + await UnitOfWork.CommitAsync(); + + //验证 + var result = ( await _repository.FindByIdsAsync( products.Select( t => t.Id ).Join() ) ).OrderBy( t => t.Code ).ToList(); + Assert.Equal( products[0].Description, result[0].Description ); + Assert.Equal( products[1].Description, result[1].Description ); + Assert.Equal( products[2].Description, result[2].Description ); + } + + #endregion + + #region Single + + /// + /// 测试查找单个实体 + /// + [Fact] + public async Task TestSingle_1() { + //常量 + var name = "TestSingle"; + + //添加实体 + var entity = await AddProductAsync( name ); + UnitOfWork.ClearCache(); + + //验证 + var result = _repository.Single( t => t.Name == name ); + Assert.Equal( entity.Code, result.Code ); + } + + #endregion + + #region SingleAsync + + /// + /// 测试查找单个实体 - 异步 + /// + [Fact] + public async Task TestSingleAsync() { + //常量 + var name = "TestSingleAsync"; + + //添加实体 + var entity = await AddProductAsync( name ); + UnitOfWork.ClearCache(); + + //验证 + var result = await _repository.SingleAsync( t => t.Name == name ); + Assert.Equal( entity.Code, result.Code ); + } + + #endregion + + #region Exists + + /// + /// 测试判断是否存在 + /// + [Fact] + public async Task TestExists() { + //添加实体 + var entity = await AddProductAsync(); + UnitOfWork.ClearCache(); + + //验证 + Assert.True( _repository.Exists( t => t.Id == entity.Id ) ); + } + + #endregion + + #region ExistsAsync + + /// + /// 测试判断是否存在 - 异步 + /// + [Fact] + public async Task TestExistsAsync() { + //添加实体 + var entity = await AddProductAsync(); + UnitOfWork.ClearCache(); + + //验证 + Assert.True( await _repository.ExistsAsync( t => t.Id == entity.Id ) ); + } + + #endregion + + #region Count + + /// + /// 测试查找数量 + /// + [Fact] + public async Task TestCount() { + //常量 + var name = "TestCount"; + var count = 3; + + //添加实体列表 + var products = ProductFakeService.GetProducts( count ); + products.ForEach( product => { + product.Init(); + product.Name = name; + } ); + await _repository.AddAsync( products ); + await UnitOfWork.CommitAsync(); + + //验证 + var result = _repository.Count( t => t.Name == name ); + Assert.Equal( count, result ); + } + + #endregion + + #region CountAsync + + /// + /// 测试查找数量 - 异步 + /// + [Fact] + public async Task TestCountAsync() { + //常量 + var name = "TestCountAsync"; + var count = 3; + + //添加实体列表 + var products = ProductFakeService.GetProducts( count ); + products.ForEach( product => { + product.Init(); + product.Name = name; + } ); + await _repository.AddAsync( products ); + await UnitOfWork.CommitAsync(); + + //验证 + var result = await _repository.CountAsync( t => t.Name == name ); + Assert.Equal( count, result ); + } + + #endregion + + #region Update + + /// + /// 测试更新方法1 - 查找并修改实体,直接提交工作单元 + /// + [Fact] + public async Task TestUpdate_1() { + //常量 + var code = "TestUpdate_1_Code"; + + //添加实体 + var entity = await AddProductAsync(); + UnitOfWork.ClearCache(); + + //查找实体并修改 + var product = await _repository.FindByIdAsync( entity.Id ); + product.Code = code; + + //直接提交工作单元 + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //验证 + var result = await _repository.FindByIdAsync( entity.Id ); + Assert.Equal( code, result.Code ); + } + + /// + /// 测试更新并发 - 使用更新方法1 + /// 更新方法1的缺陷: 通过赋值的方式更新查找实体的版本号,无法触发乐观锁 + /// + [Fact] + public async Task TestUpdate_1_Concurrency() { + //常量 + var code = "TestUpdate_1_Concurrency_Code"; + var description = "TestUpdate_1_Concurrency_Description"; + + //添加实体 + var entity = await AddProductAsync(); + UnitOfWork.ClearCache(); + + //此处模拟用户1打开表单并修改,但尚未提交,这将保存旧实体 + var product = await _repository.FindByIdAsync( entity.Id ); + product.Code = code; + UnitOfWork.ClearCache(); + + //此处模拟用户2更新该实体,这将导致版本号变化 + var product2 = await _repository.FindByIdAsync( entity.Id ); + product2.Description = description; + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //此处模拟用户1提交表单,查找实体,并进行赋值 + var result = _repository.FindById( entity.Id ); + result.Code = product.Code; + result.Description = product.Description; + result.Version = product.Version; + //提交工作单元,由于版本号变化,预期应触发乐观锁,但实际未触发 + await UnitOfWork.CommitAsync(); + + //结果:用户1覆盖了用户2设置的Description属性 + Assert.Equal( code, result.Code ); + Assert.NotEqual( description, result.Description ); + } + + /// + /// 测试更新方法2 - 创建未跟踪实体,调用dbcontext.Update方法 + /// + [Fact] + public async Task TestUpdate_2() { + //常量 + var code = "TestUpdate_2_Code"; + + //添加实体 + var entity = await AddProductAsync(); + UnitOfWork.ClearCache(); + + //创建未跟踪实体 + var product = entity.MapTo(); + product.Code = code; + //调用dbcontext.Update方法更新实体 + _repository.UpdateProduct( product ); + //提交工作单元 + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //验证 + var result = await _repository.FindByIdAsync( entity.Id ); + Assert.Equal( code, result.Code ); + } + + /// + /// 测试更新方法2的陷阱 + /// 如果在创建未跟踪实体并调用dbcontext.Update方法之前,从dbcontext中已查找出该实体,将发生异常 + /// + [Fact] + public async Task TestUpdate_2_InvalidOperation() { + //常量 + var code = "TestUpdate_2_InvalidOperation_Code"; + + //添加实体 + var entity = await AddProductAsync(); + UnitOfWork.ClearCache(); + + //模拟更新之前无意中已查找出该实体 + await _repository.FindByIdAsync( entity.Id ); + + //创建未跟踪实体 + var product = entity.MapTo(); + product.Code = code; + + //由于实体已被跟踪,调用dbcontext.Update方法更新实体将触发异常 + Assert.Throws( () => { + _repository.UpdateProduct( product ); + } ); + } + + /// + /// 测试更新并发 - 使用更新方法2 + /// + [Fact] + public async Task TestUpdate_2_Concurrency() { + //常量 + var code = "TestUpdate_2_Concurrency_Code"; + var description = "TestUpdate_2_Concurrency_Description"; + + //添加实体 + var entity = await AddProductAsync(); + UnitOfWork.ClearCache(); + + //此处模拟用户1打开表单并修改,但尚未提交,这将保存旧实体 + var product = await _repository.FindByIdAsync( entity.Id ); + product.Code = code; + UnitOfWork.ClearCache(); + + //此处模拟用户2更新该实体,这将导致版本号变化 + var product2 = await _repository.FindByIdAsync( entity.Id ); + product2.Description = description; + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //此处模拟用户1提交表单,创建一个新的实体,并赋值 + var result = product.MapTo(); + + //调用dbcontext.Update方法更新实体 + _repository.UpdateProduct( result ); + + //提交工作单元,由于版本号变化,触发乐观锁 + await Assert.ThrowsAsync( async () => { + await UnitOfWork.CommitAsync(); + } ); + } + + /// + /// 测试Util Update更新方法 - 查找并修改实体,提交工作单元 + /// + [Fact] + public async Task TestUpdate_3_1() { + //常量 + var code = "TestUpdate_3_1_Code"; + + //添加实体 + var entity = await AddProductAsync(); + UnitOfWork.ClearCache(); + + //查找实体并修改 + var product = await _repository.FindByIdAsync( entity.Id ); + product.Code = code; + + //调用Update方法 + await _repository.UpdateAsync( product ); + + //提交工作单元 + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //验证 + var result = _repository.FindById( entity.Id ); + Assert.Equal( code, result.Code ); + } + + /// + /// 测试Util Update更新方法 - 创建未跟踪实体,调用Update方法 + /// + [Fact] + public async Task TestUpdate_3_2() { + //常量 + var code = "TestUpdate_3_2_Code"; + + //添加实体 + var entity = await AddProductAsync(); + UnitOfWork.ClearCache(); + + //创建未跟踪实体 + var product = entity.MapTo(); + product.Code = code; + + //调用Update方法更新实体 + await _repository.UpdateAsync( product ); + + //提交工作单元 + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //验证 + var result = await _repository.FindByIdAsync( entity.Id ); + Assert.Equal( code, result.Code ); + } + + /// + /// 测试Util Update更新方法 - 允许在创建未跟踪实体并调用Update方法之前查找实体,不会发生异常 + /// + [Fact] + public async Task TestUpdate_3_3() { + //常量 + var code = "TestUpdate_3_3_InvalidOperation_Code"; + + //添加实体 + var entity = await AddProductAsync(); + UnitOfWork.ClearCache(); + + //模拟更新之前无意中已查找出该实体 + await _repository.FindByIdAsync( entity.Id ); + + //创建未跟踪实体 + var product = entity.MapTo(); + product.Code = code; + + //调用Update方法更新实体 + await _repository.UpdateAsync( product ); + + //提交工作单元 + _log.WriteLine( UnitOfWork.GetChangeTrackerDebugView() ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //验证 + var result = _repository.FindById( entity.Id ); + Assert.Equal( code, result.Code ); + } + + /// + /// 测试更新并发 - 使用Util Update更新方法 + /// 通过赋值的方式更新查找实体的版本号,触发乐观锁 + /// + [Fact] + public async Task TestUpdate_3_Concurrency_1() { + //常量 + var code = "TestUpdate_3_Concurrency_1_Code"; + var description = "TestUpdate_3_Concurrency_1_Description"; + + //添加实体 + var entity = await AddProductAsync(); + UnitOfWork.ClearCache(); + + //此处模拟用户1打开表单并修改,但尚未提交,这将保存旧实体 + var product = await _repository.FindByIdAsync( entity.Id ); + product.Code = code; + UnitOfWork.ClearCache(); + + //此处模拟用户2更新该实体,这将导致版本号变化 + var product2 = await _repository.FindByIdAsync( entity.Id ); + product2.Description = description; + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //此处模拟用户1提交表单,查找实体,并进行赋值 + var result = await _repository.FindByIdAsync( entity.Id ); + result.Code = product.Code; + result.Description = product.Description; + result.Version = product.Version; + + //调用Update方法更新实体时触发乐观锁 + await Assert.ThrowsAsync( async () => { + await _repository.UpdateAsync( result ); + } ); + } + + /// + /// 测试更新并发 - 使用Util Update更新方法 + /// 更新未跟踪实体触发乐观锁 + /// + [Fact] + public async Task TestUpdate_3_Concurrency_2() { + //常量 + var code = "TestUpdate_3_Concurrency_2_Code"; + var description = "TestUpdate_3_Concurrency_2_Description"; + + //添加实体 + var entity = await AddProductAsync(); + UnitOfWork.ClearCache(); + + //此处模拟用户1打开表单并修改,但尚未提交,这将保存旧实体 + var product = await _repository.FindByIdAsync( entity.Id ); + product.Code = code; + UnitOfWork.ClearCache(); + + //此处模拟用户2更新该实体,这将导致版本号变化 + var product2 = await _repository.FindByIdAsync( entity.Id ); + product2.Description = description; + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //此处模拟用户1提交表单,创建一个新的实体,并赋值 + var result = product.MapTo(); + + //调用Update方法更新实体 + await _repository.UpdateAsync( result ); + + //提交工作单元,由于版本号变化,触发乐观锁 + await Assert.ThrowsAsync( async () => { + await UnitOfWork.CommitAsync(); + } ); + } + + /// + /// 测试更新集合 + /// + [Fact] + public async Task TestUpdate_4() { + //常量 + var count = 3; + var code = "TestUpdate_4_Code"; + + //添加实体列表 + var entities = ProductFakeService.GetProducts( count ); + entities.ForEach( product => { + product.Init(); + } ); + await _repository.AddAsync( entities ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //查找实体,赋值,调用Update方法,提交工作单元 + var products = await _repository.FindByIdsAsync( entities.Select( t => t.Id ) ); + products.ForEach( product => product.Code = code ); + await _repository.UpdateAsync( products ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //验证 + var result = await _repository.FindByIdsAsync( entities.Select( t => t.Id ) ); + Assert.Equal( code, result[0].Code ); + Assert.Equal( code, result[1].Code ); + Assert.Equal( code, result[2].Code ); + } + + #endregion + + #region Remove + + /// + /// 测试通过标识移除实体 - 逻辑删除 + /// + [Fact] + public async Task TestRemoveAsync_Id_1() { + //添加实体 + var entity = await AddProductAsync(); + UnitOfWork.ClearCache(); + + //移除实体 + await _repository.RemoveAsync( entity.Id ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //验证 + var result = await _repository.FindByIdAsync( entity.Id ); + Assert.Null( result ); + } + + /// + /// 测试通过标识移除实体 - 逻辑删除 - 使用工作单元禁用逻辑删除过滤器 + /// + [Fact] + public async Task TestRemoveAsync_Id_2() { + //添加实体 + var entity = await AddProductAsync(); + UnitOfWork.ClearCache(); + + //移除实体 + await _repository.RemoveAsync( entity.Id ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //使用工作单元禁用逻辑删除过滤器,可以查出 + using( UnitOfWork.DisableDeleteFilter() ) { + var product = await _repository.FindByIdAsync( entity.Id ); + Assert.True( product.IsDeleted ); + Assert.Equal( entity.Code, product.Code ); + } + UnitOfWork.ClearCache(); + + //逻辑删除过滤器已启用,无法查出 + var result = await _repository.FindByIdAsync( entity.Id ); + Assert.Null( result ); + } + + /// + /// 测试通过标识移除实体 - 逻辑删除 - 使用仓储禁用逻辑删除过滤器 + /// + [Fact] + public async Task TestRemoveAsync_Id_3() { + //添加实体 + var entity = await AddProductAsync(); + UnitOfWork.ClearCache(); + + //移除实体 + await _repository.RemoveAsync( entity.Id ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //使用仓储禁用逻辑删除过滤器,可以查出 + using( _repository.DisableDeleteFilter() ) { + var product = await _repository.FindByIdAsync( entity.Id ); + Assert.True( product.IsDeleted ); + Assert.Equal( entity.Code, product.Code ); + } + UnitOfWork.ClearCache(); + + //逻辑删除过滤器已启用,无法查出 + var result = await _repository.FindByIdAsync( entity.Id ); + Assert.Null( result ); + } + + /// + /// 测试移除实体 - 逻辑删除 + /// + [Fact] + public async Task TestRemoveAsync_Entity() { + //添加实体 + var entity = await AddProductAsync(); + UnitOfWork.ClearCache(); + + //移除实体 + await _repository.RemoveAsync( entity ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //验证 + var result = await _repository.FindByIdAsync( entity.Id ); + Assert.Null( result ); + } + + /// + /// 测试移除实体集合 - 逻辑删除 - 通过标识列表 + /// + [Fact] + public async Task TestRemoveAsync_Entities_1() { + //常量 + var count = 3; + + //添加实体列表 + var products = ProductFakeService.GetProducts( count ).ToList(); + products.ForEach( product => { + product.Init(); + } ); + await _repository.AddAsync( products ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //移除实体集合 + var ids = products.Select( t => t.Id ).ToList(); + await _repository.RemoveAsync( ids ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //验证 + using( _repository.DisableDeleteFilter() ) { + var result = await _repository.FindByIdsAsync( ids ); + Assert.Equal( count, result.Count ); + result.ForEach( t => Assert.True( t.IsDeleted ) ); + } + } + + /// + /// 测试移除实体集合 - 逻辑删除 - 通过实体列表 + /// + [Fact] + public async Task TestRemoveAsync_Entities_2() { + //常量 + var count = 3; + + //添加实体列表 + var products = ProductFakeService.GetProducts( count ).ToList(); + products.ForEach( product => { + product.Init(); + } ); + await _repository.AddAsync( products ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //移除实体集合 + await _repository.RemoveAsync( products ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //验证 + using( _repository.DisableDeleteFilter() ) { + var result = await _repository.FindByIdsAsync( products.Select( t => t.Id ) ); + Assert.Equal( count, result.Count ); + result.ForEach( t => Assert.True( t.IsDeleted ) ); + } + } + + #endregion + + #region Audit + + /// + /// 测试设置创建审计属性 + /// + [Fact] + public async Task TestCreationAudit() { + var entity = ProductFakeService.GetProduct(); + entity.Init(); + await _repository.AddAsync( entity ); + Assert.NotEqual( TestSession.TestUserId, entity.CreatorId ); + await UnitOfWork.CommitAsync(); + Assert.Equal( TestSession.TestUserId, entity.CreatorId ); + Assert.Equal( TestSession.TestUserId, entity.LastModifierId ); + } + + /// + /// 测试设置修改审计属性 + /// + [Fact] + public async Task TestModificationAudit() { + //工作单元 + var unitOfWork = (OracleUnitOfWork)UnitOfWork; + + //常量 + var code = "TestModificationAudit"; + + //添加实体 + var entity = await AddProductAsync(); + unitOfWork.ClearCache(); + + //修改 + var product = entity.MapTo(); + product.Code = code; + await _repository.UpdateAsync( product ); + unitOfWork.SetSession( new TestSession { UserId = TestSession.TestUserId2.ToString() } ); + + //验证修改前审计属性 + Assert.Equal( TestSession.TestUserId, product.CreatorId ); + Assert.Equal( TestSession.TestUserId, product.LastModifierId ); + + //提交 + await unitOfWork.CommitAsync(); + + //验证修改后审计属性 + Assert.Equal( TestSession.TestUserId, product.CreatorId ); + Assert.Equal( TestSession.TestUserId2, product.LastModifierId ); + } + + #endregion + + #region ExtraProperties + + /// + /// 测试扩展属性 - 添加简单扩展属性 + /// + [Fact] + public async Task TestExtraProperties_1() { + //常量 + var value = "TestExtraProperties_1"; + + //添加实体 + var entity = new Product(); + entity.Init(); + entity.TestProperty1 = value; + await _repository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //验证 + var result = await _repository.FindByIdAsync( entity.Id ); + Assert.Equal( value, result.TestProperty1 ); + } + + /// + /// 测试扩展属性 - 修改简单扩展属性 + /// + [Fact] + public async Task TestExtraProperties_2() { + //常量 + var oldValue = "TestExtraProperties_2_1"; + var newValue = "TestExtraProperties_2_2"; + + //添加实体 + var entity = new Product(); + entity.Init(); + entity.TestProperty1 = oldValue; + await _repository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //验证 + var oldEntity = await _repository.FindByIdAsync( entity.Id ); + Assert.Equal( oldValue, oldEntity.TestProperty1 ); + + //修改实体 + oldEntity.TestProperty1 = newValue; + await _repository.UpdateAsync( oldEntity ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //验证 + var result = await _repository.FindByIdAsync( entity.Id ); + Assert.Equal( newValue, result.TestProperty1 ); + } + + /// + /// 测试扩展属性 - 添加对象扩展属性 + /// + [Fact] + public async Task TestExtraProperties_3() { + //常量 + var code = 2; + var name = "TestExtraProperties_3"; + var enumValue = ProductEnum.World; + + //添加实体 + var entity = new Product(); + entity.Init(); + entity.TestProperty2.Code = code; + entity.TestProperty2.Name = name; + entity.TestProperty2.EnumValue = enumValue; + await _repository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //验证 + var result = _repository.FindById( entity.Id ); + Assert.Equal( code, result.TestProperty2.Code ); + Assert.Equal( name, result.TestProperty2.Name ); + Assert.Equal( enumValue, result.TestProperty2.EnumValue ); + } + + /// + /// 测试扩展属性 - 修改对象扩展属性 + /// + [Fact] + public async Task TestExtraProperties_4() { + //常量 + var code = 2; + var oldName = "TestExtraProperties_4_1"; + var newName = "TestExtraProperties_4_2"; + var oldEnumValue = ProductEnum.Hello; + var newEnumValue = ProductEnum.World; + + //添加实体 + var entity = new Product(); + entity.Init(); + entity.TestProperty2.Code = code; + entity.TestProperty2.Name = oldName; + entity.TestProperty2.EnumValue = oldEnumValue; + await _repository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //验证 + var oldEntity = await _repository.FindByIdAsync( entity.Id ); + Assert.Equal( code, oldEntity.TestProperty2.Code ); + Assert.Equal( oldName, oldEntity.TestProperty2.Name ); + Assert.Equal( oldEnumValue, oldEntity.TestProperty2.EnumValue ); + + //修改实体 + oldEntity.TestProperty2.Name = newName; + oldEntity.TestProperty2.EnumValue = newEnumValue; + WriteTrackerDebug(); + await _repository.UpdateAsync( oldEntity ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //验证 + var result = await _repository.FindByIdAsync( entity.Id ); + Assert.Equal( newName, result.TestProperty2.Name ); + Assert.Equal( newEnumValue, result.TestProperty2.EnumValue ); + } + + /// + /// 测试扩展属性 - 添加对象集合扩展属性 + /// + [Fact] + public async Task TestExtraProperties_5() { + //常量 + var code = 1; + var name1 = "TestExtraProperties_5_1"; + var name2 = "TestExtraProperties_5_2"; + + //添加实体 + var entity = new Product(); + entity.Init(); + entity.TestProperties.Add( new ProductItem { Code = code, Name = name1 } ); + entity.TestProperties.Add( new ProductItem { Code = code, Name = name2 } ); + await _repository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //验证 + var result = await _repository.FindByIdAsync( entity.Id ); + Assert.Equal( 2, result.TestProperties.Count ); + Assert.Equal( code, result.TestProperties[0].Code ); + Assert.Equal( name1, result.TestProperties[0].Name ); + Assert.Equal( code, result.TestProperties[1].Code ); + Assert.Equal( name2, result.TestProperties[1].Name ); + } + + /// + /// 测试扩展属性 - 修改对象集合扩展属性 + /// + [Fact] + public async Task TestExtraProperties_6() { + //常量 + var code = 1; + var oldName = "TestExtraProperties_6_1"; + var newName = "TestExtraProperties_6_2"; + var name3 = "TestExtraProperties_6_3"; + + //添加实体 + var entity = new Product(); + entity.Init(); + entity.TestProperties.Add( new ProductItem { Code = code, Name = oldName } ); + entity.TestProperties.Add( new ProductItem { Code = code, Name = oldName } ); + await _repository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //验证 + var oldEntity = await _repository.FindByIdAsync( entity.Id ); + Assert.Equal( 2, oldEntity.TestProperties.Count ); + + //修改实体 + oldEntity.TestProperties[0].Name = newName; + oldEntity.TestProperties[1].Name = newName; + oldEntity.TestProperties.Add( new ProductItem { Code = code, Name = name3 } ); + await _repository.UpdateAsync( oldEntity ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //验证 + var result = await _repository.FindByIdAsync( entity.Id ); + Assert.Equal( 3, result.TestProperties.Count ); + Assert.Equal( code, result.TestProperties[0].Code ); + Assert.Equal( newName, result.TestProperties[0].Name ); + Assert.Equal( code, result.TestProperties[1].Code ); + Assert.Equal( newName, result.TestProperties[1].Name ); + Assert.Equal( code, result.TestProperties[2].Code ); + Assert.Equal( name3, result.TestProperties[2].Name ); + } + + /// + /// 测试扩展属性 - 添加多个扩展属性 + /// + [Fact] + public async Task TestExtraProperties_7() { + //常量 + var code = 2; + var name = "TestExtraProperties_7"; + + //添加实体 + var entity = new Product(); + entity.Init(); + entity.TestProperty1 = name; + entity.TestProperty2.Code = code; + entity.TestProperty2.Name = name; + entity.TestProperties.Add( new ProductItem { Code = code, Name = name } ); + entity.TestProperties.Add( new ProductItem { Code = code, Name = name } ); + await _repository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //验证 + var result = await _repository.FindByIdAsync( entity.Id ); + Assert.Equal( name, result.TestProperty1 ); + Assert.Equal( code, result.TestProperty2.Code ); + Assert.Equal( name, result.TestProperty2.Name ); + Assert.Equal( code, result.TestProperties[0].Code ); + Assert.Equal( name, result.TestProperties[0].Name ); + Assert.Equal( code, result.TestProperties[1].Code ); + Assert.Equal( name, result.TestProperties[1].Name ); + } + + /// + /// 测试扩展属性 - 修改多个扩展属性 + /// + [Fact] + public async Task TestExtraProperties_8() { + //常量 + var code = 2; + var oldName = "TestExtraProperties_8_1"; + var newName = "TestExtraProperties_8_2"; + + //添加实体 + var entity = new Product(); + entity.Init(); + entity.TestProperty1 = oldName; + entity.TestProperty2.Code = code; + entity.TestProperty2.Name = oldName; + entity.TestProperties.Add( new ProductItem { Code = code, Name = oldName } ); + entity.TestProperties.Add( new ProductItem { Code = code, Name = oldName } ); + await _repository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //验证 + var oldEntity = await _repository.FindByIdAsync( entity.Id ); + Assert.Equal( oldName, oldEntity.TestProperty1 ); + Assert.Equal( code, oldEntity.TestProperty2.Code ); + Assert.Equal( oldName, oldEntity.TestProperty2.Name ); + Assert.Equal( 2, oldEntity.TestProperties.Count ); + + //修改实体 + oldEntity.TestProperty1 = newName; + oldEntity.TestProperty2.Name = newName; + oldEntity.TestProperties[0].Name = newName; + oldEntity.TestProperties[1].Name = newName; + oldEntity.TestProperties.Add( new ProductItem{ Code = code, Name = newName } ); + await _repository.UpdateAsync( oldEntity ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //验证 + var result = await _repository.FindByIdAsync( entity.Id ); + Assert.Equal( newName, result.TestProperty1 ); + Assert.Equal( newName, result.TestProperty2.Name ); + Assert.Equal( 3, result.TestProperties.Count ); + Assert.Equal( newName, result.TestProperties[0].Name ); + Assert.Equal( newName, result.TestProperties[1].Name ); + Assert.Equal( newName, result.TestProperties[2].Name ); + } + + /// + /// 测试扩展属性 - 添加枚举扩展属性 + /// + [Fact] + public async Task TestExtraProperties_9() { + //常量 + ProductEnum value = ProductEnum.World; + + //添加实体 + var entity = new Product(); + entity.Init(); + entity.TestProperty3 = value; + await _repository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //验证 + var result = await _repository.FindByIdAsync( entity.Id ); + Assert.Equal( value, result.TestProperty3 ); + } + + /// + /// 测试扩展属性 - 修改枚举扩展属性 + /// + [Fact] + public async Task TestExtraProperties_10() { + //常量 + ProductEnum oldValue = ProductEnum.Hello; + ProductEnum newValue = ProductEnum.World; + + //添加实体 + var entity = new Product(); + entity.Init(); + entity.TestProperty3 = oldValue; + await _repository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //验证 + var oldEntity = await _repository.FindByIdAsync( entity.Id ); + Assert.Equal( oldValue, oldEntity.TestProperty3 ); + + //修改实体 + oldEntity.TestProperty3 = newValue; + await _repository.UpdateAsync( oldEntity ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //验证 + var result = await _repository.FindByIdAsync( entity.Id ); + Assert.Equal( newValue, result.TestProperty3 ); + } + + /// + /// 测试扩展属性 - 添加不可变对象扩展属性 + /// + [Fact] + public async Task TestExtraProperties_11() { + //常量 + var code = 2; + var name = "TestExtraProperties_11"; + + //添加实体 + var entity = new Product(); + entity.Init(); + entity.TestProperty4 = new ProductItem2( code, name ); + await _repository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //验证 + var result = await _repository.FindByIdAsync( entity.Id ); + Assert.Equal( code, result.TestProperty4.Code ); + Assert.Equal( name, result.TestProperty4.Name ); + } + + /// + /// 测试扩展属性 - 修改对象扩展属性 + /// + [Fact] + public async Task TestExtraProperties_12() { + //常量 + var code = 2; + var oldName = "TestExtraProperties_12_1"; + var newName = "TestExtraProperties_12_2"; + + //添加实体 + var entity = new Product(); + entity.Init(); + entity.TestProperty4 = new ProductItem2( code, oldName ); + await _repository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //验证 + var oldEntity = await _repository.FindByIdAsync( entity.Id ); + Assert.Equal( code, oldEntity.TestProperty4.Code ); + Assert.Equal( oldName, oldEntity.TestProperty4.Name ); + + //修改实体 + oldEntity.TestProperty4 = new ProductItem2( code, newName ); + WriteTrackerDebug(); + await _repository.UpdateAsync( oldEntity ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //验证 + var result = await _repository.FindByIdAsync( entity.Id ); + Assert.Equal( newName, result.TestProperty4.Name ); + } + + #endregion + } +} \ No newline at end of file diff --git a/test/Util.Data.EntityFrameworkCore.Oracle.Tests.Integration/Tests/TagRepositoryTest.cs b/test/Util.Data.EntityFrameworkCore.Oracle.Tests.Integration/Tests/TagRepositoryTest.cs new file mode 100644 index 00000000..3819f129 --- /dev/null +++ b/test/Util.Data.EntityFrameworkCore.Oracle.Tests.Integration/Tests/TagRepositoryTest.cs @@ -0,0 +1,41 @@ +using System.Threading.Tasks; +using Util.Tests.Fakes; +using Util.Tests.Infrastructure; +using Util.Tests.Repositories; +using Util.Tests.UnitOfWorks; +using Xunit; + +namespace Util.Data.EntityFrameworkCore.Tests { + /// + /// 标签仓储测试 + /// + public class TagRepositoryTest : TestBase { + /// + /// 仓储 + /// + private readonly ITagRepository _repository; + + /// + /// 测试初始化 + /// + public TagRepositoryTest( ITagRepository repository, ITestUnitOfWork unitOfWork ) : base( unitOfWork ) { + _repository = repository; + } + + /// + /// 测试添加实体 + /// + [Fact] + public async Task TestAddAsync() { + //添加实体 + var entity = TagFakeService.GetTag(); + entity.Init(); + await _repository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //验证 + Assert.True( await _repository.ExistsAsync( t => t.Id == entity.Id ) ); + } + } +} \ No newline at end of file diff --git a/test/Util.Data.EntityFrameworkCore.Oracle.Tests.Integration/Util.Data.EntityFrameworkCore.Oracle.Tests.Integration.csproj b/test/Util.Data.EntityFrameworkCore.Oracle.Tests.Integration/Util.Data.EntityFrameworkCore.Oracle.Tests.Integration.csproj new file mode 100644 index 00000000..b78ac52c --- /dev/null +++ b/test/Util.Data.EntityFrameworkCore.Oracle.Tests.Integration/Util.Data.EntityFrameworkCore.Oracle.Tests.Integration.csproj @@ -0,0 +1,40 @@ + + + + $(NetTargetFramework) + false + Util.Data.EntityFrameworkCore + Util.Data.EntityFrameworkCore.Startup + + + + + Always + + + Always + + + + + + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + diff --git a/test/Util.Data.EntityFrameworkCore.Oracle.Tests.Integration/appsettings.Development.json b/test/Util.Data.EntityFrameworkCore.Oracle.Tests.Integration/appsettings.Development.json new file mode 100644 index 00000000..59dd8ae6 --- /dev/null +++ b/test/Util.Data.EntityFrameworkCore.Oracle.Tests.Integration/appsettings.Development.json @@ -0,0 +1,11 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Trace", + "Microsoft": "Trace" + } + }, + "ConnectionStrings": { + "connection": "User Id=TEST;Password=123456;Data Source=(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=gateway.docker.internal)(PORT=11521)))(CONNECT_DATA=(SERVICE_NAME=xe)))" + } +} diff --git a/test/Util.Data.EntityFrameworkCore.Oracle.Tests.Integration/appsettings.json b/test/Util.Data.EntityFrameworkCore.Oracle.Tests.Integration/appsettings.json new file mode 100644 index 00000000..2664e2e1 --- /dev/null +++ b/test/Util.Data.EntityFrameworkCore.Oracle.Tests.Integration/appsettings.json @@ -0,0 +1,11 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Error", + "Microsoft": "Error" + } + }, + "ConnectionStrings": { + "connection": "User Id=TEST;Password=123456;Data Source=(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=gateway.docker.internal)(PORT=11521)))(CONNECT_DATA=(SERVICE_NAME=xe)))" + } +} \ No newline at end of file diff --git a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests.Integration/Filters/DeleteFilterTest.cs b/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests.Integration/Filters/DeleteFilterTest.cs new file mode 100644 index 00000000..e589e106 --- /dev/null +++ b/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests.Integration/Filters/DeleteFilterTest.cs @@ -0,0 +1,81 @@ +using Util.Tests.Models; +using Xunit; +using Xunit.Abstractions; + +namespace Util.Data.EntityFrameworkCore.Filters { + /// + /// 逻辑删除过滤器测试 + /// + public class DeleteFilterTest { + /// + /// 测试消息输出 + /// + private readonly ITestOutputHelper _testOutputHelper; + /// + /// 逻辑删除过滤器 + /// + private readonly DeleteFilter _filter; + + /// + /// 测试初始化 + /// + public DeleteFilterTest( ITestOutputHelper testOutputHelper ) { + _testOutputHelper = testOutputHelper; + _filter = new DeleteFilter(); + } + + /// + /// 测试是否启用 + /// + [Fact] + public void TestIsEnabled() { + //默认值为启用 + Assert.True( _filter.IsEnabled ); + + //禁用过滤器 + _filter.Disable(); + Assert.False( _filter.IsEnabled ); + + //启用过滤器 + _filter.Enable(); + Assert.True( _filter.IsEnabled ); + } + + /// + /// 测试禁用 + /// + [Fact] + public void TestDisable() { + //默认值为启用 + Assert.True( _filter.IsEnabled ); + + //禁用过滤器 + using( _filter.Disable() ) { + Assert.False( _filter.IsEnabled ); + } + + //恢复启用状态 + Assert.True( _filter.IsEnabled ); + } + + /// + /// 测试实体是否启用过滤器 + /// + [Fact] + public void TestIsEntityEnabled() { + Assert.False( _filter.IsEntityEnabled() ); + Assert.True( _filter.IsEntityEnabled() ); + } + + /// + /// 测试获取表达式 + /// + [Fact] + public void TestGetExpression() { + var expression = _filter.GetExpression(); + var result = "entity => Not(Property(entity, \"IsDeleted\"))"; + _testOutputHelper.WriteLine( expression.ToString() ); + Assert.Equal( result,expression.ToString() ); + } + } +} diff --git a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests.Integration/Filters/FilterManagerTest.cs b/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests.Integration/Filters/FilterManagerTest.cs new file mode 100644 index 00000000..4ac4609d --- /dev/null +++ b/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests.Integration/Filters/FilterManagerTest.cs @@ -0,0 +1,101 @@ +using Util.Data.Filters; +using Util.Domain; +using Util.Tests.Models; +using Xunit; + +namespace Util.Data.EntityFrameworkCore.Filters { + /// + /// 数据过滤器管理器测试 + /// + public class FilterManagerTest { + /// + /// 数据过滤器管理器 + /// + private readonly IFilterManager _filterManager; + + /// + /// 测试初始化 + /// + public FilterManagerTest( IFilterManager filterManager ) { + _filterManager = filterManager; + } + + /// + /// 测试获取过滤器 - 泛型 + /// + [Fact] + public void TestGetFilter_1() { + //逻辑删除过滤器已默认加载 + var filter = _filterManager.GetFilter(); + Assert.NotNull( filter ); + Assert.True( filter.IsEnabled ); + } + + /// + /// 测试获取过滤器 - 非泛型 + /// + [Fact] + public void TestGetFilter_2() { + //逻辑删除过滤器已默认加载 + var filter = _filterManager.GetFilter(typeof( IDelete ) ); + Assert.NotNull( filter ); + } + + /// + /// 测试禁用过滤器 + /// + [Fact] + public void TestDisableFilter_1() { + _filterManager.DisableFilter(); + var filter = _filterManager.GetFilter(); + Assert.False( filter.IsEnabled ); + } + + /// + /// 测试禁用过滤器 - 使用using + /// + [Fact] + public void TestDisableFilter_2() { + var filter = _filterManager.GetFilter(); + using ( _filterManager.DisableFilter() ) { + Assert.False( filter.IsEnabled ); + } + Assert.True( filter.IsEnabled ); + } + + /// + /// 测试启用过滤器 + /// + [Fact] + public void TestEnableFilter() { + var filter = _filterManager.GetFilter(); + + //禁用 + _filterManager.DisableFilter(); + Assert.False( filter.IsEnabled ); + + //启用 + _filterManager.EnableFilter(); + Assert.True( filter.IsEnabled ); + } + + /// + /// 测试实体是否启用过滤器 + /// + [Fact] + public void TestIsEntityEnabled() { + Assert.False( _filterManager.IsEntityEnabled() ); + Assert.True( _filterManager.IsEntityEnabled() ); + } + + /// + /// 测试过滤器是否启用 + /// + [Fact] + public void TestIsEnabled() { + Assert.True( _filterManager.IsEnabled() ); + Assert.False( _filterManager.IsEnabled() ); + } + } +} + diff --git a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests.Integration/Startup.cs b/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests.Integration/Startup.cs new file mode 100644 index 00000000..b2cdd13d --- /dev/null +++ b/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests.Integration/Startup.cs @@ -0,0 +1,55 @@ +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using Util.Aop; +using Util.Dates; +using Util.Helpers; +using Util.Sessions; +using Util.Tests.Infrastructure; +using Util.Tests.UnitOfWorks; +using Xunit.DependencyInjection; +using Xunit.DependencyInjection.Logging; + +namespace Util.Data.EntityFrameworkCore { + /// + /// Æô¶¯ÅäÖà + /// + public class Startup { + /// + /// ÅäÖÃÖ÷»ú + /// + public void ConfigureHost( IHostBuilder hostBuilder ) { + hostBuilder.ConfigureDefaults( null ) + .AddUtil( options => { + Environment.SetDevelopment(); + options.UseAop() + .UseUtc() + .UsePgSqlUnitOfWork( Config.GetConnectionString( "connection" ) ); + } ); + } + + /// + /// ÅäÖ÷þÎñ + /// + public void ConfigureServices( IServiceCollection services ) { + services.AddSingleton(); + InitDatabase( services ); + } + + /// + /// ³õʼ»¯Êý¾ݿâ + /// + private void InitDatabase( IServiceCollection services ) { + var unitOfWork = services.BuildServiceProvider().GetService(); + unitOfWork.EnsureDeleted(); + unitOfWork.EnsureCreated(); + } + + /// + /// ÅäÖÃÈÕ־Ìṩ³ÌÐò + /// + public void Configure( ILoggerFactory loggerFactory, ITestOutputHelperAccessor accessor ) { + loggerFactory.AddProvider( new XunitTestOutputLoggerProvider( accessor, ( s, logLevel ) => logLevel >= LogLevel.Trace ) ); + } + } +} diff --git a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests.Integration/Tests/CustomerRepositoryTest.cs b/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests.Integration/Tests/CustomerRepositoryTest.cs new file mode 100644 index 00000000..2f43c378 --- /dev/null +++ b/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests.Integration/Tests/CustomerRepositoryTest.cs @@ -0,0 +1,604 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore; +using Util.Data.Queries; +using Util.Tests.Fakes; +using Util.Tests.Infrastructure; +using Util.Tests.Models; +using Util.Tests.Repositories; +using Util.Tests.UnitOfWorks; +using Xunit; + +namespace Util.Data.EntityFrameworkCore.Tests { + /// + /// 客户仓储测试 + /// 说明: + /// 1. 测试自增长int类型标识 + /// 2. 测试日期范围查询 + /// 3. 测试分页查询 + /// 4. 测试Utc日期 + /// + public class CustomerRepositoryTest : TestBase { + + #region 测试初始化 + + /// + /// 仓储 + /// + private readonly ICustomerRepository _repository; + + /// + /// 测试初始化 + /// + public CustomerRepositoryTest( ICustomerRepository repository, ITestUnitOfWork unitOfWork ) : base( unitOfWork ) { + _repository = repository; + } + + #endregion + + #region 辅助操作 + + /// + /// 添加实体列表 + /// + /// 添加数量 + /// 客户名称 + private async Task> AddCustomersAsync( int count = 2, string name = null ) { + var customers = CustomerFakeService.GetCustomers( count ); + customers.ForEach( customer => { + if ( name != null ) + customer.Name = name; + customer.CreationTime = null; + } ); + await _repository.AddAsync( customers ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + return customers.OrderBy( t => t.Code ).ToList(); + } + + #endregion + + #region Between + + /// + /// 测试添加范围查询条件 - 日期带时间 + /// + [Fact] + public async Task TestBetween_DateTime_1() { + //常量 + var name = "TestBetween_DateTime_1"; + var birthday = "2005-5-5 05:05:05".ToDateTime(); + var minBirthday = "2005-5-6 06:05:05".ToDateTime(); + var maxBirthday = "2005-5-8 06:05:05".ToDateTime(); + + //添加实体列表 + await AddCustomersAsync(); + var customers = CustomerFakeService.GetCustomers( 5 ); + customers.ForEach( customer => { + customer.Name = name; + customer.Birthday = birthday; + birthday = birthday.AddDays( 1 ); + } ); + await _repository.AddAsync( customers ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //查询 + var result = await _repository.Find().Where( t => t.Name == name ).Between( t => t.Birthday, minBirthday, maxBirthday ).ToListAsync(); + + //验证 + Assert.Equal( 2, result.Count ); + } + + /// + /// 测试添加范围查询条件 - 日期带时间 - 包含左边界 + /// + [Fact] + public async Task TestBetween_DateTime_2() { + //常量 + var name = "TestBetween_DateTime_2"; + var birthday = "2005-5-5 05:05:05".ToDateTime(); + var minBirthday = "2005-5-6 05:05:05".ToDateTime(); + var maxBirthday = "2005-5-8 05:05:05".ToDateTime(); + + //添加实体列表 + await AddCustomersAsync(); + var customers = CustomerFakeService.GetCustomers( 5 ); + customers.ForEach( customer => { + customer.Name = name; + customer.Birthday = birthday; + birthday = birthday.AddDays( 1 ); + } ); + await _repository.AddAsync( customers ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //查询 + var result = await _repository.Find().Where( t => t.Name == name ).Between( t => t.Birthday, minBirthday, maxBirthday, boundary: Boundary.Left ).ToListAsync(); + + //验证 + Assert.Equal( 2, result.Count ); + } + + /// + /// 测试添加范围查询条件 - 日期带时间 - 包含右边界 + /// + [Fact] + public async Task TestBetween_DateTime_3() { + //常量 + var name = "TestBetween_DateTime_3"; + var birthday = "2005-5-5 05:05:05".ToDateTime(); + var minBirthday = "2005-5-6 05:05:05".ToDateTime(); + var maxBirthday = "2005-5-8 05:05:05".ToDateTime(); + + //添加实体列表 + await AddCustomersAsync(); + var customers = CustomerFakeService.GetCustomers( 5 ); + customers.ForEach( customer => { + customer.Name = name; + customer.Birthday = birthday; + birthday = birthday.AddDays( 1 ); + } ); + await _repository.AddAsync( customers ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //查询 + var result = await _repository.Find().Where( t => t.Name == name ).Between( t => t.Birthday, minBirthday, maxBirthday, boundary: Boundary.Right ).ToListAsync(); + + //验证 + Assert.Equal( 2, result.Count ); + } + + /// + /// 测试添加范围查询条件 - 日期带时间 - 包含两边 + /// + [Fact] + public async Task TestBetween_DateTime_4() { + //常量 + var name = "TestBetween_DateTime_4"; + var birthday = "2005-5-5 05:05:05".ToDateTime(); + var minBirthday = "2005-5-6 05:05:05".ToDateTime(); + var maxBirthday = "2005-5-8 05:05:05".ToDateTime(); + + //添加实体列表 + await AddCustomersAsync(); + var customers = CustomerFakeService.GetCustomers( 5 ); + customers.ForEach( customer => { + customer.Name = name; + customer.Birthday = birthday; + birthday = birthday.AddDays( 1 ); + } ); + await _repository.AddAsync( customers ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //查询 + var result = await _repository.Find().Where( t => t.Name == name ).Between( t => t.Birthday, minBirthday, maxBirthday, boundary: Boundary.Both ).ToListAsync(); + + //验证 + Assert.Equal( 3, result.Count ); + } + + /// + /// 测试添加范围查询条件 - 日期带时间 - 不包含边界 + /// + [Fact] + public async Task TestBetween_DateTime_5() { + //常量 + var name = "TestBetween_DateTime_5"; + var birthday = "2005-5-5 05:05:05".ToDateTime(); + var minBirthday = "2005-5-6 05:05:05".ToDateTime(); + var maxBirthday = "2005-5-8 05:05:05".ToDateTime(); + + //添加实体列表 + await AddCustomersAsync(); + var customers = CustomerFakeService.GetCustomers( 5 ); + customers.ForEach( customer => { + customer.Name = name; + customer.Birthday = birthday; + birthday = birthday.AddDays( 1 ); + } ); + await _repository.AddAsync( customers ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //查询 + var result = await _repository.Find().Where( t => t.Name == name ).Between( t => t.Birthday, minBirthday, maxBirthday, boundary: Boundary.Neither ).ToListAsync(); + + //验证 + Assert.Single( result ); + } + + /// + /// 测试添加范围查询条件 - 日期带时间 - 最大值为空 + /// + [Fact] + public async Task TestBetween_DateTime_6() { + //常量 + var name = "TestBetween_DateTime_6"; + var birthday = "2005-5-5 05:05:05".ToDateTime(); + var minBirthday = "2005-5-6 05:05:05".ToDateTime(); + + //添加实体列表 + await AddCustomersAsync(); + var customers = CustomerFakeService.GetCustomers( 5 ); + customers.ForEach( customer => { + customer.Name = name; + customer.Birthday = birthday; + birthday = birthday.AddDays( 1 ); + } ); + await _repository.AddAsync( customers ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //查询 + var result = await _repository.Find().Where( t => t.Name == name ).Between( t => t.Birthday, minBirthday, null, boundary: Boundary.Both ).ToListAsync(); + + //验证 + Assert.Equal( 4, result.Count ); + } + + /// + /// 测试添加范围查询条件 - 日期带时间 - 最小值为空 + /// + [Fact] + public async Task TestBetween_DateTime_7() { + //常量 + var name = "TestBetween_DateTime_7"; + var birthday = "2005-5-5 05:05:05".ToDateTime(); + var maxBirthday = "2005-5-8 05:05:05".ToDateTime(); + + //添加实体列表 + await AddCustomersAsync(); + var customers = CustomerFakeService.GetCustomers( 5 ); + customers.ForEach( customer => { + customer.Name = name; + customer.Birthday = birthday; + birthday = birthday.AddDays( 1 ); + } ); + await _repository.AddAsync( customers ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //查询 + var result = await _repository.Find().Where( t => t.Name == name ).Between( t => t.Birthday, null, maxBirthday, boundary: Boundary.Both ).ToListAsync(); + + //验证 + Assert.Equal( 4, result.Count ); + } + + /// + /// 测试添加范围查询条件 - 日期不带时间 - 包含左边界 + /// + [Fact] + public async Task TestBetween_Date_1() { + //常量 + var name = "TestBetween_Date_1"; + var birthday = "2005-5-5 05:05:05".ToDateTime(); + var minBirthday = "2005-5-6".ToDateTime(); + var maxBirthday = "2005-5-8".ToDateTime(); + + //添加实体列表 + await AddCustomersAsync(); + var customers = CustomerFakeService.GetCustomers( 5 ); + customers.ForEach( customer => { + customer.Name = name; + customer.Birthday = birthday; + birthday = birthday.AddDays( 1 ); + } ); + await _repository.AddAsync( customers ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //查询 + var result = await _repository.Find() + .Where( t => t.Name == name ) + .Between( t => t.Birthday, minBirthday, maxBirthday, false, Boundary.Left ) + .OrderBy( t => t.Birthday ) + .ToListAsync(); + + //验证 + Assert.Equal( 2, result.Count ); + Assert.Equal( 6, result[0].Birthday.SafeValue().Day ); + Assert.Equal( 7, result[1].Birthday.SafeValue().Day ); + } + + /// + /// 测试添加范围查询条件 - 日期不带时间 - 包含右边界 + /// + [Fact] + public async Task TestBetween_Date_2() { + //常量 + var name = "TestBetween_Date_2"; + var birthday = "2005-5-5 05:05:05".ToDateTime(); + var minBirthday = "2005-5-6".ToDateTime(); + var maxBirthday = "2005-5-8".ToDateTime(); + + //添加实体列表 + await AddCustomersAsync(); + var customers = CustomerFakeService.GetCustomers( 5 ); + customers.ForEach( customer => { + customer.Name = name; + customer.Birthday = birthday; + birthday = birthday.AddDays( 1 ); + } ); + await _repository.AddAsync( customers ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //查询 + var result = await _repository.Find() + .Where( t => t.Name == name ) + .Between( t => t.Birthday, minBirthday, maxBirthday, false, Boundary.Right ) + .OrderBy( t => t.Birthday ) + .ToListAsync(); + + //验证 + Assert.Equal( 2, result.Count ); + Assert.Equal( 7, result[0].Birthday.SafeValue().Day ); + Assert.Equal( 8, result[1].Birthday.SafeValue().Day ); + } + + /// + /// 测试添加范围查询条件 - 日期不带时间 - 包含两边 + /// + [Fact] + public async Task TestBetween_Date_3() { + //常量 + var name = "TestBetween_Date_3"; + var birthday = "2005-5-5 05:05:05".ToDateTime(); + var minBirthday = "2005-5-6".ToDateTime(); + var maxBirthday = "2005-5-8".ToDateTime(); + + //添加实体列表 + await AddCustomersAsync(); + var customers = CustomerFakeService.GetCustomers( 5 ); + customers.ForEach( customer => { + customer.Name = name; + customer.Birthday = birthday; + birthday = birthday.AddDays( 1 ); + } ); + await _repository.AddAsync( customers ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //查询 + var result = await _repository.Find() + .Where( t => t.Name == name ) + .Between( t => t.Birthday, minBirthday, maxBirthday, false, Boundary.Both ) + .OrderBy( t => t.Birthday ) + .ToListAsync(); + + //验证 + Assert.Equal( 3, result.Count ); + Assert.Equal( 6, result[0].Birthday.SafeValue().Day ); + Assert.Equal( 7, result[1].Birthday.SafeValue().Day ); + Assert.Equal( 8, result[2].Birthday.SafeValue().Day ); + } + + /// + /// 测试添加范围查询条件 - 日期不带时间 - 不包含边界 + /// + [Fact] + public async Task TestBetween_Date_4() { + //常量 + var name = "TestBetween_Date_4"; + var birthday = "2005-5-5 05:05:05".ToDateTime(); + var minBirthday = "2005-5-6".ToDateTime(); + var maxBirthday = "2005-5-8".ToDateTime(); + + //添加实体列表 + await AddCustomersAsync(); + var customers = CustomerFakeService.GetCustomers( 5 ); + customers.ForEach( customer => { + customer.Name = name; + customer.Birthday = birthday; + birthday = birthday.AddDays( 1 ); + } ); + await _repository.AddAsync( customers ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //查询 + var result = await _repository.Find() + .Where( t => t.Name == name ) + .Between( t => t.Birthday, minBirthday, maxBirthday, false, Boundary.Neither ) + .ToListAsync(); + + //验证 + Assert.Single( result ); + Assert.Equal( 7, result[0].Birthday.SafeValue().Day ); + } + + /// + /// 测试添加范围查询条件 - 日期不带时间 - 最大值为空 + /// + [Fact] + public async Task TestBetween_Date_5() { + //常量 + var name = "TestBetween_Date_5"; + var birthday = "2005-5-5 05:05:05".ToDateTime(); + var minBirthday = "2005-5-6".ToDateTime(); + + //添加实体列表 + await AddCustomersAsync(); + var customers = CustomerFakeService.GetCustomers( 5 ); + customers.ForEach( customer => { + customer.Nickname = name; + customer.Name = name; + customer.Birthday = birthday; + birthday = birthday.AddDays( 1 ); + } ); + await _repository.AddAsync( customers ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //查询 + var result = await _repository.Find() + .Where( t => t.Name == name ) + .Between( t => t.Birthday, minBirthday, null, false ) + .OrderBy( t => t.Birthday ) + .ToListAsync(); + + //验证 + Assert.Equal( 4, result.Count ); + Assert.Equal( 6, result[0].Birthday.SafeValue().Day ); + } + + /// + /// 测试添加范围查询条件 - 日期不带时间 - 最小值为空 + /// + [Fact] + public async Task TestBetween_Date_6() { + //常量 + var name = "TestBetween_Date_6"; + var birthday = "2005-5-5 05:05:05".ToDateTime(); + var maxBirthday = "2005-5-8".ToDateTime(); + + //添加实体列表 + await AddCustomersAsync(); + var customers = CustomerFakeService.GetCustomers( 5 ); + customers.ForEach( customer => { + customer.Name = name; + customer.Birthday = birthday; + birthday = birthday.AddDays( 1 ); + } ); + await _repository.AddAsync( customers ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //查询 + var result = await _repository.Find() + .Where( t => t.Name == name ) + .Between( t => t.Birthday, null, maxBirthday, false ) + .ToListAsync(); + + //验证 + Assert.Equal( 4, result.Count ); + } + + #endregion + + #region ToPageList + + /// + /// 测试获取分页列表 + /// + [Fact] + public async Task TestToPageList_1() { + //常量 + var name = "TestToPageList_1"; + + //添加实体列表 + var customers = await AddCustomersAsync( 10, name ); + + //创建查询参数 + var parameter = new QueryParameter { PageSize = 3, Page = 1, Order = "Code" }; + + //查询 + var result = _repository.Find().Where( t => t.Name == name ).ToPageList( parameter ); + + //验证 + Assert.Equal( 4, result.PageCount ); + Assert.Equal( 1, result.Page ); + Assert.Equal( 3, result.PageSize ); + Assert.Equal( 10, result.Total ); + Assert.Equal( 3, result.Data.Count ); + Assert.Equal( customers[0].Id, result.Data[0].Id ); + Assert.Equal( customers[1].Id, result.Data[1].Id ); + Assert.Equal( customers[2].Id, result.Data[2].Id ); + } + + /// + /// 测试获取分页列表 - 第二页 + /// + [Fact] + public async Task TestToPageList_2() { + //常量 + var name = "TestToPageList_2"; + + //添加实体列表 + var customers = await AddCustomersAsync( 10, name ); + + //创建查询参数 + var parameter = new QueryParameter { PageSize = 3, Page = 2, Order = "Code" }; + + //查询 + var result = _repository.Find().Where( t => t.Name == name ).ToPageList( parameter ); + + //验证 + Assert.Equal( 4, result.PageCount ); + Assert.Equal( 2, result.Page ); + Assert.Equal( 3, result.PageSize ); + Assert.Equal( 10, result.Total ); + Assert.Equal( 3, result.Data.Count ); + Assert.Equal( customers[3].Id, result.Data[0].Id ); + Assert.Equal( customers[4].Id, result.Data[1].Id ); + Assert.Equal( customers[5].Id, result.Data[2].Id ); + } + + /// + /// 测试获取分页列表 - Queryable设置排序 + /// + [Fact] + public async Task TestToPageList_3() { + //常量 + var name = "TestToPageList_3"; + + //添加实体列表 + var customers = await AddCustomersAsync( 10, name ); + + //创建查询参数 + var parameter = new QueryParameter { PageSize = 3, Page = 2 }; + + //查询 + var result = _repository.Find().Where( t => t.Name == name ).OrderBy( t => t.Code ).ToPageList( parameter ); + + //验证 + Assert.Equal( 4, result.PageCount ); + Assert.Equal( 2, result.Page ); + Assert.Equal( 3, result.PageSize ); + Assert.Equal( 10, result.Total ); + Assert.Equal( 3, result.Data.Count ); + Assert.Equal( customers[3].Id, result.Data[0].Id ); + Assert.Equal( customers[4].Id, result.Data[1].Id ); + Assert.Equal( customers[5].Id, result.Data[2].Id ); + } + + #endregion + + #region ToPageListAsync + + /// + /// 测试获取分页列表 + /// + [Fact] + public async Task TestToPageListAsync() { + //常量 + var name = "TestToPageListAsync"; + + //添加实体列表 + var customers = await AddCustomersAsync( 10, name ); + + //创建查询参数 + var parameter = new QueryParameter { PageSize = 3, Page = 2, Order = "Code" }; + + //查询 + var result = await _repository.Find().Where( t => t.Name == name ).ToPageListAsync( parameter ); + + //验证 + Assert.Equal( 4, result.PageCount ); + Assert.Equal( 2, result.Page ); + Assert.Equal( 3, result.PageSize ); + Assert.Equal( 10, result.Total ); + Assert.Equal( 3, result.Data.Count ); + Assert.Equal( customers[3].Id, result.Data[0].Id ); + Assert.Equal( customers[4].Id, result.Data[1].Id ); + Assert.Equal( customers[5].Id, result.Data[2].Id ); + } + + #endregion + } +} \ No newline at end of file diff --git a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests.Integration/Tests/EntityEventsTest.cs b/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests.Integration/Tests/EntityEventsTest.cs new file mode 100644 index 00000000..b4e62e8c --- /dev/null +++ b/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests.Integration/Tests/EntityEventsTest.cs @@ -0,0 +1,211 @@ +using System.Threading.Tasks; +using Util.Tests.EventHandlers; +using Util.Tests.Fakes; +using Util.Tests.Infrastructure; +using Util.Tests.Repositories; +using Util.Tests.UnitOfWorks; +using Xunit; +using Xunit.Abstractions; + +namespace Util.Data.EntityFrameworkCore.Tests { + /// + /// 实体事件测试 + /// + public class EntityEventsTest : TestBase { + + #region 测试初始化 + + /// + /// 测试输出 + /// + private readonly ITestOutputHelper _testOutputHelper; + /// + /// 产品仓储 + /// + private readonly IProductRepository _productRepository; + /// + /// 操作日志仓储 + /// + private readonly IOperationLogRepository _operationLogRepository; + + /// + /// 测试初始化 + /// + public EntityEventsTest( ITestOutputHelper testOutputHelper, IProductRepository productRepository, + IOperationLogRepository operationLogRepository, ITestUnitOfWork unitOfWork ) :base(unitOfWork){ + _testOutputHelper = testOutputHelper; + _productRepository = productRepository; + _operationLogRepository = operationLogRepository; + } + + #endregion + + #region 实体创建事件 + + /// + /// 测试实体创建事件 + /// + [Fact] + public async Task TestEntityCreatedEvent() { + //添加实体 + var entity = ProductFakeService.GetProduct(); + entity.Init(); + entity.Name = "EntityCreatedEvent"; + await _productRepository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); + + //验证 + Assert.True( await _operationLogRepository.ExistsAsync( t => t.Caption == "EntityCreatedEvent" && t.LogName == nameof( ProductCreatedEventHandler ) ) ); + } + + /// + /// 测试实体变更事件 - 创建 + /// + [Fact] + public async Task TestEntityChangedEvent_Created() { + //添加实体 + var entity = ProductFakeService.GetProduct(); + entity.Init(); + entity.Name = "EntityChangedEvent_Created"; + await _productRepository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); + + //验证 + Assert.True( await _operationLogRepository.ExistsAsync( t => t.Caption == "EntityChangedEvent_Created" && t.LogName == nameof( ProductChangedEventHandler ) ) ); + } + + #endregion + + #region 实体修改事件 + + /// + /// 测试实体修改事件 + /// + [Fact] + public async Task TestEntityUpdatedEvent() { + //添加实体 + var entity = ProductFakeService.GetProduct(); + entity.Init(); + await _productRepository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //修改实体 + var product = await _productRepository.FindByIdAsync( entity.Id ); + product.Name = "EntityUpdatedEvent"; + await _productRepository.UpdateAsync( product ); + await UnitOfWork.CommitAsync(); + + //验证 + Assert.True( await _operationLogRepository.ExistsAsync( t => t.Caption == "EntityUpdatedEvent" && t.LogName == nameof( ProductUpdatedEventHandler ) ) ); + } + + /// + /// 测试实体变更事件 - 修改 + /// + [Fact] + public async Task TestEntityChangedEvent_Updated() { + //添加实体 + var entity = ProductFakeService.GetProduct(); + entity.Init(); + await _productRepository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //修改实体 + var product = _productRepository.FindById( entity.Id ); + product.Name = "EntityChangedEvent_Updated"; + await _productRepository.UpdateAsync( product ); + await UnitOfWork.CommitAsync(); + + //验证 + Assert.True( await _operationLogRepository.ExistsAsync( t => t.Caption == "EntityChangedEvent_Updated" && t.LogName == nameof( ProductChangedEventHandler ) ) ); + } + + #endregion + + #region 实体删除事件 + + /// + /// 测试实体删除事件 - 逻辑删除 + /// + [Fact] + public async Task TestEntityDeletedEvent_1() { + //添加实体 + var entity = ProductFakeService.GetProduct(); + entity.Init(); + entity.Name = "EntityDeletedEvent"; + await _productRepository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); + + //删除实体 + await _productRepository.RemoveAsync( entity ); + await UnitOfWork.CommitAsync(); + + //验证 + Assert.True( await _operationLogRepository.ExistsAsync( t => t.Caption == "EntityDeletedEvent" && t.LogName == nameof( ProductDeletedEventHandler ) ) ); + } + + /// + /// 测试实体删除事件 - 物理删除 + /// + [Fact] + public async Task TestEntityDeletedEvent_2() { + //添加实体 + var entity = OperationLogFakeService.GetOperationLog(); + entity.Init(); + entity.LogName = "EntityDeletedEvent"; + await _operationLogRepository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); + + //删除实体 + await _operationLogRepository.RemoveAsync( entity ); + await UnitOfWork.CommitAsync(); + + //验证 + Assert.True( await _operationLogRepository.ExistsAsync( t => t.LogName == "Test" && t.Caption == nameof( OperationLogDeletedEventHandler ) && t.Content == "EntityDeletedEvent" ) ); + } + + /// + /// 测试实体变更事件 - 逻辑删除 + /// + [Fact] + public async Task TestEntityChangedEvent_Deleted_1() { + //添加实体 + var entity = ProductFakeService.GetProduct(); + entity.Init(); + entity.Name = "EntityChangedEvent_Deleted"; + await _productRepository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); + + //删除实体 + await _productRepository.RemoveAsync( entity ); + await UnitOfWork.CommitAsync(); + + //验证 + Assert.True( await _operationLogRepository.ExistsAsync( t => t.Caption == "EntityChangedEvent_Deleted" && t.LogName == nameof( ProductChangedEventHandler ) ) ); + } + + /// + /// 测试实体变更事件 - 物理删除 + /// + [Fact] + public async Task TestEntityChangedEvent_Deleted_2() { + //添加实体 + var entity = OperationLogFakeService.GetOperationLog(); + entity.Init(); + entity.LogName = "EntityChangedEvent_Deleted"; + await _operationLogRepository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); + + //删除实体 + await _operationLogRepository.RemoveAsync( entity ); + await UnitOfWork.CommitAsync(); + + //验证 + Assert.True( await _operationLogRepository.ExistsAsync( t => t.LogName == "Test" && t.Caption == nameof( OperationLogChangedEventHandler ) && t.Content == "EntityChangedEvent_Deleted" ) ); + } + + #endregion + } +} diff --git a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests.Integration/Tests/OperationLogRepositoryTest.cs b/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests.Integration/Tests/OperationLogRepositoryTest.cs new file mode 100644 index 00000000..fecbccb7 --- /dev/null +++ b/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests.Integration/Tests/OperationLogRepositoryTest.cs @@ -0,0 +1,63 @@ +using System.Threading.Tasks; +using Util.Tests.Fakes; +using Util.Tests.Infrastructure; +using Util.Tests.Repositories; +using Util.Tests.UnitOfWorks; +using Xunit; + +namespace Util.Data.EntityFrameworkCore.Tests { + /// + /// 操作日志仓储测试 + /// 说明: + /// 测试自增长long类型标识 + /// + public class OperationLogRepositoryTest : TestBase { + /// + /// 仓储 + /// + private readonly IOperationLogRepository _repository; + + /// + /// 测试初始化 + /// + public OperationLogRepositoryTest( IOperationLogRepository operationLogRepository, ITestUnitOfWork unitOfWork ) : base( unitOfWork ) { + _repository = operationLogRepository; + } + + /// + /// 测试添加实体 + /// + [Fact] + public async Task TestAdd() { + //添加实体 + var entity = OperationLogFakeService.GetOperationLog(); + await _repository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); + + //验证 + Assert.True( entity.Id > 0 ); + Assert.True( _repository.Exists( t => t.Id == entity.Id ) ); + } + + /// + /// 测试通过标识移除实体 - 物理删除 + /// + [Fact] + public async Task TestRemove_Id() { + //添加实体 + var entity = OperationLogFakeService.GetOperationLog(); + await _repository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //移除实体 + await _repository.RemoveAsync( entity.Id ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //验证 + var result = await _repository.FindByIdAsync( entity.Id ); + Assert.Null( result ); + } + } +} diff --git a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests.Integration/Tests/OrderRepositoryTest.cs b/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests.Integration/Tests/OrderRepositoryTest.cs new file mode 100644 index 00000000..076b5bd1 --- /dev/null +++ b/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests.Integration/Tests/OrderRepositoryTest.cs @@ -0,0 +1,130 @@ +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore; +using Util.Tests.Fakes; +using Util.Tests.Infrastructure; +using Util.Tests.Models; +using Util.Tests.Repositories; +using Util.Tests.UnitOfWorks; +using Xunit; + +namespace Util.Data.EntityFrameworkCore.Tests { + /// + /// 订单仓储测试 + /// 说明: + /// 1. 测试string类型标识 + /// 2. 测试一对多导航属性 + /// + public class OrderRepositoryTest : TestBase { + + #region 测试初始化 + + /// + /// 仓储 + /// + private readonly IOrderRepository _repository; + + /// + /// 测试初始化 + /// + public OrderRepositoryTest( IOrderRepository repository, ITestUnitOfWork unitOfWork ) : base( unitOfWork ) { + _repository = repository; + } + + #endregion + + #region 辅助方法 + + /// + /// 添加订单 + /// + private async Task AddOrderAsync() { + var order = OrderFakeService.GetOrder(); + order.Init(); + order.OrderItems.Add( CreateOrderItem() ); + order.OrderItems.Add( CreateOrderItem() ); + await _repository.AddAsync( order ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + return order; + } + + /// + /// 创建订单项 + /// + private OrderItem CreateOrderItem() { + var item = OrderItemFakeService.GetOrderItem(); + item.Init(); + return item; + } + + #endregion + + #region Single + + /// + /// 测试查找单个实体 + /// + [Fact] + public async Task TestSingle_1() { + //添加实体 + var entity = await AddOrderAsync(); + + //查找单个实体 + var result = await _repository.SingleAsync( t => t.Id == entity.Id ); + + //验证 + Assert.Empty( result.OrderItems ); + } + + /// + /// 测试查找单个实体 - 使用Include包含子实体集合 + /// + [Fact] + public async Task TestSingle_2() { + //添加实体 + var entity = await AddOrderAsync(); + + //查找单个实体 + var result = await _repository.SingleAsync( t => t.Id == entity.Id, queryable => queryable.Include( t => t.OrderItems ) ); + + //验证 + Assert.Equal( 2, result.OrderItems.Count ); + } + + #endregion + + #region SingleAsync + + /// + /// 测试查找单个实体 + /// + [Fact] + public async Task TestSingleAsync_1() { + //添加实体 + var entity = await AddOrderAsync(); + + //查找单个实体 + var result = await _repository.SingleAsync( t => t.Id == entity.Id ); + + //验证 + Assert.Empty( result.OrderItems ); + } + + /// + /// 测试查找单个实体 - 使用Include包含子实体集合 + /// + [Fact] + public async Task TestSingleAsync_2() { + //添加实体 + var entity = await AddOrderAsync(); + + //查找单个实体 + var result = await _repository.SingleAsync( t => t.Id == entity.Id, queryable => queryable.Include( t => t.OrderItems ) ); + + //验证 + Assert.Equal( 2, result.OrderItems.Count ); + } + + #endregion + } +} \ No newline at end of file diff --git a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests.Integration/Tests/PostRepositoryTest.cs b/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests.Integration/Tests/PostRepositoryTest.cs new file mode 100644 index 00000000..c238dde1 --- /dev/null +++ b/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests.Integration/Tests/PostRepositoryTest.cs @@ -0,0 +1,54 @@ +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore; +using Util.Tests.Fakes; +using Util.Tests.Infrastructure; +using Util.Tests.Repositories; +using Util.Tests.UnitOfWorks; +using Xunit; + +namespace Util.Data.EntityFrameworkCore.Tests { + /// + /// 贴子仓储测试 + /// 说明: + /// 1. 测试多对多 + /// + public class PostRepositoryTest : TestBase { + /// + /// 仓储 + /// + private readonly IPostRepository _repository; + + /// + /// 测试初始化 + /// + public PostRepositoryTest(IPostRepository repository, ITestUnitOfWork unitOfWork ) : base(unitOfWork){ + _repository = repository; + } + + /// + /// 测试添加实体 + /// + [Fact] + public async Task TestAddAsync() { + //添加实体 + var post = PostFakeService.GetPost(); + post.Init(); + var tag1 = TagFakeService.GetTag(); + tag1.Init(); + post.Tags.Add( tag1 ); + + var tag2 = TagFakeService.GetTag(); + tag2.Init(); + post.Tags.Add( tag2 ); + + await _repository.AddAsync( post ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //验证 + var result = await _repository.SingleAsync( t => t.Id == post.Id, queryable => queryable.Include( t => t.Tags ) ); + Assert.NotNull( result ); + Assert.Equal( 2,result.Tags.Count ); + } + } +} \ No newline at end of file diff --git a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests.Integration/Tests/ProductRepositoryTest.Queryable.cs b/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests.Integration/Tests/ProductRepositoryTest.Queryable.cs new file mode 100644 index 00000000..e03ea9c5 --- /dev/null +++ b/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests.Integration/Tests/ProductRepositoryTest.Queryable.cs @@ -0,0 +1,390 @@ +using System; +using System.Linq; +using System.Threading.Tasks; +using Util.Data.Queries; +using Util.Tests.Conditions; +using Util.Tests.Fakes; +using Xunit; + +namespace Util.Data.EntityFrameworkCore.Tests { + /// + /// 产品仓储测试 - 查询测试 + /// + public partial class ProductRepositoryTest { + + #region Where + + /// + /// 测试设置查询条件 - 添加查询条件对象 + /// + [Fact] + public async Task TestWhere() { + //常量 + var name = "TestWhere"; + + //添加实体列表 + await AddProductsAsync(); + var products = await AddProductsAsync( name: name ); + + //创建查询条件 + var condition = new ProductNameCondition( name ); + + //查询 + var result = _repository.Find().Where( condition ).ToList(); + + //验证 + Assert.Equal( products.Count, result.Count ); + Assert.True( result.TrueForAll( t => products.Any( p => p.Id == t.Id ) ) ); + } + + #endregion + + #region WhereIf + + /// + /// 测试设置查询条件 - IQueryable添加WhereIf扩展 - true + /// + [Fact] + public async Task TestWhereIf_True() { + //常量 + var name = "TestWhereIf_True"; + + //添加实体列表 + await AddProductsAsync(); + var products = await AddProductsAsync( name: name ); + + //查询 + var result = _repository.Find().WhereIf( t => t.Name == name, true ).ToList(); + + //验证 + Assert.Equal( products.Count, result.Count ); + } + + /// + /// 测试设置查询条件 - IQueryable添加WhereIf扩展 - false + /// + [Fact] + public async Task TestWhereIf_False() { + //常量 + var name = "TestWhereIf_False"; + + //添加实体列表 + await AddProductsAsync(); + var products = await AddProductsAsync( name: name ); + + //查询 + var result = _repository.Find().WhereIf( t => t.Name == name, false ).ToList(); + + //验证 + Assert.NotEqual( products.Count, result.Count ); + } + + #endregion + + #region WhereIfNotEmpty + + /// + /// 测试设置查询条件 - IQueryable添加WhereIfNotEmpty扩展 - 有效条件 + /// + [Fact] + public async Task TestWhereIfNotEmpty_Valid() { + //常量 + var name = "TestWhereIfNotEmpty_Valid"; + + //添加实体列表 + await AddProductsAsync(); + var products = await AddProductsAsync( name: name ); + + //查询 + var result = _repository.Find().WhereIfNotEmpty( t => t.Name == name ).ToList(); + + //验证 + Assert.Equal( products.Count, result.Count ); + } + + /// + /// 测试设置查询条件 - IQueryable添加WhereIfNotEmpty扩展 - 忽略条件 + /// + [Fact] + public async Task TestWhereIfNotEmpty_Ignore() { + //常量 + var name = "TestWhereIfNotEmpty_Ignore"; + + //添加实体列表 + await AddProductsAsync(); + var products = await AddProductsAsync( name: name ); + + //查询 + var result = _repository.Find().Where( t => t.Name == name ).WhereIfNotEmpty( t => t.Code == "" ).ToList(); + + //验证 + Assert.Equal( products.Count, result.Count ); + } + + /// + /// 测试设置查询条件 - IQueryable添加WhereIfNotEmpty扩展 - 无效条件,抛出异常 + /// + [Fact] + public async Task TestWhereIfNotEmpty_Invalid() { + //添加实体列表 + await AddProductsAsync(); + + //查询 + Assert.Throws( () => { + _repository.Find().WhereIfNotEmpty( t => t.Name == "a" && t.Code == "b" ); + } ); + } + + #endregion + + #region OrIfNotEmpty + + /// + /// 测试设置查询条件 - IQueryable添加OrIfNotEmpty扩展 - 有效条件 + /// + [Fact] + public async Task TestOrIfNotEmpty_Valid() { + //常量 + var name1 = "TestOrIfNotEmpty_Valid_1"; + var name2 = "TestOrIfNotEmpty_Valid_2"; + var name3 = "TestOrIfNotEmpty_Valid_3"; + + //添加实体列表 + await AddProductsAsync(); + await AddProductsAsync( 2, name1 ); + await AddProductsAsync( 3, name2 ); + await AddProductsAsync( 4, name3 ); + + //查询 + var result = _repository.Find().OrIfNotEmpty( t => t.Name == name1,t => t.Name == name2, t => t.Name == name3 ).ToList(); + + //验证 + Assert.Equal( 9, result.Count ); + } + + /// + /// 测试设置查询条件 - IQueryable添加OrIfNotEmpty扩展 - 忽略条件 + /// + [Fact] + public async Task TestOrIfNotEmpty_Ignore() { + //常量 + var name1 = "TestOrIfNotEmpty_Ignore_1"; + var name2 = "TestOrIfNotEmpty_Ignore_2"; + var name3 = "TestOrIfNotEmpty_Ignore_3"; + + //添加实体列表 + await AddProductsAsync(); + await AddProductsAsync( 2, name1 ); + await AddProductsAsync( 3, name2 ); + await AddProductsAsync( 4, name3 ); + + //查询 + var result = _repository.Find().OrIfNotEmpty( t => t.Name == name1, t => t.Name == name2, t => t.Name == "" ).ToList(); + + //验证 + Assert.Equal( 5, result.Count ); + } + + #endregion + + #region Between + + /// + /// 测试添加范围查询条件 + /// + [Fact] + public async Task TestBetween_1() { + //常量 + var name = "TestBetween_1"; + var price = 10.1M; + + //添加实体列表 + await AddProductsAsync(); + var products = ProductFakeService.GetProducts( 5 ); + products.ForEach( product => { + product.Init(); + product.Name = name; + product.Price = price++; + } ); + await _repository.AddAsync( products ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //查询 + var result = _repository.Find().Where( t => t.Name == name ).Between( t => t.Price,11.5M,13.5M ).ToList(); + + //验证 + Assert.Equal( 2, result.Count ); + } + + /// + /// 测试添加范围查询条件 - 包含左边界 + /// + [Fact] + public async Task TestBetween_2() { + //常量 + var name = "TestBetween_2"; + var price = 10.1M; + + //添加实体列表 + await AddProductsAsync(); + var products = ProductFakeService.GetProducts( 5 ); + products.ForEach( product => { + product.Init(); + product.Name = name; + product.Price = price++; + } ); + await _repository.AddAsync( products ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //查询 + var result = _repository.Find().Where( t => t.Name == name ).Between( t => t.Price, 11.1M, 13.1M,Boundary.Left ).ToList(); + + //验证 + Assert.Equal( 2, result.Count ); + } + + /// + /// 测试添加范围查询条件 - 包含右边界 + /// + [Fact] + public async Task TestBetween_3() { + //常量 + var name = "TestBetween_3"; + var price = 10.1M; + + //添加实体列表 + await AddProductsAsync(); + var products = ProductFakeService.GetProducts( 5 ); + products.ForEach( product => { + product.Init(); + product.Name = name; + product.Price = price++; + } ); + await _repository.AddAsync( products ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //查询 + var result = _repository.Find().Where( t => t.Name == name ).Between( t => t.Price, 11.1M, 13.1M, Boundary.Right ).ToList(); + + //验证 + Assert.Equal( 2, result.Count ); + } + + /// + /// 测试添加范围查询条件 - 包含两边 + /// + [Fact] + public async Task TestBetween_4() { + //常量 + var name = "TestBetween_4"; + var price = 10.1M; + + //添加实体列表 + await AddProductsAsync(); + var products = ProductFakeService.GetProducts( 5 ); + products.ForEach( product => { + product.Init(); + product.Name = name; + product.Price = price++; + } ); + await _repository.AddAsync( products ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //查询 + var result = _repository.Find().Where( t => t.Name == name ).Between( t => t.Price, 11.1M, 13.1M ).ToList(); + + //验证 + Assert.Equal( 3, result.Count ); + } + + /// + /// 测试添加范围查询条件 - 不包含边界 + /// + [Fact] + public async Task TestBetween_5() { + //常量 + var name = "TestBetween_5"; + var price = 10.1M; + + //添加实体列表 + await AddProductsAsync(); + var products = ProductFakeService.GetProducts( 5 ); + products.ForEach( product => { + product.Init(); + product.Name = name; + product.Price = price++; + } ); + await _repository.AddAsync( products ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //查询 + var result = _repository.Find().Where( t => t.Name == name ).Between( t => t.Price, 11.1M, 13.1M,Boundary.Neither ).ToList(); + + //验证 + Assert.Single( result ); + } + + /// + /// 测试添加范围查询条件 - 最大值为空 + /// + [Fact] + public async Task TestBetween_6() { + //常量 + var name = "TestBetween_6"; + var price = 10.1M; + + //添加实体列表 + await AddProductsAsync(); + var products = ProductFakeService.GetProducts( 5 ); + products.ForEach( product => { + product.Init(); + product.Name = name; + product.Price = price++; + } ); + await _repository.AddAsync( products ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //查询 + var result = _repository.Find().Where( t => t.Name == name ).Between( t => t.Price, 9.5M, null ).ToList(); + + //验证 + Assert.Equal( 5, result.Count ); + } + + /// + /// 测试添加范围查询条件 - 最小值为空 + /// + [Fact] + public async Task TestBetween_7() { + //常量 + var name = "TestBetween_7"; + var price = 10.1M; + + //添加实体列表 + await AddProductsAsync(); + var products = ProductFakeService.GetProducts( 5 ); + products.ForEach( product => { + product.Init(); + product.Name = name; + product.Price = price++; + } ); + await _repository.AddAsync( products ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //查询 + var result = _repository.Find().Where( t => t.Name == name ).Between( t => t.Price, null, 15.5M ).ToList(); + + //验证 + Assert.Equal( 5, result.Count ); + } + + #endregion + } +} diff --git a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Tests/ProductRepositoryTest.cs b/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests.Integration/Tests/ProductRepositoryTest.cs similarity index 72% rename from test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Tests/ProductRepositoryTest.cs rename to test/Util.Data.EntityFrameworkCore.PostgreSql.Tests.Integration/Tests/ProductRepositoryTest.cs index 0582b651..d99fb683 100644 --- a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Tests/ProductRepositoryTest.cs +++ b/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests.Integration/Tests/ProductRepositoryTest.cs @@ -2,12 +2,12 @@ using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; -using Util.Data.EntityFrameworkCore.Fakes; -using Util.Data.EntityFrameworkCore.Infrastructure; -using Util.Data.EntityFrameworkCore.Models; -using Util.Data.EntityFrameworkCore.Repositories; -using Util.Data.EntityFrameworkCore.UnitOfWorks; using Util.Exceptions; +using Util.Tests.Fakes; +using Util.Tests.Infrastructure; +using Util.Tests.Models; +using Util.Tests.Repositories; +using Util.Tests.UnitOfWorks; using Xunit; using Xunit.Abstractions; using Xunit.DependencyInjection; @@ -18,15 +18,16 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 说明: /// 1. 测试Guid类型标识 /// 2. 测试仓储基础方法 + /// 3. 测试扩展属性 /// public partial class ProductRepositoryTest : TestBase { #region 测试初始化 /// - /// 测试输出 + /// 日志消息 /// - private readonly ITestOutputHelper _testOutputHelper; + private readonly ITestOutputHelper _log; /// /// 仓储 /// @@ -35,9 +36,8 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// /// 测试初始化 /// - public ProductRepositoryTest( ITestOutputHelperAccessor testOutputHelperAccessor, - IProductRepository repository, IPgSqlUnitOfWork unitOfWork ) : base(unitOfWork){ - _testOutputHelper = testOutputHelperAccessor.Output; + public ProductRepositoryTest( ITestOutputHelperAccessor accessor, IProductRepository repository, ITestUnitOfWork unitOfWork ) :base(unitOfWork) { + _log = accessor.Output; _repository = repository; } @@ -45,19 +45,6 @@ namespace Util.Data.EntityFrameworkCore.Tests { #region 辅助方法 - /// - /// 添加产品 - /// - private Product AddProduct( string name = null ) { - var entity = ProductFakeService.GetProduct(); - entity.Init(); - if( name != null ) - entity.Name = name; - _repository.Add( entity ); - UnitOfWork.Commit(); - return entity; - } - /// /// 添加产品 /// @@ -71,24 +58,6 @@ namespace Util.Data.EntityFrameworkCore.Tests { return entity; } - /// - /// 添加实体列表 - /// - /// 添加数量 - /// 产品名称 - private List AddProducts( int count = 2, string name = null ) { - var products = ProductFakeService.GetProducts( count ); - products.ForEach( product => { - product.Init(); - if( name != null ) - product.Name = name; - } ); - _repository.Add( products ); - UnitOfWork.Commit(); - UnitOfWork.ClearCache(); - return products.OrderBy( t => t.Code ).ToList(); - } - /// /// 添加实体列表 /// @@ -104,14 +73,14 @@ namespace Util.Data.EntityFrameworkCore.Tests { await _repository.AddAsync( products ); await UnitOfWork.CommitAsync(); UnitOfWork.ClearCache(); - return products.OrderBy( t => t.Code ).ToList(); + return products.OrderBy( t => t.Id ).ToList(); } /// /// 打印更改跟踪调试信息 /// private void WriteTrackerDebug() { - _testOutputHelper.WriteLine( UnitOfWork.GetChangeTrackerDebugView() ); + _log.WriteLine( UnitOfWork.GetChangeTrackerDebugView() ); } #endregion @@ -122,9 +91,9 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试通过标识查找实体 - 跟踪实体 /// [Fact] - public void TestFindById_Tracking_1() { + public async Task TestFindById_Tracking_1() { //添加实体 - var entity = AddProduct(); + var entity = await AddProductAsync(); UnitOfWork.ClearCache(); //验证 @@ -137,9 +106,9 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试通过标识查找实体 - 跟踪实体 - 字符串标识 /// [Fact] - public void TestFindById_Tracking_2() { + public async Task TestFindById_Tracking_2() { //添加实体 - var entity = AddProduct(); + var entity = await AddProductAsync(); UnitOfWork.ClearCache(); //验证 @@ -152,9 +121,9 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试通过标识查找实体 - 不跟踪实体 /// [Fact] - public void TestFindById_NoTracking() { + public async Task TestFindById_NoTracking() { //添加实体 - var entity = AddProduct(); + var entity = await AddProductAsync(); UnitOfWork.ClearCache(); //验证 @@ -220,7 +189,7 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试通过标识列表查找实体列表 - 传入逗号分隔的标识列表 /// [Fact] - public void TestFindByIds_1() { + public async Task TestFindByIds_1() { //常量 var count = 3; @@ -229,8 +198,8 @@ namespace Util.Data.EntityFrameworkCore.Tests { products.ForEach( product => { product.Init(); } ); - _repository.Add( products ); - UnitOfWork.Commit(); + await _repository.AddAsync( products ); + await UnitOfWork.CommitAsync(); //验证 var result = _repository.FindByIds( products[0].Id, products[1].Id, products[2].Id ).OrderBy( t => t.Code ).ToList(); @@ -243,7 +212,7 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试通过标识列表查找实体列表 - 传入集合 /// [Fact] - public void TestFindByIds_2() { + public async Task TestFindByIds_2() { //常量 var count = 3; @@ -252,8 +221,8 @@ namespace Util.Data.EntityFrameworkCore.Tests { products.ForEach( product => { product.Init(); } ); - _repository.Add( products ); - UnitOfWork.Commit(); + await _repository.AddAsync( products ); + await UnitOfWork.CommitAsync(); //验证 var result = _repository.FindByIds( products.Select( t => t.Id ) ).OrderBy( t => t.Code ).ToList(); @@ -266,7 +235,7 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试通过标识列表查找实体列表 - 传入标识列表字符串 /// [Fact] - public void TestFindByIds_3() { + public async Task TestFindByIds_3() { //常量 var count = 3; @@ -275,8 +244,8 @@ namespace Util.Data.EntityFrameworkCore.Tests { products.ForEach( product => { product.Init(); } ); - _repository.Add( products ); - UnitOfWork.Commit(); + await _repository.AddAsync( products ); + await UnitOfWork.CommitAsync(); //验证 var result = _repository.FindByIds( products.Select( t => t.Id ).Join() ).OrderBy( t => t.Code ).ToList(); @@ -366,12 +335,12 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试查找单个实体 /// [Fact] - public void TestSingle_1() { + public async Task TestSingle_1() { //常量 var name = "TestSingle"; //添加实体 - var entity = AddProduct( name ); + var entity = await AddProductAsync( name ); UnitOfWork.ClearCache(); //验证 @@ -408,9 +377,9 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试判断是否存在 /// [Fact] - public void TestExists() { + public async Task TestExists() { //添加实体 - var entity = AddProduct(); + var entity = await AddProductAsync(); UnitOfWork.ClearCache(); //验证 @@ -442,7 +411,7 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试查找数量 /// [Fact] - public void TestCount() { + public async Task TestCount() { //常量 var name = "TestCount"; var count = 3; @@ -453,8 +422,8 @@ namespace Util.Data.EntityFrameworkCore.Tests { product.Init(); product.Name = name; } ); - _repository.Add( products ); - UnitOfWork.Commit(); + await _repository.AddAsync( products ); + await UnitOfWork.CommitAsync(); //验证 var result = _repository.Count( t => t.Name == name ); @@ -496,24 +465,24 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试更新方法1 - 查找并修改实体,直接提交工作单元 /// [Fact] - public void TestUpdate_1() { + public async Task TestUpdate_1() { //常量 var code = "TestUpdate_1_Code"; //添加实体 - var entity = AddProduct(); + var entity = await AddProductAsync(); UnitOfWork.ClearCache(); //查找实体并修改 - var product = _repository.FindById( entity.Id ); + var product = await _repository.FindByIdAsync( entity.Id ); product.Code = code; //直接提交工作单元 - UnitOfWork.Commit(); + await UnitOfWork.CommitAsync(); UnitOfWork.ClearCache(); //验证 - var result = _repository.FindById( entity.Id ); + var result = await _repository.FindByIdAsync( entity.Id ); Assert.Equal( code, result.Code ); } @@ -522,24 +491,24 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 更新方法1的缺陷: 通过赋值的方式更新查找实体的版本号,无法触发乐观锁 /// [Fact] - public void TestUpdate_1_Concurrency() { + public async Task TestUpdate_1_Concurrency() { //常量 var code = "TestUpdate_1_Concurrency_Code"; var description = "TestUpdate_1_Concurrency_Description"; //添加实体 - var entity = AddProduct(); + var entity = await AddProductAsync(); UnitOfWork.ClearCache(); //此处模拟用户1打开表单并修改,但尚未提交,这将保存旧实体 - var product = _repository.FindById( entity.Id ); + var product = await _repository.FindByIdAsync( entity.Id ); product.Code = code; UnitOfWork.ClearCache(); //此处模拟用户2更新该实体,这将导致版本号变化 - var product2 = _repository.FindById( entity.Id ); + var product2 = await _repository.FindByIdAsync( entity.Id ); product2.Description = description; - UnitOfWork.Commit(); + await UnitOfWork.CommitAsync(); UnitOfWork.ClearCache(); //此处模拟用户1提交表单,查找实体,并进行赋值 @@ -548,7 +517,7 @@ namespace Util.Data.EntityFrameworkCore.Tests { result.Description = product.Description; result.Version = product.Version; //提交工作单元,由于版本号变化,预期应触发乐观锁,但实际未触发 - UnitOfWork.Commit(); + await UnitOfWork.CommitAsync(); //结果:用户1覆盖了用户2设置的Description属性 Assert.Equal( code, result.Code ); @@ -559,12 +528,12 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试更新方法2 - 创建未跟踪实体,调用dbcontext.Update方法 /// [Fact] - public void TestUpdate_2() { + public async Task TestUpdate_2() { //常量 var code = "TestUpdate_2_Code"; //添加实体 - var entity = AddProduct(); + var entity = await AddProductAsync(); UnitOfWork.ClearCache(); //创建未跟踪实体 @@ -573,11 +542,11 @@ namespace Util.Data.EntityFrameworkCore.Tests { //调用dbcontext.Update方法更新实体 _repository.UpdateProduct( product ); //提交工作单元 - UnitOfWork.Commit(); + await UnitOfWork.CommitAsync(); UnitOfWork.ClearCache(); //验证 - var result = _repository.FindById( entity.Id ); + var result = await _repository.FindByIdAsync( entity.Id ); Assert.Equal( code, result.Code ); } @@ -586,16 +555,16 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 如果在创建未跟踪实体并调用dbcontext.Update方法之前,从dbcontext中已查找出该实体,将发生异常 /// [Fact] - public void TestUpdate_2_InvalidOperation() { + public async Task TestUpdate_2_InvalidOperation() { //常量 var code = "TestUpdate_2_InvalidOperation_Code"; //添加实体 - var entity = AddProduct(); + var entity = await AddProductAsync(); UnitOfWork.ClearCache(); //模拟更新之前无意中已查找出该实体 - _repository.FindById( entity.Id ); + await _repository.FindByIdAsync( entity.Id ); //创建未跟踪实体 var product = entity.MapTo(); @@ -611,24 +580,24 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试更新并发 - 使用更新方法2 /// [Fact] - public void TestUpdate_2_Concurrency() { + public async Task TestUpdate_2_Concurrency() { //常量 var code = "TestUpdate_2_Concurrency_Code"; var description = "TestUpdate_2_Concurrency_Description"; //添加实体 - var entity = AddProduct(); + var entity = await AddProductAsync(); UnitOfWork.ClearCache(); //此处模拟用户1打开表单并修改,但尚未提交,这将保存旧实体 - var product = _repository.FindById( entity.Id ); + var product = await _repository.FindByIdAsync( entity.Id ); product.Code = code; UnitOfWork.ClearCache(); //此处模拟用户2更新该实体,这将导致版本号变化 - var product2 = _repository.FindById( entity.Id ); + var product2 = await _repository.FindByIdAsync( entity.Id ); product2.Description = description; - UnitOfWork.Commit(); + await UnitOfWork.CommitAsync(); UnitOfWork.ClearCache(); //此处模拟用户1提交表单,创建一个新的实体,并赋值 @@ -638,8 +607,8 @@ namespace Util.Data.EntityFrameworkCore.Tests { _repository.UpdateProduct( result ); //提交工作单元,由于版本号变化,触发乐观锁 - Assert.Throws( () => { - UnitOfWork.Commit(); + await Assert.ThrowsAsync( async () => { + await UnitOfWork.CommitAsync(); } ); } @@ -647,23 +616,23 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试Util Update更新方法 - 查找并修改实体,提交工作单元 /// [Fact] - public void TestUpdate_3_1() { + public async Task TestUpdate_3_1() { //常量 var code = "TestUpdate_3_1_Code"; //添加实体 - var entity = AddProduct(); + var entity = await AddProductAsync(); UnitOfWork.ClearCache(); //查找实体并修改 - var product = _repository.FindById( entity.Id ); + var product = await _repository.FindByIdAsync( entity.Id ); product.Code = code; //调用Update方法 - _repository.Update( product ); + await _repository.UpdateAsync( product ); //提交工作单元 - UnitOfWork.Commit(); + await UnitOfWork.CommitAsync(); UnitOfWork.ClearCache(); //验证 @@ -675,189 +644,19 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试Util Update更新方法 - 创建未跟踪实体,调用Update方法 /// [Fact] - public void TestUpdate_3_2() { + public async Task TestUpdate_3_2() { //常量 var code = "TestUpdate_3_2_Code"; - //添加实体 - var entity = AddProduct(); - UnitOfWork.ClearCache(); - - //创建未跟踪实体 - var product = entity.MapTo(); - product.Code = code; - - //调用Update方法更新实体 - _repository.Update( product ); - - //提交工作单元 - UnitOfWork.Commit(); - UnitOfWork.ClearCache(); - - //验证 - var result = _repository.FindById( entity.Id ); - Assert.Equal( code, result.Code ); - } - - /// - /// 测试Util Update更新方法 - 允许在创建未跟踪实体并调用Update方法之前查找实体,不会发生异常 - /// - [Fact] - public void TestUpdate_3_3() { - //常量 - var code = "TestUpdate_3_3_InvalidOperation_Code"; - - //添加实体 - var entity = AddProduct(); - UnitOfWork.ClearCache(); - - //模拟更新之前无意中已查找出该实体 - _repository.FindById( entity.Id ); - - //创建未跟踪实体 - var product = entity.MapTo(); - product.Code = code; - - //调用Update方法更新实体 - _repository.Update( product ); - - //提交工作单元 - _testOutputHelper.WriteLine( UnitOfWork.GetChangeTrackerDebugView() ); - UnitOfWork.Commit(); - UnitOfWork.ClearCache(); - - //验证 - var result = _repository.FindById( entity.Id ); - Assert.Equal( code, result.Code ); - } - - /// - /// 测试更新并发 - 使用Util Update更新方法 - /// 通过赋值的方式更新查找实体的版本号,触发乐观锁 - /// - [Fact] - public void TestUpdate_3_Concurrency_1() { - //常量 - var code = "TestUpdate_3_Concurrency_1_Code"; - var description = "TestUpdate_3_Concurrency_1_Description"; - - //添加实体 - var entity = AddProduct(); - UnitOfWork.ClearCache(); - - //此处模拟用户1打开表单并修改,但尚未提交,这将保存旧实体 - var product = _repository.FindById( entity.Id ); - product.Code = code; - UnitOfWork.ClearCache(); - - //此处模拟用户2更新该实体,这将导致版本号变化 - var product2 = _repository.FindById( entity.Id ); - product2.Description = description; - UnitOfWork.Commit(); - UnitOfWork.ClearCache(); - - //此处模拟用户1提交表单,查找实体,并进行赋值 - var result = _repository.FindById( entity.Id ); - result.Code = product.Code; - result.Description = product.Description; - result.Version = product.Version; - - //调用Update方法更新实体时触发乐观锁 - Assert.Throws( () => { - _repository.Update( result ); - } ); - } - - /// - /// 测试更新并发 - 使用Util Update更新方法 - /// 更新未跟踪实体触发乐观锁 - /// - [Fact] - public void TestUpdate_3_Concurrency_2() { - //常量 - var code = "TestUpdate_3_Concurrency_2_Code"; - var description = "TestUpdate_3_Concurrency_2_Description"; - - //添加实体 - var entity = AddProduct(); - UnitOfWork.ClearCache(); - - //此处模拟用户1打开表单并修改,但尚未提交,这将保存旧实体 - var product = _repository.FindById( entity.Id ); - product.Code = code; - UnitOfWork.ClearCache(); - - //此处模拟用户2更新该实体,这将导致版本号变化 - var product2 = _repository.FindById( entity.Id ); - product2.Description = description; - UnitOfWork.Commit(); - UnitOfWork.ClearCache(); - - //此处模拟用户1提交表单,创建一个新的实体,并赋值 - var result = product.MapTo(); - - //调用Update方法更新实体 - _repository.Update( result ); - - //提交工作单元,由于版本号变化,触发乐观锁 - Assert.Throws( () => { - UnitOfWork.Commit(); - } ); - } - - /// - /// 测试更新集合 - /// - [Fact] - public void TestUpdate_4() { - //常量 - var count = 3; - var code = "TestUpdate_4_Code"; - - //添加实体列表 - var entities = ProductFakeService.GetProducts( count ); - entities.ForEach( product => { - product.Init(); - } ); - _repository.Add( entities ); - UnitOfWork.Commit(); - UnitOfWork.ClearCache(); - - //查找实体,赋值,调用Update方法,提交工作单元 - var products = _repository.FindByIds( entities.Select( t => t.Id ) ).ToList(); - products.ForEach( product => product.Code = code ); - _repository.Update( products ); - UnitOfWork.Commit(); - UnitOfWork.ClearCache(); - - //验证 - var result = _repository.FindByIds( entities.Select( t => t.Id ) ).ToList(); - Assert.Equal( code, result[0].Code ); - Assert.Equal( code, result[1].Code ); - Assert.Equal( code, result[2].Code ); - } - - #endregion - - #region UpdateAsync - - /// - /// 测试Util Update更新方法 - 异步 - /// - [Fact] - public async Task TestUpdateAsync_1() { - //常量 - var code = "TestUpdateAsync_1_Code"; - //添加实体 var entity = await AddProductAsync(); UnitOfWork.ClearCache(); - //查找实体并修改 - var product = await _repository.FindByIdAsync( entity.Id ); + //创建未跟踪实体 + var product = entity.MapTo(); product.Code = code; - //调用UpdateAsync方法 + //调用Update方法更新实体 await _repository.UpdateAsync( product ); //提交工作单元 @@ -870,13 +669,119 @@ namespace Util.Data.EntityFrameworkCore.Tests { } /// - /// 测试更新集合 - 异步 + /// 测试Util Update更新方法 - 允许在创建未跟踪实体并调用Update方法之前查找实体,不会发生异常 /// [Fact] - public async Task TestUpdateAsync_2() { + public async Task TestUpdate_3_3() { + //常量 + var code = "TestUpdate_3_3_InvalidOperation_Code"; + + //添加实体 + var entity = await AddProductAsync(); + UnitOfWork.ClearCache(); + + //模拟更新之前无意中已查找出该实体 + await _repository.FindByIdAsync( entity.Id ); + + //创建未跟踪实体 + var product = entity.MapTo(); + product.Code = code; + + //调用Update方法更新实体 + await _repository.UpdateAsync( product ); + + //提交工作单元 + _log.WriteLine( UnitOfWork.GetChangeTrackerDebugView() ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //验证 + var result = _repository.FindById( entity.Id ); + Assert.Equal( code, result.Code ); + } + + /// + /// 测试更新并发 - 使用Util Update更新方法 + /// 通过赋值的方式更新查找实体的版本号,触发乐观锁 + /// + [Fact] + public async Task TestUpdate_3_Concurrency_1() { + //常量 + var code = "TestUpdate_3_Concurrency_1_Code"; + var description = "TestUpdate_3_Concurrency_1_Description"; + + //添加实体 + var entity = await AddProductAsync(); + UnitOfWork.ClearCache(); + + //此处模拟用户1打开表单并修改,但尚未提交,这将保存旧实体 + var product = await _repository.FindByIdAsync( entity.Id ); + product.Code = code; + UnitOfWork.ClearCache(); + + //此处模拟用户2更新该实体,这将导致版本号变化 + var product2 = await _repository.FindByIdAsync( entity.Id ); + product2.Description = description; + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //此处模拟用户1提交表单,查找实体,并进行赋值 + var result = await _repository.FindByIdAsync( entity.Id ); + result.Code = product.Code; + result.Description = product.Description; + result.Version = product.Version; + + //调用Update方法更新实体时触发乐观锁 + await Assert.ThrowsAsync( async () => { + await _repository.UpdateAsync( result ); + } ); + } + + /// + /// 测试更新并发 - 使用Util Update更新方法 + /// 更新未跟踪实体触发乐观锁 + /// + [Fact] + public async Task TestUpdate_3_Concurrency_2() { + //常量 + var code = "TestUpdate_3_Concurrency_2_Code"; + var description = "TestUpdate_3_Concurrency_2_Description"; + + //添加实体 + var entity = await AddProductAsync(); + UnitOfWork.ClearCache(); + + //此处模拟用户1打开表单并修改,但尚未提交,这将保存旧实体 + var product = await _repository.FindByIdAsync( entity.Id ); + product.Code = code; + UnitOfWork.ClearCache(); + + //此处模拟用户2更新该实体,这将导致版本号变化 + var product2 = await _repository.FindByIdAsync( entity.Id ); + product2.Description = description; + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //此处模拟用户1提交表单,创建一个新的实体,并赋值 + var result = product.MapTo(); + + //调用Update方法更新实体 + await _repository.UpdateAsync( result ); + + //提交工作单元,由于版本号变化,触发乐观锁 + await Assert.ThrowsAsync( async () => { + await UnitOfWork.CommitAsync(); + } ); + } + + /// + /// 测试更新集合 + /// + [Fact] + public async Task TestUpdate_4() { //常量 var count = 3; - var code = "TestUpdateAsync_2_Code"; + var code = "TestUpdate_4_Code"; //添加实体列表 var entities = ProductFakeService.GetProducts( count ); @@ -887,15 +792,15 @@ namespace Util.Data.EntityFrameworkCore.Tests { await UnitOfWork.CommitAsync(); UnitOfWork.ClearCache(); - //查找实体,赋值,调用UpdateAsync方法,提交工作单元 - var products = ( await _repository.FindByIdsAsync( entities.Select( t => t.Id ) ) ).ToList(); + //查找实体,赋值,调用Update方法,提交工作单元 + var products = await _repository.FindByIdsAsync( entities.Select( t => t.Id ) ); products.ForEach( product => product.Code = code ); await _repository.UpdateAsync( products ); await UnitOfWork.CommitAsync(); UnitOfWork.ClearCache(); //验证 - var result = ( await _repository.FindByIdsAsync( entities.Select( t => t.Id ) ) ).ToList(); + var result = await _repository.FindByIdsAsync( entities.Select( t => t.Id ) ); Assert.Equal( code, result[0].Code ); Assert.Equal( code, result[1].Code ); Assert.Equal( code, result[2].Code ); @@ -905,163 +810,6 @@ namespace Util.Data.EntityFrameworkCore.Tests { #region Remove - /// - /// 测试通过标识移除实体 - 逻辑删除 - /// - [Fact] - public void TestRemove_Id_1() { - //添加实体 - var entity = AddProduct(); - UnitOfWork.ClearCache(); - - //移除实体 - _repository.Remove( entity.Id ); - UnitOfWork.Commit(); - UnitOfWork.ClearCache(); - - //验证 - var result = _repository.FindById( entity.Id ); - Assert.Null( result ); - } - - /// - /// 测试通过标识移除实体 - 逻辑删除 - 使用工作单元禁用逻辑删除过滤器 - /// - [Fact] - public void TestRemove_Id_2() { - //添加实体 - var entity = AddProduct(); - UnitOfWork.ClearCache(); - - //移除实体 - _repository.Remove( entity.Id ); - UnitOfWork.Commit(); - UnitOfWork.ClearCache(); - - //使用工作单元禁用逻辑删除过滤器,可以查出 - using( UnitOfWork.DisableDeleteFilter() ) { - var product = _repository.FindById( entity.Id ); - Assert.True( product.IsDeleted ); - Assert.Equal( entity.Code, product.Code ); - } - UnitOfWork.ClearCache(); - - //逻辑删除过滤器已启用,无法查出 - var result = _repository.FindById( entity.Id ); - Assert.Null( result ); - } - - /// - /// 测试通过标识移除实体 - 逻辑删除 - 使用仓储禁用逻辑删除过滤器 - /// - [Fact] - public void TestRemove_Id_3() { - //添加实体 - var entity = AddProduct(); - UnitOfWork.ClearCache(); - - //移除实体 - _repository.Remove( entity.Id ); - UnitOfWork.Commit(); - UnitOfWork.ClearCache(); - - //使用仓储禁用逻辑删除过滤器,可以查出 - using( _repository.DisableDeleteFilter() ) { - var product = _repository.FindById( entity.Id ); - Assert.True( product.IsDeleted ); - Assert.Equal( entity.Code, product.Code ); - } - UnitOfWork.ClearCache(); - - //逻辑删除过滤器已启用,无法查出 - var result = _repository.FindById( entity.Id ); - Assert.Null( result ); - } - - /// - /// 测试移除实体 - 逻辑删除 - /// - [Fact] - public void TestRemove_Entity() { - //添加实体 - var entity = AddProduct(); - UnitOfWork.ClearCache(); - - //移除实体 - _repository.Remove( entity ); - UnitOfWork.Commit(); - UnitOfWork.ClearCache(); - - //验证 - var result = _repository.FindById( entity.Id ); - Assert.Null( result ); - } - - /// - /// 测试移除实体集合 - 逻辑删除 - 通过标识列表 - /// - [Fact] - public void TestRemove_Entities_1() { - //常量 - var count = 3; - - //添加实体列表 - var products = ProductFakeService.GetProducts( count ).ToList(); - products.ForEach( product => { - product.Init(); - } ); - _repository.Add( products ); - UnitOfWork.Commit(); - UnitOfWork.ClearCache(); - - //移除实体集合 - var ids = products.Select( t => t.Id ).ToList(); - _repository.Remove( ids ); - UnitOfWork.Commit(); - UnitOfWork.ClearCache(); - - //验证 - using( _repository.DisableDeleteFilter() ) { - var result = _repository.FindByIds( ids ); - Assert.Equal( count, result.Count ); - result.ForEach( t => Assert.True( t.IsDeleted ) ); - } - } - - /// - /// 测试移除实体集合 - 逻辑删除 - 通过实体列表 - /// - [Fact] - public void TestRemove_Entities_2() { - //常量 - var count = 3; - - //添加实体列表 - var products = ProductFakeService.GetProducts( count ).ToList(); - products.ForEach( product => { - product.Init(); - } ); - _repository.Add( products ); - UnitOfWork.Commit(); - UnitOfWork.ClearCache(); - - //移除实体集合 - _repository.Remove( products ); - UnitOfWork.Commit(); - UnitOfWork.ClearCache(); - - //验证 - using( _repository.DisableDeleteFilter() ) { - var result = _repository.FindByIds( products.Select( t => t.Id ) ); - Assert.Equal( count, result.Count ); - result.ForEach( t => Assert.True( t.IsDeleted ) ); - } - } - - #endregion - - #region RemoveAsync - /// /// 测试通过标识移除实体 - 逻辑删除 /// @@ -1223,12 +971,12 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试设置创建审计属性 /// [Fact] - public void TestCreationAudit() { + public async Task TestCreationAudit() { var entity = ProductFakeService.GetProduct(); entity.Init(); - _repository.Add( entity ); + await _repository.AddAsync( entity ); Assert.NotEqual( TestSession.TestUserId, entity.CreatorId ); - UnitOfWork.Commit(); + await UnitOfWork.CommitAsync(); Assert.Equal( TestSession.TestUserId, entity.CreatorId ); Assert.Equal( TestSession.TestUserId, entity.LastModifierId ); } @@ -1237,7 +985,7 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试设置修改审计属性 /// [Fact] - public void TestModificationAudit() { + public async Task TestModificationAudit() { //工作单元 var unitOfWork = (PgSqlUnitOfWork)UnitOfWork; @@ -1245,13 +993,13 @@ namespace Util.Data.EntityFrameworkCore.Tests { var code = "TestModificationAudit"; //添加实体 - var entity = AddProduct(); + var entity = await AddProductAsync(); unitOfWork.ClearCache(); //修改 var product = entity.MapTo(); product.Code = code; - _repository.Update( product ); + await _repository.UpdateAsync( product ); unitOfWork.SetSession( new TestSession { UserId = TestSession.TestUserId2.ToString() } ); //验证修改前审计属性 @@ -1259,7 +1007,7 @@ namespace Util.Data.EntityFrameworkCore.Tests { Assert.Equal( TestSession.TestUserId, product.LastModifierId ); //提交 - unitOfWork.Commit(); + await unitOfWork.CommitAsync(); //验证修改后审计属性 Assert.Equal( TestSession.TestUserId, product.CreatorId ); @@ -1274,7 +1022,7 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试扩展属性 - 添加简单扩展属性 /// [Fact] - public void TestExtraProperties_1() { + public async Task TestExtraProperties_1() { //常量 var value = "TestExtraProperties_1"; @@ -1282,12 +1030,12 @@ namespace Util.Data.EntityFrameworkCore.Tests { var entity = new Product(); entity.Init(); entity.TestProperty1 = value; - _repository.Add( entity ); - UnitOfWork.Commit(); + await _repository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); UnitOfWork.ClearCache(); //验证 - var result = _repository.FindById( entity.Id ); + var result = await _repository.FindByIdAsync( entity.Id ); Assert.Equal( value, result.TestProperty1 ); } @@ -1295,7 +1043,7 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试扩展属性 - 修改简单扩展属性 /// [Fact] - public void TestExtraProperties_2() { + public async Task TestExtraProperties_2() { //常量 var oldValue = "TestExtraProperties_2_1"; var newValue = "TestExtraProperties_2_2"; @@ -1304,22 +1052,22 @@ namespace Util.Data.EntityFrameworkCore.Tests { var entity = new Product(); entity.Init(); entity.TestProperty1 = oldValue; - _repository.Add( entity ); - UnitOfWork.Commit(); + await _repository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); UnitOfWork.ClearCache(); //验证 - var oldEntity = _repository.FindById( entity.Id ); + var oldEntity = await _repository.FindByIdAsync( entity.Id ); Assert.Equal( oldValue, oldEntity.TestProperty1 ); //修改实体 oldEntity.TestProperty1 = newValue; - _repository.Update( oldEntity ); - UnitOfWork.Commit(); + await _repository.UpdateAsync( oldEntity ); + await UnitOfWork.CommitAsync(); UnitOfWork.ClearCache(); //验证 - var result = _repository.FindById( entity.Id ); + var result = await _repository.FindByIdAsync( entity.Id ); Assert.Equal( newValue, result.TestProperty1 ); } @@ -1327,7 +1075,7 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试扩展属性 - 添加对象扩展属性 /// [Fact] - public void TestExtraProperties_3() { + public async Task TestExtraProperties_3() { //常量 var code = 2; var name = "TestExtraProperties_3"; @@ -1339,8 +1087,8 @@ namespace Util.Data.EntityFrameworkCore.Tests { entity.TestProperty2.Code = code; entity.TestProperty2.Name = name; entity.TestProperty2.EnumValue = enumValue; - _repository.Add( entity ); - UnitOfWork.Commit(); + await _repository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); UnitOfWork.ClearCache(); //验证 @@ -1354,7 +1102,7 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试扩展属性 - 修改对象扩展属性 /// [Fact] - public void TestExtraProperties_4() { + public async Task TestExtraProperties_4() { //常量 var code = 2; var oldName = "TestExtraProperties_4_1"; @@ -1368,12 +1116,12 @@ namespace Util.Data.EntityFrameworkCore.Tests { entity.TestProperty2.Code = code; entity.TestProperty2.Name = oldName; entity.TestProperty2.EnumValue = oldEnumValue; - _repository.Add( entity ); - UnitOfWork.Commit(); + await _repository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); UnitOfWork.ClearCache(); //验证 - var oldEntity = _repository.FindById( entity.Id ); + var oldEntity = await _repository.FindByIdAsync( entity.Id ); Assert.Equal( code, oldEntity.TestProperty2.Code ); Assert.Equal( oldName, oldEntity.TestProperty2.Name ); Assert.Equal( oldEnumValue, oldEntity.TestProperty2.EnumValue ); @@ -1382,12 +1130,12 @@ namespace Util.Data.EntityFrameworkCore.Tests { oldEntity.TestProperty2.Name = newName; oldEntity.TestProperty2.EnumValue = newEnumValue; WriteTrackerDebug(); - _repository.Update( oldEntity ); - UnitOfWork.Commit(); + await _repository.UpdateAsync( oldEntity ); + await UnitOfWork.CommitAsync(); UnitOfWork.ClearCache(); //验证 - var result = _repository.FindById( entity.Id ); + var result = await _repository.FindByIdAsync( entity.Id ); Assert.Equal( newName, result.TestProperty2.Name ); Assert.Equal( newEnumValue, result.TestProperty2.EnumValue ); } @@ -1396,7 +1144,7 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试扩展属性 - 添加对象集合扩展属性 /// [Fact] - public void TestExtraProperties_5() { + public async Task TestExtraProperties_5() { //常量 var code = 1; var name1 = "TestExtraProperties_5_1"; @@ -1407,12 +1155,12 @@ namespace Util.Data.EntityFrameworkCore.Tests { entity.Init(); entity.TestProperties.Add( new ProductItem { Code = code, Name = name1 } ); entity.TestProperties.Add( new ProductItem { Code = code, Name = name2 } ); - _repository.Add( entity ); - UnitOfWork.Commit(); + await _repository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); UnitOfWork.ClearCache(); //验证 - var result = _repository.FindById( entity.Id ); + var result = await _repository.FindByIdAsync( entity.Id ); Assert.Equal( 2, result.TestProperties.Count ); Assert.Equal( code, result.TestProperties[0].Code ); Assert.Equal( name1, result.TestProperties[0].Name ); @@ -1424,7 +1172,7 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试扩展属性 - 修改对象集合扩展属性 /// [Fact] - public void TestExtraProperties_6() { + public async Task TestExtraProperties_6() { //常量 var code = 1; var oldName = "TestExtraProperties_6_1"; @@ -1436,24 +1184,24 @@ namespace Util.Data.EntityFrameworkCore.Tests { entity.Init(); entity.TestProperties.Add( new ProductItem { Code = code, Name = oldName } ); entity.TestProperties.Add( new ProductItem { Code = code, Name = oldName } ); - _repository.Add( entity ); - UnitOfWork.Commit(); + await _repository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); UnitOfWork.ClearCache(); //验证 - var oldEntity = _repository.FindById( entity.Id ); + var oldEntity = await _repository.FindByIdAsync( entity.Id ); Assert.Equal( 2, oldEntity.TestProperties.Count ); //修改实体 oldEntity.TestProperties[0].Name = newName; oldEntity.TestProperties[1].Name = newName; oldEntity.TestProperties.Add( new ProductItem { Code = code, Name = name3 } ); - _repository.Update( oldEntity ); - UnitOfWork.Commit(); + await _repository.UpdateAsync( oldEntity ); + await UnitOfWork.CommitAsync(); UnitOfWork.ClearCache(); //验证 - var result = _repository.FindById( entity.Id ); + var result = await _repository.FindByIdAsync( entity.Id ); Assert.Equal( 3, result.TestProperties.Count ); Assert.Equal( code, result.TestProperties[0].Code ); Assert.Equal( newName, result.TestProperties[0].Name ); @@ -1467,7 +1215,7 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试扩展属性 - 添加多个扩展属性 /// [Fact] - public void TestExtraProperties_7() { + public async Task TestExtraProperties_7() { //常量 var code = 2; var name = "TestExtraProperties_7"; @@ -1480,12 +1228,12 @@ namespace Util.Data.EntityFrameworkCore.Tests { entity.TestProperty2.Name = name; entity.TestProperties.Add( new ProductItem { Code = code, Name = name } ); entity.TestProperties.Add( new ProductItem { Code = code, Name = name } ); - _repository.Add( entity ); - UnitOfWork.Commit(); + await _repository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); UnitOfWork.ClearCache(); //验证 - var result = _repository.FindById( entity.Id ); + var result = await _repository.FindByIdAsync( entity.Id ); Assert.Equal( name, result.TestProperty1 ); Assert.Equal( code, result.TestProperty2.Code ); Assert.Equal( name, result.TestProperty2.Name ); @@ -1499,7 +1247,7 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试扩展属性 - 修改多个扩展属性 /// [Fact] - public void TestExtraProperties_8() { + public async Task TestExtraProperties_8() { //常量 var code = 2; var oldName = "TestExtraProperties_8_1"; @@ -1513,12 +1261,12 @@ namespace Util.Data.EntityFrameworkCore.Tests { entity.TestProperty2.Name = oldName; entity.TestProperties.Add( new ProductItem { Code = code, Name = oldName } ); entity.TestProperties.Add( new ProductItem { Code = code, Name = oldName } ); - _repository.Add( entity ); - UnitOfWork.Commit(); + await _repository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); UnitOfWork.ClearCache(); //验证 - var oldEntity = _repository.FindById( entity.Id ); + var oldEntity = await _repository.FindByIdAsync( entity.Id ); Assert.Equal( oldName, oldEntity.TestProperty1 ); Assert.Equal( code, oldEntity.TestProperty2.Code ); Assert.Equal( oldName, oldEntity.TestProperty2.Name ); @@ -1530,12 +1278,12 @@ namespace Util.Data.EntityFrameworkCore.Tests { oldEntity.TestProperties[0].Name = newName; oldEntity.TestProperties[1].Name = newName; oldEntity.TestProperties.Add( new ProductItem{ Code = code, Name = newName } ); - _repository.Update( oldEntity ); - UnitOfWork.Commit(); + await _repository.UpdateAsync( oldEntity ); + await UnitOfWork.CommitAsync(); UnitOfWork.ClearCache(); //验证 - var result = _repository.FindById( entity.Id ); + var result = await _repository.FindByIdAsync( entity.Id ); Assert.Equal( newName, result.TestProperty1 ); Assert.Equal( newName, result.TestProperty2.Name ); Assert.Equal( 3, result.TestProperties.Count ); @@ -1548,7 +1296,7 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试扩展属性 - 添加枚举扩展属性 /// [Fact] - public void TestExtraProperties_9() { + public async Task TestExtraProperties_9() { //常量 ProductEnum value = ProductEnum.World; @@ -1556,12 +1304,12 @@ namespace Util.Data.EntityFrameworkCore.Tests { var entity = new Product(); entity.Init(); entity.TestProperty3 = value; - _repository.Add( entity ); - UnitOfWork.Commit(); + await _repository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); UnitOfWork.ClearCache(); //验证 - var result = _repository.FindById( entity.Id ); + var result = await _repository.FindByIdAsync( entity.Id ); Assert.Equal( value, result.TestProperty3 ); } @@ -1569,7 +1317,7 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试扩展属性 - 修改枚举扩展属性 /// [Fact] - public void TestExtraProperties_10() { + public async Task TestExtraProperties_10() { //常量 ProductEnum oldValue = ProductEnum.Hello; ProductEnum newValue = ProductEnum.World; @@ -1578,22 +1326,22 @@ namespace Util.Data.EntityFrameworkCore.Tests { var entity = new Product(); entity.Init(); entity.TestProperty3 = oldValue; - _repository.Add( entity ); - UnitOfWork.Commit(); + await _repository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); UnitOfWork.ClearCache(); //验证 - var oldEntity = _repository.FindById( entity.Id ); + var oldEntity = await _repository.FindByIdAsync( entity.Id ); Assert.Equal( oldValue, oldEntity.TestProperty3 ); //修改实体 oldEntity.TestProperty3 = newValue; - _repository.Update( oldEntity ); - UnitOfWork.Commit(); + await _repository.UpdateAsync( oldEntity ); + await UnitOfWork.CommitAsync(); UnitOfWork.ClearCache(); //验证 - var result = _repository.FindById( entity.Id ); + var result = await _repository.FindByIdAsync( entity.Id ); Assert.Equal( newValue, result.TestProperty3 ); } @@ -1601,7 +1349,7 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试扩展属性 - 添加不可变对象扩展属性 /// [Fact] - public void TestExtraProperties_11() { + public async Task TestExtraProperties_11() { //常量 var code = 2; var name = "TestExtraProperties_11"; @@ -1610,12 +1358,12 @@ namespace Util.Data.EntityFrameworkCore.Tests { var entity = new Product(); entity.Init(); entity.TestProperty4 = new ProductItem2( code, name ); - _repository.Add( entity ); - UnitOfWork.Commit(); + await _repository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); UnitOfWork.ClearCache(); //验证 - var result = _repository.FindById( entity.Id ); + var result = await _repository.FindByIdAsync( entity.Id ); Assert.Equal( code, result.TestProperty4.Code ); Assert.Equal( name, result.TestProperty4.Name ); } @@ -1624,7 +1372,7 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试扩展属性 - 修改对象扩展属性 /// [Fact] - public void TestExtraProperties_12() { + public async Task TestExtraProperties_12() { //常量 var code = 2; var oldName = "TestExtraProperties_12_1"; @@ -1634,24 +1382,24 @@ namespace Util.Data.EntityFrameworkCore.Tests { var entity = new Product(); entity.Init(); entity.TestProperty4 = new ProductItem2( code, oldName ); - _repository.Add( entity ); - UnitOfWork.Commit(); + await _repository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); UnitOfWork.ClearCache(); //验证 - var oldEntity = _repository.FindById( entity.Id ); + var oldEntity = await _repository.FindByIdAsync( entity.Id ); Assert.Equal( code, oldEntity.TestProperty4.Code ); Assert.Equal( oldName, oldEntity.TestProperty4.Name ); //修改实体 oldEntity.TestProperty4 = new ProductItem2( code, newName ); WriteTrackerDebug(); - _repository.Update( oldEntity ); - UnitOfWork.Commit(); + await _repository.UpdateAsync( oldEntity ); + await UnitOfWork.CommitAsync(); UnitOfWork.ClearCache(); //验证 - var result = _repository.FindById( entity.Id ); + var result = await _repository.FindByIdAsync( entity.Id ); Assert.Equal( newName, result.TestProperty4.Name ); } diff --git a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests.Integration/Tests/TagRepositoryTest.cs b/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests.Integration/Tests/TagRepositoryTest.cs new file mode 100644 index 00000000..3819f129 --- /dev/null +++ b/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests.Integration/Tests/TagRepositoryTest.cs @@ -0,0 +1,41 @@ +using System.Threading.Tasks; +using Util.Tests.Fakes; +using Util.Tests.Infrastructure; +using Util.Tests.Repositories; +using Util.Tests.UnitOfWorks; +using Xunit; + +namespace Util.Data.EntityFrameworkCore.Tests { + /// + /// 标签仓储测试 + /// + public class TagRepositoryTest : TestBase { + /// + /// 仓储 + /// + private readonly ITagRepository _repository; + + /// + /// 测试初始化 + /// + public TagRepositoryTest( ITagRepository repository, ITestUnitOfWork unitOfWork ) : base( unitOfWork ) { + _repository = repository; + } + + /// + /// 测试添加实体 + /// + [Fact] + public async Task TestAddAsync() { + //添加实体 + var entity = TagFakeService.GetTag(); + entity.Init(); + await _repository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //验证 + Assert.True( await _repository.ExistsAsync( t => t.Id == entity.Id ) ); + } + } +} \ No newline at end of file diff --git a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests.Integration/Util.Data.EntityFrameworkCore.PostgreSql.Tests.Integration.csproj b/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests.Integration/Util.Data.EntityFrameworkCore.PostgreSql.Tests.Integration.csproj new file mode 100644 index 00000000..3803692a --- /dev/null +++ b/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests.Integration/Util.Data.EntityFrameworkCore.PostgreSql.Tests.Integration.csproj @@ -0,0 +1,39 @@ + + + + $(NetTargetFramework) + false + Util.Data.EntityFrameworkCore + Util.Data.EntityFrameworkCore.Startup + + + + + Always + + + Always + + + + + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + diff --git a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests.Integration/appsettings.Development.json b/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests.Integration/appsettings.Development.json new file mode 100644 index 00000000..483f9976 --- /dev/null +++ b/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests.Integration/appsettings.Development.json @@ -0,0 +1,11 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Trace", + "Microsoft": "Trace" + } + }, + "ConnectionStrings": { + "connection": "server=192.168.31.158;User Id=admin;password=admin;database=Util.Data.EntityFrameworkCore.Test" + } +} \ No newline at end of file diff --git a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests.Integration/appsettings.json b/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests.Integration/appsettings.json new file mode 100644 index 00000000..a6403646 --- /dev/null +++ b/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests.Integration/appsettings.json @@ -0,0 +1,11 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Error", + "Microsoft": "Error" + } + }, + "ConnectionStrings": { + "connection": "server=postgresql.common;User Id=admin;password=admin;database=Util.Data.EntityFrameworkCore.Test" + } +} \ No newline at end of file diff --git a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Fakes/CustomerFakeService.cs b/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Fakes/CustomerFakeService.cs deleted file mode 100644 index 796d330b..00000000 --- a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Fakes/CustomerFakeService.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using AutoBogus; -using Util.Data.EntityFrameworkCore.Models; - -namespace Util.Data.EntityFrameworkCore.Fakes { - /// - /// 客户模拟数据服务 - /// - public static class CustomerFakeService { - /// - /// 获取客户 - /// - public static Customer GetCustomer() { - return GetCustomers( 1 ).First(); - } - - /// - /// 获取客户列表 - /// - /// 行数 - public static List GetCustomers( int count ) { - return new AutoFaker() - .RuleFor( t => t.Code, t => t.Random.String2( 1, 100 ) ) - .RuleFor( t => t.Name, t => t.Random.String2( 1, 200 ) ) - .RuleFor( t => t.Nickname, t => t.Random.String2( 1, 50 ) ) - .RuleFor( t => t.Phone, t => t.Random.String2( 1, 50 ) ) - .RuleFor( t => t.Email, t => t.Random.String2( 1, 500 ) ) - .RuleFor( t => t.IsDeleted, false ) - .Generate( count ); - } - } -} \ No newline at end of file diff --git a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Fakes/OrderFakeService.cs b/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Fakes/OrderFakeService.cs deleted file mode 100644 index aaefd959..00000000 --- a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Fakes/OrderFakeService.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using AutoBogus; -using Util.Data.EntityFrameworkCore.Models; - -namespace Util.Data.EntityFrameworkCore.Fakes { - /// - /// 订单模拟数据服务 - /// - public static class OrderFakeService { - /// - /// 获取订单 - /// - public static Order GetOrder() { - return GetOrders( 1 ).First(); - } - - /// - /// 获取订单列表 - /// - /// 行数 - public static List GetOrders( int count ) { - return new AutoFaker() - .Ignore( t => t.OrderItems ) - .RuleFor( t => t.IsDeleted, false ) - .Generate( count ); - } - } -} \ No newline at end of file diff --git a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Fakes/ProductFakeService.cs b/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Fakes/ProductFakeService.cs deleted file mode 100644 index c9ee7992..00000000 --- a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Fakes/ProductFakeService.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using AutoBogus; -using Util.Data.EntityFrameworkCore.Models; - -namespace Util.Data.EntityFrameworkCore.Fakes { - /// - /// 产品模拟数据服务 - /// - public static class ProductFakeService { - /// - /// 获取产品 - /// - public static Product GetProduct() { - return GetProducts( 1 ).First(); - } - - /// - /// 获取产品列表 - /// - /// 行数 - public static List GetProducts( int count ) { - return new AutoFaker() - .RuleFor( t => t.Code, t => t.Random.String2( 1, 50 ) ) - .RuleFor( t => t.Name, t => t.Random.String2( 1, 500 ) ) - .RuleFor( t => t.IsDeleted, false ) - .Ignore( t => t.TestProperty1 ) - .Generate( count ); - } - } -} \ No newline at end of file diff --git a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Infrastructure/TestBase.cs b/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Infrastructure/TestBase.cs deleted file mode 100644 index 63199d92..00000000 --- a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Infrastructure/TestBase.cs +++ /dev/null @@ -1,20 +0,0 @@ -namespace Util.Data.EntityFrameworkCore.Infrastructure { - /// - /// 测试基类 - /// - public abstract class TestBase { - /// - /// 测试初始化 - /// - protected TestBase( IUnitOfWork unitOfWork ) { - UnitOfWork = unitOfWork; - } - - /// - /// 工作单元 - /// - protected IUnitOfWork UnitOfWork { - get; - } - } -} \ No newline at end of file diff --git a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Infrastructure/TestSession.cs b/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Infrastructure/TestSession.cs deleted file mode 100644 index eb618205..00000000 --- a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Infrastructure/TestSession.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System; -using Util.Sessions; - -namespace Util.Data.EntityFrameworkCore.Infrastructure { - /// - /// 测试用户会话 - /// - public class TestSession : ISession { - public TestSession() { - UserId = TestUserId.ToString(); - } - - public bool IsAuthenticated => true; - public string UserId { get; set; } - - /// - /// 测试用户标识 - /// - public static Guid TestUserId = Guid.NewGuid(); - - /// - /// 测试用户标识2 - /// - public static Guid TestUserId2 = Guid.NewGuid(); - } -} diff --git a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Models/OperationLog.cs b/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Models/OperationLog.cs deleted file mode 100644 index c4acb379..00000000 --- a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Models/OperationLog.cs +++ /dev/null @@ -1,66 +0,0 @@ -using System; -using System.ComponentModel; -using System.ComponentModel.DataAnnotations; -using Util.Domain.Entities; - -namespace Util.Data.EntityFrameworkCore.Models { - /// - /// 操作日志 - /// - [Description( "操作日志" )] - public class OperationLog : AggregateRoot { - /// - /// 初始化操作日志 - /// - public OperationLog() : this( 0 ) { - } - - /// - /// 初始化操作日志 - /// - /// 操作日志标识 - public OperationLog( long id ) : base( id ) { - } - - /// - /// 日志名称 - /// - [Description( "日志名称" )] - [Required( ErrorMessage = "日志名称不能为空" )] - [MaxLength( 50 )] - public string LogName { get; set; } - /// - /// 操作时间 - /// - [Description( "操作时间" )] - public DateTime? OperationTime { get; set; } - /// - /// 标题 - /// - [Description( "标题" )] - [MaxLength( 200 )] - public string Caption { get; set; } - /// - /// 内容 - /// - [Description( "内容" )] - public string Content { get; set; } - - /// - /// 添加变更列表 - /// - protected override void AddChanges( OperationLog other ) { - AddChange( t => t.LogName, other.LogName ); - AddChange( t => t.OperationTime, other.OperationTime ); - AddChange( t => t.Caption, other.Caption ); - AddChange( t => t.Content, other.Content ); - } - - /// - /// 初始化 - /// - public override void Init() { - OperationTime = DateTime.Now; - } - } -} \ No newline at end of file diff --git a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Models/ProductItem.cs b/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Models/ProductItem.cs deleted file mode 100644 index 8e1000a2..00000000 --- a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Models/ProductItem.cs +++ /dev/null @@ -1,19 +0,0 @@ -namespace Util.Data.EntityFrameworkCore.Models { - /// - /// 用于测试扩展属性 - /// - public class ProductItem { - /// - /// 编码 - /// - public int Code { get; set; } - /// - /// 名称 - /// - public string Name { get; set; } - /// - /// 枚举 - /// - public ProductEnum EnumValue { get; set; } - } -} diff --git a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Models/ProductItem2.cs b/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Models/ProductItem2.cs deleted file mode 100644 index a8d9e63b..00000000 --- a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Models/ProductItem2.cs +++ /dev/null @@ -1,25 +0,0 @@ - -namespace Util.Data.EntityFrameworkCore.Models { - /// - /// 用于测试不可变扩展属性 - /// - public class ProductItem2 { - - public ProductItem2() { - } - - public ProductItem2( int code, string name ) { - Code = code; - Name = name; - } - - /// - /// 编码 - /// - public int Code { get; init; } - /// - /// 名称 - /// - public string Name { get; init; } - } -} diff --git a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Repositories/ICustomerRepository.cs b/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Repositories/ICustomerRepository.cs deleted file mode 100644 index f7b64097..00000000 --- a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Repositories/ICustomerRepository.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Util.Data.EntityFrameworkCore.Models; -using Util.Domain.Repositories; - -namespace Util.Data.EntityFrameworkCore.Repositories { - /// - /// 客户仓储 - /// - public interface ICustomerRepository : IRepository { - } -} \ No newline at end of file diff --git a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Repositories/IOperationLogRepository.cs b/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Repositories/IOperationLogRepository.cs deleted file mode 100644 index 5b121efd..00000000 --- a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Repositories/IOperationLogRepository.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Util.Data.EntityFrameworkCore.Models; -using Util.Domain.Repositories; - -namespace Util.Data.EntityFrameworkCore.Repositories { - /// - /// 操作日志仓储 - /// - public interface IOperationLogRepository : IRepository { - } -} \ No newline at end of file diff --git a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Repositories/IOrderRepository.cs b/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Repositories/IOrderRepository.cs deleted file mode 100644 index 609b1814..00000000 --- a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Repositories/IOrderRepository.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Util.Data.EntityFrameworkCore.Models; -using Util.Domain.Repositories; - -namespace Util.Data.EntityFrameworkCore.Repositories { - /// - /// 订单仓储 - /// - public interface IOrderRepository : IRepository { - } -} \ No newline at end of file diff --git a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Repositories/IProductRepository.cs b/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Repositories/IProductRepository.cs deleted file mode 100644 index 900cd862..00000000 --- a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Repositories/IProductRepository.cs +++ /dev/null @@ -1,15 +0,0 @@ -using Util.Data.EntityFrameworkCore.Models; -using Util.Domain.Repositories; - -namespace Util.Data.EntityFrameworkCore.Repositories { - /// - /// 产品仓储 - /// - public interface IProductRepository : IRepository { - /// - /// 更新产品 - /// - /// 产品 - public void UpdateProduct( Product product ); - } -} \ No newline at end of file diff --git a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/UnitOfWorks/IPgSqlUnitOfWork.cs b/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/UnitOfWorks/IPgSqlUnitOfWork.cs deleted file mode 100644 index ee2b3c0f..00000000 --- a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/UnitOfWorks/IPgSqlUnitOfWork.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Util.Data.EntityFrameworkCore.UnitOfWorks { - /// - /// 工作单元 - /// - public interface IPgSqlUnitOfWork : IUnitOfWork { - } -} \ No newline at end of file diff --git a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Util.Data.EntityFrameworkCore.PostgreSql.Tests.csproj b/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Util.Data.EntityFrameworkCore.PostgreSql.Tests.csproj deleted file mode 100644 index 1af2ada2..00000000 --- a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Util.Data.EntityFrameworkCore.PostgreSql.Tests.csproj +++ /dev/null @@ -1,44 +0,0 @@ - - - - $(NetTargetFramework) - false - Util.Data.EntityFrameworkCore - Util.Data.EntityFrameworkCore.Startup - - - - - - - - - Always - true - PreserveNewest - - - - - - - - - - - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - - - - - - - - - diff --git a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/appsettings.json b/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/appsettings.json deleted file mode 100644 index f9334212..00000000 --- a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/appsettings.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "ConnectionStrings": { - "connection": "server=192.168.31.180;User Id=postgres;password=sa;database=Util.Data.EntityFrameworkCore.Test" - } -} \ No newline at end of file diff --git a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests.Integration/Filters/DeleteFilterTest.cs b/test/Util.Data.EntityFrameworkCore.SqlServer.Tests.Integration/Filters/DeleteFilterTest.cs new file mode 100644 index 00000000..e589e106 --- /dev/null +++ b/test/Util.Data.EntityFrameworkCore.SqlServer.Tests.Integration/Filters/DeleteFilterTest.cs @@ -0,0 +1,81 @@ +using Util.Tests.Models; +using Xunit; +using Xunit.Abstractions; + +namespace Util.Data.EntityFrameworkCore.Filters { + /// + /// 逻辑删除过滤器测试 + /// + public class DeleteFilterTest { + /// + /// 测试消息输出 + /// + private readonly ITestOutputHelper _testOutputHelper; + /// + /// 逻辑删除过滤器 + /// + private readonly DeleteFilter _filter; + + /// + /// 测试初始化 + /// + public DeleteFilterTest( ITestOutputHelper testOutputHelper ) { + _testOutputHelper = testOutputHelper; + _filter = new DeleteFilter(); + } + + /// + /// 测试是否启用 + /// + [Fact] + public void TestIsEnabled() { + //默认值为启用 + Assert.True( _filter.IsEnabled ); + + //禁用过滤器 + _filter.Disable(); + Assert.False( _filter.IsEnabled ); + + //启用过滤器 + _filter.Enable(); + Assert.True( _filter.IsEnabled ); + } + + /// + /// 测试禁用 + /// + [Fact] + public void TestDisable() { + //默认值为启用 + Assert.True( _filter.IsEnabled ); + + //禁用过滤器 + using( _filter.Disable() ) { + Assert.False( _filter.IsEnabled ); + } + + //恢复启用状态 + Assert.True( _filter.IsEnabled ); + } + + /// + /// 测试实体是否启用过滤器 + /// + [Fact] + public void TestIsEntityEnabled() { + Assert.False( _filter.IsEntityEnabled() ); + Assert.True( _filter.IsEntityEnabled() ); + } + + /// + /// 测试获取表达式 + /// + [Fact] + public void TestGetExpression() { + var expression = _filter.GetExpression(); + var result = "entity => Not(Property(entity, \"IsDeleted\"))"; + _testOutputHelper.WriteLine( expression.ToString() ); + Assert.Equal( result,expression.ToString() ); + } + } +} diff --git a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests.Integration/Filters/FilterManagerTest.cs b/test/Util.Data.EntityFrameworkCore.SqlServer.Tests.Integration/Filters/FilterManagerTest.cs new file mode 100644 index 00000000..4ac4609d --- /dev/null +++ b/test/Util.Data.EntityFrameworkCore.SqlServer.Tests.Integration/Filters/FilterManagerTest.cs @@ -0,0 +1,101 @@ +using Util.Data.Filters; +using Util.Domain; +using Util.Tests.Models; +using Xunit; + +namespace Util.Data.EntityFrameworkCore.Filters { + /// + /// 数据过滤器管理器测试 + /// + public class FilterManagerTest { + /// + /// 数据过滤器管理器 + /// + private readonly IFilterManager _filterManager; + + /// + /// 测试初始化 + /// + public FilterManagerTest( IFilterManager filterManager ) { + _filterManager = filterManager; + } + + /// + /// 测试获取过滤器 - 泛型 + /// + [Fact] + public void TestGetFilter_1() { + //逻辑删除过滤器已默认加载 + var filter = _filterManager.GetFilter(); + Assert.NotNull( filter ); + Assert.True( filter.IsEnabled ); + } + + /// + /// 测试获取过滤器 - 非泛型 + /// + [Fact] + public void TestGetFilter_2() { + //逻辑删除过滤器已默认加载 + var filter = _filterManager.GetFilter(typeof( IDelete ) ); + Assert.NotNull( filter ); + } + + /// + /// 测试禁用过滤器 + /// + [Fact] + public void TestDisableFilter_1() { + _filterManager.DisableFilter(); + var filter = _filterManager.GetFilter(); + Assert.False( filter.IsEnabled ); + } + + /// + /// 测试禁用过滤器 - 使用using + /// + [Fact] + public void TestDisableFilter_2() { + var filter = _filterManager.GetFilter(); + using ( _filterManager.DisableFilter() ) { + Assert.False( filter.IsEnabled ); + } + Assert.True( filter.IsEnabled ); + } + + /// + /// 测试启用过滤器 + /// + [Fact] + public void TestEnableFilter() { + var filter = _filterManager.GetFilter(); + + //禁用 + _filterManager.DisableFilter(); + Assert.False( filter.IsEnabled ); + + //启用 + _filterManager.EnableFilter(); + Assert.True( filter.IsEnabled ); + } + + /// + /// 测试实体是否启用过滤器 + /// + [Fact] + public void TestIsEntityEnabled() { + Assert.False( _filterManager.IsEntityEnabled() ); + Assert.True( _filterManager.IsEntityEnabled() ); + } + + /// + /// 测试过滤器是否启用 + /// + [Fact] + public void TestIsEnabled() { + Assert.True( _filterManager.IsEnabled() ); + Assert.False( _filterManager.IsEnabled() ); + } + } +} + diff --git a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests.Integration/Startup.cs b/test/Util.Data.EntityFrameworkCore.SqlServer.Tests.Integration/Startup.cs new file mode 100644 index 00000000..17d37d85 --- /dev/null +++ b/test/Util.Data.EntityFrameworkCore.SqlServer.Tests.Integration/Startup.cs @@ -0,0 +1,54 @@ +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using Util.Aop; +using Util.Helpers; +using Util.Sessions; +using Util.Tests.Infrastructure; +using Util.Tests.UnitOfWorks; +using Xunit.DependencyInjection; +using Xunit.DependencyInjection.Logging; +using Environment = Util.Helpers.Environment; + +namespace Util.Data.EntityFrameworkCore { + /// + /// Æô¶¯ÅäÖà + /// + public class Startup { + /// + /// ÅäÖÃÖ÷»ú + /// + public void ConfigureHost( IHostBuilder hostBuilder ) { + hostBuilder.ConfigureDefaults( null ) + .AddUtil( options => { + Environment.SetDevelopment(); + options.UseAop() + .UseSqlServerUnitOfWork( Config.GetConnectionString( "connection" ) ); + } ); + } + + /// + /// ÅäÖ÷þÎñ + /// + public void ConfigureServices( IServiceCollection services ) { + services.AddSingleton(); + InitDatabase( services ); + } + + /// + /// ³õʼ»¯Êý¾ݿâ + /// + private void InitDatabase( IServiceCollection services ) { + var unitOfWork = services.BuildServiceProvider().GetService(); + unitOfWork.EnsureDeleted(); + unitOfWork.EnsureCreated(); + } + + /// + /// ÅäÖÃÈÕ־Ìṩ³ÌÐò + /// + public void Configure( ILoggerFactory loggerFactory, ITestOutputHelperAccessor accessor ) { + loggerFactory.AddProvider( new XunitTestOutputLoggerProvider( accessor, ( s, logLevel ) => logLevel >= LogLevel.Trace ) ); + } + } +} diff --git a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests.Integration/Tests/CustomerRepositoryTest.cs b/test/Util.Data.EntityFrameworkCore.SqlServer.Tests.Integration/Tests/CustomerRepositoryTest.cs new file mode 100644 index 00000000..2f43c378 --- /dev/null +++ b/test/Util.Data.EntityFrameworkCore.SqlServer.Tests.Integration/Tests/CustomerRepositoryTest.cs @@ -0,0 +1,604 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore; +using Util.Data.Queries; +using Util.Tests.Fakes; +using Util.Tests.Infrastructure; +using Util.Tests.Models; +using Util.Tests.Repositories; +using Util.Tests.UnitOfWorks; +using Xunit; + +namespace Util.Data.EntityFrameworkCore.Tests { + /// + /// 客户仓储测试 + /// 说明: + /// 1. 测试自增长int类型标识 + /// 2. 测试日期范围查询 + /// 3. 测试分页查询 + /// 4. 测试Utc日期 + /// + public class CustomerRepositoryTest : TestBase { + + #region 测试初始化 + + /// + /// 仓储 + /// + private readonly ICustomerRepository _repository; + + /// + /// 测试初始化 + /// + public CustomerRepositoryTest( ICustomerRepository repository, ITestUnitOfWork unitOfWork ) : base( unitOfWork ) { + _repository = repository; + } + + #endregion + + #region 辅助操作 + + /// + /// 添加实体列表 + /// + /// 添加数量 + /// 客户名称 + private async Task> AddCustomersAsync( int count = 2, string name = null ) { + var customers = CustomerFakeService.GetCustomers( count ); + customers.ForEach( customer => { + if ( name != null ) + customer.Name = name; + customer.CreationTime = null; + } ); + await _repository.AddAsync( customers ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + return customers.OrderBy( t => t.Code ).ToList(); + } + + #endregion + + #region Between + + /// + /// 测试添加范围查询条件 - 日期带时间 + /// + [Fact] + public async Task TestBetween_DateTime_1() { + //常量 + var name = "TestBetween_DateTime_1"; + var birthday = "2005-5-5 05:05:05".ToDateTime(); + var minBirthday = "2005-5-6 06:05:05".ToDateTime(); + var maxBirthday = "2005-5-8 06:05:05".ToDateTime(); + + //添加实体列表 + await AddCustomersAsync(); + var customers = CustomerFakeService.GetCustomers( 5 ); + customers.ForEach( customer => { + customer.Name = name; + customer.Birthday = birthday; + birthday = birthday.AddDays( 1 ); + } ); + await _repository.AddAsync( customers ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //查询 + var result = await _repository.Find().Where( t => t.Name == name ).Between( t => t.Birthday, minBirthday, maxBirthday ).ToListAsync(); + + //验证 + Assert.Equal( 2, result.Count ); + } + + /// + /// 测试添加范围查询条件 - 日期带时间 - 包含左边界 + /// + [Fact] + public async Task TestBetween_DateTime_2() { + //常量 + var name = "TestBetween_DateTime_2"; + var birthday = "2005-5-5 05:05:05".ToDateTime(); + var minBirthday = "2005-5-6 05:05:05".ToDateTime(); + var maxBirthday = "2005-5-8 05:05:05".ToDateTime(); + + //添加实体列表 + await AddCustomersAsync(); + var customers = CustomerFakeService.GetCustomers( 5 ); + customers.ForEach( customer => { + customer.Name = name; + customer.Birthday = birthday; + birthday = birthday.AddDays( 1 ); + } ); + await _repository.AddAsync( customers ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //查询 + var result = await _repository.Find().Where( t => t.Name == name ).Between( t => t.Birthday, minBirthday, maxBirthday, boundary: Boundary.Left ).ToListAsync(); + + //验证 + Assert.Equal( 2, result.Count ); + } + + /// + /// 测试添加范围查询条件 - 日期带时间 - 包含右边界 + /// + [Fact] + public async Task TestBetween_DateTime_3() { + //常量 + var name = "TestBetween_DateTime_3"; + var birthday = "2005-5-5 05:05:05".ToDateTime(); + var minBirthday = "2005-5-6 05:05:05".ToDateTime(); + var maxBirthday = "2005-5-8 05:05:05".ToDateTime(); + + //添加实体列表 + await AddCustomersAsync(); + var customers = CustomerFakeService.GetCustomers( 5 ); + customers.ForEach( customer => { + customer.Name = name; + customer.Birthday = birthday; + birthday = birthday.AddDays( 1 ); + } ); + await _repository.AddAsync( customers ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //查询 + var result = await _repository.Find().Where( t => t.Name == name ).Between( t => t.Birthday, minBirthday, maxBirthday, boundary: Boundary.Right ).ToListAsync(); + + //验证 + Assert.Equal( 2, result.Count ); + } + + /// + /// 测试添加范围查询条件 - 日期带时间 - 包含两边 + /// + [Fact] + public async Task TestBetween_DateTime_4() { + //常量 + var name = "TestBetween_DateTime_4"; + var birthday = "2005-5-5 05:05:05".ToDateTime(); + var minBirthday = "2005-5-6 05:05:05".ToDateTime(); + var maxBirthday = "2005-5-8 05:05:05".ToDateTime(); + + //添加实体列表 + await AddCustomersAsync(); + var customers = CustomerFakeService.GetCustomers( 5 ); + customers.ForEach( customer => { + customer.Name = name; + customer.Birthday = birthday; + birthday = birthday.AddDays( 1 ); + } ); + await _repository.AddAsync( customers ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //查询 + var result = await _repository.Find().Where( t => t.Name == name ).Between( t => t.Birthday, minBirthday, maxBirthday, boundary: Boundary.Both ).ToListAsync(); + + //验证 + Assert.Equal( 3, result.Count ); + } + + /// + /// 测试添加范围查询条件 - 日期带时间 - 不包含边界 + /// + [Fact] + public async Task TestBetween_DateTime_5() { + //常量 + var name = "TestBetween_DateTime_5"; + var birthday = "2005-5-5 05:05:05".ToDateTime(); + var minBirthday = "2005-5-6 05:05:05".ToDateTime(); + var maxBirthday = "2005-5-8 05:05:05".ToDateTime(); + + //添加实体列表 + await AddCustomersAsync(); + var customers = CustomerFakeService.GetCustomers( 5 ); + customers.ForEach( customer => { + customer.Name = name; + customer.Birthday = birthday; + birthday = birthday.AddDays( 1 ); + } ); + await _repository.AddAsync( customers ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //查询 + var result = await _repository.Find().Where( t => t.Name == name ).Between( t => t.Birthday, minBirthday, maxBirthday, boundary: Boundary.Neither ).ToListAsync(); + + //验证 + Assert.Single( result ); + } + + /// + /// 测试添加范围查询条件 - 日期带时间 - 最大值为空 + /// + [Fact] + public async Task TestBetween_DateTime_6() { + //常量 + var name = "TestBetween_DateTime_6"; + var birthday = "2005-5-5 05:05:05".ToDateTime(); + var minBirthday = "2005-5-6 05:05:05".ToDateTime(); + + //添加实体列表 + await AddCustomersAsync(); + var customers = CustomerFakeService.GetCustomers( 5 ); + customers.ForEach( customer => { + customer.Name = name; + customer.Birthday = birthday; + birthday = birthday.AddDays( 1 ); + } ); + await _repository.AddAsync( customers ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //查询 + var result = await _repository.Find().Where( t => t.Name == name ).Between( t => t.Birthday, minBirthday, null, boundary: Boundary.Both ).ToListAsync(); + + //验证 + Assert.Equal( 4, result.Count ); + } + + /// + /// 测试添加范围查询条件 - 日期带时间 - 最小值为空 + /// + [Fact] + public async Task TestBetween_DateTime_7() { + //常量 + var name = "TestBetween_DateTime_7"; + var birthday = "2005-5-5 05:05:05".ToDateTime(); + var maxBirthday = "2005-5-8 05:05:05".ToDateTime(); + + //添加实体列表 + await AddCustomersAsync(); + var customers = CustomerFakeService.GetCustomers( 5 ); + customers.ForEach( customer => { + customer.Name = name; + customer.Birthday = birthday; + birthday = birthday.AddDays( 1 ); + } ); + await _repository.AddAsync( customers ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //查询 + var result = await _repository.Find().Where( t => t.Name == name ).Between( t => t.Birthday, null, maxBirthday, boundary: Boundary.Both ).ToListAsync(); + + //验证 + Assert.Equal( 4, result.Count ); + } + + /// + /// 测试添加范围查询条件 - 日期不带时间 - 包含左边界 + /// + [Fact] + public async Task TestBetween_Date_1() { + //常量 + var name = "TestBetween_Date_1"; + var birthday = "2005-5-5 05:05:05".ToDateTime(); + var minBirthday = "2005-5-6".ToDateTime(); + var maxBirthday = "2005-5-8".ToDateTime(); + + //添加实体列表 + await AddCustomersAsync(); + var customers = CustomerFakeService.GetCustomers( 5 ); + customers.ForEach( customer => { + customer.Name = name; + customer.Birthday = birthday; + birthday = birthday.AddDays( 1 ); + } ); + await _repository.AddAsync( customers ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //查询 + var result = await _repository.Find() + .Where( t => t.Name == name ) + .Between( t => t.Birthday, minBirthday, maxBirthday, false, Boundary.Left ) + .OrderBy( t => t.Birthday ) + .ToListAsync(); + + //验证 + Assert.Equal( 2, result.Count ); + Assert.Equal( 6, result[0].Birthday.SafeValue().Day ); + Assert.Equal( 7, result[1].Birthday.SafeValue().Day ); + } + + /// + /// 测试添加范围查询条件 - 日期不带时间 - 包含右边界 + /// + [Fact] + public async Task TestBetween_Date_2() { + //常量 + var name = "TestBetween_Date_2"; + var birthday = "2005-5-5 05:05:05".ToDateTime(); + var minBirthday = "2005-5-6".ToDateTime(); + var maxBirthday = "2005-5-8".ToDateTime(); + + //添加实体列表 + await AddCustomersAsync(); + var customers = CustomerFakeService.GetCustomers( 5 ); + customers.ForEach( customer => { + customer.Name = name; + customer.Birthday = birthday; + birthday = birthday.AddDays( 1 ); + } ); + await _repository.AddAsync( customers ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //查询 + var result = await _repository.Find() + .Where( t => t.Name == name ) + .Between( t => t.Birthday, minBirthday, maxBirthday, false, Boundary.Right ) + .OrderBy( t => t.Birthday ) + .ToListAsync(); + + //验证 + Assert.Equal( 2, result.Count ); + Assert.Equal( 7, result[0].Birthday.SafeValue().Day ); + Assert.Equal( 8, result[1].Birthday.SafeValue().Day ); + } + + /// + /// 测试添加范围查询条件 - 日期不带时间 - 包含两边 + /// + [Fact] + public async Task TestBetween_Date_3() { + //常量 + var name = "TestBetween_Date_3"; + var birthday = "2005-5-5 05:05:05".ToDateTime(); + var minBirthday = "2005-5-6".ToDateTime(); + var maxBirthday = "2005-5-8".ToDateTime(); + + //添加实体列表 + await AddCustomersAsync(); + var customers = CustomerFakeService.GetCustomers( 5 ); + customers.ForEach( customer => { + customer.Name = name; + customer.Birthday = birthday; + birthday = birthday.AddDays( 1 ); + } ); + await _repository.AddAsync( customers ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //查询 + var result = await _repository.Find() + .Where( t => t.Name == name ) + .Between( t => t.Birthday, minBirthday, maxBirthday, false, Boundary.Both ) + .OrderBy( t => t.Birthday ) + .ToListAsync(); + + //验证 + Assert.Equal( 3, result.Count ); + Assert.Equal( 6, result[0].Birthday.SafeValue().Day ); + Assert.Equal( 7, result[1].Birthday.SafeValue().Day ); + Assert.Equal( 8, result[2].Birthday.SafeValue().Day ); + } + + /// + /// 测试添加范围查询条件 - 日期不带时间 - 不包含边界 + /// + [Fact] + public async Task TestBetween_Date_4() { + //常量 + var name = "TestBetween_Date_4"; + var birthday = "2005-5-5 05:05:05".ToDateTime(); + var minBirthday = "2005-5-6".ToDateTime(); + var maxBirthday = "2005-5-8".ToDateTime(); + + //添加实体列表 + await AddCustomersAsync(); + var customers = CustomerFakeService.GetCustomers( 5 ); + customers.ForEach( customer => { + customer.Name = name; + customer.Birthday = birthday; + birthday = birthday.AddDays( 1 ); + } ); + await _repository.AddAsync( customers ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //查询 + var result = await _repository.Find() + .Where( t => t.Name == name ) + .Between( t => t.Birthday, minBirthday, maxBirthday, false, Boundary.Neither ) + .ToListAsync(); + + //验证 + Assert.Single( result ); + Assert.Equal( 7, result[0].Birthday.SafeValue().Day ); + } + + /// + /// 测试添加范围查询条件 - 日期不带时间 - 最大值为空 + /// + [Fact] + public async Task TestBetween_Date_5() { + //常量 + var name = "TestBetween_Date_5"; + var birthday = "2005-5-5 05:05:05".ToDateTime(); + var minBirthday = "2005-5-6".ToDateTime(); + + //添加实体列表 + await AddCustomersAsync(); + var customers = CustomerFakeService.GetCustomers( 5 ); + customers.ForEach( customer => { + customer.Nickname = name; + customer.Name = name; + customer.Birthday = birthday; + birthday = birthday.AddDays( 1 ); + } ); + await _repository.AddAsync( customers ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //查询 + var result = await _repository.Find() + .Where( t => t.Name == name ) + .Between( t => t.Birthday, minBirthday, null, false ) + .OrderBy( t => t.Birthday ) + .ToListAsync(); + + //验证 + Assert.Equal( 4, result.Count ); + Assert.Equal( 6, result[0].Birthday.SafeValue().Day ); + } + + /// + /// 测试添加范围查询条件 - 日期不带时间 - 最小值为空 + /// + [Fact] + public async Task TestBetween_Date_6() { + //常量 + var name = "TestBetween_Date_6"; + var birthday = "2005-5-5 05:05:05".ToDateTime(); + var maxBirthday = "2005-5-8".ToDateTime(); + + //添加实体列表 + await AddCustomersAsync(); + var customers = CustomerFakeService.GetCustomers( 5 ); + customers.ForEach( customer => { + customer.Name = name; + customer.Birthday = birthday; + birthday = birthday.AddDays( 1 ); + } ); + await _repository.AddAsync( customers ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //查询 + var result = await _repository.Find() + .Where( t => t.Name == name ) + .Between( t => t.Birthday, null, maxBirthday, false ) + .ToListAsync(); + + //验证 + Assert.Equal( 4, result.Count ); + } + + #endregion + + #region ToPageList + + /// + /// 测试获取分页列表 + /// + [Fact] + public async Task TestToPageList_1() { + //常量 + var name = "TestToPageList_1"; + + //添加实体列表 + var customers = await AddCustomersAsync( 10, name ); + + //创建查询参数 + var parameter = new QueryParameter { PageSize = 3, Page = 1, Order = "Code" }; + + //查询 + var result = _repository.Find().Where( t => t.Name == name ).ToPageList( parameter ); + + //验证 + Assert.Equal( 4, result.PageCount ); + Assert.Equal( 1, result.Page ); + Assert.Equal( 3, result.PageSize ); + Assert.Equal( 10, result.Total ); + Assert.Equal( 3, result.Data.Count ); + Assert.Equal( customers[0].Id, result.Data[0].Id ); + Assert.Equal( customers[1].Id, result.Data[1].Id ); + Assert.Equal( customers[2].Id, result.Data[2].Id ); + } + + /// + /// 测试获取分页列表 - 第二页 + /// + [Fact] + public async Task TestToPageList_2() { + //常量 + var name = "TestToPageList_2"; + + //添加实体列表 + var customers = await AddCustomersAsync( 10, name ); + + //创建查询参数 + var parameter = new QueryParameter { PageSize = 3, Page = 2, Order = "Code" }; + + //查询 + var result = _repository.Find().Where( t => t.Name == name ).ToPageList( parameter ); + + //验证 + Assert.Equal( 4, result.PageCount ); + Assert.Equal( 2, result.Page ); + Assert.Equal( 3, result.PageSize ); + Assert.Equal( 10, result.Total ); + Assert.Equal( 3, result.Data.Count ); + Assert.Equal( customers[3].Id, result.Data[0].Id ); + Assert.Equal( customers[4].Id, result.Data[1].Id ); + Assert.Equal( customers[5].Id, result.Data[2].Id ); + } + + /// + /// 测试获取分页列表 - Queryable设置排序 + /// + [Fact] + public async Task TestToPageList_3() { + //常量 + var name = "TestToPageList_3"; + + //添加实体列表 + var customers = await AddCustomersAsync( 10, name ); + + //创建查询参数 + var parameter = new QueryParameter { PageSize = 3, Page = 2 }; + + //查询 + var result = _repository.Find().Where( t => t.Name == name ).OrderBy( t => t.Code ).ToPageList( parameter ); + + //验证 + Assert.Equal( 4, result.PageCount ); + Assert.Equal( 2, result.Page ); + Assert.Equal( 3, result.PageSize ); + Assert.Equal( 10, result.Total ); + Assert.Equal( 3, result.Data.Count ); + Assert.Equal( customers[3].Id, result.Data[0].Id ); + Assert.Equal( customers[4].Id, result.Data[1].Id ); + Assert.Equal( customers[5].Id, result.Data[2].Id ); + } + + #endregion + + #region ToPageListAsync + + /// + /// 测试获取分页列表 + /// + [Fact] + public async Task TestToPageListAsync() { + //常量 + var name = "TestToPageListAsync"; + + //添加实体列表 + var customers = await AddCustomersAsync( 10, name ); + + //创建查询参数 + var parameter = new QueryParameter { PageSize = 3, Page = 2, Order = "Code" }; + + //查询 + var result = await _repository.Find().Where( t => t.Name == name ).ToPageListAsync( parameter ); + + //验证 + Assert.Equal( 4, result.PageCount ); + Assert.Equal( 2, result.Page ); + Assert.Equal( 3, result.PageSize ); + Assert.Equal( 10, result.Total ); + Assert.Equal( 3, result.Data.Count ); + Assert.Equal( customers[3].Id, result.Data[0].Id ); + Assert.Equal( customers[4].Id, result.Data[1].Id ); + Assert.Equal( customers[5].Id, result.Data[2].Id ); + } + + #endregion + } +} \ No newline at end of file diff --git a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests.Integration/Tests/EntityEventsTest.cs b/test/Util.Data.EntityFrameworkCore.SqlServer.Tests.Integration/Tests/EntityEventsTest.cs new file mode 100644 index 00000000..b4e62e8c --- /dev/null +++ b/test/Util.Data.EntityFrameworkCore.SqlServer.Tests.Integration/Tests/EntityEventsTest.cs @@ -0,0 +1,211 @@ +using System.Threading.Tasks; +using Util.Tests.EventHandlers; +using Util.Tests.Fakes; +using Util.Tests.Infrastructure; +using Util.Tests.Repositories; +using Util.Tests.UnitOfWorks; +using Xunit; +using Xunit.Abstractions; + +namespace Util.Data.EntityFrameworkCore.Tests { + /// + /// 实体事件测试 + /// + public class EntityEventsTest : TestBase { + + #region 测试初始化 + + /// + /// 测试输出 + /// + private readonly ITestOutputHelper _testOutputHelper; + /// + /// 产品仓储 + /// + private readonly IProductRepository _productRepository; + /// + /// 操作日志仓储 + /// + private readonly IOperationLogRepository _operationLogRepository; + + /// + /// 测试初始化 + /// + public EntityEventsTest( ITestOutputHelper testOutputHelper, IProductRepository productRepository, + IOperationLogRepository operationLogRepository, ITestUnitOfWork unitOfWork ) :base(unitOfWork){ + _testOutputHelper = testOutputHelper; + _productRepository = productRepository; + _operationLogRepository = operationLogRepository; + } + + #endregion + + #region 实体创建事件 + + /// + /// 测试实体创建事件 + /// + [Fact] + public async Task TestEntityCreatedEvent() { + //添加实体 + var entity = ProductFakeService.GetProduct(); + entity.Init(); + entity.Name = "EntityCreatedEvent"; + await _productRepository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); + + //验证 + Assert.True( await _operationLogRepository.ExistsAsync( t => t.Caption == "EntityCreatedEvent" && t.LogName == nameof( ProductCreatedEventHandler ) ) ); + } + + /// + /// 测试实体变更事件 - 创建 + /// + [Fact] + public async Task TestEntityChangedEvent_Created() { + //添加实体 + var entity = ProductFakeService.GetProduct(); + entity.Init(); + entity.Name = "EntityChangedEvent_Created"; + await _productRepository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); + + //验证 + Assert.True( await _operationLogRepository.ExistsAsync( t => t.Caption == "EntityChangedEvent_Created" && t.LogName == nameof( ProductChangedEventHandler ) ) ); + } + + #endregion + + #region 实体修改事件 + + /// + /// 测试实体修改事件 + /// + [Fact] + public async Task TestEntityUpdatedEvent() { + //添加实体 + var entity = ProductFakeService.GetProduct(); + entity.Init(); + await _productRepository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //修改实体 + var product = await _productRepository.FindByIdAsync( entity.Id ); + product.Name = "EntityUpdatedEvent"; + await _productRepository.UpdateAsync( product ); + await UnitOfWork.CommitAsync(); + + //验证 + Assert.True( await _operationLogRepository.ExistsAsync( t => t.Caption == "EntityUpdatedEvent" && t.LogName == nameof( ProductUpdatedEventHandler ) ) ); + } + + /// + /// 测试实体变更事件 - 修改 + /// + [Fact] + public async Task TestEntityChangedEvent_Updated() { + //添加实体 + var entity = ProductFakeService.GetProduct(); + entity.Init(); + await _productRepository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //修改实体 + var product = _productRepository.FindById( entity.Id ); + product.Name = "EntityChangedEvent_Updated"; + await _productRepository.UpdateAsync( product ); + await UnitOfWork.CommitAsync(); + + //验证 + Assert.True( await _operationLogRepository.ExistsAsync( t => t.Caption == "EntityChangedEvent_Updated" && t.LogName == nameof( ProductChangedEventHandler ) ) ); + } + + #endregion + + #region 实体删除事件 + + /// + /// 测试实体删除事件 - 逻辑删除 + /// + [Fact] + public async Task TestEntityDeletedEvent_1() { + //添加实体 + var entity = ProductFakeService.GetProduct(); + entity.Init(); + entity.Name = "EntityDeletedEvent"; + await _productRepository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); + + //删除实体 + await _productRepository.RemoveAsync( entity ); + await UnitOfWork.CommitAsync(); + + //验证 + Assert.True( await _operationLogRepository.ExistsAsync( t => t.Caption == "EntityDeletedEvent" && t.LogName == nameof( ProductDeletedEventHandler ) ) ); + } + + /// + /// 测试实体删除事件 - 物理删除 + /// + [Fact] + public async Task TestEntityDeletedEvent_2() { + //添加实体 + var entity = OperationLogFakeService.GetOperationLog(); + entity.Init(); + entity.LogName = "EntityDeletedEvent"; + await _operationLogRepository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); + + //删除实体 + await _operationLogRepository.RemoveAsync( entity ); + await UnitOfWork.CommitAsync(); + + //验证 + Assert.True( await _operationLogRepository.ExistsAsync( t => t.LogName == "Test" && t.Caption == nameof( OperationLogDeletedEventHandler ) && t.Content == "EntityDeletedEvent" ) ); + } + + /// + /// 测试实体变更事件 - 逻辑删除 + /// + [Fact] + public async Task TestEntityChangedEvent_Deleted_1() { + //添加实体 + var entity = ProductFakeService.GetProduct(); + entity.Init(); + entity.Name = "EntityChangedEvent_Deleted"; + await _productRepository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); + + //删除实体 + await _productRepository.RemoveAsync( entity ); + await UnitOfWork.CommitAsync(); + + //验证 + Assert.True( await _operationLogRepository.ExistsAsync( t => t.Caption == "EntityChangedEvent_Deleted" && t.LogName == nameof( ProductChangedEventHandler ) ) ); + } + + /// + /// 测试实体变更事件 - 物理删除 + /// + [Fact] + public async Task TestEntityChangedEvent_Deleted_2() { + //添加实体 + var entity = OperationLogFakeService.GetOperationLog(); + entity.Init(); + entity.LogName = "EntityChangedEvent_Deleted"; + await _operationLogRepository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); + + //删除实体 + await _operationLogRepository.RemoveAsync( entity ); + await UnitOfWork.CommitAsync(); + + //验证 + Assert.True( await _operationLogRepository.ExistsAsync( t => t.LogName == "Test" && t.Caption == nameof( OperationLogChangedEventHandler ) && t.Content == "EntityChangedEvent_Deleted" ) ); + } + + #endregion + } +} diff --git a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests.Integration/Tests/OperationLogRepositoryTest.cs b/test/Util.Data.EntityFrameworkCore.SqlServer.Tests.Integration/Tests/OperationLogRepositoryTest.cs new file mode 100644 index 00000000..fecbccb7 --- /dev/null +++ b/test/Util.Data.EntityFrameworkCore.SqlServer.Tests.Integration/Tests/OperationLogRepositoryTest.cs @@ -0,0 +1,63 @@ +using System.Threading.Tasks; +using Util.Tests.Fakes; +using Util.Tests.Infrastructure; +using Util.Tests.Repositories; +using Util.Tests.UnitOfWorks; +using Xunit; + +namespace Util.Data.EntityFrameworkCore.Tests { + /// + /// 操作日志仓储测试 + /// 说明: + /// 测试自增长long类型标识 + /// + public class OperationLogRepositoryTest : TestBase { + /// + /// 仓储 + /// + private readonly IOperationLogRepository _repository; + + /// + /// 测试初始化 + /// + public OperationLogRepositoryTest( IOperationLogRepository operationLogRepository, ITestUnitOfWork unitOfWork ) : base( unitOfWork ) { + _repository = operationLogRepository; + } + + /// + /// 测试添加实体 + /// + [Fact] + public async Task TestAdd() { + //添加实体 + var entity = OperationLogFakeService.GetOperationLog(); + await _repository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); + + //验证 + Assert.True( entity.Id > 0 ); + Assert.True( _repository.Exists( t => t.Id == entity.Id ) ); + } + + /// + /// 测试通过标识移除实体 - 物理删除 + /// + [Fact] + public async Task TestRemove_Id() { + //添加实体 + var entity = OperationLogFakeService.GetOperationLog(); + await _repository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //移除实体 + await _repository.RemoveAsync( entity.Id ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //验证 + var result = await _repository.FindByIdAsync( entity.Id ); + Assert.Null( result ); + } + } +} diff --git a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests.Integration/Tests/OrderRepositoryTest.cs b/test/Util.Data.EntityFrameworkCore.SqlServer.Tests.Integration/Tests/OrderRepositoryTest.cs new file mode 100644 index 00000000..076b5bd1 --- /dev/null +++ b/test/Util.Data.EntityFrameworkCore.SqlServer.Tests.Integration/Tests/OrderRepositoryTest.cs @@ -0,0 +1,130 @@ +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore; +using Util.Tests.Fakes; +using Util.Tests.Infrastructure; +using Util.Tests.Models; +using Util.Tests.Repositories; +using Util.Tests.UnitOfWorks; +using Xunit; + +namespace Util.Data.EntityFrameworkCore.Tests { + /// + /// 订单仓储测试 + /// 说明: + /// 1. 测试string类型标识 + /// 2. 测试一对多导航属性 + /// + public class OrderRepositoryTest : TestBase { + + #region 测试初始化 + + /// + /// 仓储 + /// + private readonly IOrderRepository _repository; + + /// + /// 测试初始化 + /// + public OrderRepositoryTest( IOrderRepository repository, ITestUnitOfWork unitOfWork ) : base( unitOfWork ) { + _repository = repository; + } + + #endregion + + #region 辅助方法 + + /// + /// 添加订单 + /// + private async Task AddOrderAsync() { + var order = OrderFakeService.GetOrder(); + order.Init(); + order.OrderItems.Add( CreateOrderItem() ); + order.OrderItems.Add( CreateOrderItem() ); + await _repository.AddAsync( order ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + return order; + } + + /// + /// 创建订单项 + /// + private OrderItem CreateOrderItem() { + var item = OrderItemFakeService.GetOrderItem(); + item.Init(); + return item; + } + + #endregion + + #region Single + + /// + /// 测试查找单个实体 + /// + [Fact] + public async Task TestSingle_1() { + //添加实体 + var entity = await AddOrderAsync(); + + //查找单个实体 + var result = await _repository.SingleAsync( t => t.Id == entity.Id ); + + //验证 + Assert.Empty( result.OrderItems ); + } + + /// + /// 测试查找单个实体 - 使用Include包含子实体集合 + /// + [Fact] + public async Task TestSingle_2() { + //添加实体 + var entity = await AddOrderAsync(); + + //查找单个实体 + var result = await _repository.SingleAsync( t => t.Id == entity.Id, queryable => queryable.Include( t => t.OrderItems ) ); + + //验证 + Assert.Equal( 2, result.OrderItems.Count ); + } + + #endregion + + #region SingleAsync + + /// + /// 测试查找单个实体 + /// + [Fact] + public async Task TestSingleAsync_1() { + //添加实体 + var entity = await AddOrderAsync(); + + //查找单个实体 + var result = await _repository.SingleAsync( t => t.Id == entity.Id ); + + //验证 + Assert.Empty( result.OrderItems ); + } + + /// + /// 测试查找单个实体 - 使用Include包含子实体集合 + /// + [Fact] + public async Task TestSingleAsync_2() { + //添加实体 + var entity = await AddOrderAsync(); + + //查找单个实体 + var result = await _repository.SingleAsync( t => t.Id == entity.Id, queryable => queryable.Include( t => t.OrderItems ) ); + + //验证 + Assert.Equal( 2, result.OrderItems.Count ); + } + + #endregion + } +} \ No newline at end of file diff --git a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests.Integration/Tests/PostRepositoryTest.cs b/test/Util.Data.EntityFrameworkCore.SqlServer.Tests.Integration/Tests/PostRepositoryTest.cs new file mode 100644 index 00000000..c238dde1 --- /dev/null +++ b/test/Util.Data.EntityFrameworkCore.SqlServer.Tests.Integration/Tests/PostRepositoryTest.cs @@ -0,0 +1,54 @@ +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore; +using Util.Tests.Fakes; +using Util.Tests.Infrastructure; +using Util.Tests.Repositories; +using Util.Tests.UnitOfWorks; +using Xunit; + +namespace Util.Data.EntityFrameworkCore.Tests { + /// + /// 贴子仓储测试 + /// 说明: + /// 1. 测试多对多 + /// + public class PostRepositoryTest : TestBase { + /// + /// 仓储 + /// + private readonly IPostRepository _repository; + + /// + /// 测试初始化 + /// + public PostRepositoryTest(IPostRepository repository, ITestUnitOfWork unitOfWork ) : base(unitOfWork){ + _repository = repository; + } + + /// + /// 测试添加实体 + /// + [Fact] + public async Task TestAddAsync() { + //添加实体 + var post = PostFakeService.GetPost(); + post.Init(); + var tag1 = TagFakeService.GetTag(); + tag1.Init(); + post.Tags.Add( tag1 ); + + var tag2 = TagFakeService.GetTag(); + tag2.Init(); + post.Tags.Add( tag2 ); + + await _repository.AddAsync( post ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //验证 + var result = await _repository.SingleAsync( t => t.Id == post.Id, queryable => queryable.Include( t => t.Tags ) ); + Assert.NotNull( result ); + Assert.Equal( 2,result.Tags.Count ); + } + } +} \ No newline at end of file diff --git a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests.Integration/Tests/ProductRepositoryTest.Queryable.cs b/test/Util.Data.EntityFrameworkCore.SqlServer.Tests.Integration/Tests/ProductRepositoryTest.Queryable.cs new file mode 100644 index 00000000..e03ea9c5 --- /dev/null +++ b/test/Util.Data.EntityFrameworkCore.SqlServer.Tests.Integration/Tests/ProductRepositoryTest.Queryable.cs @@ -0,0 +1,390 @@ +using System; +using System.Linq; +using System.Threading.Tasks; +using Util.Data.Queries; +using Util.Tests.Conditions; +using Util.Tests.Fakes; +using Xunit; + +namespace Util.Data.EntityFrameworkCore.Tests { + /// + /// 产品仓储测试 - 查询测试 + /// + public partial class ProductRepositoryTest { + + #region Where + + /// + /// 测试设置查询条件 - 添加查询条件对象 + /// + [Fact] + public async Task TestWhere() { + //常量 + var name = "TestWhere"; + + //添加实体列表 + await AddProductsAsync(); + var products = await AddProductsAsync( name: name ); + + //创建查询条件 + var condition = new ProductNameCondition( name ); + + //查询 + var result = _repository.Find().Where( condition ).ToList(); + + //验证 + Assert.Equal( products.Count, result.Count ); + Assert.True( result.TrueForAll( t => products.Any( p => p.Id == t.Id ) ) ); + } + + #endregion + + #region WhereIf + + /// + /// 测试设置查询条件 - IQueryable添加WhereIf扩展 - true + /// + [Fact] + public async Task TestWhereIf_True() { + //常量 + var name = "TestWhereIf_True"; + + //添加实体列表 + await AddProductsAsync(); + var products = await AddProductsAsync( name: name ); + + //查询 + var result = _repository.Find().WhereIf( t => t.Name == name, true ).ToList(); + + //验证 + Assert.Equal( products.Count, result.Count ); + } + + /// + /// 测试设置查询条件 - IQueryable添加WhereIf扩展 - false + /// + [Fact] + public async Task TestWhereIf_False() { + //常量 + var name = "TestWhereIf_False"; + + //添加实体列表 + await AddProductsAsync(); + var products = await AddProductsAsync( name: name ); + + //查询 + var result = _repository.Find().WhereIf( t => t.Name == name, false ).ToList(); + + //验证 + Assert.NotEqual( products.Count, result.Count ); + } + + #endregion + + #region WhereIfNotEmpty + + /// + /// 测试设置查询条件 - IQueryable添加WhereIfNotEmpty扩展 - 有效条件 + /// + [Fact] + public async Task TestWhereIfNotEmpty_Valid() { + //常量 + var name = "TestWhereIfNotEmpty_Valid"; + + //添加实体列表 + await AddProductsAsync(); + var products = await AddProductsAsync( name: name ); + + //查询 + var result = _repository.Find().WhereIfNotEmpty( t => t.Name == name ).ToList(); + + //验证 + Assert.Equal( products.Count, result.Count ); + } + + /// + /// 测试设置查询条件 - IQueryable添加WhereIfNotEmpty扩展 - 忽略条件 + /// + [Fact] + public async Task TestWhereIfNotEmpty_Ignore() { + //常量 + var name = "TestWhereIfNotEmpty_Ignore"; + + //添加实体列表 + await AddProductsAsync(); + var products = await AddProductsAsync( name: name ); + + //查询 + var result = _repository.Find().Where( t => t.Name == name ).WhereIfNotEmpty( t => t.Code == "" ).ToList(); + + //验证 + Assert.Equal( products.Count, result.Count ); + } + + /// + /// 测试设置查询条件 - IQueryable添加WhereIfNotEmpty扩展 - 无效条件,抛出异常 + /// + [Fact] + public async Task TestWhereIfNotEmpty_Invalid() { + //添加实体列表 + await AddProductsAsync(); + + //查询 + Assert.Throws( () => { + _repository.Find().WhereIfNotEmpty( t => t.Name == "a" && t.Code == "b" ); + } ); + } + + #endregion + + #region OrIfNotEmpty + + /// + /// 测试设置查询条件 - IQueryable添加OrIfNotEmpty扩展 - 有效条件 + /// + [Fact] + public async Task TestOrIfNotEmpty_Valid() { + //常量 + var name1 = "TestOrIfNotEmpty_Valid_1"; + var name2 = "TestOrIfNotEmpty_Valid_2"; + var name3 = "TestOrIfNotEmpty_Valid_3"; + + //添加实体列表 + await AddProductsAsync(); + await AddProductsAsync( 2, name1 ); + await AddProductsAsync( 3, name2 ); + await AddProductsAsync( 4, name3 ); + + //查询 + var result = _repository.Find().OrIfNotEmpty( t => t.Name == name1,t => t.Name == name2, t => t.Name == name3 ).ToList(); + + //验证 + Assert.Equal( 9, result.Count ); + } + + /// + /// 测试设置查询条件 - IQueryable添加OrIfNotEmpty扩展 - 忽略条件 + /// + [Fact] + public async Task TestOrIfNotEmpty_Ignore() { + //常量 + var name1 = "TestOrIfNotEmpty_Ignore_1"; + var name2 = "TestOrIfNotEmpty_Ignore_2"; + var name3 = "TestOrIfNotEmpty_Ignore_3"; + + //添加实体列表 + await AddProductsAsync(); + await AddProductsAsync( 2, name1 ); + await AddProductsAsync( 3, name2 ); + await AddProductsAsync( 4, name3 ); + + //查询 + var result = _repository.Find().OrIfNotEmpty( t => t.Name == name1, t => t.Name == name2, t => t.Name == "" ).ToList(); + + //验证 + Assert.Equal( 5, result.Count ); + } + + #endregion + + #region Between + + /// + /// 测试添加范围查询条件 + /// + [Fact] + public async Task TestBetween_1() { + //常量 + var name = "TestBetween_1"; + var price = 10.1M; + + //添加实体列表 + await AddProductsAsync(); + var products = ProductFakeService.GetProducts( 5 ); + products.ForEach( product => { + product.Init(); + product.Name = name; + product.Price = price++; + } ); + await _repository.AddAsync( products ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //查询 + var result = _repository.Find().Where( t => t.Name == name ).Between( t => t.Price,11.5M,13.5M ).ToList(); + + //验证 + Assert.Equal( 2, result.Count ); + } + + /// + /// 测试添加范围查询条件 - 包含左边界 + /// + [Fact] + public async Task TestBetween_2() { + //常量 + var name = "TestBetween_2"; + var price = 10.1M; + + //添加实体列表 + await AddProductsAsync(); + var products = ProductFakeService.GetProducts( 5 ); + products.ForEach( product => { + product.Init(); + product.Name = name; + product.Price = price++; + } ); + await _repository.AddAsync( products ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //查询 + var result = _repository.Find().Where( t => t.Name == name ).Between( t => t.Price, 11.1M, 13.1M,Boundary.Left ).ToList(); + + //验证 + Assert.Equal( 2, result.Count ); + } + + /// + /// 测试添加范围查询条件 - 包含右边界 + /// + [Fact] + public async Task TestBetween_3() { + //常量 + var name = "TestBetween_3"; + var price = 10.1M; + + //添加实体列表 + await AddProductsAsync(); + var products = ProductFakeService.GetProducts( 5 ); + products.ForEach( product => { + product.Init(); + product.Name = name; + product.Price = price++; + } ); + await _repository.AddAsync( products ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //查询 + var result = _repository.Find().Where( t => t.Name == name ).Between( t => t.Price, 11.1M, 13.1M, Boundary.Right ).ToList(); + + //验证 + Assert.Equal( 2, result.Count ); + } + + /// + /// 测试添加范围查询条件 - 包含两边 + /// + [Fact] + public async Task TestBetween_4() { + //常量 + var name = "TestBetween_4"; + var price = 10.1M; + + //添加实体列表 + await AddProductsAsync(); + var products = ProductFakeService.GetProducts( 5 ); + products.ForEach( product => { + product.Init(); + product.Name = name; + product.Price = price++; + } ); + await _repository.AddAsync( products ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //查询 + var result = _repository.Find().Where( t => t.Name == name ).Between( t => t.Price, 11.1M, 13.1M ).ToList(); + + //验证 + Assert.Equal( 3, result.Count ); + } + + /// + /// 测试添加范围查询条件 - 不包含边界 + /// + [Fact] + public async Task TestBetween_5() { + //常量 + var name = "TestBetween_5"; + var price = 10.1M; + + //添加实体列表 + await AddProductsAsync(); + var products = ProductFakeService.GetProducts( 5 ); + products.ForEach( product => { + product.Init(); + product.Name = name; + product.Price = price++; + } ); + await _repository.AddAsync( products ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //查询 + var result = _repository.Find().Where( t => t.Name == name ).Between( t => t.Price, 11.1M, 13.1M,Boundary.Neither ).ToList(); + + //验证 + Assert.Single( result ); + } + + /// + /// 测试添加范围查询条件 - 最大值为空 + /// + [Fact] + public async Task TestBetween_6() { + //常量 + var name = "TestBetween_6"; + var price = 10.1M; + + //添加实体列表 + await AddProductsAsync(); + var products = ProductFakeService.GetProducts( 5 ); + products.ForEach( product => { + product.Init(); + product.Name = name; + product.Price = price++; + } ); + await _repository.AddAsync( products ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //查询 + var result = _repository.Find().Where( t => t.Name == name ).Between( t => t.Price, 9.5M, null ).ToList(); + + //验证 + Assert.Equal( 5, result.Count ); + } + + /// + /// 测试添加范围查询条件 - 最小值为空 + /// + [Fact] + public async Task TestBetween_7() { + //常量 + var name = "TestBetween_7"; + var price = 10.1M; + + //添加实体列表 + await AddProductsAsync(); + var products = ProductFakeService.GetProducts( 5 ); + products.ForEach( product => { + product.Init(); + product.Name = name; + product.Price = price++; + } ); + await _repository.AddAsync( products ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //查询 + var result = _repository.Find().Where( t => t.Name == name ).Between( t => t.Price, null, 15.5M ).ToList(); + + //验证 + Assert.Equal( 5, result.Count ); + } + + #endregion + } +} diff --git a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Tests/ProductRepositoryTest.cs b/test/Util.Data.EntityFrameworkCore.SqlServer.Tests.Integration/Tests/ProductRepositoryTest.cs similarity index 73% rename from test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Tests/ProductRepositoryTest.cs rename to test/Util.Data.EntityFrameworkCore.SqlServer.Tests.Integration/Tests/ProductRepositoryTest.cs index 8ea724eb..1475f044 100644 --- a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Tests/ProductRepositoryTest.cs +++ b/test/Util.Data.EntityFrameworkCore.SqlServer.Tests.Integration/Tests/ProductRepositoryTest.cs @@ -2,12 +2,12 @@ using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; -using Util.Data.EntityFrameworkCore.Fakes; -using Util.Data.EntityFrameworkCore.Infrastructure; -using Util.Data.EntityFrameworkCore.Models; -using Util.Data.EntityFrameworkCore.Repositories; -using Util.Data.EntityFrameworkCore.UnitOfWorks; using Util.Exceptions; +using Util.Tests.Fakes; +using Util.Tests.Infrastructure; +using Util.Tests.Models; +using Util.Tests.Repositories; +using Util.Tests.UnitOfWorks; using Xunit; using Xunit.Abstractions; using Xunit.DependencyInjection; @@ -18,6 +18,7 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 说明: /// 1. 测试Guid类型标识 /// 2. 测试仓储基础方法 + /// 3. 测试扩展属性 /// public partial class ProductRepositoryTest : TestBase { @@ -35,7 +36,7 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// /// 测试初始化 /// - public ProductRepositoryTest( ITestOutputHelperAccessor accessor, IProductRepository repository,ISqlServerUnitOfWork unitOfWork ) :base(unitOfWork) { + public ProductRepositoryTest( ITestOutputHelperAccessor accessor, IProductRepository repository, ITestUnitOfWork unitOfWork ) :base(unitOfWork) { _log = accessor.Output; _repository = repository; } @@ -44,19 +45,6 @@ namespace Util.Data.EntityFrameworkCore.Tests { #region 辅助方法 - /// - /// 添加产品 - /// - private Product AddProduct( string name = null ) { - var entity = ProductFakeService.GetProduct(); - entity.Init(); - if( name != null ) - entity.Name = name; - _repository.Add( entity ); - UnitOfWork.Commit(); - return entity; - } - /// /// 添加产品 /// @@ -70,24 +58,6 @@ namespace Util.Data.EntityFrameworkCore.Tests { return entity; } - /// - /// 添加实体列表 - /// - /// 添加数量 - /// 产品名称 - private List AddProducts( int count = 2, string name = null ) { - var products = ProductFakeService.GetProducts( count ); - products.ForEach( product => { - product.Init(); - if( name != null ) - product.Name = name; - } ); - _repository.Add( products ); - UnitOfWork.Commit(); - UnitOfWork.ClearCache(); - return products.OrderBy( t => t.Id ).ToList(); - } - /// /// 添加实体列表 /// @@ -121,9 +91,9 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试通过标识查找实体 - 跟踪实体 /// [Fact] - public void TestFindById_Tracking_1() { + public async Task TestFindById_Tracking_1() { //添加实体 - var entity = AddProduct(); + var entity = await AddProductAsync(); UnitOfWork.ClearCache(); //验证 @@ -136,9 +106,9 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试通过标识查找实体 - 跟踪实体 - 字符串标识 /// [Fact] - public void TestFindById_Tracking_2() { + public async Task TestFindById_Tracking_2() { //添加实体 - var entity = AddProduct(); + var entity = await AddProductAsync(); UnitOfWork.ClearCache(); //验证 @@ -151,9 +121,9 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试通过标识查找实体 - 不跟踪实体 /// [Fact] - public void TestFindById_NoTracking() { + public async Task TestFindById_NoTracking() { //添加实体 - var entity = AddProduct(); + var entity = await AddProductAsync(); UnitOfWork.ClearCache(); //验证 @@ -219,7 +189,7 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试通过标识列表查找实体列表 - 传入逗号分隔的标识列表 /// [Fact] - public void TestFindByIds_1() { + public async Task TestFindByIds_1() { //常量 var count = 3; @@ -228,8 +198,8 @@ namespace Util.Data.EntityFrameworkCore.Tests { products.ForEach( product => { product.Init(); } ); - _repository.Add( products ); - UnitOfWork.Commit(); + await _repository.AddAsync( products ); + await UnitOfWork.CommitAsync(); //验证 var result = _repository.FindByIds( products[0].Id, products[1].Id, products[2].Id ).OrderBy( t => t.Code ).ToList(); @@ -242,7 +212,7 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试通过标识列表查找实体列表 - 传入集合 /// [Fact] - public void TestFindByIds_2() { + public async Task TestFindByIds_2() { //常量 var count = 3; @@ -251,8 +221,8 @@ namespace Util.Data.EntityFrameworkCore.Tests { products.ForEach( product => { product.Init(); } ); - _repository.Add( products ); - UnitOfWork.Commit(); + await _repository.AddAsync( products ); + await UnitOfWork.CommitAsync(); //验证 var result = _repository.FindByIds( products.Select( t => t.Id ) ).OrderBy( t => t.Code ).ToList(); @@ -265,7 +235,7 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试通过标识列表查找实体列表 - 传入标识列表字符串 /// [Fact] - public void TestFindByIds_3() { + public async Task TestFindByIds_3() { //常量 var count = 3; @@ -274,8 +244,8 @@ namespace Util.Data.EntityFrameworkCore.Tests { products.ForEach( product => { product.Init(); } ); - _repository.Add( products ); - UnitOfWork.Commit(); + await _repository.AddAsync( products ); + await UnitOfWork.CommitAsync(); //验证 var result = _repository.FindByIds( products.Select( t => t.Id ).Join() ).OrderBy( t => t.Code ).ToList(); @@ -365,12 +335,12 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试查找单个实体 /// [Fact] - public void TestSingle_1() { + public async Task TestSingle_1() { //常量 var name = "TestSingle"; //添加实体 - var entity = AddProduct( name ); + var entity = await AddProductAsync( name ); UnitOfWork.ClearCache(); //验证 @@ -407,9 +377,9 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试判断是否存在 /// [Fact] - public void TestExists() { + public async Task TestExists() { //添加实体 - var entity = AddProduct(); + var entity = await AddProductAsync(); UnitOfWork.ClearCache(); //验证 @@ -441,7 +411,7 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试查找数量 /// [Fact] - public void TestCount() { + public async Task TestCount() { //常量 var name = "TestCount"; var count = 3; @@ -452,8 +422,8 @@ namespace Util.Data.EntityFrameworkCore.Tests { product.Init(); product.Name = name; } ); - _repository.Add( products ); - UnitOfWork.Commit(); + await _repository.AddAsync( products ); + await UnitOfWork.CommitAsync(); //验证 var result = _repository.Count( t => t.Name == name ); @@ -495,24 +465,24 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试更新方法1 - 查找并修改实体,直接提交工作单元 /// [Fact] - public void TestUpdate_1() { + public async Task TestUpdate_1() { //常量 var code = "TestUpdate_1_Code"; //添加实体 - var entity = AddProduct(); + var entity = await AddProductAsync(); UnitOfWork.ClearCache(); //查找实体并修改 - var product = _repository.FindById( entity.Id ); + var product = await _repository.FindByIdAsync( entity.Id ); product.Code = code; //直接提交工作单元 - UnitOfWork.Commit(); + await UnitOfWork.CommitAsync(); UnitOfWork.ClearCache(); //验证 - var result = _repository.FindById( entity.Id ); + var result = await _repository.FindByIdAsync( entity.Id ); Assert.Equal( code, result.Code ); } @@ -521,24 +491,24 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 更新方法1的缺陷: 通过赋值的方式更新查找实体的版本号,无法触发乐观锁 /// [Fact] - public void TestUpdate_1_Concurrency() { + public async Task TestUpdate_1_Concurrency() { //常量 var code = "TestUpdate_1_Concurrency_Code"; var description = "TestUpdate_1_Concurrency_Description"; //添加实体 - var entity = AddProduct(); + var entity = await AddProductAsync(); UnitOfWork.ClearCache(); //此处模拟用户1打开表单并修改,但尚未提交,这将保存旧实体 - var product = _repository.FindById( entity.Id ); + var product = await _repository.FindByIdAsync( entity.Id ); product.Code = code; UnitOfWork.ClearCache(); //此处模拟用户2更新该实体,这将导致版本号变化 - var product2 = _repository.FindById( entity.Id ); + var product2 = await _repository.FindByIdAsync( entity.Id ); product2.Description = description; - UnitOfWork.Commit(); + await UnitOfWork.CommitAsync(); UnitOfWork.ClearCache(); //此处模拟用户1提交表单,查找实体,并进行赋值 @@ -547,7 +517,7 @@ namespace Util.Data.EntityFrameworkCore.Tests { result.Description = product.Description; result.Version = product.Version; //提交工作单元,由于版本号变化,预期应触发乐观锁,但实际未触发 - UnitOfWork.Commit(); + await UnitOfWork.CommitAsync(); //结果:用户1覆盖了用户2设置的Description属性 Assert.Equal( code, result.Code ); @@ -558,12 +528,12 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试更新方法2 - 创建未跟踪实体,调用dbcontext.Update方法 /// [Fact] - public void TestUpdate_2() { + public async Task TestUpdate_2() { //常量 var code = "TestUpdate_2_Code"; //添加实体 - var entity = AddProduct(); + var entity = await AddProductAsync(); UnitOfWork.ClearCache(); //创建未跟踪实体 @@ -572,11 +542,11 @@ namespace Util.Data.EntityFrameworkCore.Tests { //调用dbcontext.Update方法更新实体 _repository.UpdateProduct( product ); //提交工作单元 - UnitOfWork.Commit(); + await UnitOfWork.CommitAsync(); UnitOfWork.ClearCache(); //验证 - var result = _repository.FindById( entity.Id ); + var result = await _repository.FindByIdAsync( entity.Id ); Assert.Equal( code, result.Code ); } @@ -585,16 +555,16 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 如果在创建未跟踪实体并调用dbcontext.Update方法之前,从dbcontext中已查找出该实体,将发生异常 /// [Fact] - public void TestUpdate_2_InvalidOperation() { + public async Task TestUpdate_2_InvalidOperation() { //常量 var code = "TestUpdate_2_InvalidOperation_Code"; //添加实体 - var entity = AddProduct(); + var entity = await AddProductAsync(); UnitOfWork.ClearCache(); //模拟更新之前无意中已查找出该实体 - _repository.FindById( entity.Id ); + await _repository.FindByIdAsync( entity.Id ); //创建未跟踪实体 var product = entity.MapTo(); @@ -610,24 +580,24 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试更新并发 - 使用更新方法2 /// [Fact] - public void TestUpdate_2_Concurrency() { + public async Task TestUpdate_2_Concurrency() { //常量 var code = "TestUpdate_2_Concurrency_Code"; var description = "TestUpdate_2_Concurrency_Description"; //添加实体 - var entity = AddProduct(); + var entity = await AddProductAsync(); UnitOfWork.ClearCache(); //此处模拟用户1打开表单并修改,但尚未提交,这将保存旧实体 - var product = _repository.FindById( entity.Id ); + var product = await _repository.FindByIdAsync( entity.Id ); product.Code = code; UnitOfWork.ClearCache(); //此处模拟用户2更新该实体,这将导致版本号变化 - var product2 = _repository.FindById( entity.Id ); + var product2 = await _repository.FindByIdAsync( entity.Id ); product2.Description = description; - UnitOfWork.Commit(); + await UnitOfWork.CommitAsync(); UnitOfWork.ClearCache(); //此处模拟用户1提交表单,创建一个新的实体,并赋值 @@ -637,8 +607,8 @@ namespace Util.Data.EntityFrameworkCore.Tests { _repository.UpdateProduct( result ); //提交工作单元,由于版本号变化,触发乐观锁 - Assert.Throws( () => { - UnitOfWork.Commit(); + await Assert.ThrowsAsync( async () => { + await UnitOfWork.CommitAsync(); } ); } @@ -646,23 +616,23 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试Util Update更新方法 - 查找并修改实体,提交工作单元 /// [Fact] - public void TestUpdate_3_1() { + public async Task TestUpdate_3_1() { //常量 var code = "TestUpdate_3_1_Code"; //添加实体 - var entity = AddProduct(); + var entity = await AddProductAsync(); UnitOfWork.ClearCache(); //查找实体并修改 - var product = _repository.FindById( entity.Id ); + var product = await _repository.FindByIdAsync( entity.Id ); product.Code = code; //调用Update方法 - _repository.Update( product ); + await _repository.UpdateAsync( product ); //提交工作单元 - UnitOfWork.Commit(); + await UnitOfWork.CommitAsync(); UnitOfWork.ClearCache(); //验证 @@ -674,189 +644,19 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试Util Update更新方法 - 创建未跟踪实体,调用Update方法 /// [Fact] - public void TestUpdate_3_2() { + public async Task TestUpdate_3_2() { //常量 var code = "TestUpdate_3_2_Code"; - //添加实体 - var entity = AddProduct(); - UnitOfWork.ClearCache(); - - //创建未跟踪实体 - var product = entity.MapTo(); - product.Code = code; - - //调用Update方法更新实体 - _repository.Update( product ); - - //提交工作单元 - UnitOfWork.Commit(); - UnitOfWork.ClearCache(); - - //验证 - var result = _repository.FindById( entity.Id ); - Assert.Equal( code, result.Code ); - } - - /// - /// 测试Util Update更新方法 - 允许在创建未跟踪实体并调用Update方法之前查找实体,不会发生异常 - /// - [Fact] - public void TestUpdate_3_3() { - //常量 - var code = "TestUpdate_3_3_InvalidOperation_Code"; - - //添加实体 - var entity = AddProduct(); - UnitOfWork.ClearCache(); - - //模拟更新之前无意中已查找出该实体 - _repository.FindById( entity.Id ); - - //创建未跟踪实体 - var product = entity.MapTo(); - product.Code = code; - - //调用Update方法更新实体 - _repository.Update( product ); - - //提交工作单元 - _log.WriteLine( UnitOfWork.GetChangeTrackerDebugView() ); - UnitOfWork.Commit(); - UnitOfWork.ClearCache(); - - //验证 - var result = _repository.FindById( entity.Id ); - Assert.Equal( code, result.Code ); - } - - /// - /// 测试更新并发 - 使用Util Update更新方法 - /// 通过赋值的方式更新查找实体的版本号,触发乐观锁 - /// - [Fact] - public void TestUpdate_3_Concurrency_1() { - //常量 - var code = "TestUpdate_3_Concurrency_1_Code"; - var description = "TestUpdate_3_Concurrency_1_Description"; - - //添加实体 - var entity = AddProduct(); - UnitOfWork.ClearCache(); - - //此处模拟用户1打开表单并修改,但尚未提交,这将保存旧实体 - var product = _repository.FindById( entity.Id ); - product.Code = code; - UnitOfWork.ClearCache(); - - //此处模拟用户2更新该实体,这将导致版本号变化 - var product2 = _repository.FindById( entity.Id ); - product2.Description = description; - UnitOfWork.Commit(); - UnitOfWork.ClearCache(); - - //此处模拟用户1提交表单,查找实体,并进行赋值 - var result = _repository.FindById( entity.Id ); - result.Code = product.Code; - result.Description = product.Description; - result.Version = product.Version; - - //调用Update方法更新实体时触发乐观锁 - Assert.Throws( () => { - _repository.Update( result ); - } ); - } - - /// - /// 测试更新并发 - 使用Util Update更新方法 - /// 更新未跟踪实体触发乐观锁 - /// - [Fact] - public void TestUpdate_3_Concurrency_2() { - //常量 - var code = "TestUpdate_3_Concurrency_2_Code"; - var description = "TestUpdate_3_Concurrency_2_Description"; - - //添加实体 - var entity = AddProduct(); - UnitOfWork.ClearCache(); - - //此处模拟用户1打开表单并修改,但尚未提交,这将保存旧实体 - var product = _repository.FindById( entity.Id ); - product.Code = code; - UnitOfWork.ClearCache(); - - //此处模拟用户2更新该实体,这将导致版本号变化 - var product2 = _repository.FindById( entity.Id ); - product2.Description = description; - UnitOfWork.Commit(); - UnitOfWork.ClearCache(); - - //此处模拟用户1提交表单,创建一个新的实体,并赋值 - var result = product.MapTo(); - - //调用Update方法更新实体 - _repository.Update( result ); - - //提交工作单元,由于版本号变化,触发乐观锁 - Assert.Throws( () => { - UnitOfWork.Commit(); - } ); - } - - /// - /// 测试更新集合 - /// - [Fact] - public void TestUpdate_4() { - //常量 - var count = 3; - var code = "TestUpdate_4_Code"; - - //添加实体列表 - var entities = ProductFakeService.GetProducts( count ); - entities.ForEach( product => { - product.Init(); - } ); - _repository.Add( entities ); - UnitOfWork.Commit(); - UnitOfWork.ClearCache(); - - //查找实体,赋值,调用Update方法,提交工作单元 - var products = _repository.FindByIds( entities.Select( t => t.Id ) ).ToList(); - products.ForEach( product => product.Code = code ); - _repository.Update( products ); - UnitOfWork.Commit(); - UnitOfWork.ClearCache(); - - //验证 - var result = _repository.FindByIds( entities.Select( t => t.Id ) ).ToList(); - Assert.Equal( code, result[0].Code ); - Assert.Equal( code, result[1].Code ); - Assert.Equal( code, result[2].Code ); - } - - #endregion - - #region UpdateAsync - - /// - /// 测试Util Update更新方法 - 异步 - /// - [Fact] - public async Task TestUpdateAsync_1() { - //常量 - var code = "TestUpdateAsync_1_Code"; - //添加实体 var entity = await AddProductAsync(); UnitOfWork.ClearCache(); - //查找实体并修改 - var product = await _repository.FindByIdAsync( entity.Id ); + //创建未跟踪实体 + var product = entity.MapTo(); product.Code = code; - //调用UpdateAsync方法 + //调用Update方法更新实体 await _repository.UpdateAsync( product ); //提交工作单元 @@ -869,13 +669,119 @@ namespace Util.Data.EntityFrameworkCore.Tests { } /// - /// 测试更新集合 - 异步 + /// 测试Util Update更新方法 - 允许在创建未跟踪实体并调用Update方法之前查找实体,不会发生异常 /// [Fact] - public async Task TestUpdateAsync_2() { + public async Task TestUpdate_3_3() { + //常量 + var code = "TestUpdate_3_3_InvalidOperation_Code"; + + //添加实体 + var entity = await AddProductAsync(); + UnitOfWork.ClearCache(); + + //模拟更新之前无意中已查找出该实体 + await _repository.FindByIdAsync( entity.Id ); + + //创建未跟踪实体 + var product = entity.MapTo(); + product.Code = code; + + //调用Update方法更新实体 + await _repository.UpdateAsync( product ); + + //提交工作单元 + _log.WriteLine( UnitOfWork.GetChangeTrackerDebugView() ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //验证 + var result = _repository.FindById( entity.Id ); + Assert.Equal( code, result.Code ); + } + + /// + /// 测试更新并发 - 使用Util Update更新方法 + /// 通过赋值的方式更新查找实体的版本号,触发乐观锁 + /// + [Fact] + public async Task TestUpdate_3_Concurrency_1() { + //常量 + var code = "TestUpdate_3_Concurrency_1_Code"; + var description = "TestUpdate_3_Concurrency_1_Description"; + + //添加实体 + var entity = await AddProductAsync(); + UnitOfWork.ClearCache(); + + //此处模拟用户1打开表单并修改,但尚未提交,这将保存旧实体 + var product = await _repository.FindByIdAsync( entity.Id ); + product.Code = code; + UnitOfWork.ClearCache(); + + //此处模拟用户2更新该实体,这将导致版本号变化 + var product2 = await _repository.FindByIdAsync( entity.Id ); + product2.Description = description; + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //此处模拟用户1提交表单,查找实体,并进行赋值 + var result = await _repository.FindByIdAsync( entity.Id ); + result.Code = product.Code; + result.Description = product.Description; + result.Version = product.Version; + + //调用Update方法更新实体时触发乐观锁 + await Assert.ThrowsAsync( async () => { + await _repository.UpdateAsync( result ); + } ); + } + + /// + /// 测试更新并发 - 使用Util Update更新方法 + /// 更新未跟踪实体触发乐观锁 + /// + [Fact] + public async Task TestUpdate_3_Concurrency_2() { + //常量 + var code = "TestUpdate_3_Concurrency_2_Code"; + var description = "TestUpdate_3_Concurrency_2_Description"; + + //添加实体 + var entity = await AddProductAsync(); + UnitOfWork.ClearCache(); + + //此处模拟用户1打开表单并修改,但尚未提交,这将保存旧实体 + var product = await _repository.FindByIdAsync( entity.Id ); + product.Code = code; + UnitOfWork.ClearCache(); + + //此处模拟用户2更新该实体,这将导致版本号变化 + var product2 = await _repository.FindByIdAsync( entity.Id ); + product2.Description = description; + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //此处模拟用户1提交表单,创建一个新的实体,并赋值 + var result = product.MapTo(); + + //调用Update方法更新实体 + await _repository.UpdateAsync( result ); + + //提交工作单元,由于版本号变化,触发乐观锁 + await Assert.ThrowsAsync( async () => { + await UnitOfWork.CommitAsync(); + } ); + } + + /// + /// 测试更新集合 + /// + [Fact] + public async Task TestUpdate_4() { //常量 var count = 3; - var code = "TestUpdateAsync_2_Code"; + var code = "TestUpdate_4_Code"; //添加实体列表 var entities = ProductFakeService.GetProducts( count ); @@ -886,15 +792,15 @@ namespace Util.Data.EntityFrameworkCore.Tests { await UnitOfWork.CommitAsync(); UnitOfWork.ClearCache(); - //查找实体,赋值,调用UpdateAsync方法,提交工作单元 - var products = ( await _repository.FindByIdsAsync( entities.Select( t => t.Id ) ) ).ToList(); + //查找实体,赋值,调用Update方法,提交工作单元 + var products = await _repository.FindByIdsAsync( entities.Select( t => t.Id ) ); products.ForEach( product => product.Code = code ); await _repository.UpdateAsync( products ); await UnitOfWork.CommitAsync(); UnitOfWork.ClearCache(); //验证 - var result = ( await _repository.FindByIdsAsync( entities.Select( t => t.Id ) ) ).ToList(); + var result = await _repository.FindByIdsAsync( entities.Select( t => t.Id ) ); Assert.Equal( code, result[0].Code ); Assert.Equal( code, result[1].Code ); Assert.Equal( code, result[2].Code ); @@ -904,163 +810,6 @@ namespace Util.Data.EntityFrameworkCore.Tests { #region Remove - /// - /// 测试通过标识移除实体 - 逻辑删除 - /// - [Fact] - public void TestRemove_Id_1() { - //添加实体 - var entity = AddProduct(); - UnitOfWork.ClearCache(); - - //移除实体 - _repository.Remove( entity.Id ); - UnitOfWork.Commit(); - UnitOfWork.ClearCache(); - - //验证 - var result = _repository.FindById( entity.Id ); - Assert.Null( result ); - } - - /// - /// 测试通过标识移除实体 - 逻辑删除 - 使用工作单元禁用逻辑删除过滤器 - /// - [Fact] - public void TestRemove_Id_2() { - //添加实体 - var entity = AddProduct(); - UnitOfWork.ClearCache(); - - //移除实体 - _repository.Remove( entity.Id ); - UnitOfWork.Commit(); - UnitOfWork.ClearCache(); - - //使用工作单元禁用逻辑删除过滤器,可以查出 - using( UnitOfWork.DisableDeleteFilter() ) { - var product = _repository.FindById( entity.Id ); - Assert.True( product.IsDeleted ); - Assert.Equal( entity.Code, product.Code ); - } - UnitOfWork.ClearCache(); - - //逻辑删除过滤器已启用,无法查出 - var result = _repository.FindById( entity.Id ); - Assert.Null( result ); - } - - /// - /// 测试通过标识移除实体 - 逻辑删除 - 使用仓储禁用逻辑删除过滤器 - /// - [Fact] - public void TestRemove_Id_3() { - //添加实体 - var entity = AddProduct(); - UnitOfWork.ClearCache(); - - //移除实体 - _repository.Remove( entity.Id ); - UnitOfWork.Commit(); - UnitOfWork.ClearCache(); - - //使用仓储禁用逻辑删除过滤器,可以查出 - using( _repository.DisableDeleteFilter() ) { - var product = _repository.FindById( entity.Id ); - Assert.True( product.IsDeleted ); - Assert.Equal( entity.Code, product.Code ); - } - UnitOfWork.ClearCache(); - - //逻辑删除过滤器已启用,无法查出 - var result = _repository.FindById( entity.Id ); - Assert.Null( result ); - } - - /// - /// 测试移除实体 - 逻辑删除 - /// - [Fact] - public void TestRemove_Entity() { - //添加实体 - var entity = AddProduct(); - UnitOfWork.ClearCache(); - - //移除实体 - _repository.Remove( entity ); - UnitOfWork.Commit(); - UnitOfWork.ClearCache(); - - //验证 - var result = _repository.FindById( entity.Id ); - Assert.Null( result ); - } - - /// - /// 测试移除实体集合 - 逻辑删除 - 通过标识列表 - /// - [Fact] - public void TestRemove_Entities_1() { - //常量 - var count = 3; - - //添加实体列表 - var products = ProductFakeService.GetProducts( count ).ToList(); - products.ForEach( product => { - product.Init(); - } ); - _repository.Add( products ); - UnitOfWork.Commit(); - UnitOfWork.ClearCache(); - - //移除实体集合 - var ids = products.Select( t => t.Id ).ToList(); - _repository.Remove( ids ); - UnitOfWork.Commit(); - UnitOfWork.ClearCache(); - - //验证 - using( _repository.DisableDeleteFilter() ) { - var result = _repository.FindByIds( ids ); - Assert.Equal( count, result.Count ); - result.ForEach( t => Assert.True( t.IsDeleted ) ); - } - } - - /// - /// 测试移除实体集合 - 逻辑删除 - 通过实体列表 - /// - [Fact] - public void TestRemove_Entities_2() { - //常量 - var count = 3; - - //添加实体列表 - var products = ProductFakeService.GetProducts( count ).ToList(); - products.ForEach( product => { - product.Init(); - } ); - _repository.Add( products ); - UnitOfWork.Commit(); - UnitOfWork.ClearCache(); - - //移除实体集合 - _repository.Remove( products ); - UnitOfWork.Commit(); - UnitOfWork.ClearCache(); - - //验证 - using( _repository.DisableDeleteFilter() ) { - var result = _repository.FindByIds( products.Select( t => t.Id ) ); - Assert.Equal( count, result.Count ); - result.ForEach( t => Assert.True( t.IsDeleted ) ); - } - } - - #endregion - - #region RemoveAsync - /// /// 测试通过标识移除实体 - 逻辑删除 /// @@ -1222,12 +971,12 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试设置创建审计属性 /// [Fact] - public void TestCreationAudit() { + public async Task TestCreationAudit() { var entity = ProductFakeService.GetProduct(); entity.Init(); - _repository.Add( entity ); + await _repository.AddAsync( entity ); Assert.NotEqual( TestSession.TestUserId, entity.CreatorId ); - UnitOfWork.Commit(); + await UnitOfWork.CommitAsync(); Assert.Equal( TestSession.TestUserId, entity.CreatorId ); Assert.Equal( TestSession.TestUserId, entity.LastModifierId ); } @@ -1236,7 +985,7 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试设置修改审计属性 /// [Fact] - public void TestModificationAudit() { + public async Task TestModificationAudit() { //工作单元 var unitOfWork = (SqlServerUnitOfWork)UnitOfWork; @@ -1244,13 +993,13 @@ namespace Util.Data.EntityFrameworkCore.Tests { var code = "TestModificationAudit"; //添加实体 - var entity = AddProduct(); + var entity = await AddProductAsync(); unitOfWork.ClearCache(); //修改 var product = entity.MapTo(); product.Code = code; - _repository.Update( product ); + await _repository.UpdateAsync( product ); unitOfWork.SetSession( new TestSession { UserId = TestSession.TestUserId2.ToString() } ); //验证修改前审计属性 @@ -1258,7 +1007,7 @@ namespace Util.Data.EntityFrameworkCore.Tests { Assert.Equal( TestSession.TestUserId, product.LastModifierId ); //提交 - unitOfWork.Commit(); + await unitOfWork.CommitAsync(); //验证修改后审计属性 Assert.Equal( TestSession.TestUserId, product.CreatorId ); @@ -1273,7 +1022,7 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试扩展属性 - 添加简单扩展属性 /// [Fact] - public void TestExtraProperties_1() { + public async Task TestExtraProperties_1() { //常量 var value = "TestExtraProperties_1"; @@ -1281,12 +1030,12 @@ namespace Util.Data.EntityFrameworkCore.Tests { var entity = new Product(); entity.Init(); entity.TestProperty1 = value; - _repository.Add( entity ); - UnitOfWork.Commit(); + await _repository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); UnitOfWork.ClearCache(); //验证 - var result = _repository.FindById( entity.Id ); + var result = await _repository.FindByIdAsync( entity.Id ); Assert.Equal( value, result.TestProperty1 ); } @@ -1294,7 +1043,7 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试扩展属性 - 修改简单扩展属性 /// [Fact] - public void TestExtraProperties_2() { + public async Task TestExtraProperties_2() { //常量 var oldValue = "TestExtraProperties_2_1"; var newValue = "TestExtraProperties_2_2"; @@ -1303,22 +1052,22 @@ namespace Util.Data.EntityFrameworkCore.Tests { var entity = new Product(); entity.Init(); entity.TestProperty1 = oldValue; - _repository.Add( entity ); - UnitOfWork.Commit(); + await _repository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); UnitOfWork.ClearCache(); //验证 - var oldEntity = _repository.FindById( entity.Id ); + var oldEntity = await _repository.FindByIdAsync( entity.Id ); Assert.Equal( oldValue, oldEntity.TestProperty1 ); //修改实体 oldEntity.TestProperty1 = newValue; - _repository.Update( oldEntity ); - UnitOfWork.Commit(); + await _repository.UpdateAsync( oldEntity ); + await UnitOfWork.CommitAsync(); UnitOfWork.ClearCache(); //验证 - var result = _repository.FindById( entity.Id ); + var result = await _repository.FindByIdAsync( entity.Id ); Assert.Equal( newValue, result.TestProperty1 ); } @@ -1326,7 +1075,7 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试扩展属性 - 添加对象扩展属性 /// [Fact] - public void TestExtraProperties_3() { + public async Task TestExtraProperties_3() { //常量 var code = 2; var name = "TestExtraProperties_3"; @@ -1338,8 +1087,8 @@ namespace Util.Data.EntityFrameworkCore.Tests { entity.TestProperty2.Code = code; entity.TestProperty2.Name = name; entity.TestProperty2.EnumValue = enumValue; - _repository.Add( entity ); - UnitOfWork.Commit(); + await _repository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); UnitOfWork.ClearCache(); //验证 @@ -1353,7 +1102,7 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试扩展属性 - 修改对象扩展属性 /// [Fact] - public void TestExtraProperties_4() { + public async Task TestExtraProperties_4() { //常量 var code = 2; var oldName = "TestExtraProperties_4_1"; @@ -1367,12 +1116,12 @@ namespace Util.Data.EntityFrameworkCore.Tests { entity.TestProperty2.Code = code; entity.TestProperty2.Name = oldName; entity.TestProperty2.EnumValue = oldEnumValue; - _repository.Add( entity ); - UnitOfWork.Commit(); + await _repository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); UnitOfWork.ClearCache(); //验证 - var oldEntity = _repository.FindById( entity.Id ); + var oldEntity = await _repository.FindByIdAsync( entity.Id ); Assert.Equal( code, oldEntity.TestProperty2.Code ); Assert.Equal( oldName, oldEntity.TestProperty2.Name ); Assert.Equal( oldEnumValue, oldEntity.TestProperty2.EnumValue ); @@ -1381,12 +1130,12 @@ namespace Util.Data.EntityFrameworkCore.Tests { oldEntity.TestProperty2.Name = newName; oldEntity.TestProperty2.EnumValue = newEnumValue; WriteTrackerDebug(); - _repository.Update( oldEntity ); - UnitOfWork.Commit(); + await _repository.UpdateAsync( oldEntity ); + await UnitOfWork.CommitAsync(); UnitOfWork.ClearCache(); //验证 - var result = _repository.FindById( entity.Id ); + var result = await _repository.FindByIdAsync( entity.Id ); Assert.Equal( newName, result.TestProperty2.Name ); Assert.Equal( newEnumValue, result.TestProperty2.EnumValue ); } @@ -1395,7 +1144,7 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试扩展属性 - 添加对象集合扩展属性 /// [Fact] - public void TestExtraProperties_5() { + public async Task TestExtraProperties_5() { //常量 var code = 1; var name1 = "TestExtraProperties_5_1"; @@ -1406,12 +1155,12 @@ namespace Util.Data.EntityFrameworkCore.Tests { entity.Init(); entity.TestProperties.Add( new ProductItem { Code = code, Name = name1 } ); entity.TestProperties.Add( new ProductItem { Code = code, Name = name2 } ); - _repository.Add( entity ); - UnitOfWork.Commit(); + await _repository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); UnitOfWork.ClearCache(); //验证 - var result = _repository.FindById( entity.Id ); + var result = await _repository.FindByIdAsync( entity.Id ); Assert.Equal( 2, result.TestProperties.Count ); Assert.Equal( code, result.TestProperties[0].Code ); Assert.Equal( name1, result.TestProperties[0].Name ); @@ -1423,7 +1172,7 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试扩展属性 - 修改对象集合扩展属性 /// [Fact] - public void TestExtraProperties_6() { + public async Task TestExtraProperties_6() { //常量 var code = 1; var oldName = "TestExtraProperties_6_1"; @@ -1435,24 +1184,24 @@ namespace Util.Data.EntityFrameworkCore.Tests { entity.Init(); entity.TestProperties.Add( new ProductItem { Code = code, Name = oldName } ); entity.TestProperties.Add( new ProductItem { Code = code, Name = oldName } ); - _repository.Add( entity ); - UnitOfWork.Commit(); + await _repository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); UnitOfWork.ClearCache(); //验证 - var oldEntity = _repository.FindById( entity.Id ); + var oldEntity = await _repository.FindByIdAsync( entity.Id ); Assert.Equal( 2, oldEntity.TestProperties.Count ); //修改实体 oldEntity.TestProperties[0].Name = newName; oldEntity.TestProperties[1].Name = newName; oldEntity.TestProperties.Add( new ProductItem { Code = code, Name = name3 } ); - _repository.Update( oldEntity ); - UnitOfWork.Commit(); + await _repository.UpdateAsync( oldEntity ); + await UnitOfWork.CommitAsync(); UnitOfWork.ClearCache(); //验证 - var result = _repository.FindById( entity.Id ); + var result = await _repository.FindByIdAsync( entity.Id ); Assert.Equal( 3, result.TestProperties.Count ); Assert.Equal( code, result.TestProperties[0].Code ); Assert.Equal( newName, result.TestProperties[0].Name ); @@ -1466,7 +1215,7 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试扩展属性 - 添加多个扩展属性 /// [Fact] - public void TestExtraProperties_7() { + public async Task TestExtraProperties_7() { //常量 var code = 2; var name = "TestExtraProperties_7"; @@ -1479,12 +1228,12 @@ namespace Util.Data.EntityFrameworkCore.Tests { entity.TestProperty2.Name = name; entity.TestProperties.Add( new ProductItem { Code = code, Name = name } ); entity.TestProperties.Add( new ProductItem { Code = code, Name = name } ); - _repository.Add( entity ); - UnitOfWork.Commit(); + await _repository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); UnitOfWork.ClearCache(); //验证 - var result = _repository.FindById( entity.Id ); + var result = await _repository.FindByIdAsync( entity.Id ); Assert.Equal( name, result.TestProperty1 ); Assert.Equal( code, result.TestProperty2.Code ); Assert.Equal( name, result.TestProperty2.Name ); @@ -1498,7 +1247,7 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试扩展属性 - 修改多个扩展属性 /// [Fact] - public void TestExtraProperties_8() { + public async Task TestExtraProperties_8() { //常量 var code = 2; var oldName = "TestExtraProperties_8_1"; @@ -1512,12 +1261,12 @@ namespace Util.Data.EntityFrameworkCore.Tests { entity.TestProperty2.Name = oldName; entity.TestProperties.Add( new ProductItem { Code = code, Name = oldName } ); entity.TestProperties.Add( new ProductItem { Code = code, Name = oldName } ); - _repository.Add( entity ); - UnitOfWork.Commit(); + await _repository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); UnitOfWork.ClearCache(); //验证 - var oldEntity = _repository.FindById( entity.Id ); + var oldEntity = await _repository.FindByIdAsync( entity.Id ); Assert.Equal( oldName, oldEntity.TestProperty1 ); Assert.Equal( code, oldEntity.TestProperty2.Code ); Assert.Equal( oldName, oldEntity.TestProperty2.Name ); @@ -1529,12 +1278,12 @@ namespace Util.Data.EntityFrameworkCore.Tests { oldEntity.TestProperties[0].Name = newName; oldEntity.TestProperties[1].Name = newName; oldEntity.TestProperties.Add( new ProductItem{ Code = code, Name = newName } ); - _repository.Update( oldEntity ); - UnitOfWork.Commit(); + await _repository.UpdateAsync( oldEntity ); + await UnitOfWork.CommitAsync(); UnitOfWork.ClearCache(); //验证 - var result = _repository.FindById( entity.Id ); + var result = await _repository.FindByIdAsync( entity.Id ); Assert.Equal( newName, result.TestProperty1 ); Assert.Equal( newName, result.TestProperty2.Name ); Assert.Equal( 3, result.TestProperties.Count ); @@ -1547,7 +1296,7 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试扩展属性 - 添加枚举扩展属性 /// [Fact] - public void TestExtraProperties_9() { + public async Task TestExtraProperties_9() { //常量 ProductEnum value = ProductEnum.World; @@ -1555,12 +1304,12 @@ namespace Util.Data.EntityFrameworkCore.Tests { var entity = new Product(); entity.Init(); entity.TestProperty3 = value; - _repository.Add( entity ); - UnitOfWork.Commit(); + await _repository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); UnitOfWork.ClearCache(); //验证 - var result = _repository.FindById( entity.Id ); + var result = await _repository.FindByIdAsync( entity.Id ); Assert.Equal( value, result.TestProperty3 ); } @@ -1568,7 +1317,7 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试扩展属性 - 修改枚举扩展属性 /// [Fact] - public void TestExtraProperties_10() { + public async Task TestExtraProperties_10() { //常量 ProductEnum oldValue = ProductEnum.Hello; ProductEnum newValue = ProductEnum.World; @@ -1577,22 +1326,22 @@ namespace Util.Data.EntityFrameworkCore.Tests { var entity = new Product(); entity.Init(); entity.TestProperty3 = oldValue; - _repository.Add( entity ); - UnitOfWork.Commit(); + await _repository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); UnitOfWork.ClearCache(); //验证 - var oldEntity = _repository.FindById( entity.Id ); + var oldEntity = await _repository.FindByIdAsync( entity.Id ); Assert.Equal( oldValue, oldEntity.TestProperty3 ); //修改实体 oldEntity.TestProperty3 = newValue; - _repository.Update( oldEntity ); - UnitOfWork.Commit(); + await _repository.UpdateAsync( oldEntity ); + await UnitOfWork.CommitAsync(); UnitOfWork.ClearCache(); //验证 - var result = _repository.FindById( entity.Id ); + var result = await _repository.FindByIdAsync( entity.Id ); Assert.Equal( newValue, result.TestProperty3 ); } @@ -1600,7 +1349,7 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试扩展属性 - 添加不可变对象扩展属性 /// [Fact] - public void TestExtraProperties_11() { + public async Task TestExtraProperties_11() { //常量 var code = 2; var name = "TestExtraProperties_11"; @@ -1609,12 +1358,12 @@ namespace Util.Data.EntityFrameworkCore.Tests { var entity = new Product(); entity.Init(); entity.TestProperty4 = new ProductItem2( code, name ); - _repository.Add( entity ); - UnitOfWork.Commit(); + await _repository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); UnitOfWork.ClearCache(); //验证 - var result = _repository.FindById( entity.Id ); + var result = await _repository.FindByIdAsync( entity.Id ); Assert.Equal( code, result.TestProperty4.Code ); Assert.Equal( name, result.TestProperty4.Name ); } @@ -1623,7 +1372,7 @@ namespace Util.Data.EntityFrameworkCore.Tests { /// 测试扩展属性 - 修改对象扩展属性 /// [Fact] - public void TestExtraProperties_12() { + public async Task TestExtraProperties_12() { //常量 var code = 2; var oldName = "TestExtraProperties_12_1"; @@ -1633,24 +1382,24 @@ namespace Util.Data.EntityFrameworkCore.Tests { var entity = new Product(); entity.Init(); entity.TestProperty4 = new ProductItem2( code, oldName ); - _repository.Add( entity ); - UnitOfWork.Commit(); + await _repository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); UnitOfWork.ClearCache(); //验证 - var oldEntity = _repository.FindById( entity.Id ); + var oldEntity = await _repository.FindByIdAsync( entity.Id ); Assert.Equal( code, oldEntity.TestProperty4.Code ); Assert.Equal( oldName, oldEntity.TestProperty4.Name ); //修改实体 oldEntity.TestProperty4 = new ProductItem2( code, newName ); WriteTrackerDebug(); - _repository.Update( oldEntity ); - UnitOfWork.Commit(); + await _repository.UpdateAsync( oldEntity ); + await UnitOfWork.CommitAsync(); UnitOfWork.ClearCache(); //验证 - var result = _repository.FindById( entity.Id ); + var result = await _repository.FindByIdAsync( entity.Id ); Assert.Equal( newName, result.TestProperty4.Name ); } diff --git a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests.Integration/Tests/TagRepositoryTest.cs b/test/Util.Data.EntityFrameworkCore.SqlServer.Tests.Integration/Tests/TagRepositoryTest.cs new file mode 100644 index 00000000..3819f129 --- /dev/null +++ b/test/Util.Data.EntityFrameworkCore.SqlServer.Tests.Integration/Tests/TagRepositoryTest.cs @@ -0,0 +1,41 @@ +using System.Threading.Tasks; +using Util.Tests.Fakes; +using Util.Tests.Infrastructure; +using Util.Tests.Repositories; +using Util.Tests.UnitOfWorks; +using Xunit; + +namespace Util.Data.EntityFrameworkCore.Tests { + /// + /// 标签仓储测试 + /// + public class TagRepositoryTest : TestBase { + /// + /// 仓储 + /// + private readonly ITagRepository _repository; + + /// + /// 测试初始化 + /// + public TagRepositoryTest( ITagRepository repository, ITestUnitOfWork unitOfWork ) : base( unitOfWork ) { + _repository = repository; + } + + /// + /// 测试添加实体 + /// + [Fact] + public async Task TestAddAsync() { + //添加实体 + var entity = TagFakeService.GetTag(); + entity.Init(); + await _repository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //验证 + Assert.True( await _repository.ExistsAsync( t => t.Id == entity.Id ) ); + } + } +} \ No newline at end of file diff --git a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Util.Data.EntityFrameworkCore.SqlServer.Tests.csproj b/test/Util.Data.EntityFrameworkCore.SqlServer.Tests.Integration/Util.Data.EntityFrameworkCore.SqlServer.Tests.Integration.csproj similarity index 56% rename from test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Util.Data.EntityFrameworkCore.SqlServer.Tests.csproj rename to test/Util.Data.EntityFrameworkCore.SqlServer.Tests.Integration/Util.Data.EntityFrameworkCore.SqlServer.Tests.Integration.csproj index 736f134f..06ba43d3 100644 --- a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Util.Data.EntityFrameworkCore.SqlServer.Tests.csproj +++ b/test/Util.Data.EntityFrameworkCore.SqlServer.Tests.Integration/Util.Data.EntityFrameworkCore.SqlServer.Tests.Integration.csproj @@ -8,42 +8,36 @@ - - true - PreserveNewest - Always - + + Always + + + Always + - - - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive - + - + runtime; build; native; contentfiles; analyzers; buildtransitive all - + runtime; build; native; contentfiles; analyzers; buildtransitive all - - - - - - - + diff --git a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/appsettings.json b/test/Util.Data.EntityFrameworkCore.SqlServer.Tests.Integration/appsettings.Development.json similarity index 100% rename from test/Util.Data.EntityFrameworkCore.SqlServer.Tests/appsettings.json rename to test/Util.Data.EntityFrameworkCore.SqlServer.Tests.Integration/appsettings.Development.json diff --git a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests.Integration/appsettings.json b/test/Util.Data.EntityFrameworkCore.SqlServer.Tests.Integration/appsettings.json new file mode 100644 index 00000000..c5bee3e6 --- /dev/null +++ b/test/Util.Data.EntityFrameworkCore.SqlServer.Tests.Integration/appsettings.json @@ -0,0 +1,11 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Error", + "Microsoft": "Error" + } + }, + "ConnectionStrings": { + "connection": "Server=192.168.31.123\\sql2014;Database=Util.Data.EntityFrameworkCore.Test;uid=sa;pwd=sa;MultipleActiveResultSets=true;" + } +} \ No newline at end of file diff --git a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Conditions/ProductNameCondition.cs b/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Conditions/ProductNameCondition.cs deleted file mode 100644 index a45ea6fa..00000000 --- a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Conditions/ProductNameCondition.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System; -using System.Linq.Expressions; -using Util.Data.EntityFrameworkCore.Models; - -namespace Util.Data.EntityFrameworkCore.Conditions { - /// - /// 产品名称查询条件 - /// - public class ProductNameCondition : ICondition { - /// - /// 产品名称 - /// - private readonly string _name; - - /// - /// 初始化产品名称查询条件 - /// - /// 产品名称 - public ProductNameCondition( string name ) { - _name = name; - } - - /// - /// 获取查询条件 - /// - public Expression> GetCondition() { - return t => t.Name == _name; - } - } -} diff --git a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Document/PowerDesigner/Util_Data_EF_Test_SqlServer.pdb b/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Document/PowerDesigner/Util_Data_EF_Test_SqlServer.pdb deleted file mode 100644 index 57483481..00000000 --- a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Document/PowerDesigner/Util_Data_EF_Test_SqlServer.pdb +++ /dev/null @@ -1,7789 +0,0 @@ - - - - - - - -00000000-0000-0000-0000-000000000000 - - -BD608590-48FF-4C8E-8926-A4C7815777DB -Util_Data_EF_Test_SqlServer -Util_Data_EF_Test_SqlServer -1621773501 -Xiadao -1634474813 -Xiadao -[FolderOptions] - -[FolderOptions\Physical Objects] -GenerationCheckModel=Yes -GenerationPath= -GenerationOptions= -GenerationTasks= -GenerationTargets= -GenerationSelections= -RevPkey=Yes -RevFkey=Yes -RevAkey=Yes -RevCheck=Yes -RevIndx=Yes -RevOpts=Yes -RevViewAsTabl=No -RevViewOpts=Yes -RevSystAsTabl=Yes -RevTablPerm=No -RevViewPerm=No -RevProcPerm=No -RevDbpkPerm=No -RevSqncPerm=No -RevAdtPerm=No -RevUserPriv=No -RevUserOpts=No -RevGrpePriv=No -RevRolePriv=No -RevDtbsOpts=Yes -RevDtbsPerm=No -RevViewIndx=Yes -RevJidxOpts=Yes -RevStats=No -RevTspcPerm=No -RevCaseSensitive=No -GenTrgrStdMsg=Yes -GenTrgrMsgTab= -GenTrgrMsgNo= -GenTrgrMsgTxt= -TrgrPreserve=No -TrgrIns=Yes -TrgrUpd=Yes -TrgrDel=Yes -TrgrC2Ins=Yes -TrgrC2Upd=Yes -TrgrC3=Yes -TrgrC4=Yes -TrgrC5=Yes -TrgrC6=Yes -TrgrC7=Yes -TrgrC8=Yes -TrgrC9=Yes -TrgrC10=Yes -TrgrC11=Yes -TrgrC1=Yes -TrgrC12Ins=Yes -TrgrC12Upd=Yes -TrgrC13=Yes -UpdateTableStatistics=Yes -UpdateColumnStatistics=Yes -DeploymentMode=REP - -[FolderOptions\Physical Objects\Database Generation] -GenScriptName=crebas -GenScriptName0= -GenScriptName1= -GenScriptName2= -GenScriptName3= -GenScriptName4= -GenScriptName5= -GenScriptName6= -GenScriptName7= -GenScriptName8= -GenScriptName9= -GenPathName= -GenSingleFile=Yes -GenODBC=No -GenCheckModel=Yes -GenScriptPrev=Yes -GenArchiveModel=No -GenUseSync=No -GenSyncChoice=0 -GenSyncArch= -GenSyncRmg=0 - -[FolderOptions\Physical Objects\Database Generation\Format] -GenScriptTitle=Yes -GenScriptNamLabl=No -GenScriptQDtbs=No -GenScriptQOwnr=Yes -GenScriptCase=0 -GenScriptEncoding=ANSI -GenScriptNAcct=No -IdentifierDelimiter=" - -[FolderOptions\Physical Objects\Database Generation\Database] -Create=Yes -Open=Yes -Close=Yes -Drop=Yes -Permission=No - -[FolderOptions\Physical Objects\Database Generation\Database\Create] -Physical Options=Yes -Header=Yes -Footer=Yes - -[FolderOptions\Physical Objects\Database Generation\Tablespace] -Create=Yes -Drop=Yes -Comment=Yes -Permission=No - -[FolderOptions\Physical Objects\Database Generation\Tablespace\Create] -Header=Yes -Footer=Yes - -[FolderOptions\Physical Objects\Database Generation\Storage] -Create=Yes -Drop=Yes -Comment=Yes - -[FolderOptions\Physical Objects\Database Generation\User] -Create=Yes -Drop=Yes -Comment=Yes -Privilege=No - -[FolderOptions\Physical Objects\Database Generation\User\Create] -Physical Options=No - -[FolderOptions\Physical Objects\Database Generation\Group] -Create=Yes -Drop=Yes -Comment=Yes -Privilege=No - -[FolderOptions\Physical Objects\Database Generation\Role] -Create=Yes -Drop=Yes -Privilege=No - -[FolderOptions\Physical Objects\Database Generation\UserDefinedDataType] -Create=Yes -Comment=Yes -Drop=Yes - -[FolderOptions\Physical Objects\Database Generation\UserDefinedDataType\Create] -Default value=Yes -Check=Yes - -[FolderOptions\Physical Objects\Database Generation\AbstractDataType] -Create=Yes -Header=Yes -Footer=Yes -Drop=Yes -Comment=Yes -Install JAVA class=Yes -Remove JAVA class=Yes -Permission=No - -[FolderOptions\Physical Objects\Database Generation\Rule] -Create=Yes -Drop=Yes -Comment=Yes - -[FolderOptions\Physical Objects\Database Generation\Default] -Create=Yes -Comment=Yes -Drop=Yes - -[FolderOptions\Physical Objects\Database Generation\Sequence] -Create=Yes -Drop=Yes -Comment=Yes -Permission=No - -[FolderOptions\Physical Objects\Database Generation\Table&&Column] - -[FolderOptions\Physical Objects\Database Generation\Table&&Column\Table] -Create=Yes -Drop=Yes -Comment=Yes -Permission=No - -[FolderOptions\Physical Objects\Database Generation\Table&&Column\Table\Create] -Check=Yes -Physical Options=Yes -Header=Yes -Footer=Yes - -[FolderOptions\Physical Objects\Database Generation\Table&&Column\Table\Create\Check] -Constraint declaration=No - -[FolderOptions\Physical Objects\Database Generation\Table&&Column\Column] -User datatype=Yes -Default value=Yes -Check=Yes -Physical Options=Yes -Comment=Yes - -[FolderOptions\Physical Objects\Database Generation\Table&&Column\Column\Check] -Constraint declaration=No - -[FolderOptions\Physical Objects\Database Generation\Table&&Column\Key] - -[FolderOptions\Physical Objects\Database Generation\Table&&Column\Key\Primary key] -Create=Yes -Drop=Yes -Comment=Yes - -[FolderOptions\Physical Objects\Database Generation\Table&&Column\Key\Primary key\Create] -Constraint declaration=No -Physical Options=Yes - -[FolderOptions\Physical Objects\Database Generation\Table&&Column\Key\Alternate key] -Create=Yes -Drop=Yes -Comment=Yes - -[FolderOptions\Physical Objects\Database Generation\Table&&Column\Key\Alternate key\Create] -Constraint declaration=No -Physical Options=Yes - -[FolderOptions\Physical Objects\Database Generation\Table&&Column\Foreign key] -Create=Yes -Drop=Yes -Comment=Yes - -[FolderOptions\Physical Objects\Database Generation\Table&&Column\Foreign key\Create] -Constraint declaration=Yes - -[FolderOptions\Physical Objects\Database Generation\Table&&Column\Index] -Create=Yes -Drop=Yes -Comment=Yes - -[FolderOptions\Physical Objects\Database Generation\Table&&Column\Index\Create] -Constraint declaration=Yes -Physical Options=Yes - -[FolderOptions\Physical Objects\Database Generation\Table&&Column\Index\Filter] -Primary key=No -Foreign key=Yes -Alternate key=No -Cluster=Yes -Other=Yes - -[FolderOptions\Physical Objects\Database Generation\Table&&Column\Trigger] -Create=Yes -Drop=Yes -Comment=Yes - -[FolderOptions\Physical Objects\Database Generation\Table&&Column\Trigger\Filter] -For insert=Yes -For update=Yes -For delete=Yes -For other=Yes - -[FolderOptions\Physical Objects\Database Generation\View] -Create=Yes -Drop=Yes -Comment=Yes -Permission=No - -[FolderOptions\Physical Objects\Database Generation\View\Create] -Force Column list=No -Physical Options=Yes -Header=Yes -Footer=Yes - -[FolderOptions\Physical Objects\Database Generation\View\ViewColumn] -Comment=Yes - -[FolderOptions\Physical Objects\Database Generation\View\ViewIndex] -Create=Yes -Drop=Yes -Comment=Yes - -[FolderOptions\Physical Objects\Database Generation\View\ViewIndex\Create] -Physical Options=Yes - -[FolderOptions\Physical Objects\Database Generation\View\ViewIndex\Filter] -Cluster=Yes -Other=Yes - -[FolderOptions\Physical Objects\Database Generation\View\Trigger] -Create=Yes -Drop=Yes -Comment=Yes - -[FolderOptions\Physical Objects\Database Generation\View\Trigger\Filter] -For insert=Yes -For update=Yes -For delete=Yes -For other=Yes - -[FolderOptions\Physical Objects\Database Generation\DBMSTrigger] -Create=Yes -Drop=Yes -Comment=Yes - -[FolderOptions\Physical Objects\Database Generation\Synonym] -Create=Yes -Drop=Yes - -[FolderOptions\Physical Objects\Database Generation\Synonym\Filter] -Table=Yes -View=Yes -Proc=Yes -Synonym=Yes -Database Package=Yes -Sequence=Yes - -[FolderOptions\Physical Objects\Database Generation\JoinIndex] -Create=Yes -Drop=Yes -Comment=Yes - -[FolderOptions\Physical Objects\Database Generation\JoinIndex\Create] -Physical Options=Yes -Header=Yes -Footer=Yes - -[FolderOptions\Physical Objects\Database Generation\Procedure] -Create=Yes -Drop=Yes -Comment=Yes -Permission=No - -[FolderOptions\Physical Objects\Database Generation\Procedure\Create] -Header=Yes -Footer=Yes - -[FolderOptions\Physical Objects\Database Generation\DatabasePackage] -Create=Yes -Drop=Yes -Permission=No - -[FolderOptions\Physical Objects\Database Generation\WebService] -Create=Yes -Drop=Yes -Comment=Yes - -[FolderOptions\Physical Objects\Database Generation\Dimension] -Create=Yes -Drop=Yes - -[FolderOptions\Physical Objects\Database Generation\Synchronization] -GenBackupTabl=1 -GenKeepBackTabl=1 -GenTmpTablDrop=No -GenKeepTablOpts=No - -[FolderOptions\Physical Objects\Database Generation\User <<Schema>>] -Create=Yes -Drop=Yes -Comment=Yes - -[FolderOptions\Physical Objects\Database Generation\User <<User>>] -Create=Yes -Drop=Yes -Comment=Yes -Privilege=No - -[FolderOptions\Physical Objects\Database Generation\ExtendedObject <<Aggregate>>] -Create=Yes -Drop=Yes - -[FolderOptions\Physical Objects\Database Generation\ExtendedObject <<Aggregate>>\ExtendedSubObject <<AggregateParameter>>] -Create=Yes - -[FolderOptions\Physical Objects\Database Generation\ExtendedObject <<Assembly>>] -Create=Yes -Drop=Yes - -[FolderOptions\Physical Objects\Database Generation\ExtendedObject <<AsymmetricKey>>] -Create=Yes -Drop=Yes - -[FolderOptions\Physical Objects\Database Generation\ExtendedObject <<Certificate>>] -Create=Yes -Drop=Yes - -[FolderOptions\Physical Objects\Database Generation\ExtendedObject <<Contract>>] -Create=Yes -Drop=Yes - -[FolderOptions\Physical Objects\Database Generation\ExtendedObject <<EndPoint>>] -Create=Yes -Drop=Yes - -[FolderOptions\Physical Objects\Database Generation\ExtendedObject <<EventNotification>>] -Create=Yes -Drop=Yes - -[FolderOptions\Physical Objects\Database Generation\ExtendedObject <<FullTextCatalog>>] -Create=Yes -Drop=Yes - -[FolderOptions\Physical Objects\Database Generation\ExtendedObject <<MessageType>>] -Create=Yes -Drop=Yes - -[FolderOptions\Physical Objects\Database Generation\ExtendedObject <<PartitionFunction>>] -Create=Yes -Drop=Yes - -[FolderOptions\Physical Objects\Database Generation\ExtendedObject <<PartitionScheme>>] -Create=Yes -Drop=Yes - -[FolderOptions\Physical Objects\Database Generation\ExtendedObject <<Queue>>] -Create=Yes -Drop=Yes - -[FolderOptions\Physical Objects\Database Generation\ExtendedObject <<RemoteServiceBinding>>] -Create=Yes -Drop=Yes - -[FolderOptions\Physical Objects\Database Generation\ExtendedObject <<ResourcePool>>] -Create=Yes -Drop=Yes - -[FolderOptions\Physical Objects\Database Generation\ExtendedObject <<Route>>] -Create=Yes -Drop=Yes - -[FolderOptions\Physical Objects\Database Generation\ExtendedObject <<Service>>] -Create=Yes -Drop=Yes - -[FolderOptions\Physical Objects\Database Generation\ExtendedObject <<SymmetricKey>>] -Create=Yes -Drop=Yes - -[FolderOptions\Physical Objects\Database Generation\ExtendedObject <<WorkloadGroup>>] -Create=Yes -Drop=Yes - -[FolderOptions\Physical Objects\Database Generation\ExtendedObject <<XMLSchemaCollection>>] -Create=Yes -Drop=Yes - -[FolderOptions\Physical Objects\Test Data] -GenDataPathName= -GenDataSinglefile=Yes -GenDataScriptName=testdata -GenDataScriptName0= -GenDataScriptName1= -GenDataScriptName2= -GenDataScriptName3= -GenDataScriptName4= -GenDataScriptName5= -GenDataScriptName6= -GenDataScriptName7= -GenDataScriptName8= -GenDataScriptName9= -GenDataOdbc=0 -GenDataDelOld=No -GenDataTitle=No -GenDataDefNumRows=20 -GenDataCommit=0 -GenDataPacket=0 -GenDataOwner=No -GenDataProfNumb= -GenDataProfChar= -GenDataProfDate= -GenDataCSVSeparator=, -GenDataFileFormat=CSV -GenDataUseWizard=No - -[FolderOptions\Pdm] -IndxIQName=%COLUMN%_%INDEXTYPE% -IndxPK=Yes -IndxFK=Yes -IndxAK=Yes -IndxPKName=%TABLE%_PK -IndxFKName=%REFR%_FK -IndxAKName=%AKEY%_AK -IndxPreserve=No -IndxThreshold=0 -IndxStats=No -RefrPreserve=No -JidxPreserve=No -RbldMultiFact=Yes -RbldMultiDim=Yes -RbldMultiJidx=Yes -CubePreserve=No -TablStProcPreserve=No -ProcDepPreserve=Yes -TrgrDepPreserve=Yes -CubeScriptPath= -CubeScriptCase=0 -CubeScriptEncoding=ANSI -CubeScriptNacct=No -CubeScriptHeader=No -CubeScriptExt=csv -CubeScriptExt0=txt -CubeScriptExt1= -CubeScriptExt2= -CubeScriptSep=, -CubeScriptDeli=" -EstimationYears=0 -DfltDomnName=D_%.U:VALUE% -DfltColnName=D_%.U:VALUE% -DfltReuse=Yes -DfltDrop=Yes -[ModelOptions] - -[ModelOptions\Physical Objects] -CaseSensitive=No -DisplayName=Yes -EnableTrans=No -UseTerm=No -EnableRequirements=No -EnableFullShortcut=Yes -SynchroCode=Yes -DefaultDttp= -IgnoreOwner=No -RebuildTrigger=Yes -RefrUnique=No -RefrAutoMigrate=Yes -RefrMigrateReuse=Yes -RefrMigrateDomain=Yes -RefrMigrateCheck=Yes -RefrMigrateRule=Yes -RefrMigrateExtd=No -RefrMigrDefaultLink=No -RefrDfltImpl=D -RefrPrgtColn=No -RefrMigrateToEnd=No -RebuildTriggerDep=No -ColnFKName=%.3:PARENT%_%COLUMN% -ColnFKNameUse=No -DomnCopyDttp=Yes -DomnCopyChck=No -DomnCopyRule=No -DomnCopyMand=No -DomnCopyExtd=No -DomnCopyProf=No -Notation=0 -DomnDefaultMandatory=No -ColnDefaultMandatory=No -TablDefaultOwner= -ViewDefaultOwner= -TrgrDefaultOwnerTabl= -TrgrDefaultOwnerView= -IdxDefaultOwnerTabl= -IdxDefaultOwnerView= -JdxDefaultOwner= -DBPackDefaultOwner= -SeqDefaultOwner= -ProcDefaultOwner= -DBMSTrgrDefaultOwner= -Currency=USD -RefrDeleteConstraint=0 -RefrUpdateConstraint=0 -RefrParentMandatory=No -RefrParentChangeAllow=Yes -RefrCheckOnCommit=No - -[ModelOptions\Physical Objects\NamingOptionsTemplates] - -[ModelOptions\Physical Objects\ClssNamingOptions] - -[ModelOptions\Physical Objects\ClssNamingOptions\PDMPCKG] - -[ModelOptions\Physical Objects\ClssNamingOptions\PDMPCKG\Name] -Template= -MaxLen=254 -Case=M -ValidChar= -InvldChar= -AllValid=Yes -NoAccent=No -DefaultChar= -Script= -ConvTable= -ConvTablePath=%_HOME%\Resource Files\Conversion Tables - -[ModelOptions\Physical Objects\ClssNamingOptions\PDMPCKG\Code] -Template= -MaxLen=254 -Case=M -ValidChar= -InvldChar= -AllValid=Yes -NoAccent=No -DefaultChar= -Script= -ConvTable= -ConvTablePath=%_HOME%\Resource Files\Conversion Tables - -[ModelOptions\Physical Objects\ClssNamingOptions\PDMDOMN] - -[ModelOptions\Physical Objects\ClssNamingOptions\PDMDOMN\Name] -Template= -MaxLen=254 -Case=M -ValidChar= -InvldChar= -AllValid=Yes -NoAccent=No -DefaultChar= -Script= -ConvTable= -ConvTablePath=%_HOME%\Resource Files\Conversion Tables - -[ModelOptions\Physical Objects\ClssNamingOptions\PDMDOMN\Code] -Template= -MaxLen=128 -Case=M -ValidChar= -InvldChar= -AllValid=Yes -NoAccent=No -DefaultChar= -Script= -ConvTable= -ConvTablePath=%_HOME%\Resource Files\Conversion Tables - -[ModelOptions\Physical Objects\ClssNamingOptions\TABL] - -[ModelOptions\Physical Objects\ClssNamingOptions\TABL\Name] -Template= -MaxLen=254 -Case=M -ValidChar= -InvldChar= -AllValid=Yes -NoAccent=No -DefaultChar= -Script= -ConvTable= -ConvTablePath=%_HOME%\Resource Files\Conversion Tables - -[ModelOptions\Physical Objects\ClssNamingOptions\TABL\Code] -Template= -MaxLen=128 -Case=M -ValidChar= -InvldChar= -AllValid=Yes -NoAccent=No -DefaultChar= -Script= -ConvTable= -ConvTablePath=%_HOME%\Resource Files\Conversion Tables - -[ModelOptions\Physical Objects\ClssNamingOptions\COLN] - -[ModelOptions\Physical Objects\ClssNamingOptions\COLN\Name] -Template= -MaxLen=254 -Case=M -ValidChar= -InvldChar= -AllValid=Yes -NoAccent=No -DefaultChar= -Script= -ConvTable= -ConvTablePath=%_HOME%\Resource Files\Conversion Tables - -[ModelOptions\Physical Objects\ClssNamingOptions\COLN\Code] -Template= -MaxLen=128 -Case=M -ValidChar= -InvldChar= -AllValid=Yes -NoAccent=No -DefaultChar= -Script= -ConvTable= -ConvTablePath=%_HOME%\Resource Files\Conversion Tables - -[ModelOptions\Physical Objects\ClssNamingOptions\INDX] - -[ModelOptions\Physical Objects\ClssNamingOptions\INDX\Name] -Template= -MaxLen=254 -Case=M -ValidChar= -InvldChar= -AllValid=Yes -NoAccent=No -DefaultChar= -Script= -ConvTable= -ConvTablePath=%_HOME%\Resource Files\Conversion Tables - -[ModelOptions\Physical Objects\ClssNamingOptions\INDX\Code] -Template= -MaxLen=254 -Case=M -ValidChar= -InvldChar= -AllValid=Yes -NoAccent=No -DefaultChar= -Script= -ConvTable= -ConvTablePath=%_HOME%\Resource Files\Conversion Tables - -[ModelOptions\Physical Objects\ClssNamingOptions\REFR] - -[ModelOptions\Physical Objects\ClssNamingOptions\REFR\Name] -Template= -MaxLen=254 -Case=M -ValidChar= -InvldChar= -AllValid=Yes -NoAccent=No -DefaultChar= -Script= -ConvTable= -ConvTablePath=%_HOME%\Resource Files\Conversion Tables - -[ModelOptions\Physical Objects\ClssNamingOptions\REFR\Code] -Template= -MaxLen=254 -Case=M -ValidChar= -InvldChar= -AllValid=Yes -NoAccent=No -DefaultChar= -Script= -ConvTable= -ConvTablePath=%_HOME%\Resource Files\Conversion Tables - -[ModelOptions\Physical Objects\ClssNamingOptions\VREF] - -[ModelOptions\Physical Objects\ClssNamingOptions\VREF\Name] -Template= -MaxLen=254 -Case=M -ValidChar= -InvldChar= -AllValid=Yes -NoAccent=No -DefaultChar= -Script= -ConvTable= -ConvTablePath=%_HOME%\Resource Files\Conversion Tables - -[ModelOptions\Physical Objects\ClssNamingOptions\VREF\Code] -Template= -MaxLen=254 -Case=M -ValidChar= -InvldChar= -AllValid=Yes -NoAccent=No -DefaultChar= -Script= -ConvTable= -ConvTablePath=%_HOME%\Resource Files\Conversion Tables - -[ModelOptions\Physical Objects\ClssNamingOptions\VIEW] - -[ModelOptions\Physical Objects\ClssNamingOptions\VIEW\Name] -Template= -MaxLen=254 -Case=M -ValidChar= -InvldChar= -AllValid=Yes -NoAccent=No -DefaultChar= -Script= -ConvTable= -ConvTablePath=%_HOME%\Resource Files\Conversion Tables - -[ModelOptions\Physical Objects\ClssNamingOptions\VIEW\Code] -Template= -MaxLen=128 -Case=M -ValidChar= -InvldChar= -AllValid=Yes -NoAccent=No -DefaultChar= -Script= -ConvTable= -ConvTablePath=%_HOME%\Resource Files\Conversion Tables - -[ModelOptions\Physical Objects\ClssNamingOptions\VIEWC] - -[ModelOptions\Physical Objects\ClssNamingOptions\VIEWC\Name] -Template= -MaxLen=254 -Case=M -ValidChar= -InvldChar= -AllValid=Yes -NoAccent=No -DefaultChar= -Script= -ConvTable= -ConvTablePath=%_HOME%\Resource Files\Conversion Tables - -[ModelOptions\Physical Objects\ClssNamingOptions\VIEWC\Code] -Template= -MaxLen=254 -Case=M -ValidChar= -InvldChar= -AllValid=Yes -NoAccent=No -DefaultChar= -Script= -ConvTable= -ConvTablePath=%_HOME%\Resource Files\Conversion Tables - -[ModelOptions\Physical Objects\ClssNamingOptions\WEBSERV] - -[ModelOptions\Physical Objects\ClssNamingOptions\WEBSERV\Name] -Template= -MaxLen=254 -Case=M -ValidChar= -InvldChar= -AllValid=Yes -NoAccent=No -DefaultChar= -Script= -ConvTable= -ConvTablePath=%_HOME%\Resource Files\Conversion Tables - -[ModelOptions\Physical Objects\ClssNamingOptions\WEBSERV\Code] -Template= -MaxLen=254 -Case=M -ValidChar='a'-'z','A'-'Z','0'-'9',"/-_.!~*'()" -InvldChar= -AllValid=Yes -NoAccent=No -DefaultChar= -Script= -ConvTable= -ConvTablePath=%_HOME%\Resource Files\Conversion Tables - -[ModelOptions\Physical Objects\ClssNamingOptions\WEBOP] - -[ModelOptions\Physical Objects\ClssNamingOptions\WEBOP\Name] -Template= -MaxLen=254 -Case=M -ValidChar= -InvldChar= -AllValid=Yes -NoAccent=No -DefaultChar= -Script= -ConvTable= -ConvTablePath=%_HOME%\Resource Files\Conversion Tables - -[ModelOptions\Physical Objects\ClssNamingOptions\WEBOP\Code] -Template= -MaxLen=254 -Case=M -ValidChar='a'-'z','A'-'Z','0'-'9',"/-_.!~*'()" -InvldChar= -AllValid=Yes -NoAccent=No -DefaultChar= -Script= -ConvTable= -ConvTablePath=%_HOME%\Resource Files\Conversion Tables - -[ModelOptions\Physical Objects\ClssNamingOptions\WPARAM] - -[ModelOptions\Physical Objects\ClssNamingOptions\WPARAM\Name] -Template= -MaxLen=254 -Case=M -ValidChar= -InvldChar= -AllValid=Yes -NoAccent=No -DefaultChar= -Script= -ConvTable= -ConvTablePath=%_HOME%\Resource Files\Conversion Tables - -[ModelOptions\Physical Objects\ClssNamingOptions\WPARAM\Code] -Template= -MaxLen=254 -Case=M -ValidChar= -InvldChar= -AllValid=Yes -NoAccent=No -DefaultChar= -Script= -ConvTable= -ConvTablePath=%_HOME%\Resource Files\Conversion Tables - -[ModelOptions\Physical Objects\ClssNamingOptions\FACT] - -[ModelOptions\Physical Objects\ClssNamingOptions\FACT\Name] -Template= -MaxLen=254 -Case=M -ValidChar= -InvldChar= -AllValid=Yes -NoAccent=No -DefaultChar= -Script= -ConvTable= -ConvTablePath=%_HOME%\Resource Files\Conversion Tables - -[ModelOptions\Physical Objects\ClssNamingOptions\FACT\Code] -Template= -MaxLen=254 -Case=M -ValidChar= -InvldChar= -AllValid=Yes -NoAccent=No -DefaultChar= -Script= -ConvTable= -ConvTablePath=%_HOME%\Resource Files\Conversion Tables - -[ModelOptions\Physical Objects\ClssNamingOptions\DIMN] - -[ModelOptions\Physical Objects\ClssNamingOptions\DIMN\Name] -Template= -MaxLen=254 -Case=M -ValidChar= -InvldChar= -AllValid=Yes -NoAccent=No -DefaultChar= -Script= -ConvTable= -ConvTablePath=%_HOME%\Resource Files\Conversion Tables - -[ModelOptions\Physical Objects\ClssNamingOptions\DIMN\Code] -Template= -MaxLen=254 -Case=M -ValidChar= -InvldChar= -AllValid=Yes -NoAccent=No -DefaultChar= -Script= -ConvTable= -ConvTablePath=%_HOME%\Resource Files\Conversion Tables - -[ModelOptions\Physical Objects\ClssNamingOptions\MEAS] - -[ModelOptions\Physical Objects\ClssNamingOptions\MEAS\Name] -Template= -MaxLen=254 -Case=M -ValidChar= -InvldChar= -AllValid=Yes -NoAccent=No -DefaultChar= -Script= -ConvTable= -ConvTablePath=%_HOME%\Resource Files\Conversion Tables - -[ModelOptions\Physical Objects\ClssNamingOptions\MEAS\Code] -Template= -MaxLen=254 -Case=M -ValidChar= -InvldChar= -AllValid=Yes -NoAccent=No -DefaultChar= -Script= -ConvTable= -ConvTablePath=%_HOME%\Resource Files\Conversion Tables - -[ModelOptions\Physical Objects\ClssNamingOptions\DATTR] - -[ModelOptions\Physical Objects\ClssNamingOptions\DATTR\Name] -Template= -MaxLen=254 -Case=M -ValidChar= -InvldChar= -AllValid=Yes -NoAccent=No -DefaultChar= -Script= -ConvTable= -ConvTablePath=%_HOME%\Resource Files\Conversion Tables - -[ModelOptions\Physical Objects\ClssNamingOptions\DATTR\Code] -Template= -MaxLen=254 -Case=M -ValidChar= -InvldChar= -AllValid=Yes -NoAccent=No -DefaultChar= -Script= -ConvTable= -ConvTablePath=%_HOME%\Resource Files\Conversion Tables - -[ModelOptions\Physical Objects\ClssNamingOptions\FILO] - -[ModelOptions\Physical Objects\ClssNamingOptions\FILO\Name] -Template= -MaxLen=254 -Case=M -ValidChar= -InvldChar= -AllValid=Yes -NoAccent=No -DefaultChar= -Script= -ConvTable= -ConvTablePath=%_HOME%\Resource Files\Conversion Tables - -[ModelOptions\Physical Objects\ClssNamingOptions\FILO\Code] -Template= -MaxLen=254 -Case=M -ValidChar= -InvldChar= -AllValid=Yes -NoAccent=No -DefaultChar= -Script= -ConvTable= -ConvTablePath=%_HOME%\Resource Files\Conversion Tables - -[ModelOptions\Physical Objects\ClssNamingOptions\FRMEOBJ] - -[ModelOptions\Physical Objects\ClssNamingOptions\FRMEOBJ\Name] -Template= -MaxLen=254 -Case=M -ValidChar= -InvldChar= -AllValid=Yes -NoAccent=No -DefaultChar= -Script= -ConvTable= -ConvTablePath=%_HOME%\Resource Files\Conversion Tables - -[ModelOptions\Physical Objects\ClssNamingOptions\FRMEOBJ\Code] -Template= -MaxLen=254 -Case=M -ValidChar= -InvldChar= -AllValid=Yes -NoAccent=No -DefaultChar= -Script= -ConvTable= -ConvTablePath=%_HOME%\Resource Files\Conversion Tables - -[ModelOptions\Physical Objects\ClssNamingOptions\FRMELNK] - -[ModelOptions\Physical Objects\ClssNamingOptions\FRMELNK\Name] -Template= -MaxLen=254 -Case=M -ValidChar= -InvldChar= -AllValid=Yes -NoAccent=No -DefaultChar= -Script= -ConvTable= -ConvTablePath=%_HOME%\Resource Files\Conversion Tables - -[ModelOptions\Physical Objects\ClssNamingOptions\FRMELNK\Code] -Template= -MaxLen=254 -Case=M -ValidChar= -InvldChar= -AllValid=Yes -NoAccent=No -DefaultChar= -Script= -ConvTable= -ConvTablePath=%_HOME%\Resource Files\Conversion Tables - -[ModelOptions\Physical Objects\ClssNamingOptions\AREA] - -[ModelOptions\Physical Objects\ClssNamingOptions\AREA\Name] -Template= -MaxLen=254 -Case=M -ValidChar= -InvldChar= -AllValid=Yes -NoAccent=No -DefaultChar= -Script= -ConvTable= -ConvTablePath=%_HOME%\Resource Files\Conversion Tables - -[ModelOptions\Physical Objects\ClssNamingOptions\AREA\Code] -Template= -MaxLen=254 -Case=M -ValidChar= -InvldChar= -AllValid=Yes -NoAccent=No -DefaultChar= -Script= -ConvTable= -ConvTablePath=%_HOME%\Resource Files\Conversion Tables - -[ModelOptions\Physical Objects\ClssNamingOptions\DefaultClass] - -[ModelOptions\Physical Objects\ClssNamingOptions\DefaultClass\Name] -Template= -MaxLen=254 -Case=M -ValidChar= -InvldChar= -AllValid=Yes -NoAccent=No -DefaultChar= -Script= -ConvTable= -ConvTablePath=%_HOME%\Resource Files\Conversion Tables - -[ModelOptions\Physical Objects\ClssNamingOptions\DefaultClass\Code] -Template= -MaxLen=254 -Case=M -ValidChar= -InvldChar= -AllValid=Yes -NoAccent=No -DefaultChar= -Script= -ConvTable= -ConvTablePath=%_HOME%\Resource Files\Conversion Tables - -[ModelOptions\Connection] - -[ModelOptions\Pdm] - -[ModelOptions\Generate] - -[ModelOptions\Generate\Xsm] -GenRootElement=Yes -GenComplexType=No -GenAttribute=Yes -CheckModel=Yes -SaveLinks=Yes -ORMapping=No -NameToCode=No - -[ModelOptions\Generate\Pdm] -RRMapping=No - -[ModelOptions\Generate\Cdm] -CheckModel=Yes -SaveLinks=Yes -NameToCode=No -Notation=2 - -[ModelOptions\Generate\Oom] -CheckModel=Yes -SaveLinks=Yes -ORMapping=No -NameToCode=Yes -ClassPrefix= - -[ModelOptions\Generate\Ldm] -CheckModel=Yes -SaveLinks=Yes -NameToCode=No - -[ModelOptions\Default Opts] - -[ModelOptions\Default Opts\TABL] -PhysOpts= - -[ModelOptions\Default Opts\COLN] -PhysOpts= - -[ModelOptions\Default Opts\INDX] -PhysOpts= - -[ModelOptions\Default Opts\AKEY] -PhysOpts= - -[ModelOptions\Default Opts\PKEY] -PhysOpts= - -[ModelOptions\Default Opts\STOR] -PhysOpts= - -[ModelOptions\Default Opts\TSPC] -PhysOpts= - -[ModelOptions\Default Opts\SQNC] -PhysOpts= - -[ModelOptions\Default Opts\DTBS] -PhysOpts= - -[ModelOptions\Default Opts\USER] -PhysOpts= - -[ModelOptions\Default Opts\JIDX] -PhysOpts= - -[ModelOptions\Default Opts\FRMEOBJ<<ResourcePool>>] -PhysOpts= - -[ModelOptions\Default Opts\FRMEOBJ<<WorkloadGroup>>] -PhysOpts= - -[ModelOptions\Default Opts\FRMESOB<<ResourcePool>>] -PhysOpts= - -[ModelOptions\Default Opts\FRMESOB<<WorkloadGroup>>] -PhysOpts= -D:\Util\util-v5\test\Util.Data.EntityFrameworkCore.SqlServer.Tests\Document\PowerDesigner\Util_Data_EF_Test_SqlServer.pdm - - -A3B2D737-907D-4CA0-A2C1-04B156933B64 -Microsoft SQL Server 2014 -MSSQLSRV2014 -1621773500 -Xiadao -1621773500 -Xiadao - -49106F9E-F946-45DB-871A-64C75D3FA370 -4BA9F647-DAB1-11D1-9944-006097355D9B - - - - -C56CB1A6-55BD-4ED3-A5CA-5072B8B00F10 -main -main -1621773501 -Xiadao -1628408459 -Xiadao -[DisplayPreferences] - -[DisplayPreferences\PDM] - -[DisplayPreferences\General] -Adjust to text=Yes -Snap Grid=No -Constrain Labels=Yes -Display Grid=No -Show Page Delimiter=Yes -Show Links intersections=Yes -Activate automatic link routing=Yes -Grid size=800 -Graphic unit=2 -Window color=255 255 255 -Background image= -Background mode=8 -Watermark image= -Watermark mode=8 -Show watermark on screen=No -Gradient mode=0 -Gradient end color=255 255 255 -Show Swimlane=No -SwimlaneVert=Yes -TreeVert=No -CompDark=0 - -[DisplayPreferences\Object] -Show Icon=No -Mode=2 -Trunc Length=40 -Word Length=40 -Word Text=!"#$%&')*+,-./:;=>?@\]^_`|}~ -Shortcut IntIcon=Yes -Shortcut IntLoct=Yes -Shortcut IntFullPath=No -Shortcut IntLastPackage=Yes -Shortcut ExtIcon=Yes -Shortcut ExtLoct=No -Shortcut ExtFullPath=No -Shortcut ExtLastPackage=Yes -Shortcut ExtIncludeModl=Yes -Area.IconPicture=Yes -Area.Stereotype=Yes -Area.Comment=No -Area.TextStyle=No -Area.SubSymbols=Yes -Area_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Architecture Area Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <Separator Name="Separator" />[CRLF] <StandardAttribute Name="Comment" Attribute="Comment" Prefix="" Suffix="" Alignment="LEFT" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -EObjShowStrn=Yes -ExtendedObject.Comment=No -ExtendedObject.IconPicture=No -ExtendedObject.TextStyle=No -ExtendedObject_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Object Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <Separator Name="Separator" />[CRLF] <StandardAttribute Name="Comment" Attribute="Comment" Prefix="" Suffix="" Alignment="LEFT" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -ELnkShowStrn=Yes -ELnkShowName=Yes -ExtendedLink_SymbolLayout=<Form>[CRLF] <Form Name="Center" >[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] </Form>[CRLF] <Form Name="Source" >[CRLF] </Form>[CRLF] <Form Name="Destination" >[CRLF] </Form>[CRLF]</Form> -ExtDpdShowStrn=Yes -ExtendedDependency_SymbolLayout=<Form>[CRLF] <Form Name="Center" >[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Caption="" Mandatory="No" />[CRLF] </Form>[CRLF] <Form Name="Source" >[CRLF] </Form>[CRLF] <Form Name="Destination" >[CRLF] </Form>[CRLF]</Form> -FileObject.Stereotype=No -FileObject.DisplayName=Yes -FileObject.LocationOrName=No -FileObject.IconPicture=No -FileObject.TextStyle=No -FileObject.IconMode=Yes -FileObject_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <ExclusiveChoice Name="Exclusive Choice" Mandatory="Yes" Display="HorizontalRadios" >[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Location" Attribute="LocationOrName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] </ExclusiveChoice>[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -Package.Stereotype=Yes -Package.Comment=No -Package.IconPicture=No -Package.TextStyle=No -Package_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <Separator Name="Separator" />[CRLF] <StandardAttribute Name="Comment" Attribute="Comment" Prefix="" Suffix="" Alignment="LEFT" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -Display Model Version=Yes -Table.Stereotype=Yes -Table.DisplayName=Yes -Table.OwnerDisplayName=No -Table.Columns=Yes -Table.Columns._Filter="All Columns" PDMCOLNALL -Table.Columns._Columns=Stereotype DataType KeyIndicator -Table.Columns._Limit=-5 -Table.Keys=No -Table.Keys._Columns=Stereotype Indicator -Table.Indexes=No -Table.Indexes._Columns=Stereotype -Table.Triggers=No -Table.Triggers._Columns=Stereotype -Table.Comment=No -Table.IconPicture=No -Table.TextStyle=No -Table_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <ExclusiveChoice Name="Exclusive Choice" Mandatory="Yes" Display="HorizontalRadios" >[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Owner and Name" Attribute="OwnerDisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] </ExclusiveChoice>[CRLF] <Separator Name="Separator" />[CRLF] <StandardCollection Name="Columns" Collection="Columns" Columns="Stereotype No\r\nDisplayName Yes\r\nDataType No\r\nSymbolDataType No &quot;Domain or Data type&quot;\r\nDomain No\r\nKeyIndicator No\r\nIndexIndicator No\r\nNullStatus No" Filters="&quot;All Columns&quot; PDMCOLNALL &quot;&quot;\r\n&quot;PK Columns&quot; PDMCOLNPK &quot;\&quot;PRIM \&quot;TRUE\&quot; TRUE\&quot;&quot;\r\n&quot;Key Columns&quot; PDMCOLNKEY &quot;\&quot;KEYS \&quot;TRUE\&quot; TRUE\&quot;&quot;" HasLimit="Yes" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardCollection Name="Keys" Collection="Keys" Columns="Stereotype No\r\nDisplayName Yes\r\nIndicator No" HasLimit="No" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardCollection Name="Indexes" Collection="Indexes" Columns="Stereotype No\r\nDisplayName Yes\r\nIndicator No" HasLimit="No" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardCollection Name="Triggers" Collection="Triggers" Columns="Stereotype No\r\nDisplayName Yes" HasLimit="No" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Comment" Attribute="Comment" Prefix="" Suffix="" Alignment="LEFT" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -View.Stereotype=Yes -View.DisplayName=Yes -View.OwnerDisplayName=No -View.Columns=Yes -View.Columns._Columns=DisplayName -View.Columns._Limit=-5 -View.TemporaryVTables=Yes -View.Indexes=No -View.Comment=No -View.IconPicture=No -View.TextStyle=No -View_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <ExclusiveChoice Name="Exclusive Choice" Mandatory="Yes" Display="HorizontalRadios" >[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Owner and Name" Attribute="OwnerDisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] </ExclusiveChoice>[CRLF] <Separator Name="Separator" />[CRLF] <StandardCollection Name="Columns" Collection="Columns" Columns="DisplayName No\r\nExpression No\r\nDataType No\r\nSymbolDataType No &quot;Domain or Data type&quot;\r\nIndexIndicator No" HasLimit="Yes" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardCollection Name="Tables" Collection="TemporaryVTables" Columns="Name Yes" HasLimit="No" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardCollection Name="Indexes" Collection="Indexes" Columns="DisplayName Yes" HasLimit="No" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Comment" Attribute="Comment" Prefix="" Suffix="" Alignment="LEFT" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -Procedure.Stereotype=No -Procedure.DisplayName=Yes -Procedure.OwnerDisplayName=No -Procedure.Comment=No -Procedure.IconPicture=No -Procedure.TextStyle=No -Procedure_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <ExclusiveChoice Name="Exclusive Choice" Mandatory="Yes" Display="HorizontalRadios" >[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Owner and Name" Attribute="OwnerDisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] </ExclusiveChoice>[CRLF] <Separator Name="Separator" />[CRLF] <StandardAttribute Name="Comment" Attribute="Comment" Prefix="" Suffix="" Alignment="LEFT" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -Reference.Cardinality=No -Reference.ImplementationType=No -Reference.ChildRole=Yes -Reference.Stereotype=Yes -Reference.DisplayName=No -Reference.ForeignKeyConstraintName=No -Reference.JoinExpression=No -Reference.Integrity=No -Reference.ParentRole=Yes -Reference_SymbolLayout=<Form>[CRLF] <Form Name="Source" >[CRLF] <StandardAttribute Name="Cardinality" Attribute="Cardinality" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Implementation" Attribute="ImplementationType" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Child Role" Attribute="ChildRole" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] </Form>[CRLF] <Form Name="Center" >[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Caption="" Mandatory="No" />[CRLF] <ExclusiveChoice Name="Exclusive Choice" Mandatory="No" Display="HorizontalRadios" >[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Cons&amp;traint Name" Attribute="ForeignKeyConstraintName" Prefix="" Suffix="" Caption="Cons&amp;traint Name" Mandatory="No" />[CRLF] <StandardAttribute Name="Join" Attribute="JoinExpression" Prefix="" Suffix="" Caption="Join" Mandatory="No" />[CRLF] </ExclusiveChoice>[CRLF] <StandardAttribute Name="Referential integrity" Attribute="Integrity" Prefix="" Suffix="" Caption="Referential integrity" Mandatory="No" />[CRLF] </Form>[CRLF] <Form Name="Destination" >[CRLF] <StandardAttribute Name="Parent Role" Attribute="ParentRole" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] </Form>[CRLF]</Form> -ViewReference.ChildRole=Yes -ViewReference.Stereotype=Yes -ViewReference.DisplayName=No -ViewReference.JoinExpression=No -ViewReference.ParentRole=Yes -ViewReference_SymbolLayout=<Form>[CRLF] <Form Name="Source" >[CRLF] <StandardAttribute Name="Child Role" Attribute="ChildRole" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] </Form>[CRLF] <Form Name="Center" >[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Caption="" Mandatory="No" />[CRLF] <ExclusiveChoice Name="Exclusive Choice" Mandatory="No" Display="HorizontalRadios" >[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Join Expression" Attribute="JoinExpression" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] </ExclusiveChoice>[CRLF] </Form>[CRLF] <Form Name="Destination" >[CRLF] <StandardAttribute Name="Parent Role" Attribute="ParentRole" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] </Form>[CRLF]</Form> - -[DisplayPreferences\Symbol] - -[DisplayPreferences\Symbol\AREA] -STRNFont=新宋体,8,N -STRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -LABLFont=新宋体,8,N -LABLFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=9600 -Height=8000 -Brush color=253 249 234 -Fill Color=Yes -Brush style=6 -Brush bitmap mode=12 -Brush gradient mode=16 -Brush gradient color=245 230 173 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 121 98 6 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\FRMEOBJ] -STRNFont=新宋体,8,N -STRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -LABLFont=新宋体,8,N -LABLFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=6000 -Height=2000 -Brush color=255 255 255 -Fill Color=Yes -Brush style=6 -Brush bitmap mode=12 -Brush gradient mode=64 -Brush gradient color=192 192 192 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 255 128 128 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\FRMELNK] -CENTERFont=新宋体,8,N -CENTERFont color=0 0 0 -Line style=1 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Brush color=255 255 255 -Fill Color=Yes -Brush style=1 -Brush bitmap mode=12 -Brush gradient mode=0 -Brush gradient color=118 118 118 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 128 128 255 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\USRDEPD] -CENTERFont=新宋体,8,N -CENTERFont color=0 0 0 -Line style=1 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Brush color=255 255 255 -Fill Color=Yes -Brush style=1 -Brush bitmap mode=12 -Brush gradient mode=0 -Brush gradient color=118 118 118 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=2 0 128 128 255 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\FILO] -OBJSTRNFont=新宋体,8,N -OBJSTRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -LCNMFont=新宋体,8,N -LCNMFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=4800 -Height=3600 -Brush color=255 255 255 -Fill Color=Yes -Brush style=1 -Brush bitmap mode=12 -Brush gradient mode=0 -Brush gradient color=118 118 118 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 0 0 255 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\PDMPCKG] -STRNFont=新宋体,8,N -STRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -LABLFont=新宋体,8,N -LABLFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=4800 -Height=4000 -Brush color=255 255 192 -Fill Color=Yes -Brush style=6 -Brush bitmap mode=12 -Brush gradient mode=65 -Brush gradient color=255 255 255 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 178 178 178 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\TABL] -STRNFont=新宋体,8,N -STRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -OWNRDISPNAMEFont=新宋体,8,N -OWNRDISPNAMEFont color=0 0 0 -ColumnsFont=新宋体,8,N -ColumnsFont color=0 0 0 -TablePkColumnsFont=新宋体,8,U -TablePkColumnsFont color=0 0 0 -TableFkColumnsFont=新宋体,8,N -TableFkColumnsFont color=0 0 0 -KeysFont=新宋体,8,N -KeysFont color=0 0 0 -IndexesFont=新宋体,8,N -IndexesFont color=0 0 0 -TriggersFont=新宋体,8,N -TriggersFont color=0 0 0 -LABLFont=新宋体,8,N -LABLFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=4800 -Height=4000 -Brush color=178 214 252 -Fill Color=Yes -Brush style=6 -Brush bitmap mode=12 -Brush gradient mode=65 -Brush gradient color=255 255 255 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 0 128 192 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\VIEW] -STRNFont=新宋体,8,N -STRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -OWNRDISPNAMEFont=新宋体,8,N -OWNRDISPNAMEFont color=0 0 0 -ColumnsFont=新宋体,8,N -ColumnsFont color=0 0 0 -TablePkColumnsFont=新宋体,8,U -TablePkColumnsFont color=0 0 0 -TableFkColumnsFont=新宋体,8,N -TableFkColumnsFont color=0 0 0 -TemporaryVTablesFont=新宋体,8,N -TemporaryVTablesFont color=0 0 0 -IndexesFont=新宋体,8,N -IndexesFont color=0 0 0 -LABLFont=新宋体,8,N -LABLFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=4800 -Height=4000 -Brush color=208 208 255 -Fill Color=Yes -Brush style=6 -Brush bitmap mode=12 -Brush gradient mode=65 -Brush gradient color=255 255 255 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 128 128 192 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\PROC] -STRNFont=新宋体,8,N -STRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -OWNRDISPNAMEFont=新宋体,8,N -OWNRDISPNAMEFont color=0 0 0 -LABLFont=新宋体,8,N -LABLFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=4000 -Height=1000 -Brush color=255 255 192 -Fill Color=Yes -Brush style=6 -Brush bitmap mode=12 -Brush gradient mode=65 -Brush gradient color=255 255 255 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 128 108 0 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\REFR] -SOURCEFont=新宋体,8,N -SOURCEFont color=0 0 0 -CENTERFont=新宋体,8,N -CENTERFont color=0 0 0 -DESTINATIONFont=新宋体,8,N -DESTINATIONFont color=0 0 0 -Line style=1 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Brush color=255 255 255 -Fill Color=Yes -Brush style=1 -Brush bitmap mode=12 -Brush gradient mode=0 -Brush gradient color=118 118 118 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 0 128 192 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\VREF] -SOURCEFont=新宋体,8,N -SOURCEFont color=0 0 0 -CENTERFont=新宋体,8,N -CENTERFont color=0 0 0 -DESTINATIONFont=新宋体,8,N -DESTINATIONFont color=0 0 0 -Line style=1 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Brush color=255 255 255 -Fill Color=Yes -Brush style=1 -Brush bitmap mode=12 -Brush gradient mode=0 -Brush gradient color=118 118 118 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 128 128 192 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\Free Symbol] -Free TextFont=新宋体,8,N -Free TextFont color=0 0 0 -Line style=0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Brush color=255 255 255 -Fill Color=Yes -Brush style=1 -Brush bitmap mode=12 -Brush gradient mode=0 -Brush gradient color=118 118 118 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 0 0 255 -Shadow color=192 192 192 -Shadow=0 -(8268, 11693) -((315,354), (433,354)) -1 -15 - - - - -5B174033-3747-4F4B-AC04-DF359F148251 -01-系统 -01-系统 -1628409272 -Xiadao -1629975739 -Xiadao - - -A446ED61-03A1-4E6B-A725-E0FB09EC3A5F -01-日志 -01-日志 -1628409272 -Xiadao -1629975739 -Xiadao -[DisplayPreferences] - -[DisplayPreferences\PDM] - -[DisplayPreferences\General] -Adjust to text=Yes -Snap Grid=No -Constrain Labels=Yes -Display Grid=No -Show Page Delimiter=Yes -Show Links intersections=Yes -Activate automatic link routing=Yes -Grid size=800 -Graphic unit=2 -Window color=255 255 255 -Background image= -Background mode=8 -Watermark image= -Watermark mode=8 -Show watermark on screen=No -Gradient mode=0 -Gradient end color=255 255 255 -Show Swimlane=No -SwimlaneVert=Yes -TreeVert=No -CompDark=0 - -[DisplayPreferences\Object] -Show Icon=No -Mode=2 -Trunc Length=40 -Word Length=40 -Word Text=!"#$%&')*+,-./:;=>?@\]^_`|}~ -Shortcut IntIcon=Yes -Shortcut IntLoct=Yes -Shortcut IntFullPath=No -Shortcut IntLastPackage=Yes -Shortcut ExtIcon=Yes -Shortcut ExtLoct=No -Shortcut ExtFullPath=No -Shortcut ExtLastPackage=Yes -Shortcut ExtIncludeModl=Yes -Area.IconPicture=Yes -Area.Stereotype=Yes -Area.Comment=No -Area.TextStyle=No -Area.SubSymbols=Yes -Area_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Architecture Area Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <Separator Name="Separator" />[CRLF] <StandardAttribute Name="Comment" Attribute="Comment" Prefix="" Suffix="" Alignment="LEFT" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -EObjShowStrn=Yes -ExtendedObject.Comment=No -ExtendedObject.IconPicture=No -ExtendedObject.TextStyle=No -ExtendedObject_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Object Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <Separator Name="Separator" />[CRLF] <StandardAttribute Name="Comment" Attribute="Comment" Prefix="" Suffix="" Alignment="LEFT" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -ELnkShowStrn=Yes -ELnkShowName=Yes -ExtendedLink_SymbolLayout=<Form>[CRLF] <Form Name="Center" >[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] </Form>[CRLF] <Form Name="Source" >[CRLF] </Form>[CRLF] <Form Name="Destination" >[CRLF] </Form>[CRLF]</Form> -ExtDpdShowStrn=Yes -ExtendedDependency_SymbolLayout=<Form>[CRLF] <Form Name="Center" >[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Caption="" Mandatory="No" />[CRLF] </Form>[CRLF] <Form Name="Source" >[CRLF] </Form>[CRLF] <Form Name="Destination" >[CRLF] </Form>[CRLF]</Form> -FileObject.Stereotype=No -FileObject.DisplayName=Yes -FileObject.LocationOrName=No -FileObject.IconPicture=No -FileObject.TextStyle=No -FileObject.IconMode=Yes -FileObject_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <ExclusiveChoice Name="Exclusive Choice" Mandatory="Yes" Display="HorizontalRadios" >[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Location" Attribute="LocationOrName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] </ExclusiveChoice>[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -Package.Stereotype=Yes -Package.Comment=No -Package.IconPicture=No -Package.TextStyle=No -Package_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <Separator Name="Separator" />[CRLF] <StandardAttribute Name="Comment" Attribute="Comment" Prefix="" Suffix="" Alignment="LEFT" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -Display Model Version=Yes -Table.Stereotype=Yes -Table.DisplayName=Yes -Table.OwnerDisplayName=No -Table.Columns=Yes -Table.Columns._Filter="All Columns" PDMCOLNALL -Table.Columns._Columns=Stereotype DataType KeyIndicator -Table.Columns._Limit=-5 -Table.Keys=No -Table.Keys._Columns=Stereotype Indicator -Table.Indexes=No -Table.Indexes._Columns=Stereotype -Table.Triggers=No -Table.Triggers._Columns=Stereotype -Table.Comment=No -Table.IconPicture=No -Table.TextStyle=No -Table_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <ExclusiveChoice Name="Exclusive Choice" Mandatory="Yes" Display="HorizontalRadios" >[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Owner and Name" Attribute="OwnerDisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] </ExclusiveChoice>[CRLF] <Separator Name="Separator" />[CRLF] <StandardCollection Name="Columns" Collection="Columns" Columns="Stereotype No\r\nDisplayName Yes\r\nDataType No\r\nSymbolDataType No &quot;Domain or Data type&quot;\r\nDomain No\r\nKeyIndicator No\r\nIndexIndicator No\r\nNullStatus No" Filters="&quot;All Columns&quot; PDMCOLNALL &quot;&quot;\r\n&quot;PK Columns&quot; PDMCOLNPK &quot;\&quot;PRIM \&quot;TRUE\&quot; TRUE\&quot;&quot;\r\n&quot;Key Columns&quot; PDMCOLNKEY &quot;\&quot;KEYS \&quot;TRUE\&quot; TRUE\&quot;&quot;" HasLimit="Yes" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardCollection Name="Keys" Collection="Keys" Columns="Stereotype No\r\nDisplayName Yes\r\nIndicator No" HasLimit="No" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardCollection Name="Indexes" Collection="Indexes" Columns="Stereotype No\r\nDisplayName Yes\r\nIndicator No" HasLimit="No" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardCollection Name="Triggers" Collection="Triggers" Columns="Stereotype No\r\nDisplayName Yes" HasLimit="No" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Comment" Attribute="Comment" Prefix="" Suffix="" Alignment="LEFT" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -View.Stereotype=Yes -View.DisplayName=Yes -View.OwnerDisplayName=No -View.Columns=Yes -View.Columns._Columns=DisplayName -View.Columns._Limit=-5 -View.TemporaryVTables=Yes -View.Indexes=No -View.Comment=No -View.IconPicture=No -View.TextStyle=No -View_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <ExclusiveChoice Name="Exclusive Choice" Mandatory="Yes" Display="HorizontalRadios" >[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Owner and Name" Attribute="OwnerDisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] </ExclusiveChoice>[CRLF] <Separator Name="Separator" />[CRLF] <StandardCollection Name="Columns" Collection="Columns" Columns="DisplayName No\r\nExpression No\r\nDataType No\r\nSymbolDataType No &quot;Domain or Data type&quot;\r\nIndexIndicator No" HasLimit="Yes" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardCollection Name="Tables" Collection="TemporaryVTables" Columns="Name Yes" HasLimit="No" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardCollection Name="Indexes" Collection="Indexes" Columns="DisplayName Yes" HasLimit="No" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Comment" Attribute="Comment" Prefix="" Suffix="" Alignment="LEFT" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -Procedure.Stereotype=No -Procedure.DisplayName=Yes -Procedure.OwnerDisplayName=No -Procedure.Comment=No -Procedure.IconPicture=No -Procedure.TextStyle=No -Procedure_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <ExclusiveChoice Name="Exclusive Choice" Mandatory="Yes" Display="HorizontalRadios" >[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Owner and Name" Attribute="OwnerDisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] </ExclusiveChoice>[CRLF] <Separator Name="Separator" />[CRLF] <StandardAttribute Name="Comment" Attribute="Comment" Prefix="" Suffix="" Alignment="LEFT" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -Reference.Cardinality=No -Reference.ImplementationType=No -Reference.ChildRole=Yes -Reference.Stereotype=Yes -Reference.DisplayName=No -Reference.ForeignKeyConstraintName=No -Reference.JoinExpression=No -Reference.Integrity=No -Reference.ParentRole=Yes -Reference_SymbolLayout=<Form>[CRLF] <Form Name="Source" >[CRLF] <StandardAttribute Name="Cardinality" Attribute="Cardinality" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Implementation" Attribute="ImplementationType" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Child Role" Attribute="ChildRole" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] </Form>[CRLF] <Form Name="Center" >[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Caption="" Mandatory="No" />[CRLF] <ExclusiveChoice Name="Exclusive Choice" Mandatory="No" Display="HorizontalRadios" >[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Cons&amp;traint Name" Attribute="ForeignKeyConstraintName" Prefix="" Suffix="" Caption="Cons&amp;traint Name" Mandatory="No" />[CRLF] <StandardAttribute Name="Join" Attribute="JoinExpression" Prefix="" Suffix="" Caption="Join" Mandatory="No" />[CRLF] </ExclusiveChoice>[CRLF] <StandardAttribute Name="Referential integrity" Attribute="Integrity" Prefix="" Suffix="" Caption="Referential integrity" Mandatory="No" />[CRLF] </Form>[CRLF] <Form Name="Destination" >[CRLF] <StandardAttribute Name="Parent Role" Attribute="ParentRole" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] </Form>[CRLF]</Form> -ViewReference.ChildRole=Yes -ViewReference.Stereotype=Yes -ViewReference.DisplayName=No -ViewReference.JoinExpression=No -ViewReference.ParentRole=Yes -ViewReference_SymbolLayout=<Form>[CRLF] <Form Name="Source" >[CRLF] <StandardAttribute Name="Child Role" Attribute="ChildRole" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] </Form>[CRLF] <Form Name="Center" >[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Caption="" Mandatory="No" />[CRLF] <ExclusiveChoice Name="Exclusive Choice" Mandatory="No" Display="HorizontalRadios" >[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Join Expression" Attribute="JoinExpression" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] </ExclusiveChoice>[CRLF] </Form>[CRLF] <Form Name="Destination" >[CRLF] <StandardAttribute Name="Parent Role" Attribute="ParentRole" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] </Form>[CRLF]</Form> - -[DisplayPreferences\Symbol] - -[DisplayPreferences\Symbol\AREA] -STRNFont=新宋体,8,N -STRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -LABLFont=新宋体,8,N -LABLFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=9600 -Height=8000 -Brush color=253 249 234 -Fill Color=Yes -Brush style=6 -Brush bitmap mode=12 -Brush gradient mode=16 -Brush gradient color=245 230 173 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 121 98 6 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\FRMEOBJ] -STRNFont=新宋体,8,N -STRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -LABLFont=新宋体,8,N -LABLFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=6000 -Height=2000 -Brush color=255 255 255 -Fill Color=Yes -Brush style=6 -Brush bitmap mode=12 -Brush gradient mode=64 -Brush gradient color=192 192 192 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 255 128 128 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\FRMELNK] -CENTERFont=新宋体,8,N -CENTERFont color=0 0 0 -Line style=1 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Brush color=255 255 255 -Fill Color=Yes -Brush style=1 -Brush bitmap mode=12 -Brush gradient mode=0 -Brush gradient color=118 118 118 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 128 128 255 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\USRDEPD] -CENTERFont=新宋体,8,N -CENTERFont color=0 0 0 -Line style=1 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Brush color=255 255 255 -Fill Color=Yes -Brush style=1 -Brush bitmap mode=12 -Brush gradient mode=0 -Brush gradient color=118 118 118 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=2 0 128 128 255 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\FILO] -OBJSTRNFont=新宋体,8,N -OBJSTRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -LCNMFont=新宋体,8,N -LCNMFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=4800 -Height=3600 -Brush color=255 255 255 -Fill Color=Yes -Brush style=1 -Brush bitmap mode=12 -Brush gradient mode=0 -Brush gradient color=118 118 118 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 0 0 255 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\PDMPCKG] -STRNFont=新宋体,8,N -STRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -LABLFont=新宋体,8,N -LABLFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=4800 -Height=4000 -Brush color=255 255 192 -Fill Color=Yes -Brush style=6 -Brush bitmap mode=12 -Brush gradient mode=65 -Brush gradient color=255 255 255 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 178 178 178 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\TABL] -STRNFont=新宋体,8,N -STRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -OWNRDISPNAMEFont=新宋体,8,N -OWNRDISPNAMEFont color=0 0 0 -ColumnsFont=新宋体,8,N -ColumnsFont color=0 0 0 -TablePkColumnsFont=新宋体,8,U -TablePkColumnsFont color=0 0 0 -TableFkColumnsFont=新宋体,8,N -TableFkColumnsFont color=0 0 0 -KeysFont=新宋体,8,N -KeysFont color=0 0 0 -IndexesFont=新宋体,8,N -IndexesFont color=0 0 0 -TriggersFont=新宋体,8,N -TriggersFont color=0 0 0 -LABLFont=新宋体,8,N -LABLFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=4800 -Height=4000 -Brush color=178 214 252 -Fill Color=Yes -Brush style=6 -Brush bitmap mode=12 -Brush gradient mode=65 -Brush gradient color=255 255 255 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 0 128 192 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\VIEW] -STRNFont=新宋体,8,N -STRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -OWNRDISPNAMEFont=新宋体,8,N -OWNRDISPNAMEFont color=0 0 0 -ColumnsFont=新宋体,8,N -ColumnsFont color=0 0 0 -TablePkColumnsFont=新宋体,8,U -TablePkColumnsFont color=0 0 0 -TableFkColumnsFont=新宋体,8,N -TableFkColumnsFont color=0 0 0 -TemporaryVTablesFont=新宋体,8,N -TemporaryVTablesFont color=0 0 0 -IndexesFont=新宋体,8,N -IndexesFont color=0 0 0 -LABLFont=新宋体,8,N -LABLFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=4800 -Height=4000 -Brush color=208 208 255 -Fill Color=Yes -Brush style=6 -Brush bitmap mode=12 -Brush gradient mode=65 -Brush gradient color=255 255 255 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 128 128 192 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\PROC] -STRNFont=新宋体,8,N -STRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -OWNRDISPNAMEFont=新宋体,8,N -OWNRDISPNAMEFont color=0 0 0 -LABLFont=新宋体,8,N -LABLFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=4000 -Height=1000 -Brush color=255 255 192 -Fill Color=Yes -Brush style=6 -Brush bitmap mode=12 -Brush gradient mode=65 -Brush gradient color=255 255 255 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 128 108 0 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\REFR] -SOURCEFont=新宋体,8,N -SOURCEFont color=0 0 0 -CENTERFont=新宋体,8,N -CENTERFont color=0 0 0 -DESTINATIONFont=新宋体,8,N -DESTINATIONFont color=0 0 0 -Line style=1 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Brush color=255 255 255 -Fill Color=Yes -Brush style=1 -Brush bitmap mode=12 -Brush gradient mode=0 -Brush gradient color=118 118 118 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 0 128 192 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\VREF] -SOURCEFont=新宋体,8,N -SOURCEFont color=0 0 0 -CENTERFont=新宋体,8,N -CENTERFont color=0 0 0 -DESTINATIONFont=新宋体,8,N -DESTINATIONFont color=0 0 0 -Line style=1 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Brush color=255 255 255 -Fill Color=Yes -Brush style=1 -Brush bitmap mode=12 -Brush gradient mode=0 -Brush gradient color=118 118 118 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 128 128 192 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\Free Symbol] -Free TextFont=新宋体,8,N -Free TextFont color=0 0 0 -Line style=0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Brush color=255 255 255 -Fill Color=Yes -Brush style=1 -Brush bitmap mode=12 -Brush gradient mode=0 -Brush gradient color=118 118 118 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 0 0 255 -Shadow color=192 192 192 -Shadow=0 -(8268, 11693) -((315,354), (433,354)) -1 -15 - - -1629975622 -1630311342 --1 -((-7982,10396), (11754,18244)) -0 -12615680 -16570034 -12632256 -STRN 0 新宋体,8,N -DISPNAME 0 新宋体,8,N -OWNRDISPNAME 0 新宋体,8,N -Columns 0 新宋体,8,N -TablePkColumns 0 新宋体,8,U -TableFkColumns 0 新宋体,8,N -Keys 0 新宋体,8,N -Indexes 0 新宋体,8,N -Triggers 0 新宋体,8,N -LABL 0 新宋体,8,N -6 -65 -16777215 -1 - - - - - - - - - - - - -949A22D1-AB0B-4C02-820B-205FBF277B88 -操作日志( OperationLog ) -OperationLog -1629975622 -Xiadao -1630311339 -Xiadao -操作日志 - - - -C8213067-897B-474A-AFD2-9F0A1600A3A2 -操作标识( LogId ) -LogId -1629975622 -Xiadao -1632131121 -Xiadao -操作标识 -bigint -1 -1 - - -E89DAF52-EBB1-44DB-AA5A-C8073BB431A4 -日志名称( LogName ) -LogName -1629975622 -Xiadao -1630311265 -Xiadao -日志名称 -nvarchar(50) -50 -1 - - -4800B877-CF81-40F2-B59C-C55FFF19E93A -操作时间( OperationTime ) -OperationTime -1629975622 -Xiadao -1630311280 -Xiadao -操作时间 -datetime - - -9E39A0DE-079C-4551-9A28-C59EC2F333C0 -标题( Caption ) -Caption -1629975622 -Xiadao -1629975622 -Xiadao -标题 -nvarchar(200) -200 - - -5B4B72EA-85F3-460F-9C1A-9E8B1DB9E30C -内容( Content ) -Content -1629975622 -Xiadao -1629975622 -Xiadao -内容 -nvarchar(MAX) - - -6FDCFFAE-E6A4-4BF8-B5C0-BFBAB701123D -版本号( Version ) -Version -1629975622 -Xiadao -1629975622 -Xiadao -版本号 -timestamp - - - - -582657C8-71B5-4F31-B217-003C571715CB -Key_1 -Key_1 -1629975622 -Xiadao -1629975622 -Xiadao - - - - - - - -638A3E2A-3249-48D9-B9A7-2F187B061389 -cls_idx_operationtime -cls_idx_operationtime -1629975622 -Xiadao -1629975892 -Xiadao - - -5C29C73F-8823-419C-851E-07105BA3DECD -1629975622 -Xiadao -1629975622 -Xiadao - - - - - - - - - - - - - - - - - - - - - - - - - - -42F88B7C-14FB-49BA-90CD-C8D1EB1ADAE1 -03 - 商品 -03 - 商品 -1630573249 -Xiadao -1633533744 -Xiadao - - -87C3BEB1-BEE0-4859-B685-17CFFF11B062 -02 - 产品 -02 - 产品 -1630573249 -Xiadao -1633533744 -Xiadao -[DisplayPreferences] - -[DisplayPreferences\PDM] - -[DisplayPreferences\General] -Adjust to text=Yes -Snap Grid=No -Constrain Labels=Yes -Display Grid=No -Show Page Delimiter=Yes -Show Links intersections=Yes -Activate automatic link routing=Yes -Grid size=800 -Graphic unit=2 -Window color=255 255 255 -Background image= -Background mode=8 -Watermark image= -Watermark mode=8 -Show watermark on screen=No -Gradient mode=0 -Gradient end color=255 255 255 -Show Swimlane=No -SwimlaneVert=Yes -TreeVert=No -CompDark=0 - -[DisplayPreferences\Object] -Show Icon=No -Mode=2 -Trunc Length=40 -Word Length=40 -Word Text=!"#$%&')*+,-./:;=>?@\]^_`|}~ -Shortcut IntIcon=Yes -Shortcut IntLoct=Yes -Shortcut IntFullPath=No -Shortcut IntLastPackage=Yes -Shortcut ExtIcon=Yes -Shortcut ExtLoct=No -Shortcut ExtFullPath=No -Shortcut ExtLastPackage=Yes -Shortcut ExtIncludeModl=Yes -Area.IconPicture=Yes -Area.Stereotype=Yes -Area.Comment=No -Area.TextStyle=No -Area.SubSymbols=Yes -Area_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Architecture Area Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <Separator Name="Separator" />[CRLF] <StandardAttribute Name="Comment" Attribute="Comment" Prefix="" Suffix="" Alignment="LEFT" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -EObjShowStrn=Yes -ExtendedObject.Comment=No -ExtendedObject.IconPicture=No -ExtendedObject.TextStyle=No -ExtendedObject_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Object Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <Separator Name="Separator" />[CRLF] <StandardAttribute Name="Comment" Attribute="Comment" Prefix="" Suffix="" Alignment="LEFT" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -ELnkShowStrn=Yes -ELnkShowName=Yes -ExtendedLink_SymbolLayout=<Form>[CRLF] <Form Name="Center" >[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] </Form>[CRLF] <Form Name="Source" >[CRLF] </Form>[CRLF] <Form Name="Destination" >[CRLF] </Form>[CRLF]</Form> -ExtDpdShowStrn=Yes -ExtendedDependency_SymbolLayout=<Form>[CRLF] <Form Name="Center" >[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Caption="" Mandatory="No" />[CRLF] </Form>[CRLF] <Form Name="Source" >[CRLF] </Form>[CRLF] <Form Name="Destination" >[CRLF] </Form>[CRLF]</Form> -FileObject.Stereotype=No -FileObject.DisplayName=Yes -FileObject.LocationOrName=No -FileObject.IconPicture=No -FileObject.TextStyle=No -FileObject.IconMode=Yes -FileObject_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <ExclusiveChoice Name="Exclusive Choice" Mandatory="Yes" Display="HorizontalRadios" >[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Location" Attribute="LocationOrName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] </ExclusiveChoice>[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -Package.Stereotype=Yes -Package.Comment=No -Package.IconPicture=No -Package.TextStyle=No -Package_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <Separator Name="Separator" />[CRLF] <StandardAttribute Name="Comment" Attribute="Comment" Prefix="" Suffix="" Alignment="LEFT" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -Display Model Version=Yes -Table.Stereotype=Yes -Table.DisplayName=Yes -Table.OwnerDisplayName=No -Table.Columns=Yes -Table.Columns._Filter="All Columns" PDMCOLNALL -Table.Columns._Columns=Stereotype DataType KeyIndicator -Table.Columns._Limit=-5 -Table.Keys=No -Table.Keys._Columns=Stereotype Indicator -Table.Indexes=No -Table.Indexes._Columns=Stereotype -Table.Triggers=No -Table.Triggers._Columns=Stereotype -Table.Comment=No -Table.IconPicture=No -Table.TextStyle=No -Table_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <ExclusiveChoice Name="Exclusive Choice" Mandatory="Yes" Display="HorizontalRadios" >[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Owner and Name" Attribute="OwnerDisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] </ExclusiveChoice>[CRLF] <Separator Name="Separator" />[CRLF] <StandardCollection Name="Columns" Collection="Columns" Columns="Stereotype No\r\nDisplayName Yes\r\nDataType No\r\nSymbolDataType No &quot;Domain or Data type&quot;\r\nDomain No\r\nKeyIndicator No\r\nIndexIndicator No\r\nNullStatus No" Filters="&quot;All Columns&quot; PDMCOLNALL &quot;&quot;\r\n&quot;PK Columns&quot; PDMCOLNPK &quot;\&quot;PRIM \&quot;TRUE\&quot; TRUE\&quot;&quot;\r\n&quot;Key Columns&quot; PDMCOLNKEY &quot;\&quot;KEYS \&quot;TRUE\&quot; TRUE\&quot;&quot;" HasLimit="Yes" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardCollection Name="Keys" Collection="Keys" Columns="Stereotype No\r\nDisplayName Yes\r\nIndicator No" HasLimit="No" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardCollection Name="Indexes" Collection="Indexes" Columns="Stereotype No\r\nDisplayName Yes\r\nIndicator No" HasLimit="No" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardCollection Name="Triggers" Collection="Triggers" Columns="Stereotype No\r\nDisplayName Yes" HasLimit="No" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Comment" Attribute="Comment" Prefix="" Suffix="" Alignment="LEFT" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -View.Stereotype=Yes -View.DisplayName=Yes -View.OwnerDisplayName=No -View.Columns=Yes -View.Columns._Columns=DisplayName -View.Columns._Limit=-5 -View.TemporaryVTables=Yes -View.Indexes=No -View.Comment=No -View.IconPicture=No -View.TextStyle=No -View_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <ExclusiveChoice Name="Exclusive Choice" Mandatory="Yes" Display="HorizontalRadios" >[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Owner and Name" Attribute="OwnerDisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] </ExclusiveChoice>[CRLF] <Separator Name="Separator" />[CRLF] <StandardCollection Name="Columns" Collection="Columns" Columns="DisplayName No\r\nExpression No\r\nDataType No\r\nSymbolDataType No &quot;Domain or Data type&quot;\r\nIndexIndicator No" HasLimit="Yes" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardCollection Name="Tables" Collection="TemporaryVTables" Columns="Name Yes" HasLimit="No" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardCollection Name="Indexes" Collection="Indexes" Columns="DisplayName Yes" HasLimit="No" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Comment" Attribute="Comment" Prefix="" Suffix="" Alignment="LEFT" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -Procedure.Stereotype=No -Procedure.DisplayName=Yes -Procedure.OwnerDisplayName=No -Procedure.Comment=No -Procedure.IconPicture=No -Procedure.TextStyle=No -Procedure_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <ExclusiveChoice Name="Exclusive Choice" Mandatory="Yes" Display="HorizontalRadios" >[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Owner and Name" Attribute="OwnerDisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] </ExclusiveChoice>[CRLF] <Separator Name="Separator" />[CRLF] <StandardAttribute Name="Comment" Attribute="Comment" Prefix="" Suffix="" Alignment="LEFT" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -Reference.Cardinality=No -Reference.ImplementationType=No -Reference.ChildRole=Yes -Reference.Stereotype=Yes -Reference.DisplayName=No -Reference.ForeignKeyConstraintName=No -Reference.JoinExpression=No -Reference.Integrity=No -Reference.ParentRole=Yes -Reference_SymbolLayout=<Form>[CRLF] <Form Name="Source" >[CRLF] <StandardAttribute Name="Cardinality" Attribute="Cardinality" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Implementation" Attribute="ImplementationType" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Child Role" Attribute="ChildRole" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] </Form>[CRLF] <Form Name="Center" >[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Caption="" Mandatory="No" />[CRLF] <ExclusiveChoice Name="Exclusive Choice" Mandatory="No" Display="HorizontalRadios" >[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Cons&amp;traint Name" Attribute="ForeignKeyConstraintName" Prefix="" Suffix="" Caption="Cons&amp;traint Name" Mandatory="No" />[CRLF] <StandardAttribute Name="Join" Attribute="JoinExpression" Prefix="" Suffix="" Caption="Join" Mandatory="No" />[CRLF] </ExclusiveChoice>[CRLF] <StandardAttribute Name="Referential integrity" Attribute="Integrity" Prefix="" Suffix="" Caption="Referential integrity" Mandatory="No" />[CRLF] </Form>[CRLF] <Form Name="Destination" >[CRLF] <StandardAttribute Name="Parent Role" Attribute="ParentRole" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] </Form>[CRLF]</Form> -ViewReference.ChildRole=Yes -ViewReference.Stereotype=Yes -ViewReference.DisplayName=No -ViewReference.JoinExpression=No -ViewReference.ParentRole=Yes -ViewReference_SymbolLayout=<Form>[CRLF] <Form Name="Source" >[CRLF] <StandardAttribute Name="Child Role" Attribute="ChildRole" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] </Form>[CRLF] <Form Name="Center" >[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Caption="" Mandatory="No" />[CRLF] <ExclusiveChoice Name="Exclusive Choice" Mandatory="No" Display="HorizontalRadios" >[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Join Expression" Attribute="JoinExpression" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] </ExclusiveChoice>[CRLF] </Form>[CRLF] <Form Name="Destination" >[CRLF] <StandardAttribute Name="Parent Role" Attribute="ParentRole" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] </Form>[CRLF]</Form> - -[DisplayPreferences\Symbol] - -[DisplayPreferences\Symbol\AREA] -STRNFont=新宋体,8,N -STRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -LABLFont=新宋体,8,N -LABLFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=9600 -Height=8000 -Brush color=253 249 234 -Fill Color=Yes -Brush style=6 -Brush bitmap mode=12 -Brush gradient mode=16 -Brush gradient color=245 230 173 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 121 98 6 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\FRMEOBJ] -STRNFont=新宋体,8,N -STRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -LABLFont=新宋体,8,N -LABLFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=6000 -Height=2000 -Brush color=255 255 255 -Fill Color=Yes -Brush style=6 -Brush bitmap mode=12 -Brush gradient mode=64 -Brush gradient color=192 192 192 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 255 128 128 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\FRMELNK] -CENTERFont=新宋体,8,N -CENTERFont color=0 0 0 -Line style=1 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Brush color=255 255 255 -Fill Color=Yes -Brush style=1 -Brush bitmap mode=12 -Brush gradient mode=0 -Brush gradient color=118 118 118 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 128 128 255 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\USRDEPD] -CENTERFont=新宋体,8,N -CENTERFont color=0 0 0 -Line style=1 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Brush color=255 255 255 -Fill Color=Yes -Brush style=1 -Brush bitmap mode=12 -Brush gradient mode=0 -Brush gradient color=118 118 118 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=2 0 128 128 255 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\FILO] -OBJSTRNFont=新宋体,8,N -OBJSTRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -LCNMFont=新宋体,8,N -LCNMFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=4800 -Height=3600 -Brush color=255 255 255 -Fill Color=Yes -Brush style=1 -Brush bitmap mode=12 -Brush gradient mode=0 -Brush gradient color=118 118 118 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 0 0 255 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\PDMPCKG] -STRNFont=新宋体,8,N -STRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -LABLFont=新宋体,8,N -LABLFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=4800 -Height=4000 -Brush color=255 255 192 -Fill Color=Yes -Brush style=6 -Brush bitmap mode=12 -Brush gradient mode=65 -Brush gradient color=255 255 255 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 178 178 178 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\TABL] -STRNFont=新宋体,8,N -STRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -OWNRDISPNAMEFont=新宋体,8,N -OWNRDISPNAMEFont color=0 0 0 -ColumnsFont=新宋体,8,N -ColumnsFont color=0 0 0 -TablePkColumnsFont=新宋体,8,U -TablePkColumnsFont color=0 0 0 -TableFkColumnsFont=新宋体,8,N -TableFkColumnsFont color=0 0 0 -KeysFont=新宋体,8,N -KeysFont color=0 0 0 -IndexesFont=新宋体,8,N -IndexesFont color=0 0 0 -TriggersFont=新宋体,8,N -TriggersFont color=0 0 0 -LABLFont=新宋体,8,N -LABLFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=4800 -Height=4000 -Brush color=178 214 252 -Fill Color=Yes -Brush style=6 -Brush bitmap mode=12 -Brush gradient mode=65 -Brush gradient color=255 255 255 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 0 128 192 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\VIEW] -STRNFont=新宋体,8,N -STRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -OWNRDISPNAMEFont=新宋体,8,N -OWNRDISPNAMEFont color=0 0 0 -ColumnsFont=新宋体,8,N -ColumnsFont color=0 0 0 -TablePkColumnsFont=新宋体,8,U -TablePkColumnsFont color=0 0 0 -TableFkColumnsFont=新宋体,8,N -TableFkColumnsFont color=0 0 0 -TemporaryVTablesFont=新宋体,8,N -TemporaryVTablesFont color=0 0 0 -IndexesFont=新宋体,8,N -IndexesFont color=0 0 0 -LABLFont=新宋体,8,N -LABLFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=4800 -Height=4000 -Brush color=208 208 255 -Fill Color=Yes -Brush style=6 -Brush bitmap mode=12 -Brush gradient mode=65 -Brush gradient color=255 255 255 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 128 128 192 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\PROC] -STRNFont=新宋体,8,N -STRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -OWNRDISPNAMEFont=新宋体,8,N -OWNRDISPNAMEFont color=0 0 0 -LABLFont=新宋体,8,N -LABLFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=4000 -Height=1000 -Brush color=255 255 192 -Fill Color=Yes -Brush style=6 -Brush bitmap mode=12 -Brush gradient mode=65 -Brush gradient color=255 255 255 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 128 108 0 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\REFR] -SOURCEFont=新宋体,8,N -SOURCEFont color=0 0 0 -CENTERFont=新宋体,8,N -CENTERFont color=0 0 0 -DESTINATIONFont=新宋体,8,N -DESTINATIONFont color=0 0 0 -Line style=1 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Brush color=255 255 255 -Fill Color=Yes -Brush style=1 -Brush bitmap mode=12 -Brush gradient mode=0 -Brush gradient color=118 118 118 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 0 128 192 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\VREF] -SOURCEFont=新宋体,8,N -SOURCEFont color=0 0 0 -CENTERFont=新宋体,8,N -CENTERFont color=0 0 0 -DESTINATIONFont=新宋体,8,N -DESTINATIONFont color=0 0 0 -Line style=1 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Brush color=255 255 255 -Fill Color=Yes -Brush style=1 -Brush bitmap mode=12 -Brush gradient mode=0 -Brush gradient color=118 118 118 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 128 128 192 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\Free Symbol] -Free TextFont=新宋体,8,N -Free TextFont color=0 0 0 -Line style=0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Brush color=255 255 255 -Fill Color=Yes -Brush style=1 -Brush bitmap mode=12 -Brush gradient mode=0 -Brush gradient color=118 118 118 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 0 0 255 -Shadow color=192 192 192 -Shadow=0 -(8268, 11693) -((315,354), (433,354)) -1 -15 - - -1633533744 -1633533744 -((-837,16780), (413,21922)) -((-212,17180),(-212,21522)) -1 -1 -12615680 -12632256 -CENTER 0 新宋体,8,N -SOURCE 0 新宋体,8,N -DESTINATION 0 新宋体,8,N - - - - - - - - - - - -1630573318 -1633533747 --1 -((-13007,3856), (13007,17180)) -0 -12615680 -16570034 -12632256 -STRN 0 新宋体,8,N -DISPNAME 0 新宋体,8,N -OWNRDISPNAME 0 新宋体,8,N -Columns 0 新宋体,8,N -TablePkColumns 0 新宋体,8,U -TableFkColumns 0 新宋体,8,N -Keys 0 新宋体,8,N -Indexes 0 新宋体,8,N -Triggers 0 新宋体,8,N -LABL 0 新宋体,8,N -6 -65 -16777215 -1 - - - - - -1633533736 -1633533739 --1 -((-12920,21522), (12496,35554)) -0 -12615680 -16570034 -12632256 -STRN 0 新宋体,8,N -DISPNAME 0 新宋体,8,N -OWNRDISPNAME 0 新宋体,8,N -Columns 0 新宋体,8,N -TablePkColumns 0 新宋体,8,U -TableFkColumns 0 新宋体,8,N -Keys 0 新宋体,8,N -Indexes 0 新宋体,8,N -Triggers 0 新宋体,8,N -LABL 0 新宋体,8,N -6 -65 -16777215 -1 - - - - - - - -C398C3C5-829A-40BE-95F9-939CE009E188 -01 - 商品分类 -01 - 商品分类 -1633532812 -Xiadao -1633533722 -Xiadao -[DisplayPreferences] - -[DisplayPreferences\PDM] - -[DisplayPreferences\General] -Adjust to text=Yes -Snap Grid=No -Constrain Labels=Yes -Display Grid=No -Show Page Delimiter=Yes -Show Links intersections=Yes -Activate automatic link routing=Yes -Grid size=800 -Graphic unit=2 -Window color=255 255 255 -Background image= -Background mode=8 -Watermark image= -Watermark mode=8 -Show watermark on screen=No -Gradient mode=0 -Gradient end color=255 255 255 -Show Swimlane=No -SwimlaneVert=Yes -TreeVert=No -CompDark=0 - -[DisplayPreferences\Object] -Show Icon=No -Mode=2 -Trunc Length=40 -Word Length=40 -Word Text=!"#$%&')*+,-./:;=>?@\]^_`|}~ -Shortcut IntIcon=Yes -Shortcut IntLoct=Yes -Shortcut IntFullPath=No -Shortcut IntLastPackage=Yes -Shortcut ExtIcon=Yes -Shortcut ExtLoct=No -Shortcut ExtFullPath=No -Shortcut ExtLastPackage=Yes -Shortcut ExtIncludeModl=Yes -Area.IconPicture=Yes -Area.Stereotype=Yes -Area.Comment=No -Area.TextStyle=No -Area.SubSymbols=Yes -Area_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Architecture Area Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <Separator Name="Separator" />[CRLF] <StandardAttribute Name="Comment" Attribute="Comment" Prefix="" Suffix="" Alignment="LEFT" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -EObjShowStrn=Yes -ExtendedObject.Comment=No -ExtendedObject.IconPicture=No -ExtendedObject.TextStyle=No -ExtendedObject_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Object Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <Separator Name="Separator" />[CRLF] <StandardAttribute Name="Comment" Attribute="Comment" Prefix="" Suffix="" Alignment="LEFT" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -ELnkShowStrn=Yes -ELnkShowName=Yes -ExtendedLink_SymbolLayout=<Form>[CRLF] <Form Name="Center" >[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] </Form>[CRLF] <Form Name="Source" >[CRLF] </Form>[CRLF] <Form Name="Destination" >[CRLF] </Form>[CRLF]</Form> -ExtDpdShowStrn=Yes -ExtendedDependency_SymbolLayout=<Form>[CRLF] <Form Name="Center" >[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Caption="" Mandatory="No" />[CRLF] </Form>[CRLF] <Form Name="Source" >[CRLF] </Form>[CRLF] <Form Name="Destination" >[CRLF] </Form>[CRLF]</Form> -FileObject.Stereotype=No -FileObject.DisplayName=Yes -FileObject.LocationOrName=No -FileObject.IconPicture=No -FileObject.TextStyle=No -FileObject.IconMode=Yes -FileObject_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <ExclusiveChoice Name="Exclusive Choice" Mandatory="Yes" Display="HorizontalRadios" >[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Location" Attribute="LocationOrName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] </ExclusiveChoice>[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -Package.Stereotype=Yes -Package.Comment=No -Package.IconPicture=No -Package.TextStyle=No -Package_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <Separator Name="Separator" />[CRLF] <StandardAttribute Name="Comment" Attribute="Comment" Prefix="" Suffix="" Alignment="LEFT" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -Display Model Version=Yes -Table.Stereotype=Yes -Table.DisplayName=Yes -Table.OwnerDisplayName=No -Table.Columns=Yes -Table.Columns._Filter="All Columns" PDMCOLNALL -Table.Columns._Columns=Stereotype DataType KeyIndicator -Table.Columns._Limit=-5 -Table.Keys=No -Table.Keys._Columns=Stereotype Indicator -Table.Indexes=No -Table.Indexes._Columns=Stereotype -Table.Triggers=No -Table.Triggers._Columns=Stereotype -Table.Comment=No -Table.IconPicture=No -Table.TextStyle=No -Table_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <ExclusiveChoice Name="Exclusive Choice" Mandatory="Yes" Display="HorizontalRadios" >[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Owner and Name" Attribute="OwnerDisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] </ExclusiveChoice>[CRLF] <Separator Name="Separator" />[CRLF] <StandardCollection Name="Columns" Collection="Columns" Columns="Stereotype No\r\nDisplayName Yes\r\nDataType No\r\nSymbolDataType No &quot;Domain or Data type&quot;\r\nDomain No\r\nKeyIndicator No\r\nIndexIndicator No\r\nNullStatus No" Filters="&quot;All Columns&quot; PDMCOLNALL &quot;&quot;\r\n&quot;PK Columns&quot; PDMCOLNPK &quot;\&quot;PRIM \&quot;TRUE\&quot; TRUE\&quot;&quot;\r\n&quot;Key Columns&quot; PDMCOLNKEY &quot;\&quot;KEYS \&quot;TRUE\&quot; TRUE\&quot;&quot;" HasLimit="Yes" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardCollection Name="Keys" Collection="Keys" Columns="Stereotype No\r\nDisplayName Yes\r\nIndicator No" HasLimit="No" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardCollection Name="Indexes" Collection="Indexes" Columns="Stereotype No\r\nDisplayName Yes\r\nIndicator No" HasLimit="No" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardCollection Name="Triggers" Collection="Triggers" Columns="Stereotype No\r\nDisplayName Yes" HasLimit="No" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Comment" Attribute="Comment" Prefix="" Suffix="" Alignment="LEFT" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -View.Stereotype=Yes -View.DisplayName=Yes -View.OwnerDisplayName=No -View.Columns=Yes -View.Columns._Columns=DisplayName -View.Columns._Limit=-5 -View.TemporaryVTables=Yes -View.Indexes=No -View.Comment=No -View.IconPicture=No -View.TextStyle=No -View_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <ExclusiveChoice Name="Exclusive Choice" Mandatory="Yes" Display="HorizontalRadios" >[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Owner and Name" Attribute="OwnerDisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] </ExclusiveChoice>[CRLF] <Separator Name="Separator" />[CRLF] <StandardCollection Name="Columns" Collection="Columns" Columns="DisplayName No\r\nExpression No\r\nDataType No\r\nSymbolDataType No &quot;Domain or Data type&quot;\r\nIndexIndicator No" HasLimit="Yes" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardCollection Name="Tables" Collection="TemporaryVTables" Columns="Name Yes" HasLimit="No" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardCollection Name="Indexes" Collection="Indexes" Columns="DisplayName Yes" HasLimit="No" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Comment" Attribute="Comment" Prefix="" Suffix="" Alignment="LEFT" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -Procedure.Stereotype=No -Procedure.DisplayName=Yes -Procedure.OwnerDisplayName=No -Procedure.Comment=No -Procedure.IconPicture=No -Procedure.TextStyle=No -Procedure_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <ExclusiveChoice Name="Exclusive Choice" Mandatory="Yes" Display="HorizontalRadios" >[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Owner and Name" Attribute="OwnerDisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] </ExclusiveChoice>[CRLF] <Separator Name="Separator" />[CRLF] <StandardAttribute Name="Comment" Attribute="Comment" Prefix="" Suffix="" Alignment="LEFT" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -Reference.Cardinality=No -Reference.ImplementationType=No -Reference.ChildRole=Yes -Reference.Stereotype=Yes -Reference.DisplayName=No -Reference.ForeignKeyConstraintName=No -Reference.JoinExpression=No -Reference.Integrity=No -Reference.ParentRole=Yes -Reference_SymbolLayout=<Form>[CRLF] <Form Name="Source" >[CRLF] <StandardAttribute Name="Cardinality" Attribute="Cardinality" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Implementation" Attribute="ImplementationType" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Child Role" Attribute="ChildRole" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] </Form>[CRLF] <Form Name="Center" >[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Caption="" Mandatory="No" />[CRLF] <ExclusiveChoice Name="Exclusive Choice" Mandatory="No" Display="HorizontalRadios" >[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Cons&amp;traint Name" Attribute="ForeignKeyConstraintName" Prefix="" Suffix="" Caption="Cons&amp;traint Name" Mandatory="No" />[CRLF] <StandardAttribute Name="Join" Attribute="JoinExpression" Prefix="" Suffix="" Caption="Join" Mandatory="No" />[CRLF] </ExclusiveChoice>[CRLF] <StandardAttribute Name="Referential integrity" Attribute="Integrity" Prefix="" Suffix="" Caption="Referential integrity" Mandatory="No" />[CRLF] </Form>[CRLF] <Form Name="Destination" >[CRLF] <StandardAttribute Name="Parent Role" Attribute="ParentRole" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] </Form>[CRLF]</Form> -ViewReference.ChildRole=Yes -ViewReference.Stereotype=Yes -ViewReference.DisplayName=No -ViewReference.JoinExpression=No -ViewReference.ParentRole=Yes -ViewReference_SymbolLayout=<Form>[CRLF] <Form Name="Source" >[CRLF] <StandardAttribute Name="Child Role" Attribute="ChildRole" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] </Form>[CRLF] <Form Name="Center" >[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Caption="" Mandatory="No" />[CRLF] <ExclusiveChoice Name="Exclusive Choice" Mandatory="No" Display="HorizontalRadios" >[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Join Expression" Attribute="JoinExpression" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] </ExclusiveChoice>[CRLF] </Form>[CRLF] <Form Name="Destination" >[CRLF] <StandardAttribute Name="Parent Role" Attribute="ParentRole" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] </Form>[CRLF]</Form> - -[DisplayPreferences\Symbol] - -[DisplayPreferences\Symbol\AREA] -STRNFont=新宋体,8,N -STRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -LABLFont=新宋体,8,N -LABLFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=9600 -Height=8000 -Brush color=253 249 234 -Fill Color=Yes -Brush style=6 -Brush bitmap mode=12 -Brush gradient mode=16 -Brush gradient color=245 230 173 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 121 98 6 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\FRMEOBJ] -STRNFont=新宋体,8,N -STRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -LABLFont=新宋体,8,N -LABLFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=6000 -Height=2000 -Brush color=255 255 255 -Fill Color=Yes -Brush style=6 -Brush bitmap mode=12 -Brush gradient mode=64 -Brush gradient color=192 192 192 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 255 128 128 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\FRMELNK] -CENTERFont=新宋体,8,N -CENTERFont color=0 0 0 -Line style=1 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Brush color=255 255 255 -Fill Color=Yes -Brush style=1 -Brush bitmap mode=12 -Brush gradient mode=0 -Brush gradient color=118 118 118 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 128 128 255 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\USRDEPD] -CENTERFont=新宋体,8,N -CENTERFont color=0 0 0 -Line style=1 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Brush color=255 255 255 -Fill Color=Yes -Brush style=1 -Brush bitmap mode=12 -Brush gradient mode=0 -Brush gradient color=118 118 118 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=2 0 128 128 255 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\FILO] -OBJSTRNFont=新宋体,8,N -OBJSTRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -LCNMFont=新宋体,8,N -LCNMFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=4800 -Height=3600 -Brush color=255 255 255 -Fill Color=Yes -Brush style=1 -Brush bitmap mode=12 -Brush gradient mode=0 -Brush gradient color=118 118 118 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 0 0 255 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\PDMPCKG] -STRNFont=新宋体,8,N -STRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -LABLFont=新宋体,8,N -LABLFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=4800 -Height=4000 -Brush color=255 255 192 -Fill Color=Yes -Brush style=6 -Brush bitmap mode=12 -Brush gradient mode=65 -Brush gradient color=255 255 255 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 178 178 178 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\TABL] -STRNFont=新宋体,8,N -STRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -OWNRDISPNAMEFont=新宋体,8,N -OWNRDISPNAMEFont color=0 0 0 -ColumnsFont=新宋体,8,N -ColumnsFont color=0 0 0 -TablePkColumnsFont=新宋体,8,U -TablePkColumnsFont color=0 0 0 -TableFkColumnsFont=新宋体,8,N -TableFkColumnsFont color=0 0 0 -KeysFont=新宋体,8,N -KeysFont color=0 0 0 -IndexesFont=新宋体,8,N -IndexesFont color=0 0 0 -TriggersFont=新宋体,8,N -TriggersFont color=0 0 0 -LABLFont=新宋体,8,N -LABLFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=4800 -Height=4000 -Brush color=178 214 252 -Fill Color=Yes -Brush style=6 -Brush bitmap mode=12 -Brush gradient mode=65 -Brush gradient color=255 255 255 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 0 128 192 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\VIEW] -STRNFont=新宋体,8,N -STRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -OWNRDISPNAMEFont=新宋体,8,N -OWNRDISPNAMEFont color=0 0 0 -ColumnsFont=新宋体,8,N -ColumnsFont color=0 0 0 -TablePkColumnsFont=新宋体,8,U -TablePkColumnsFont color=0 0 0 -TableFkColumnsFont=新宋体,8,N -TableFkColumnsFont color=0 0 0 -TemporaryVTablesFont=新宋体,8,N -TemporaryVTablesFont color=0 0 0 -IndexesFont=新宋体,8,N -IndexesFont color=0 0 0 -LABLFont=新宋体,8,N -LABLFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=4800 -Height=4000 -Brush color=208 208 255 -Fill Color=Yes -Brush style=6 -Brush bitmap mode=12 -Brush gradient mode=65 -Brush gradient color=255 255 255 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 128 128 192 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\PROC] -STRNFont=新宋体,8,N -STRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -OWNRDISPNAMEFont=新宋体,8,N -OWNRDISPNAMEFont color=0 0 0 -LABLFont=新宋体,8,N -LABLFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=4000 -Height=1000 -Brush color=255 255 192 -Fill Color=Yes -Brush style=6 -Brush bitmap mode=12 -Brush gradient mode=65 -Brush gradient color=255 255 255 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 128 108 0 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\REFR] -SOURCEFont=新宋体,8,N -SOURCEFont color=0 0 0 -CENTERFont=新宋体,8,N -CENTERFont color=0 0 0 -DESTINATIONFont=新宋体,8,N -DESTINATIONFont color=0 0 0 -Line style=1 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Brush color=255 255 255 -Fill Color=Yes -Brush style=1 -Brush bitmap mode=12 -Brush gradient mode=0 -Brush gradient color=118 118 118 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 0 128 192 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\VREF] -SOURCEFont=新宋体,8,N -SOURCEFont color=0 0 0 -CENTERFont=新宋体,8,N -CENTERFont color=0 0 0 -DESTINATIONFont=新宋体,8,N -DESTINATIONFont color=0 0 0 -Line style=1 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Brush color=255 255 255 -Fill Color=Yes -Brush style=1 -Brush bitmap mode=12 -Brush gradient mode=0 -Brush gradient color=118 118 118 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 128 128 192 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\Free Symbol] -Free TextFont=新宋体,8,N -Free TextFont color=0 0 0 -Line style=0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Brush color=255 255 255 -Fill Color=Yes -Brush style=1 -Brush bitmap mode=12 -Brush gradient mode=0 -Brush gradient color=118 118 118 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 0 0 255 -Shadow color=192 192 192 -Shadow=0 -(8268, 11693) -((315,354), (433,354)) -1 -15 - - -1633532827 -1633533177 --1 -((-12708,-5713), (12708,8319)) -0 -12615680 -16570034 -12632256 -STRN 0 新宋体,8,N -DISPNAME 0 新宋体,8,N -OWNRDISPNAME 0 新宋体,8,N -Columns 0 新宋体,8,N -TablePkColumns 0 新宋体,8,U -TableFkColumns 0 新宋体,8,N -Keys 0 新宋体,8,N -Indexes 0 新宋体,8,N -Triggers 0 新宋体,8,N -LABL 0 新宋体,8,N -6 -65 -16777215 -1 - - - - - - - - - - - - -2E6FA781-2BB6-4E53-8EE0-A2A7D9DBE25F -产品( Product ) -Product -1630573318 -Xiadao -1633533744 -Xiadao -产品 - - - -0DD9B87E-220F-42B9-B413-36A8A1F4B1EE -产品标识( ProductId ) -ProductId -1630573318 -Xiadao -1632130941 -Xiadao -产品标识 -uniqueidentifier -1 - - -BE7ECC82-51E4-472F-B342-D4CC23017A5E -商品分类标识( CategoryId ) -CategoryId -1633533744 -Xiadao -1633533744 -Xiadao -商品分类标识 -uniqueidentifier -1 - - -5F17AE72-B38B-47B3-9B46-1F84BA2989BA -产品编码( Code ) -Code -1630573318 -Xiadao -1630573457 -Xiadao -产品编码 -nvarchar(50) -50 -1 - - -42290B46-1FB2-4848-A0AC-B2024D188B5A -产品名称( Name ) -Name -1630573318 -Xiadao -1630573451 -Xiadao -产品名称 -nvarchar(500) -500 -1 - - -63B017CF-FF55-4386-ADAC-7FB9456F607B -价格( Price ) -Price -1630574746 -Xiadao -1630575791 -Xiadao -价格 -decimal(12,2) -12 -2 -1 - - -BC9C2BB4-685B-414C-8291-D2E5BBA68B28 -描述( Description ) -Description -1630573318 -Xiadao -1630573318 -Xiadao -描述 -nvarchar(max) - - -13AF1493-B069-43CB-BF04-5DD8B2E18A7F -启用( Enabled ) -Enabled -1630573318 -Xiadao -1630573318 -Xiadao -启用 -bit -1 - - -845EAFE3-41A0-40E6-95C9-8D70C497A413 -创建时间( CreationTime ) -CreationTime -1630573318 -Xiadao -1630573318 -Xiadao -创建时间 -datetime - - -084AE8C8-3B07-4E96-B8A4-32B5B7019A7F -创建人( CreatorId ) -CreatorId -1630573318 -Xiadao -1630573318 -Xiadao -创建人 -uniqueidentifier - - -9762DFFF-C9CD-4E75-90E7-1BAB83A0DBE3 -最后修改时间( LastModificationTime ) -LastModificationTime -1630573318 -Xiadao -1630573318 -Xiadao -最后修改时间 -datetime - - -5CBEDA96-F634-494C-859C-08B453CE7EAE -最后修改人( LastModifierId ) -LastModifierId -1630573318 -Xiadao -1630573318 -Xiadao -最后修改人 -uniqueidentifier - - -F9BCB29D-0D82-4C2F-9CEB-C161DB09575B -是否删除( IsDeleted ) -IsDeleted -1630573318 -Xiadao -1630573318 -Xiadao -是否删除 -bit -1 - - -C9E864FE-4E4F-4F81-9575-65956CDDB38D -版本号( Version ) -Version -1630573318 -Xiadao -1630573318 -Xiadao -版本号 -timestamp - - - - -11966CCA-4A4A-4A22-A805-B1F6B86FD532 -Key_1 -Key_1 -1630573318 -Xiadao -1630573318 -Xiadao - - - - - - - -87EDE0C9-D4D2-497E-81AA-2F02A6665502 -clus_idx_creationtime -clus_idx_creationtime -1630573318 -Xiadao -1630573318 -Xiadao - - -5C2306EF-091F-42C1-A571-5BB4A923DADC -1630573318 -Xiadao -1630573318 -Xiadao - - - - - - - - - - - - - - - - - - - - - -68A8C690-3BAD-4989-A402-6E78036C39DD -商品分类( Category ) -Category -1633532827 -Xiadao -1633533174 -Xiadao -商品分类 - - - -8EDCBA7E-22C9-48D5-B4B6-6C5806A44CAD -商品分类标识( CategoryId ) -CategoryId -1633532827 -Xiadao -1633533086 -Xiadao -商品分类标识 -uniqueidentifier -1 - - -80258690-088B-4A72-A925-9E9D1828DEC2 -商品分类编码( Code ) -Code -1633532827 -Xiadao -1633533106 -Xiadao -商品分类编码 -nvarchar(50) -50 -1 - - -BDC48015-9EC6-474B-BD0E-F9B534283F40 -商品分类名称( Name ) -Name -1633532827 -Xiadao -1633533122 -Xiadao -商品分类名称 -nvarchar(500) -500 -1 - - -6D18CC60-6A06-4F0B-BE91-6E4615AD3A61 -父标识( ParentId ) -ParentId -1633532827 -Xiadao -1633533142 -Xiadao -父标识 -uniqueidentifier - - -73A570E0-37FF-4B5C-9553-50CEB1AAE744 -路径( Path ) -Path -1633532827 -Xiadao -1633532827 -Xiadao -路径 -nvarchar(800) -800 -1 - - -0B42DC52-73C0-4719-A9D6-972BFE5B6B27 -层级( Level ) -Level -1633532827 -Xiadao -1633533156 -Xiadao -层级 -int -1 - - -B248AA93-2559-47C3-9B03-457AD81DBF57 -启用( Enabled ) -Enabled -1633532827 -Xiadao -1633532827 -Xiadao -启用 -bit -1 - - -2620C75C-873F-4693-B100-EA0C48AE487C -排序号 ( SortId ) -SortId -1633532827 -Xiadao -1633532827 -Xiadao -排序号 -int -1 - - -37786EB3-5BCE-44DD-85EB-9BAEFDBF6FDE -创建时间( CreationTime ) -CreationTime -1633532827 -Xiadao -1633532827 -Xiadao -创建时间 -datetime - - -52665D94-4A1F-48AA-806A-798675E955D8 -创建人( CreatorId ) -CreatorId -1633532827 -Xiadao -1633532827 -Xiadao -创建人 -uniqueidentifier - - -D05FFB71-CA2D-47D0-A25F-2E4CAF8931FA -最后修改时间( LastModificationTime ) -LastModificationTime -1633532827 -Xiadao -1633532827 -Xiadao -最后修改时间 -datetime - - -D67FBC03-A2C4-451F-AD75-B2886D351F80 -最后修改人( LastModifierId ) -LastModifierId -1633532827 -Xiadao -1633532827 -Xiadao -最后修改人 -uniqueidentifier - - -DDF20537-59FF-4FF7-A0E4-2F0A816C91FD -是否删除( IsDeleted ) -IsDeleted -1633532827 -Xiadao -1633532827 -Xiadao -是否删除 -bit -1 - - -2AF37E8E-34EE-4CC9-AA3B-060E8B273BB8 -版本号( Version ) -Version -1633532827 -Xiadao -1633532827 -Xiadao -版本号 -timestamp - - - - -2018F823-DCD9-49BE-AC2A-AC1E5FFDC83E -Key_1 -Key_1 -1633532827 -Xiadao -1633532827 -Xiadao - - - - - - - -2CABB6DB-BB9D-436F-BCEE-61F7C68AFBFB -clus_idx_creationtime -clus_idx_creationtime -1633532827 -Xiadao -1633532827 -Xiadao - - -4C99862B-E21E-4365-BE20-174BDDF08D84 -1633532827 -Xiadao -1633532827 -Xiadao - - - - - - - - - - - - - - - - - - - - - - - - - - -1F0AC123-FCDF-4573-824E-3AFF39254A6C -Reference_1 -Reference_1 -1633533744 -Xiadao -1633533744 -Xiadao -0..* - - - - - - - - - - - -C42734EF-BD87-467D-B189-EFECE817845F -1633533744 -Xiadao -1633533744 -Xiadao - - - - - - - - - - - - -8FF613F9-EF5E-4C61-8D3F-AA347DBDEAE9 -04 - 订单 -04 - 订单 -1631776163 -Xiadao -1634469208 -Xiadao - - -A7854049-DB95-46D3-BCC9-EE9A705D71C8 -01 - 订单 -01 - 订单 -1631776163 -Xiadao -1634469208 -Xiadao -[DisplayPreferences] - -[DisplayPreferences\PDM] - -[DisplayPreferences\General] -Adjust to text=Yes -Snap Grid=No -Constrain Labels=Yes -Display Grid=No -Show Page Delimiter=Yes -Show Links intersections=Yes -Activate automatic link routing=Yes -Grid size=800 -Graphic unit=2 -Window color=255 255 255 -Background image= -Background mode=8 -Watermark image= -Watermark mode=8 -Show watermark on screen=No -Gradient mode=0 -Gradient end color=255 255 255 -Show Swimlane=No -SwimlaneVert=Yes -TreeVert=No -CompDark=0 - -[DisplayPreferences\Object] -Show Icon=No -Mode=2 -Trunc Length=40 -Word Length=40 -Word Text=!"#$%&')*+,-./:;=>?@\]^_`|}~ -Shortcut IntIcon=Yes -Shortcut IntLoct=Yes -Shortcut IntFullPath=No -Shortcut IntLastPackage=Yes -Shortcut ExtIcon=Yes -Shortcut ExtLoct=No -Shortcut ExtFullPath=No -Shortcut ExtLastPackage=Yes -Shortcut ExtIncludeModl=Yes -Area.IconPicture=Yes -Area.Stereotype=Yes -Area.Comment=No -Area.TextStyle=No -Area.SubSymbols=Yes -Area_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Architecture Area Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <Separator Name="Separator" />[CRLF] <StandardAttribute Name="Comment" Attribute="Comment" Prefix="" Suffix="" Alignment="LEFT" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -EObjShowStrn=Yes -ExtendedObject.Comment=No -ExtendedObject.IconPicture=No -ExtendedObject.TextStyle=No -ExtendedObject_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Object Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <Separator Name="Separator" />[CRLF] <StandardAttribute Name="Comment" Attribute="Comment" Prefix="" Suffix="" Alignment="LEFT" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -ELnkShowStrn=Yes -ELnkShowName=Yes -ExtendedLink_SymbolLayout=<Form>[CRLF] <Form Name="Center" >[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] </Form>[CRLF] <Form Name="Source" >[CRLF] </Form>[CRLF] <Form Name="Destination" >[CRLF] </Form>[CRLF]</Form> -ExtDpdShowStrn=Yes -ExtendedDependency_SymbolLayout=<Form>[CRLF] <Form Name="Center" >[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Caption="" Mandatory="No" />[CRLF] </Form>[CRLF] <Form Name="Source" >[CRLF] </Form>[CRLF] <Form Name="Destination" >[CRLF] </Form>[CRLF]</Form> -FileObject.Stereotype=No -FileObject.DisplayName=Yes -FileObject.LocationOrName=No -FileObject.IconPicture=No -FileObject.TextStyle=No -FileObject.IconMode=Yes -FileObject_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <ExclusiveChoice Name="Exclusive Choice" Mandatory="Yes" Display="HorizontalRadios" >[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Location" Attribute="LocationOrName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] </ExclusiveChoice>[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -Package.Stereotype=Yes -Package.Comment=No -Package.IconPicture=No -Package.TextStyle=No -Package_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <Separator Name="Separator" />[CRLF] <StandardAttribute Name="Comment" Attribute="Comment" Prefix="" Suffix="" Alignment="LEFT" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -Display Model Version=Yes -Table.Stereotype=Yes -Table.DisplayName=Yes -Table.OwnerDisplayName=No -Table.Columns=Yes -Table.Columns._Filter="All Columns" PDMCOLNALL -Table.Columns._Columns=Stereotype DataType KeyIndicator -Table.Columns._Limit=-5 -Table.Keys=No -Table.Keys._Columns=Stereotype Indicator -Table.Indexes=No -Table.Indexes._Columns=Stereotype -Table.Triggers=No -Table.Triggers._Columns=Stereotype -Table.Comment=No -Table.IconPicture=No -Table.TextStyle=No -Table_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <ExclusiveChoice Name="Exclusive Choice" Mandatory="Yes" Display="HorizontalRadios" >[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Owner and Name" Attribute="OwnerDisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] </ExclusiveChoice>[CRLF] <Separator Name="Separator" />[CRLF] <StandardCollection Name="Columns" Collection="Columns" Columns="Stereotype No\r\nDisplayName Yes\r\nDataType No\r\nSymbolDataType No &quot;Domain or Data type&quot;\r\nDomain No\r\nKeyIndicator No\r\nIndexIndicator No\r\nNullStatus No" Filters="&quot;All Columns&quot; PDMCOLNALL &quot;&quot;\r\n&quot;PK Columns&quot; PDMCOLNPK &quot;\&quot;PRIM \&quot;TRUE\&quot; TRUE\&quot;&quot;\r\n&quot;Key Columns&quot; PDMCOLNKEY &quot;\&quot;KEYS \&quot;TRUE\&quot; TRUE\&quot;&quot;" HasLimit="Yes" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardCollection Name="Keys" Collection="Keys" Columns="Stereotype No\r\nDisplayName Yes\r\nIndicator No" HasLimit="No" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardCollection Name="Indexes" Collection="Indexes" Columns="Stereotype No\r\nDisplayName Yes\r\nIndicator No" HasLimit="No" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardCollection Name="Triggers" Collection="Triggers" Columns="Stereotype No\r\nDisplayName Yes" HasLimit="No" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Comment" Attribute="Comment" Prefix="" Suffix="" Alignment="LEFT" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -View.Stereotype=Yes -View.DisplayName=Yes -View.OwnerDisplayName=No -View.Columns=Yes -View.Columns._Columns=DisplayName -View.Columns._Limit=-5 -View.TemporaryVTables=Yes -View.Indexes=No -View.Comment=No -View.IconPicture=No -View.TextStyle=No -View_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <ExclusiveChoice Name="Exclusive Choice" Mandatory="Yes" Display="HorizontalRadios" >[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Owner and Name" Attribute="OwnerDisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] </ExclusiveChoice>[CRLF] <Separator Name="Separator" />[CRLF] <StandardCollection Name="Columns" Collection="Columns" Columns="DisplayName No\r\nExpression No\r\nDataType No\r\nSymbolDataType No &quot;Domain or Data type&quot;\r\nIndexIndicator No" HasLimit="Yes" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardCollection Name="Tables" Collection="TemporaryVTables" Columns="Name Yes" HasLimit="No" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardCollection Name="Indexes" Collection="Indexes" Columns="DisplayName Yes" HasLimit="No" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Comment" Attribute="Comment" Prefix="" Suffix="" Alignment="LEFT" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -Procedure.Stereotype=No -Procedure.DisplayName=Yes -Procedure.OwnerDisplayName=No -Procedure.Comment=No -Procedure.IconPicture=No -Procedure.TextStyle=No -Procedure_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <ExclusiveChoice Name="Exclusive Choice" Mandatory="Yes" Display="HorizontalRadios" >[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Owner and Name" Attribute="OwnerDisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] </ExclusiveChoice>[CRLF] <Separator Name="Separator" />[CRLF] <StandardAttribute Name="Comment" Attribute="Comment" Prefix="" Suffix="" Alignment="LEFT" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -Reference.Cardinality=No -Reference.ImplementationType=No -Reference.ChildRole=Yes -Reference.Stereotype=Yes -Reference.DisplayName=No -Reference.ForeignKeyConstraintName=No -Reference.JoinExpression=No -Reference.Integrity=No -Reference.ParentRole=Yes -Reference_SymbolLayout=<Form>[CRLF] <Form Name="Source" >[CRLF] <StandardAttribute Name="Cardinality" Attribute="Cardinality" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Implementation" Attribute="ImplementationType" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Child Role" Attribute="ChildRole" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] </Form>[CRLF] <Form Name="Center" >[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Caption="" Mandatory="No" />[CRLF] <ExclusiveChoice Name="Exclusive Choice" Mandatory="No" Display="HorizontalRadios" >[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Cons&amp;traint Name" Attribute="ForeignKeyConstraintName" Prefix="" Suffix="" Caption="Cons&amp;traint Name" Mandatory="No" />[CRLF] <StandardAttribute Name="Join" Attribute="JoinExpression" Prefix="" Suffix="" Caption="Join" Mandatory="No" />[CRLF] </ExclusiveChoice>[CRLF] <StandardAttribute Name="Referential integrity" Attribute="Integrity" Prefix="" Suffix="" Caption="Referential integrity" Mandatory="No" />[CRLF] </Form>[CRLF] <Form Name="Destination" >[CRLF] <StandardAttribute Name="Parent Role" Attribute="ParentRole" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] </Form>[CRLF]</Form> -ViewReference.ChildRole=Yes -ViewReference.Stereotype=Yes -ViewReference.DisplayName=No -ViewReference.JoinExpression=No -ViewReference.ParentRole=Yes -ViewReference_SymbolLayout=<Form>[CRLF] <Form Name="Source" >[CRLF] <StandardAttribute Name="Child Role" Attribute="ChildRole" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] </Form>[CRLF] <Form Name="Center" >[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Caption="" Mandatory="No" />[CRLF] <ExclusiveChoice Name="Exclusive Choice" Mandatory="No" Display="HorizontalRadios" >[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Join Expression" Attribute="JoinExpression" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] </ExclusiveChoice>[CRLF] </Form>[CRLF] <Form Name="Destination" >[CRLF] <StandardAttribute Name="Parent Role" Attribute="ParentRole" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] </Form>[CRLF]</Form> - -[DisplayPreferences\Symbol] - -[DisplayPreferences\Symbol\AREA] -STRNFont=新宋体,8,N -STRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -LABLFont=新宋体,8,N -LABLFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=9600 -Height=8000 -Brush color=253 249 234 -Fill Color=Yes -Brush style=6 -Brush bitmap mode=12 -Brush gradient mode=16 -Brush gradient color=245 230 173 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 121 98 6 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\FRMEOBJ] -STRNFont=新宋体,8,N -STRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -LABLFont=新宋体,8,N -LABLFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=6000 -Height=2000 -Brush color=255 255 255 -Fill Color=Yes -Brush style=6 -Brush bitmap mode=12 -Brush gradient mode=64 -Brush gradient color=192 192 192 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 255 128 128 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\FRMELNK] -CENTERFont=新宋体,8,N -CENTERFont color=0 0 0 -Line style=1 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Brush color=255 255 255 -Fill Color=Yes -Brush style=1 -Brush bitmap mode=12 -Brush gradient mode=0 -Brush gradient color=118 118 118 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 128 128 255 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\USRDEPD] -CENTERFont=新宋体,8,N -CENTERFont color=0 0 0 -Line style=1 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Brush color=255 255 255 -Fill Color=Yes -Brush style=1 -Brush bitmap mode=12 -Brush gradient mode=0 -Brush gradient color=118 118 118 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=2 0 128 128 255 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\FILO] -OBJSTRNFont=新宋体,8,N -OBJSTRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -LCNMFont=新宋体,8,N -LCNMFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=4800 -Height=3600 -Brush color=255 255 255 -Fill Color=Yes -Brush style=1 -Brush bitmap mode=12 -Brush gradient mode=0 -Brush gradient color=118 118 118 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 0 0 255 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\PDMPCKG] -STRNFont=新宋体,8,N -STRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -LABLFont=新宋体,8,N -LABLFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=4800 -Height=4000 -Brush color=255 255 192 -Fill Color=Yes -Brush style=6 -Brush bitmap mode=12 -Brush gradient mode=65 -Brush gradient color=255 255 255 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 178 178 178 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\TABL] -STRNFont=新宋体,8,N -STRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -OWNRDISPNAMEFont=新宋体,8,N -OWNRDISPNAMEFont color=0 0 0 -ColumnsFont=新宋体,8,N -ColumnsFont color=0 0 0 -TablePkColumnsFont=新宋体,8,U -TablePkColumnsFont color=0 0 0 -TableFkColumnsFont=新宋体,8,N -TableFkColumnsFont color=0 0 0 -KeysFont=新宋体,8,N -KeysFont color=0 0 0 -IndexesFont=新宋体,8,N -IndexesFont color=0 0 0 -TriggersFont=新宋体,8,N -TriggersFont color=0 0 0 -LABLFont=新宋体,8,N -LABLFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=4800 -Height=4000 -Brush color=178 214 252 -Fill Color=Yes -Brush style=6 -Brush bitmap mode=12 -Brush gradient mode=65 -Brush gradient color=255 255 255 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 0 128 192 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\VIEW] -STRNFont=新宋体,8,N -STRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -OWNRDISPNAMEFont=新宋体,8,N -OWNRDISPNAMEFont color=0 0 0 -ColumnsFont=新宋体,8,N -ColumnsFont color=0 0 0 -TablePkColumnsFont=新宋体,8,U -TablePkColumnsFont color=0 0 0 -TableFkColumnsFont=新宋体,8,N -TableFkColumnsFont color=0 0 0 -TemporaryVTablesFont=新宋体,8,N -TemporaryVTablesFont color=0 0 0 -IndexesFont=新宋体,8,N -IndexesFont color=0 0 0 -LABLFont=新宋体,8,N -LABLFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=4800 -Height=4000 -Brush color=208 208 255 -Fill Color=Yes -Brush style=6 -Brush bitmap mode=12 -Brush gradient mode=65 -Brush gradient color=255 255 255 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 128 128 192 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\PROC] -STRNFont=新宋体,8,N -STRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -OWNRDISPNAMEFont=新宋体,8,N -OWNRDISPNAMEFont color=0 0 0 -LABLFont=新宋体,8,N -LABLFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=4000 -Height=1000 -Brush color=255 255 192 -Fill Color=Yes -Brush style=6 -Brush bitmap mode=12 -Brush gradient mode=65 -Brush gradient color=255 255 255 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 128 108 0 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\REFR] -SOURCEFont=新宋体,8,N -SOURCEFont color=0 0 0 -CENTERFont=新宋体,8,N -CENTERFont color=0 0 0 -DESTINATIONFont=新宋体,8,N -DESTINATIONFont color=0 0 0 -Line style=1 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Brush color=255 255 255 -Fill Color=Yes -Brush style=1 -Brush bitmap mode=12 -Brush gradient mode=0 -Brush gradient color=118 118 118 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 0 128 192 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\VREF] -SOURCEFont=新宋体,8,N -SOURCEFont color=0 0 0 -CENTERFont=新宋体,8,N -CENTERFont color=0 0 0 -DESTINATIONFont=新宋体,8,N -DESTINATIONFont color=0 0 0 -Line style=1 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Brush color=255 255 255 -Fill Color=Yes -Brush style=1 -Brush bitmap mode=12 -Brush gradient mode=0 -Brush gradient color=118 118 118 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 128 128 192 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\Free Symbol] -Free TextFont=新宋体,8,N -Free TextFont color=0 0 0 -Line style=0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Brush color=255 255 255 -Fill Color=Yes -Brush style=1 -Brush bitmap mode=12 -Brush gradient mode=0 -Brush gradient color=118 118 118 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 0 0 255 -Shadow color=192 192 192 -Shadow=0 -(8268, 11693) -((315,354), (433,354)) -1 -15 - - -1631785980 -1631786175 -((-7856,-17298), (-6606,-11748)) -((-7231,-12148),(-7231,-16898)) -1 -1 -12615680 -12632256 -CENTER 0 新宋体,8,N -SOURCE 0 新宋体,8,N -DESTINATION 0 新宋体,8,N -3 - - - - - - - - - - - -1631786394 -1631786394 -((-7742,-5806), (-6492,-1775)) -((-7117,-5406),(-7117,-2175)) -1 -1 -12615680 -12632256 -CENTER 0 新宋体,8,N -SOURCE 0 新宋体,8,N -DESTINATION 0 新宋体,8,N - - - - - - - - - - - -1634469208 -1634469208 -((-6802,7545), (-5552,12659)) -((-6177,7945),(-6177,12259)) -1 -1 -12615680 -12632256 -CENTER 0 新宋体,8,N -SOURCE 0 新宋体,8,N -DESTINATION 0 新宋体,8,N - - - - - - - - - - - -1631776192 -1631786172 --1 -((-18140,-2175), (3906,7945)) -0 -12615680 -16570034 -12632256 -STRN 0 新宋体,8,N -DISPNAME 0 新宋体,8,N -OWNRDISPNAME 0 新宋体,8,N -Columns 0 新宋体,8,N -TablePkColumns 0 新宋体,8,U -TableFkColumns 0 新宋体,8,N -Keys 0 新宋体,8,N -Indexes 0 新宋体,8,N -Triggers 0 新宋体,8,N -LABL 0 新宋体,8,N -6 -65 -16777215 -1 - - - - - -1631776209 -1631786169 --1 -((-18310,-12148), (4922,-5406)) -0 -12615680 -16570034 -12632256 -STRN 0 新宋体,8,N -DISPNAME 0 新宋体,8,N -OWNRDISPNAME 0 新宋体,8,N -Columns 0 新宋体,8,N -TablePkColumns 0 新宋体,8,U -TableFkColumns 0 新宋体,8,N -Keys 0 新宋体,8,N -Indexes 0 新宋体,8,N -Triggers 0 新宋体,8,N -LABL 0 新宋体,8,N -6 -65 -16777215 -1 - - - - - -1631785959 -1631785966 --1 -((-17412,-30179), (9034,-16841)) -0 -12615680 -16570034 -12632256 -STRN 0 新宋体,8,N -DISPNAME 0 新宋体,8,N -OWNRDISPNAME 0 新宋体,8,N -Columns 0 新宋体,8,N -TablePkColumns 0 新宋体,8,U -TableFkColumns 0 新宋体,8,N -Keys 0 新宋体,8,N -Indexes 0 新宋体,8,N -Triggers 0 新宋体,8,N -LABL 0 新宋体,8,N -6 -65 -16777215 -1 - - - - - -1634469187 -1634469214 --1 -((-17663,12259), (5309,28103)) -0 -12615680 -16570034 -12632256 -STRN 0 新宋体,8,N -DISPNAME 0 新宋体,8,N -OWNRDISPNAME 0 新宋体,8,N -Columns 0 新宋体,8,N -TablePkColumns 0 新宋体,8,U -TableFkColumns 0 新宋体,8,N -Keys 0 新宋体,8,N -Indexes 0 新宋体,8,N -Triggers 0 新宋体,8,N -LABL 0 新宋体,8,N -6 -65 -16777215 -1 - - - - - - - - - - - - -CD94F13A-7AC3-404B-8C30-07349EB77FFC -订单( Order ) -Order -1631776192 -Xiadao -1634469988 -Xiadao -订单 - - - -F832F242-7A0F-416D-8D03-DB9FA0B93497 -订单标识( OrderId ) -OrderId -1631776192 -Xiadao -1632130976 -Xiadao -订单标识 -nvarchar(256) -256 -1 - - -E99D2B7D-948B-4F31-B2DF-98CBC8EF9599 -客户标识( CustomerId ) -CustomerId -1634469208 -Xiadao -1634469233 -Xiadao -客户标识 -int -1 -1 - - -777BE324-C260-497E-BE0B-C699CB638F6E -客户名称( CustomerName ) -CustomerName -1631776192 -Xiadao -1631776192 -Xiadao -客户名称 -nvarchar(200) -200 - - -5393A178-F4BF-4A32-96B2-FB371880E49F -金额( Amount ) -Amount -1631776192 -Xiadao -1631786241 -Xiadao -金额 -decimal(15,2) -15 -2 -1 - - -0F11D2A5-36F2-440C-9EC8-2008E3760849 -下单时间( PlaceOrderTime ) -PlaceOrderTime -1631776192 -Xiadao -1631776192 -Xiadao -下单时间 -datetime -1 - - -D8F68ED7-51B4-4B1B-9671-E84B258BF14B -订单状态( State ) -State -1631776192 -Xiadao -1631776192 -Xiadao -订单状态 -int -1 - - -6B467CE5-C50D-496E-8DD5-1D297B64FCE1 -是否删除( IsDeleted ) -IsDeleted -1631776192 -Xiadao -1631776192 -Xiadao -是否删除 -bit -1 - - -0953EE6D-44A5-4A38-8A5F-FF29C368DCD5 -版本号( Version ) -Version -1631776192 -Xiadao -1631776192 -Xiadao -版本号 -timestamp - - - - -4D3D59AA-84F6-42AA-A57F-B7BBF76F7A52 -Key_1 -Key_1 -1631776192 -Xiadao -1631776192 -Xiadao - - - - - - - -337371E1-6706-499E-898F-4734CED5264D -clus_idx_placetime -clus_idx_placetime -1631776192 -Xiadao -1631776192 -Xiadao - - -DAFF9F3A-32AD-45DF-A817-C526ACDF629D -1631776192 -Xiadao -1631776192 -Xiadao - - - - - - - - - - - - - - - - - - - - - -28D8BD2F-1F80-4EFE-97E4-33992A0636C7 -订单明细( OrderItem ) -OrderItem -1631776209 -Xiadao -1631786407 -Xiadao -订单明细 - - - -E8EBFC5B-F75B-41D2-865D-84697FA961E5 -订单明细标识( OrderItemId ) -OrderItemId -1631776209 -Xiadao -1632130998 -Xiadao -订单明细标识 -uniqueidentifier -1 - - -199BF524-5555-404A-840B-B1AE6C69F24E -订单标识( OrderId ) -OrderId -1631786394 -Xiadao -1632131006 -Xiadao -订单标识 -nvarchar(256) -256 -1 -1 - - -EA92698D-332D-4912-A000-AEDC558F968C -产品标识( ProductId ) -ProductId -1631785980 -Xiadao -1632131014 -Xiadao -产品标识 -uniqueidentifier -1 - - -F41E0B62-8456-4A76-8F6B-FC8DBA4DA214 -产品名称( ProductName ) -ProductName -1631776209 -Xiadao -1631786137 -Xiadao -产品名称 -nvarchar(500) -500 -1 - - -7EEB28F6-5976-4306-A1B1-A8B67D2A138A -单价( Price ) -Price -1631776209 -Xiadao -1631786154 -Xiadao -单价 -decimal(12,2) -12 -2 -1 - - -68CE9F04-BF44-435D-A44B-ABBF790C2261 -数量( Quantity ) -Quantity -1631776209 -Xiadao -1631776209 -Xiadao -数量 -int -1 - - - - -8C1ED9AC-57EE-4F0F-A886-931AD5EABE52 -clus_idx_orderitemid -clus_idx_orderitemid -1631776209 -Xiadao -1631776209 -Xiadao - - - - - - - - - - - - - - - - -9487E398-F6C4-48D5-998D-197532328D09 -产品( Product ) -Product -1631785959 -Xiadao -1631785959 -Xiadao - -2E6FA781-2BB6-4E53-8EE0-A2A7D9DBE25F -380BAA40-0042-11D2-BD28-00A02478ECC9 -<Model>::03 - 商品 - - -59E00B00-F3C8-47DB-935E-F1E23E284FAD -客户( Customer ) -Customer -1634469187 -Xiadao -1634469187 -Xiadao - -BD102691-5783-434C-9D80-CC022FC53A38 -380BAA40-0042-11D2-BD28-00A02478ECC9 -<Model>::02- 客户 - - - - -D3B1007E-23E8-4F7C-847C-D05BC6C5A03A -Reference_2 -Reference_2 -1631785980 -Xiadao -1631785980 -Xiadao -0..* - - - - - - - - - - - -4DE26E79-A278-4115-8750-404DB4A2FA5B -1631785980 -Xiadao -1631785980 -Xiadao - - - - - - - - - - -E891B7D4-9C5D-47BE-9C74-2ADDFFABD5EF -Reference_3 -Reference_3 -1631786394 -Xiadao -1631786394 -Xiadao -0..* - - - - - - - - - - - -E86F9047-6AE9-412B-9155-E33141187310 -1631786394 -Xiadao -1631786394 -Xiadao - - - - - - - - - - -43FDC985-84BF-458E-A19B-D9D29E34C66A -Reference_4 -Reference_4 -1634469208 -Xiadao -1634469208 -Xiadao -0..* - - - - - - - - - - - -AB93EA2F-DB82-4A48-8A24-EFED2909DB39 -1634469208 -Xiadao -1634469208 -Xiadao - - - - - - - - - - - - -787E9839-BD38-4DAF-907E-4CC09AC6C353 -02- 客户 -02- 客户 -1631784514 -Xiadao -1631784626 -Xiadao - - -4E4FADC5-9A54-47F8-AD0B-8399B8F0B4AA -01 - 客户 -01 - 客户 -1631784514 -Xiadao -1631784626 -Xiadao -[DisplayPreferences] - -[DisplayPreferences\PDM] - -[DisplayPreferences\General] -Adjust to text=Yes -Snap Grid=No -Constrain Labels=Yes -Display Grid=No -Show Page Delimiter=Yes -Show Links intersections=Yes -Activate automatic link routing=Yes -Grid size=800 -Graphic unit=2 -Window color=255 255 255 -Background image= -Background mode=8 -Watermark image= -Watermark mode=8 -Show watermark on screen=No -Gradient mode=0 -Gradient end color=255 255 255 -Show Swimlane=No -SwimlaneVert=Yes -TreeVert=No -CompDark=0 - -[DisplayPreferences\Object] -Show Icon=No -Mode=2 -Trunc Length=40 -Word Length=40 -Word Text=!"#$%&')*+,-./:;=>?@\]^_`|}~ -Shortcut IntIcon=Yes -Shortcut IntLoct=Yes -Shortcut IntFullPath=No -Shortcut IntLastPackage=Yes -Shortcut ExtIcon=Yes -Shortcut ExtLoct=No -Shortcut ExtFullPath=No -Shortcut ExtLastPackage=Yes -Shortcut ExtIncludeModl=Yes -Area.IconPicture=Yes -Area.Stereotype=Yes -Area.Comment=No -Area.TextStyle=No -Area.SubSymbols=Yes -Area_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Architecture Area Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <Separator Name="Separator" />[CRLF] <StandardAttribute Name="Comment" Attribute="Comment" Prefix="" Suffix="" Alignment="LEFT" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -EObjShowStrn=Yes -ExtendedObject.Comment=No -ExtendedObject.IconPicture=No -ExtendedObject.TextStyle=No -ExtendedObject_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Object Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <Separator Name="Separator" />[CRLF] <StandardAttribute Name="Comment" Attribute="Comment" Prefix="" Suffix="" Alignment="LEFT" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -ELnkShowStrn=Yes -ELnkShowName=Yes -ExtendedLink_SymbolLayout=<Form>[CRLF] <Form Name="Center" >[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] </Form>[CRLF] <Form Name="Source" >[CRLF] </Form>[CRLF] <Form Name="Destination" >[CRLF] </Form>[CRLF]</Form> -ExtDpdShowStrn=Yes -ExtendedDependency_SymbolLayout=<Form>[CRLF] <Form Name="Center" >[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Caption="" Mandatory="No" />[CRLF] </Form>[CRLF] <Form Name="Source" >[CRLF] </Form>[CRLF] <Form Name="Destination" >[CRLF] </Form>[CRLF]</Form> -FileObject.Stereotype=No -FileObject.DisplayName=Yes -FileObject.LocationOrName=No -FileObject.IconPicture=No -FileObject.TextStyle=No -FileObject.IconMode=Yes -FileObject_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <ExclusiveChoice Name="Exclusive Choice" Mandatory="Yes" Display="HorizontalRadios" >[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Location" Attribute="LocationOrName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] </ExclusiveChoice>[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -Package.Stereotype=Yes -Package.Comment=No -Package.IconPicture=No -Package.TextStyle=No -Package_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <Separator Name="Separator" />[CRLF] <StandardAttribute Name="Comment" Attribute="Comment" Prefix="" Suffix="" Alignment="LEFT" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -Display Model Version=Yes -Table.Stereotype=Yes -Table.DisplayName=Yes -Table.OwnerDisplayName=No -Table.Columns=Yes -Table.Columns._Filter="All Columns" PDMCOLNALL -Table.Columns._Columns=Stereotype DataType KeyIndicator -Table.Columns._Limit=-5 -Table.Keys=No -Table.Keys._Columns=Stereotype Indicator -Table.Indexes=No -Table.Indexes._Columns=Stereotype -Table.Triggers=No -Table.Triggers._Columns=Stereotype -Table.Comment=No -Table.IconPicture=No -Table.TextStyle=No -Table_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <ExclusiveChoice Name="Exclusive Choice" Mandatory="Yes" Display="HorizontalRadios" >[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Owner and Name" Attribute="OwnerDisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] </ExclusiveChoice>[CRLF] <Separator Name="Separator" />[CRLF] <StandardCollection Name="Columns" Collection="Columns" Columns="Stereotype No\r\nDisplayName Yes\r\nDataType No\r\nSymbolDataType No &quot;Domain or Data type&quot;\r\nDomain No\r\nKeyIndicator No\r\nIndexIndicator No\r\nNullStatus No" Filters="&quot;All Columns&quot; PDMCOLNALL &quot;&quot;\r\n&quot;PK Columns&quot; PDMCOLNPK &quot;\&quot;PRIM \&quot;TRUE\&quot; TRUE\&quot;&quot;\r\n&quot;Key Columns&quot; PDMCOLNKEY &quot;\&quot;KEYS \&quot;TRUE\&quot; TRUE\&quot;&quot;" HasLimit="Yes" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardCollection Name="Keys" Collection="Keys" Columns="Stereotype No\r\nDisplayName Yes\r\nIndicator No" HasLimit="No" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardCollection Name="Indexes" Collection="Indexes" Columns="Stereotype No\r\nDisplayName Yes\r\nIndicator No" HasLimit="No" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardCollection Name="Triggers" Collection="Triggers" Columns="Stereotype No\r\nDisplayName Yes" HasLimit="No" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Comment" Attribute="Comment" Prefix="" Suffix="" Alignment="LEFT" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -View.Stereotype=Yes -View.DisplayName=Yes -View.OwnerDisplayName=No -View.Columns=Yes -View.Columns._Columns=DisplayName -View.Columns._Limit=-5 -View.TemporaryVTables=Yes -View.Indexes=No -View.Comment=No -View.IconPicture=No -View.TextStyle=No -View_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <ExclusiveChoice Name="Exclusive Choice" Mandatory="Yes" Display="HorizontalRadios" >[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Owner and Name" Attribute="OwnerDisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] </ExclusiveChoice>[CRLF] <Separator Name="Separator" />[CRLF] <StandardCollection Name="Columns" Collection="Columns" Columns="DisplayName No\r\nExpression No\r\nDataType No\r\nSymbolDataType No &quot;Domain or Data type&quot;\r\nIndexIndicator No" HasLimit="Yes" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardCollection Name="Tables" Collection="TemporaryVTables" Columns="Name Yes" HasLimit="No" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardCollection Name="Indexes" Collection="Indexes" Columns="DisplayName Yes" HasLimit="No" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Comment" Attribute="Comment" Prefix="" Suffix="" Alignment="LEFT" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -Procedure.Stereotype=No -Procedure.DisplayName=Yes -Procedure.OwnerDisplayName=No -Procedure.Comment=No -Procedure.IconPicture=No -Procedure.TextStyle=No -Procedure_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <ExclusiveChoice Name="Exclusive Choice" Mandatory="Yes" Display="HorizontalRadios" >[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Owner and Name" Attribute="OwnerDisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] </ExclusiveChoice>[CRLF] <Separator Name="Separator" />[CRLF] <StandardAttribute Name="Comment" Attribute="Comment" Prefix="" Suffix="" Alignment="LEFT" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -Reference.Cardinality=No -Reference.ImplementationType=No -Reference.ChildRole=Yes -Reference.Stereotype=Yes -Reference.DisplayName=No -Reference.ForeignKeyConstraintName=No -Reference.JoinExpression=No -Reference.Integrity=No -Reference.ParentRole=Yes -Reference_SymbolLayout=<Form>[CRLF] <Form Name="Source" >[CRLF] <StandardAttribute Name="Cardinality" Attribute="Cardinality" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Implementation" Attribute="ImplementationType" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Child Role" Attribute="ChildRole" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] </Form>[CRLF] <Form Name="Center" >[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Caption="" Mandatory="No" />[CRLF] <ExclusiveChoice Name="Exclusive Choice" Mandatory="No" Display="HorizontalRadios" >[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Cons&amp;traint Name" Attribute="ForeignKeyConstraintName" Prefix="" Suffix="" Caption="Cons&amp;traint Name" Mandatory="No" />[CRLF] <StandardAttribute Name="Join" Attribute="JoinExpression" Prefix="" Suffix="" Caption="Join" Mandatory="No" />[CRLF] </ExclusiveChoice>[CRLF] <StandardAttribute Name="Referential integrity" Attribute="Integrity" Prefix="" Suffix="" Caption="Referential integrity" Mandatory="No" />[CRLF] </Form>[CRLF] <Form Name="Destination" >[CRLF] <StandardAttribute Name="Parent Role" Attribute="ParentRole" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] </Form>[CRLF]</Form> -ViewReference.ChildRole=Yes -ViewReference.Stereotype=Yes -ViewReference.DisplayName=No -ViewReference.JoinExpression=No -ViewReference.ParentRole=Yes -ViewReference_SymbolLayout=<Form>[CRLF] <Form Name="Source" >[CRLF] <StandardAttribute Name="Child Role" Attribute="ChildRole" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] </Form>[CRLF] <Form Name="Center" >[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Caption="" Mandatory="No" />[CRLF] <ExclusiveChoice Name="Exclusive Choice" Mandatory="No" Display="HorizontalRadios" >[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Join Expression" Attribute="JoinExpression" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] </ExclusiveChoice>[CRLF] </Form>[CRLF] <Form Name="Destination" >[CRLF] <StandardAttribute Name="Parent Role" Attribute="ParentRole" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] </Form>[CRLF]</Form> - -[DisplayPreferences\Symbol] - -[DisplayPreferences\Symbol\AREA] -STRNFont=新宋体,8,N -STRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -LABLFont=新宋体,8,N -LABLFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=9600 -Height=8000 -Brush color=253 249 234 -Fill Color=Yes -Brush style=6 -Brush bitmap mode=12 -Brush gradient mode=16 -Brush gradient color=245 230 173 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 121 98 6 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\FRMEOBJ] -STRNFont=新宋体,8,N -STRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -LABLFont=新宋体,8,N -LABLFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=6000 -Height=2000 -Brush color=255 255 255 -Fill Color=Yes -Brush style=6 -Brush bitmap mode=12 -Brush gradient mode=64 -Brush gradient color=192 192 192 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 255 128 128 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\FRMELNK] -CENTERFont=新宋体,8,N -CENTERFont color=0 0 0 -Line style=1 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Brush color=255 255 255 -Fill Color=Yes -Brush style=1 -Brush bitmap mode=12 -Brush gradient mode=0 -Brush gradient color=118 118 118 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 128 128 255 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\USRDEPD] -CENTERFont=新宋体,8,N -CENTERFont color=0 0 0 -Line style=1 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Brush color=255 255 255 -Fill Color=Yes -Brush style=1 -Brush bitmap mode=12 -Brush gradient mode=0 -Brush gradient color=118 118 118 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=2 0 128 128 255 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\FILO] -OBJSTRNFont=新宋体,8,N -OBJSTRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -LCNMFont=新宋体,8,N -LCNMFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=4800 -Height=3600 -Brush color=255 255 255 -Fill Color=Yes -Brush style=1 -Brush bitmap mode=12 -Brush gradient mode=0 -Brush gradient color=118 118 118 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 0 0 255 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\PDMPCKG] -STRNFont=新宋体,8,N -STRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -LABLFont=新宋体,8,N -LABLFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=4800 -Height=4000 -Brush color=255 255 192 -Fill Color=Yes -Brush style=6 -Brush bitmap mode=12 -Brush gradient mode=65 -Brush gradient color=255 255 255 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 178 178 178 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\TABL] -STRNFont=新宋体,8,N -STRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -OWNRDISPNAMEFont=新宋体,8,N -OWNRDISPNAMEFont color=0 0 0 -ColumnsFont=新宋体,8,N -ColumnsFont color=0 0 0 -TablePkColumnsFont=新宋体,8,U -TablePkColumnsFont color=0 0 0 -TableFkColumnsFont=新宋体,8,N -TableFkColumnsFont color=0 0 0 -KeysFont=新宋体,8,N -KeysFont color=0 0 0 -IndexesFont=新宋体,8,N -IndexesFont color=0 0 0 -TriggersFont=新宋体,8,N -TriggersFont color=0 0 0 -LABLFont=新宋体,8,N -LABLFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=4800 -Height=4000 -Brush color=178 214 252 -Fill Color=Yes -Brush style=6 -Brush bitmap mode=12 -Brush gradient mode=65 -Brush gradient color=255 255 255 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 0 128 192 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\VIEW] -STRNFont=新宋体,8,N -STRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -OWNRDISPNAMEFont=新宋体,8,N -OWNRDISPNAMEFont color=0 0 0 -ColumnsFont=新宋体,8,N -ColumnsFont color=0 0 0 -TablePkColumnsFont=新宋体,8,U -TablePkColumnsFont color=0 0 0 -TableFkColumnsFont=新宋体,8,N -TableFkColumnsFont color=0 0 0 -TemporaryVTablesFont=新宋体,8,N -TemporaryVTablesFont color=0 0 0 -IndexesFont=新宋体,8,N -IndexesFont color=0 0 0 -LABLFont=新宋体,8,N -LABLFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=4800 -Height=4000 -Brush color=208 208 255 -Fill Color=Yes -Brush style=6 -Brush bitmap mode=12 -Brush gradient mode=65 -Brush gradient color=255 255 255 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 128 128 192 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\PROC] -STRNFont=新宋体,8,N -STRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -OWNRDISPNAMEFont=新宋体,8,N -OWNRDISPNAMEFont color=0 0 0 -LABLFont=新宋体,8,N -LABLFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=4000 -Height=1000 -Brush color=255 255 192 -Fill Color=Yes -Brush style=6 -Brush bitmap mode=12 -Brush gradient mode=65 -Brush gradient color=255 255 255 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 128 108 0 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\REFR] -SOURCEFont=新宋体,8,N -SOURCEFont color=0 0 0 -CENTERFont=新宋体,8,N -CENTERFont color=0 0 0 -DESTINATIONFont=新宋体,8,N -DESTINATIONFont color=0 0 0 -Line style=1 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Brush color=255 255 255 -Fill Color=Yes -Brush style=1 -Brush bitmap mode=12 -Brush gradient mode=0 -Brush gradient color=118 118 118 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 0 128 192 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\VREF] -SOURCEFont=新宋体,8,N -SOURCEFont color=0 0 0 -CENTERFont=新宋体,8,N -CENTERFont color=0 0 0 -DESTINATIONFont=新宋体,8,N -DESTINATIONFont color=0 0 0 -Line style=1 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Brush color=255 255 255 -Fill Color=Yes -Brush style=1 -Brush bitmap mode=12 -Brush gradient mode=0 -Brush gradient color=118 118 118 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 128 128 192 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\Free Symbol] -Free TextFont=新宋体,8,N -Free TextFont color=0 0 0 -Line style=0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Brush color=255 255 255 -Fill Color=Yes -Brush style=1 -Brush bitmap mode=12 -Brush gradient mode=0 -Brush gradient color=118 118 118 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 0 0 255 -Shadow color=192 192 192 -Shadow=0 -(8268, 11693) -((315,354), (433,354)) -1 -15 - - -1631784563 -1631788824 --1 -((-13248,-17405), (9724,-2855)) -0 -12615680 -16570034 -12632256 -STRN 0 新宋体,8,N -DISPNAME 0 新宋体,8,N -OWNRDISPNAME 0 新宋体,8,N -Columns 0 新宋体,8,N -TablePkColumns 0 新宋体,8,U -TableFkColumns 0 新宋体,8,N -Keys 0 新宋体,8,N -Indexes 0 新宋体,8,N -Triggers 0 新宋体,8,N -LABL 0 新宋体,8,N -6 -65 -16777215 -1 - - - - - - - - - - - - -BD102691-5783-434C-9D80-CC022FC53A38 -客户( Customer ) -Customer -1631784563 -Xiadao -1631788821 -Xiadao -客户 - - - -35488561-5B22-4184-93DE-8614D1B5EAB0 -客户标识( CustomerId ) -CustomerId -1631784592 -Xiadao -1631785156 -Xiadao -客户标识 -int -1 -1 - - -E2C97AB7-BD0D-4CD7-8889-BF08061515F0 -编码( Code ) -Code -1631784563 -Xiadao -1631784563 -Xiadao -编码 -nvarchar(100) -100 - - -8BA50C63-275A-4011-9C70-1EA831837025 -姓名( Name ) -Name -1631784563 -Xiadao -1631784563 -Xiadao -姓名 -nvarchar(200) -200 - - -9803F730-D585-4692-8FE0-D406D9591166 -昵称( Nickname ) -Nickname -1631784563 -Xiadao -1631784563 -Xiadao -昵称 -nvarchar(50) -50 - - -C2DD58A8-0910-44E4-8B40-4C0D5BCF8422 -性别( Gender ) -Gender -1631784563 -Xiadao -1631784563 -Xiadao -性别 -int - - -25AE0B51-33E9-4700-AAC7-C511A8BA098B -出生日期( Birthday ) -Birthday -1631784563 -Xiadao -1631784563 -Xiadao -出生日期 -datetime - - -5B340712-D0DA-4152-954C-A44FAA83AAB9 -民族( Nation ) -Nation -1631784563 -Xiadao -1631784563 -Xiadao -民族 -int - - -A8A2CD10-A1E0-465F-A0DE-FC956E3EE09A -手机号( Phone ) -Phone -1631784563 -Xiadao -1631784563 -Xiadao -手机号 -nvarchar(50) -50 - - -83D69016-E2AC-43D6-86E7-9DF60ACCF899 -电子邮件( Email ) -Email -1631784563 -Xiadao -1631784563 -Xiadao -电子邮件 -nvarchar(500) -500 - - -C3288051-E1C4-436F-8791-E3B8CBC59592 -创建时间( CreationTime ) -CreationTime -1631784563 -Xiadao -1631784563 -Xiadao -创建时间 -datetime - - -38087254-9712-4E05-8556-484658221223 -创建人( CreatorId ) -CreatorId -1631784563 -Xiadao -1631784563 -Xiadao -创建人 -uniqueidentifier - - -630E284E-442F-47C7-9CE7-72A50715BE6B -最后修改时间( LastModificationTime ) -LastModificationTime -1631784563 -Xiadao -1631784563 -Xiadao -最后修改时间 -datetime - - -1D7D1D1E-7EF6-41C1-9C2F-C26083508E09 -最后修改人( LastModifierId ) -LastModifierId -1631784563 -Xiadao -1631784563 -Xiadao -最后修改人 -uniqueidentifier - - -E75E55F0-A608-458C-9743-4950D71F6DA0 -是否删除( IsDeleted ) -IsDeleted -1631784563 -Xiadao -1631784563 -Xiadao -是否删除 -bit -1 - - -D2CBCEDE-4263-49E5-A0E2-F3D3AD7D4BA5 -版本号( Version ) -Version -1631784563 -Xiadao -1631784563 -Xiadao -版本号 -timestamp - - - - -B1C30BB8-8AE2-4E41-ACEC-1FD073EED22B -Key_1 -Key_1 -1631784563 -Xiadao -1631785156 -Xiadao - - - - - - - - - - - - - - - - - - -BF4ED0CA-69B4-4DE1-996C-34192084F70D -05 - 博客 -05 - 博客 -1634474081 -Xiadao -1634479459 -Xiadao - - -7294C4E9-50EA-443A-861F-4ABD810E34DC -01 - 贴子 -01 - 贴子 -1634474081 -Xiadao -1634479459 -Xiadao -[DisplayPreferences] - -[DisplayPreferences\PDM] - -[DisplayPreferences\General] -Adjust to text=Yes -Snap Grid=No -Constrain Labels=Yes -Display Grid=No -Show Page Delimiter=Yes -Show Links intersections=Yes -Activate automatic link routing=Yes -Grid size=800 -Graphic unit=2 -Window color=255 255 255 -Background image= -Background mode=8 -Watermark image= -Watermark mode=8 -Show watermark on screen=No -Gradient mode=0 -Gradient end color=255 255 255 -Show Swimlane=No -SwimlaneVert=Yes -TreeVert=No -CompDark=0 - -[DisplayPreferences\Object] -Show Icon=No -Mode=2 -Trunc Length=40 -Word Length=40 -Word Text=!"#$%&')*+,-./:;=>?@\]^_`|}~ -Shortcut IntIcon=Yes -Shortcut IntLoct=Yes -Shortcut IntFullPath=No -Shortcut IntLastPackage=Yes -Shortcut ExtIcon=Yes -Shortcut ExtLoct=No -Shortcut ExtFullPath=No -Shortcut ExtLastPackage=Yes -Shortcut ExtIncludeModl=Yes -Area.IconPicture=Yes -Area.Stereotype=Yes -Area.Comment=No -Area.TextStyle=No -Area.SubSymbols=Yes -Area_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Architecture Area Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <Separator Name="Separator" />[CRLF] <StandardAttribute Name="Comment" Attribute="Comment" Prefix="" Suffix="" Alignment="LEFT" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -EObjShowStrn=Yes -ExtendedObject.Comment=No -ExtendedObject.IconPicture=No -ExtendedObject.TextStyle=No -ExtendedObject_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Object Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <Separator Name="Separator" />[CRLF] <StandardAttribute Name="Comment" Attribute="Comment" Prefix="" Suffix="" Alignment="LEFT" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -ELnkShowStrn=Yes -ELnkShowName=Yes -ExtendedLink_SymbolLayout=<Form>[CRLF] <Form Name="Center" >[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] </Form>[CRLF] <Form Name="Source" >[CRLF] </Form>[CRLF] <Form Name="Destination" >[CRLF] </Form>[CRLF]</Form> -ExtDpdShowStrn=Yes -ExtendedDependency_SymbolLayout=<Form>[CRLF] <Form Name="Center" >[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Caption="" Mandatory="No" />[CRLF] </Form>[CRLF] <Form Name="Source" >[CRLF] </Form>[CRLF] <Form Name="Destination" >[CRLF] </Form>[CRLF]</Form> -FileObject.Stereotype=No -FileObject.DisplayName=Yes -FileObject.LocationOrName=No -FileObject.IconPicture=No -FileObject.TextStyle=No -FileObject.IconMode=Yes -FileObject_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <ExclusiveChoice Name="Exclusive Choice" Mandatory="Yes" Display="HorizontalRadios" >[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Location" Attribute="LocationOrName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] </ExclusiveChoice>[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -Package.Stereotype=Yes -Package.Comment=No -Package.IconPicture=No -Package.TextStyle=No -Package_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <Separator Name="Separator" />[CRLF] <StandardAttribute Name="Comment" Attribute="Comment" Prefix="" Suffix="" Alignment="LEFT" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -Display Model Version=Yes -Table.Stereotype=Yes -Table.DisplayName=Yes -Table.OwnerDisplayName=No -Table.Columns=Yes -Table.Columns._Filter="All Columns" PDMCOLNALL -Table.Columns._Columns=Stereotype DataType KeyIndicator -Table.Columns._Limit=-5 -Table.Keys=No -Table.Keys._Columns=Stereotype Indicator -Table.Indexes=No -Table.Indexes._Columns=Stereotype -Table.Triggers=No -Table.Triggers._Columns=Stereotype -Table.Comment=No -Table.IconPicture=No -Table.TextStyle=No -Table_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <ExclusiveChoice Name="Exclusive Choice" Mandatory="Yes" Display="HorizontalRadios" >[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Owner and Name" Attribute="OwnerDisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] </ExclusiveChoice>[CRLF] <Separator Name="Separator" />[CRLF] <StandardCollection Name="Columns" Collection="Columns" Columns="Stereotype No\r\nDisplayName Yes\r\nDataType No\r\nSymbolDataType No &quot;Domain or Data type&quot;\r\nDomain No\r\nKeyIndicator No\r\nIndexIndicator No\r\nNullStatus No" Filters="&quot;All Columns&quot; PDMCOLNALL &quot;&quot;\r\n&quot;PK Columns&quot; PDMCOLNPK &quot;\&quot;PRIM \&quot;TRUE\&quot; TRUE\&quot;&quot;\r\n&quot;Key Columns&quot; PDMCOLNKEY &quot;\&quot;KEYS \&quot;TRUE\&quot; TRUE\&quot;&quot;" HasLimit="Yes" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardCollection Name="Keys" Collection="Keys" Columns="Stereotype No\r\nDisplayName Yes\r\nIndicator No" HasLimit="No" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardCollection Name="Indexes" Collection="Indexes" Columns="Stereotype No\r\nDisplayName Yes\r\nIndicator No" HasLimit="No" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardCollection Name="Triggers" Collection="Triggers" Columns="Stereotype No\r\nDisplayName Yes" HasLimit="No" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Comment" Attribute="Comment" Prefix="" Suffix="" Alignment="LEFT" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -View.Stereotype=Yes -View.DisplayName=Yes -View.OwnerDisplayName=No -View.Columns=Yes -View.Columns._Columns=DisplayName -View.Columns._Limit=-5 -View.TemporaryVTables=Yes -View.Indexes=No -View.Comment=No -View.IconPicture=No -View.TextStyle=No -View_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <ExclusiveChoice Name="Exclusive Choice" Mandatory="Yes" Display="HorizontalRadios" >[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Owner and Name" Attribute="OwnerDisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] </ExclusiveChoice>[CRLF] <Separator Name="Separator" />[CRLF] <StandardCollection Name="Columns" Collection="Columns" Columns="DisplayName No\r\nExpression No\r\nDataType No\r\nSymbolDataType No &quot;Domain or Data type&quot;\r\nIndexIndicator No" HasLimit="Yes" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardCollection Name="Tables" Collection="TemporaryVTables" Columns="Name Yes" HasLimit="No" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardCollection Name="Indexes" Collection="Indexes" Columns="DisplayName Yes" HasLimit="No" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Comment" Attribute="Comment" Prefix="" Suffix="" Alignment="LEFT" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -Procedure.Stereotype=No -Procedure.DisplayName=Yes -Procedure.OwnerDisplayName=No -Procedure.Comment=No -Procedure.IconPicture=No -Procedure.TextStyle=No -Procedure_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <ExclusiveChoice Name="Exclusive Choice" Mandatory="Yes" Display="HorizontalRadios" >[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Owner and Name" Attribute="OwnerDisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] </ExclusiveChoice>[CRLF] <Separator Name="Separator" />[CRLF] <StandardAttribute Name="Comment" Attribute="Comment" Prefix="" Suffix="" Alignment="LEFT" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -Reference.Cardinality=No -Reference.ImplementationType=No -Reference.ChildRole=Yes -Reference.Stereotype=Yes -Reference.DisplayName=No -Reference.ForeignKeyConstraintName=No -Reference.JoinExpression=No -Reference.Integrity=No -Reference.ParentRole=Yes -Reference_SymbolLayout=<Form>[CRLF] <Form Name="Source" >[CRLF] <StandardAttribute Name="Cardinality" Attribute="Cardinality" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Implementation" Attribute="ImplementationType" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Child Role" Attribute="ChildRole" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] </Form>[CRLF] <Form Name="Center" >[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Caption="" Mandatory="No" />[CRLF] <ExclusiveChoice Name="Exclusive Choice" Mandatory="No" Display="HorizontalRadios" >[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Cons&amp;traint Name" Attribute="ForeignKeyConstraintName" Prefix="" Suffix="" Caption="Cons&amp;traint Name" Mandatory="No" />[CRLF] <StandardAttribute Name="Join" Attribute="JoinExpression" Prefix="" Suffix="" Caption="Join" Mandatory="No" />[CRLF] </ExclusiveChoice>[CRLF] <StandardAttribute Name="Referential integrity" Attribute="Integrity" Prefix="" Suffix="" Caption="Referential integrity" Mandatory="No" />[CRLF] </Form>[CRLF] <Form Name="Destination" >[CRLF] <StandardAttribute Name="Parent Role" Attribute="ParentRole" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] </Form>[CRLF]</Form> -ViewReference.ChildRole=Yes -ViewReference.Stereotype=Yes -ViewReference.DisplayName=No -ViewReference.JoinExpression=No -ViewReference.ParentRole=Yes -ViewReference_SymbolLayout=<Form>[CRLF] <Form Name="Source" >[CRLF] <StandardAttribute Name="Child Role" Attribute="ChildRole" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] </Form>[CRLF] <Form Name="Center" >[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Caption="" Mandatory="No" />[CRLF] <ExclusiveChoice Name="Exclusive Choice" Mandatory="No" Display="HorizontalRadios" >[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Join Expression" Attribute="JoinExpression" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] </ExclusiveChoice>[CRLF] </Form>[CRLF] <Form Name="Destination" >[CRLF] <StandardAttribute Name="Parent Role" Attribute="ParentRole" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] </Form>[CRLF]</Form> - -[DisplayPreferences\Symbol] - -[DisplayPreferences\Symbol\AREA] -STRNFont=新宋体,8,N -STRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -LABLFont=新宋体,8,N -LABLFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=9600 -Height=8000 -Brush color=253 249 234 -Fill Color=Yes -Brush style=6 -Brush bitmap mode=12 -Brush gradient mode=16 -Brush gradient color=245 230 173 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 121 98 6 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\FRMEOBJ] -STRNFont=新宋体,8,N -STRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -LABLFont=新宋体,8,N -LABLFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=6000 -Height=2000 -Brush color=255 255 255 -Fill Color=Yes -Brush style=6 -Brush bitmap mode=12 -Brush gradient mode=64 -Brush gradient color=192 192 192 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 255 128 128 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\FRMELNK] -CENTERFont=新宋体,8,N -CENTERFont color=0 0 0 -Line style=1 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Brush color=255 255 255 -Fill Color=Yes -Brush style=1 -Brush bitmap mode=12 -Brush gradient mode=0 -Brush gradient color=118 118 118 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 128 128 255 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\USRDEPD] -CENTERFont=新宋体,8,N -CENTERFont color=0 0 0 -Line style=1 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Brush color=255 255 255 -Fill Color=Yes -Brush style=1 -Brush bitmap mode=12 -Brush gradient mode=0 -Brush gradient color=118 118 118 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=2 0 128 128 255 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\FILO] -OBJSTRNFont=新宋体,8,N -OBJSTRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -LCNMFont=新宋体,8,N -LCNMFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=4800 -Height=3600 -Brush color=255 255 255 -Fill Color=Yes -Brush style=1 -Brush bitmap mode=12 -Brush gradient mode=0 -Brush gradient color=118 118 118 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 0 0 255 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\PDMPCKG] -STRNFont=新宋体,8,N -STRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -LABLFont=新宋体,8,N -LABLFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=4800 -Height=4000 -Brush color=255 255 192 -Fill Color=Yes -Brush style=6 -Brush bitmap mode=12 -Brush gradient mode=65 -Brush gradient color=255 255 255 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 178 178 178 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\TABL] -STRNFont=新宋体,8,N -STRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -OWNRDISPNAMEFont=新宋体,8,N -OWNRDISPNAMEFont color=0 0 0 -ColumnsFont=新宋体,8,N -ColumnsFont color=0 0 0 -TablePkColumnsFont=新宋体,8,U -TablePkColumnsFont color=0 0 0 -TableFkColumnsFont=新宋体,8,N -TableFkColumnsFont color=0 0 0 -KeysFont=新宋体,8,N -KeysFont color=0 0 0 -IndexesFont=新宋体,8,N -IndexesFont color=0 0 0 -TriggersFont=新宋体,8,N -TriggersFont color=0 0 0 -LABLFont=新宋体,8,N -LABLFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=4800 -Height=4000 -Brush color=178 214 252 -Fill Color=Yes -Brush style=6 -Brush bitmap mode=12 -Brush gradient mode=65 -Brush gradient color=255 255 255 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 0 128 192 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\VIEW] -STRNFont=新宋体,8,N -STRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -OWNRDISPNAMEFont=新宋体,8,N -OWNRDISPNAMEFont color=0 0 0 -ColumnsFont=新宋体,8,N -ColumnsFont color=0 0 0 -TablePkColumnsFont=新宋体,8,U -TablePkColumnsFont color=0 0 0 -TableFkColumnsFont=新宋体,8,N -TableFkColumnsFont color=0 0 0 -TemporaryVTablesFont=新宋体,8,N -TemporaryVTablesFont color=0 0 0 -IndexesFont=新宋体,8,N -IndexesFont color=0 0 0 -LABLFont=新宋体,8,N -LABLFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=4800 -Height=4000 -Brush color=208 208 255 -Fill Color=Yes -Brush style=6 -Brush bitmap mode=12 -Brush gradient mode=65 -Brush gradient color=255 255 255 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 128 128 192 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\PROC] -STRNFont=新宋体,8,N -STRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -OWNRDISPNAMEFont=新宋体,8,N -OWNRDISPNAMEFont color=0 0 0 -LABLFont=新宋体,8,N -LABLFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=4000 -Height=1000 -Brush color=255 255 192 -Fill Color=Yes -Brush style=6 -Brush bitmap mode=12 -Brush gradient mode=65 -Brush gradient color=255 255 255 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 128 108 0 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\REFR] -SOURCEFont=新宋体,8,N -SOURCEFont color=0 0 0 -CENTERFont=新宋体,8,N -CENTERFont color=0 0 0 -DESTINATIONFont=新宋体,8,N -DESTINATIONFont color=0 0 0 -Line style=1 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Brush color=255 255 255 -Fill Color=Yes -Brush style=1 -Brush bitmap mode=12 -Brush gradient mode=0 -Brush gradient color=118 118 118 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 0 128 192 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\VREF] -SOURCEFont=新宋体,8,N -SOURCEFont color=0 0 0 -CENTERFont=新宋体,8,N -CENTERFont color=0 0 0 -DESTINATIONFont=新宋体,8,N -DESTINATIONFont color=0 0 0 -Line style=1 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Brush color=255 255 255 -Fill Color=Yes -Brush style=1 -Brush bitmap mode=12 -Brush gradient mode=0 -Brush gradient color=118 118 118 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 128 128 192 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\Free Symbol] -Free TextFont=新宋体,8,N -Free TextFont color=0 0 0 -Line style=0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Brush color=255 255 255 -Fill Color=Yes -Brush style=1 -Brush bitmap mode=12 -Brush gradient mode=0 -Brush gradient color=118 118 118 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 0 0 255 -Shadow color=192 192 192 -Shadow=0 -(8268, 11693) -((315,354), (433,354)) -1 -15 - - -1634479458 -1634479458 -((2264,-5792), (3514,-872)) -((2889,-5392),(2889,-1272)) -1 -1 -12615680 -12632256 -CENTER 0 新宋体,8,N -SOURCE 0 新宋体,8,N -DESTINATION 0 新宋体,8,N - - - - - - - - - - - -1634479459 -1634479459 -((1862,-13883), (3112,-8992)) -((2487,-9392),(2487,-13483)) -1 -1 -12615680 -12632256 -CENTER 0 新宋体,8,N -SOURCE 0 新宋体,8,N -DESTINATION 0 新宋体,8,N - - - - - - - - - - - -1634474232 -1634475107 --1 -((-8597,-1272), (14375,8596)) -0 -12615680 -16570034 -12632256 -STRN 0 新宋体,8,N -DISPNAME 0 新宋体,8,N -OWNRDISPNAME 0 新宋体,8,N -Columns 0 新宋体,8,N -TablePkColumns 0 新宋体,8,U -TableFkColumns 0 新宋体,8,N -Keys 0 新宋体,8,N -Indexes 0 新宋体,8,N -Triggers 0 新宋体,8,N -LABL 0 新宋体,8,N -6 -65 -16777215 -1 - - - - - -1634479401 -1634479404 --1 -((-8999,-23351), (13973,-13483)) -0 -12615680 -16570034 -12632256 -STRN 0 新宋体,8,N -DISPNAME 0 新宋体,8,N -OWNRDISPNAME 0 新宋体,8,N -Columns 0 新宋体,8,N -TablePkColumns 0 新宋体,8,U -TableFkColumns 0 新宋体,8,N -Keys 0 新宋体,8,N -Indexes 0 新宋体,8,N -Triggers 0 新宋体,8,N -LABL 0 新宋体,8,N -6 -65 -16777215 -1 - - - - - -1634479425 -1634479430 --1 -((-8486,-9392), (14443,-5392)) -0 -12615680 -16570034 -12632256 -STRN 0 新宋体,8,N -DISPNAME 0 新宋体,8,N -OWNRDISPNAME 0 新宋体,8,N -Columns 0 新宋体,8,N -TablePkColumns 0 新宋体,8,U -TableFkColumns 0 新宋体,8,N -Keys 0 新宋体,8,N -Indexes 0 新宋体,8,N -Triggers 0 新宋体,8,N -LABL 0 新宋体,8,N -6 -65 -16777215 -1 - - - - - - - -BAF8B5BF-7B38-492B-8881-67DE30E29196 -02 - 标签 -02 - 标签 -1634474204 -Xiadao -1634476877 -Xiadao -[DisplayPreferences] - -[DisplayPreferences\PDM] - -[DisplayPreferences\General] -Adjust to text=Yes -Snap Grid=No -Constrain Labels=Yes -Display Grid=No -Show Page Delimiter=Yes -Show Links intersections=Yes -Activate automatic link routing=Yes -Grid size=800 -Graphic unit=2 -Window color=255 255 255 -Background image= -Background mode=8 -Watermark image= -Watermark mode=8 -Show watermark on screen=No -Gradient mode=0 -Gradient end color=255 255 255 -Show Swimlane=No -SwimlaneVert=Yes -TreeVert=No -CompDark=0 - -[DisplayPreferences\Object] -Show Icon=No -Mode=2 -Trunc Length=40 -Word Length=40 -Word Text=!"#$%&')*+,-./:;=>?@\]^_`|}~ -Shortcut IntIcon=Yes -Shortcut IntLoct=Yes -Shortcut IntFullPath=No -Shortcut IntLastPackage=Yes -Shortcut ExtIcon=Yes -Shortcut ExtLoct=No -Shortcut ExtFullPath=No -Shortcut ExtLastPackage=Yes -Shortcut ExtIncludeModl=Yes -Area.IconPicture=Yes -Area.Stereotype=Yes -Area.Comment=No -Area.TextStyle=No -Area.SubSymbols=Yes -Area_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Architecture Area Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <Separator Name="Separator" />[CRLF] <StandardAttribute Name="Comment" Attribute="Comment" Prefix="" Suffix="" Alignment="LEFT" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -EObjShowStrn=Yes -ExtendedObject.Comment=No -ExtendedObject.IconPicture=No -ExtendedObject.TextStyle=No -ExtendedObject_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Object Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <Separator Name="Separator" />[CRLF] <StandardAttribute Name="Comment" Attribute="Comment" Prefix="" Suffix="" Alignment="LEFT" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -ELnkShowStrn=Yes -ELnkShowName=Yes -ExtendedLink_SymbolLayout=<Form>[CRLF] <Form Name="Center" >[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] </Form>[CRLF] <Form Name="Source" >[CRLF] </Form>[CRLF] <Form Name="Destination" >[CRLF] </Form>[CRLF]</Form> -ExtDpdShowStrn=Yes -ExtendedDependency_SymbolLayout=<Form>[CRLF] <Form Name="Center" >[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Caption="" Mandatory="No" />[CRLF] </Form>[CRLF] <Form Name="Source" >[CRLF] </Form>[CRLF] <Form Name="Destination" >[CRLF] </Form>[CRLF]</Form> -FileObject.Stereotype=No -FileObject.DisplayName=Yes -FileObject.LocationOrName=No -FileObject.IconPicture=No -FileObject.TextStyle=No -FileObject.IconMode=Yes -FileObject_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <ExclusiveChoice Name="Exclusive Choice" Mandatory="Yes" Display="HorizontalRadios" >[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Location" Attribute="LocationOrName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] </ExclusiveChoice>[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -Package.Stereotype=Yes -Package.Comment=No -Package.IconPicture=No -Package.TextStyle=No -Package_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <Separator Name="Separator" />[CRLF] <StandardAttribute Name="Comment" Attribute="Comment" Prefix="" Suffix="" Alignment="LEFT" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -Display Model Version=Yes -Table.Stereotype=Yes -Table.DisplayName=Yes -Table.OwnerDisplayName=No -Table.Columns=Yes -Table.Columns._Filter="All Columns" PDMCOLNALL -Table.Columns._Columns=Stereotype DataType KeyIndicator -Table.Columns._Limit=-5 -Table.Keys=No -Table.Keys._Columns=Stereotype Indicator -Table.Indexes=No -Table.Indexes._Columns=Stereotype -Table.Triggers=No -Table.Triggers._Columns=Stereotype -Table.Comment=No -Table.IconPicture=No -Table.TextStyle=No -Table_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <ExclusiveChoice Name="Exclusive Choice" Mandatory="Yes" Display="HorizontalRadios" >[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Owner and Name" Attribute="OwnerDisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] </ExclusiveChoice>[CRLF] <Separator Name="Separator" />[CRLF] <StandardCollection Name="Columns" Collection="Columns" Columns="Stereotype No\r\nDisplayName Yes\r\nDataType No\r\nSymbolDataType No &quot;Domain or Data type&quot;\r\nDomain No\r\nKeyIndicator No\r\nIndexIndicator No\r\nNullStatus No" Filters="&quot;All Columns&quot; PDMCOLNALL &quot;&quot;\r\n&quot;PK Columns&quot; PDMCOLNPK &quot;\&quot;PRIM \&quot;TRUE\&quot; TRUE\&quot;&quot;\r\n&quot;Key Columns&quot; PDMCOLNKEY &quot;\&quot;KEYS \&quot;TRUE\&quot; TRUE\&quot;&quot;" HasLimit="Yes" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardCollection Name="Keys" Collection="Keys" Columns="Stereotype No\r\nDisplayName Yes\r\nIndicator No" HasLimit="No" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardCollection Name="Indexes" Collection="Indexes" Columns="Stereotype No\r\nDisplayName Yes\r\nIndicator No" HasLimit="No" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardCollection Name="Triggers" Collection="Triggers" Columns="Stereotype No\r\nDisplayName Yes" HasLimit="No" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Comment" Attribute="Comment" Prefix="" Suffix="" Alignment="LEFT" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -View.Stereotype=Yes -View.DisplayName=Yes -View.OwnerDisplayName=No -View.Columns=Yes -View.Columns._Columns=DisplayName -View.Columns._Limit=-5 -View.TemporaryVTables=Yes -View.Indexes=No -View.Comment=No -View.IconPicture=No -View.TextStyle=No -View_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <ExclusiveChoice Name="Exclusive Choice" Mandatory="Yes" Display="HorizontalRadios" >[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Owner and Name" Attribute="OwnerDisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] </ExclusiveChoice>[CRLF] <Separator Name="Separator" />[CRLF] <StandardCollection Name="Columns" Collection="Columns" Columns="DisplayName No\r\nExpression No\r\nDataType No\r\nSymbolDataType No &quot;Domain or Data type&quot;\r\nIndexIndicator No" HasLimit="Yes" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardCollection Name="Tables" Collection="TemporaryVTables" Columns="Name Yes" HasLimit="No" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardCollection Name="Indexes" Collection="Indexes" Columns="DisplayName Yes" HasLimit="No" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Comment" Attribute="Comment" Prefix="" Suffix="" Alignment="LEFT" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -Procedure.Stereotype=No -Procedure.DisplayName=Yes -Procedure.OwnerDisplayName=No -Procedure.Comment=No -Procedure.IconPicture=No -Procedure.TextStyle=No -Procedure_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <ExclusiveChoice Name="Exclusive Choice" Mandatory="Yes" Display="HorizontalRadios" >[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Owner and Name" Attribute="OwnerDisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] </ExclusiveChoice>[CRLF] <Separator Name="Separator" />[CRLF] <StandardAttribute Name="Comment" Attribute="Comment" Prefix="" Suffix="" Alignment="LEFT" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -Reference.Cardinality=No -Reference.ImplementationType=No -Reference.ChildRole=Yes -Reference.Stereotype=Yes -Reference.DisplayName=No -Reference.ForeignKeyConstraintName=No -Reference.JoinExpression=No -Reference.Integrity=No -Reference.ParentRole=Yes -Reference_SymbolLayout=<Form>[CRLF] <Form Name="Source" >[CRLF] <StandardAttribute Name="Cardinality" Attribute="Cardinality" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Implementation" Attribute="ImplementationType" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Child Role" Attribute="ChildRole" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] </Form>[CRLF] <Form Name="Center" >[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Caption="" Mandatory="No" />[CRLF] <ExclusiveChoice Name="Exclusive Choice" Mandatory="No" Display="HorizontalRadios" >[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Cons&amp;traint Name" Attribute="ForeignKeyConstraintName" Prefix="" Suffix="" Caption="Cons&amp;traint Name" Mandatory="No" />[CRLF] <StandardAttribute Name="Join" Attribute="JoinExpression" Prefix="" Suffix="" Caption="Join" Mandatory="No" />[CRLF] </ExclusiveChoice>[CRLF] <StandardAttribute Name="Referential integrity" Attribute="Integrity" Prefix="" Suffix="" Caption="Referential integrity" Mandatory="No" />[CRLF] </Form>[CRLF] <Form Name="Destination" >[CRLF] <StandardAttribute Name="Parent Role" Attribute="ParentRole" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] </Form>[CRLF]</Form> -ViewReference.ChildRole=Yes -ViewReference.Stereotype=Yes -ViewReference.DisplayName=No -ViewReference.JoinExpression=No -ViewReference.ParentRole=Yes -ViewReference_SymbolLayout=<Form>[CRLF] <Form Name="Source" >[CRLF] <StandardAttribute Name="Child Role" Attribute="ChildRole" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] </Form>[CRLF] <Form Name="Center" >[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Caption="" Mandatory="No" />[CRLF] <ExclusiveChoice Name="Exclusive Choice" Mandatory="No" Display="HorizontalRadios" >[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Join Expression" Attribute="JoinExpression" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] </ExclusiveChoice>[CRLF] </Form>[CRLF] <Form Name="Destination" >[CRLF] <StandardAttribute Name="Parent Role" Attribute="ParentRole" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] </Form>[CRLF]</Form> - -[DisplayPreferences\Symbol] - -[DisplayPreferences\Symbol\AREA] -STRNFont=新宋体,8,N -STRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -LABLFont=新宋体,8,N -LABLFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=9600 -Height=8000 -Brush color=253 249 234 -Fill Color=Yes -Brush style=6 -Brush bitmap mode=12 -Brush gradient mode=16 -Brush gradient color=245 230 173 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 121 98 6 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\FRMEOBJ] -STRNFont=新宋体,8,N -STRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -LABLFont=新宋体,8,N -LABLFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=6000 -Height=2000 -Brush color=255 255 255 -Fill Color=Yes -Brush style=6 -Brush bitmap mode=12 -Brush gradient mode=64 -Brush gradient color=192 192 192 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 255 128 128 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\FRMELNK] -CENTERFont=新宋体,8,N -CENTERFont color=0 0 0 -Line style=1 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Brush color=255 255 255 -Fill Color=Yes -Brush style=1 -Brush bitmap mode=12 -Brush gradient mode=0 -Brush gradient color=118 118 118 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 128 128 255 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\USRDEPD] -CENTERFont=新宋体,8,N -CENTERFont color=0 0 0 -Line style=1 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Brush color=255 255 255 -Fill Color=Yes -Brush style=1 -Brush bitmap mode=12 -Brush gradient mode=0 -Brush gradient color=118 118 118 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=2 0 128 128 255 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\FILO] -OBJSTRNFont=新宋体,8,N -OBJSTRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -LCNMFont=新宋体,8,N -LCNMFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=4800 -Height=3600 -Brush color=255 255 255 -Fill Color=Yes -Brush style=1 -Brush bitmap mode=12 -Brush gradient mode=0 -Brush gradient color=118 118 118 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 0 0 255 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\PDMPCKG] -STRNFont=新宋体,8,N -STRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -LABLFont=新宋体,8,N -LABLFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=4800 -Height=4000 -Brush color=255 255 192 -Fill Color=Yes -Brush style=6 -Brush bitmap mode=12 -Brush gradient mode=65 -Brush gradient color=255 255 255 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 178 178 178 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\TABL] -STRNFont=新宋体,8,N -STRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -OWNRDISPNAMEFont=新宋体,8,N -OWNRDISPNAMEFont color=0 0 0 -ColumnsFont=新宋体,8,N -ColumnsFont color=0 0 0 -TablePkColumnsFont=新宋体,8,U -TablePkColumnsFont color=0 0 0 -TableFkColumnsFont=新宋体,8,N -TableFkColumnsFont color=0 0 0 -KeysFont=新宋体,8,N -KeysFont color=0 0 0 -IndexesFont=新宋体,8,N -IndexesFont color=0 0 0 -TriggersFont=新宋体,8,N -TriggersFont color=0 0 0 -LABLFont=新宋体,8,N -LABLFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=4800 -Height=4000 -Brush color=178 214 252 -Fill Color=Yes -Brush style=6 -Brush bitmap mode=12 -Brush gradient mode=65 -Brush gradient color=255 255 255 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 0 128 192 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\VIEW] -STRNFont=新宋体,8,N -STRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -OWNRDISPNAMEFont=新宋体,8,N -OWNRDISPNAMEFont color=0 0 0 -ColumnsFont=新宋体,8,N -ColumnsFont color=0 0 0 -TablePkColumnsFont=新宋体,8,U -TablePkColumnsFont color=0 0 0 -TableFkColumnsFont=新宋体,8,N -TableFkColumnsFont color=0 0 0 -TemporaryVTablesFont=新宋体,8,N -TemporaryVTablesFont color=0 0 0 -IndexesFont=新宋体,8,N -IndexesFont color=0 0 0 -LABLFont=新宋体,8,N -LABLFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=4800 -Height=4000 -Brush color=208 208 255 -Fill Color=Yes -Brush style=6 -Brush bitmap mode=12 -Brush gradient mode=65 -Brush gradient color=255 255 255 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 128 128 192 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\PROC] -STRNFont=新宋体,8,N -STRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -OWNRDISPNAMEFont=新宋体,8,N -OWNRDISPNAMEFont color=0 0 0 -LABLFont=新宋体,8,N -LABLFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=4000 -Height=1000 -Brush color=255 255 192 -Fill Color=Yes -Brush style=6 -Brush bitmap mode=12 -Brush gradient mode=65 -Brush gradient color=255 255 255 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 128 108 0 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\REFR] -SOURCEFont=新宋体,8,N -SOURCEFont color=0 0 0 -CENTERFont=新宋体,8,N -CENTERFont color=0 0 0 -DESTINATIONFont=新宋体,8,N -DESTINATIONFont color=0 0 0 -Line style=1 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Brush color=255 255 255 -Fill Color=Yes -Brush style=1 -Brush bitmap mode=12 -Brush gradient mode=0 -Brush gradient color=118 118 118 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 0 128 192 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\VREF] -SOURCEFont=新宋体,8,N -SOURCEFont color=0 0 0 -CENTERFont=新宋体,8,N -CENTERFont color=0 0 0 -DESTINATIONFont=新宋体,8,N -DESTINATIONFont color=0 0 0 -Line style=1 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Brush color=255 255 255 -Fill Color=Yes -Brush style=1 -Brush bitmap mode=12 -Brush gradient mode=0 -Brush gradient color=118 118 118 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 128 128 192 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\Free Symbol] -Free TextFont=新宋体,8,N -Free TextFont color=0 0 0 -Line style=0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Brush color=255 255 255 -Fill Color=Yes -Brush style=1 -Brush bitmap mode=12 -Brush gradient mode=0 -Brush gradient color=118 118 118 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 0 0 255 -Shadow color=192 192 192 -Shadow=0 -(8268, 11693) -((315,354), (433,354)) -1 -15 - - -1634476877 -1634476877 --1 -((-11486,-4934), (11486,4934)) -0 -12615680 -16570034 -12632256 -STRN 0 新宋体,8,N -DISPNAME 0 新宋体,8,N -OWNRDISPNAME 0 新宋体,8,N -Columns 0 新宋体,8,N -TablePkColumns 0 新宋体,8,U -TableFkColumns 0 新宋体,8,N -Keys 0 新宋体,8,N -Indexes 0 新宋体,8,N -Triggers 0 新宋体,8,N -LABL 0 新宋体,8,N -6 -65 -16777215 -1 - - - - - - - - - - - - -AD5D38BE-D347-4730-9E27-61B07401B54F -贴子( Post ) -Post -1634474232 -Xiadao -1634475057 -Xiadao -贴子 - - - -9C6B17C1-0BC3-4E5A-9BFE-DA9EB826215B -贴子标识( PostId ) -PostId -1634474232 -Xiadao -1634474886 -Xiadao -贴子标识 -uniqueidentifier -1 - - -24A86E90-D048-47AB-8494-8B710CEF76B2 -标题( Title ) -Title -1634475012 -Xiadao -1634475050 -Xiadao -标题 -nvarchar(200) -200 - - -9E716B3E-83C9-48FA-8653-7A3CBF1D830F -内容( Content ) -Content -1634475024 -Xiadao -1634475098 -Xiadao -内容 -nvarchar(max) - - -0817F3C5-C814-4EEB-AF12-FC7011041E4C -创建时间( CreationTime ) -CreationTime -1634474232 -Xiadao -1634474232 -Xiadao -创建时间 -datetime - - -12CE5BFA-2E78-4BCF-AB26-7A385A929A04 -创建人( CreatorId ) -CreatorId -1634474232 -Xiadao -1634474232 -Xiadao -创建人 -uniqueidentifier - - -7D319909-9F8D-4E1A-8D56-E2610BB9965F -最后修改时间( LastModificationTime ) -LastModificationTime -1634474232 -Xiadao -1634474232 -Xiadao -最后修改时间 -datetime - - -53467064-BC0C-4E59-950B-D315922DF76A -最后修改人( LastModifierId ) -LastModifierId -1634474232 -Xiadao -1634474232 -Xiadao -最后修改人 -uniqueidentifier - - -517E8891-2178-486D-ADF1-C5C97CE2EA73 -是否删除( IsDeleted ) -IsDeleted -1634474232 -Xiadao -1634474232 -Xiadao -是否删除 -bit -1 - - -7F85AB0F-4461-4CF5-8B88-DD31DA801207 -版本号( Version ) -Version -1634474232 -Xiadao -1634474232 -Xiadao -版本号 -timestamp - - - - -BC4763C8-712B-4794-BA5E-60E44783C441 -Key_1 -Key_1 -1634474232 -Xiadao -1634474232 -Xiadao - - - - - - - - - - - - - - - - -59F96735-771C-4357-ADD4-2320DD4DEC35 -标签( Tag ) -Tag -1634476877 -Xiadao -1634479393 -Xiadao -标签 - - - -86DF057E-2824-43ED-BA24-A0DC217C0AE3 -标签标识( TagId ) -TagId -1634476877 -Xiadao -1634477808 -Xiadao -标签标识 -uniqueidentifier -1 - - -E737B960-5739-4FBD-A17A-15A05F628EE7 -标签名称( Name ) -Name -1634476877 -Xiadao -1634479390 -Xiadao -标签名称 -nvarchar(200) -200 - - -E8080B7D-AC52-4AE9-915D-3F9833507F0F -创建时间( CreationTime ) -CreationTime -1634476877 -Xiadao -1634476877 -Xiadao -创建时间 -datetime - - -D864B12A-89CB-455D-992D-73C4C8B0F8CF -创建人( CreatorId ) -CreatorId -1634476877 -Xiadao -1634476877 -Xiadao -创建人 -uniqueidentifier - - -B7D6FEDF-E506-4E72-B07E-9E43CA7586B8 -最后修改时间( LastModificationTime ) -LastModificationTime -1634476877 -Xiadao -1634476877 -Xiadao -最后修改时间 -datetime - - -9BF7A667-53B0-4C14-AFE3-2BDC35E6D98D -最后修改人( LastModifierId ) -LastModifierId -1634476877 -Xiadao -1634476877 -Xiadao -最后修改人 -uniqueidentifier - - -CC86B34B-17D4-4646-9083-67CB26C9BCB6 -是否删除( IsDeleted ) -IsDeleted -1634476877 -Xiadao -1634476877 -Xiadao -是否删除 -bit -1 - - -917F88C5-D945-4985-88AC-F9E7EEF26A20 -版本号( Version ) -Version -1634476877 -Xiadao -1634476877 -Xiadao -版本号 -timestamp - - - - -9FEC9F44-352A-417D-BF86-0E0B7B0CD479 -Key_1 -Key_1 -1634476877 -Xiadao -1634476877 -Xiadao - - - - - - - - - - - - - - - - -EE018CC5-5B90-4B18-812F-23CF6A62CEB8 -贴子标签( PostTag ) -PostTag -1634479425 -Xiadao -1634479466 -Xiadao -贴子标签 - - - -AB478AEC-D7B9-41A0-89D4-7105B613005E -贴子标识( PostId ) -PostId -1634479458 -Xiadao -1634479466 -Xiadao -贴子标识 -uniqueidentifier -1 -1 - - -1A893A25-070C-4021-8586-54F8184DE82B -标签标识( TagId ) -TagId -1634479459 -Xiadao -1634479466 -Xiadao -标签标识 -uniqueidentifier -1 -1 - - - - -77A13292-0F54-4E5F-A383-FDCBC1365C4B -Key_1 -Key_1 -1634479461 -Xiadao -1634479466 -Xiadao - - - - - - - - - - - - - - - - -D5309618-C047-447B-8DE9-E414DAAE10E6 -Reference_5 -Reference_5 -1634479458 -Xiadao -1634479458 -Xiadao -0..* - - - - - - - - - - - -970BA17E-3EB3-4216-B9FF-60F8F48FCFB2 -1634479458 -Xiadao -1634479458 -Xiadao - - - - - - - - - - -692D0A36-D763-4AE5-B8FA-8C44E75FF676 -Reference_6 -Reference_6 -1634479459 -Xiadao -1634479459 -Xiadao -0..* - - - - - - - - - - - -BE5EE49E-8AC3-4876-AC26-C89DA2B1E8C7 -1634479459 -Xiadao -1634479459 -Xiadao - - - - - - - - - - - - - - - - - -89128D3A-55E9-4B29-B560-E400E18B70B1 -客户( Customers ) -Customers -1631784547 -Xiadao -1634474807 -Xiadao -Schema - - -915433E0-4A0F-426D-BC0E-C0359F88BF04 -销售( Sales ) -Sales -1631776192 -Xiadao -1631776192 -Xiadao -Schema - - -1DEAC531-1773-4DDC-BEAE-B1A35BEBE14C -商品( Products ) -Products -1630573318 -Xiadao -1630573931 -Xiadao -Schema - - -0CF6239F-4164-45DF-8938-51466B41925C -系统( Systems ) -Systems -1628410313 -Xiadao -1630573931 -Xiadao -Schema - - -AF2EB7EE-8810-4EE5-B730-9398534C9C6D -博客( Blogs ) -Blogs -1634474809 -Xiadao -1634474839 -Xiadao -Schema - - - - -A23AC743-1D1E-443A-B485-E4B2622424BD -测试_01_1( Test_01_1 ) -Test_01_1 -1625384268 -Xiadao -1629976764 -Xiadao -测试_01_1 - - - -DD65CB8E-9805-46DC-AAFD-C7A11369E2BA -测试标识( TestId ) -TestId -1625384268 -Xiadao -1625384268 -Xiadao -测试标识 -uniqueidentifier -1 - - -9BBDB808-B190-4EB1-AC90-0D5427AE2D47 -字符串值( StringValue ) -StringValue -1625384268 -Xiadao -1625384268 -Xiadao -字符串值 -nvarchar(200) -200 - - -9C8F3B63-4EAC-4C61-96AB-8F67CBEB9B6E -整型值( IntValue ) -IntValue -1625733148 -Xiadao -1625738048 -Xiadao -整型值 -int - - -F21FBB89-DA2A-4AFF-910E-E36B4661291E -可空整型值( NullableIntValue ) -NullableIntValue -1625754273 -Xiadao -1625754399 -Xiadao -可空整型值 -int - - -35A58EB3-7253-49EB-9B1D-945C918A94B0 -长整型值( LongValue ) -LongValue -1625763436 -Xiadao -1625763483 -Xiadao -长整型值 -bigint - - -B10CEFAD-3CE3-4DE9-95F1-A680A1DF9656 -可空长整型值( NullableLongValue ) -NullableLongValue -1625763450 -Xiadao -1625763544 -Xiadao -可空长整型值 -bigint - - -84A19594-775B-473D-BA0E-DBBF37305BDC -Guid值( GuidValue ) -GuidValue -1625757818 -Xiadao -1625757888 -Xiadao -Guid值 -uniqueidentifier - - -E9A1F657-BD25-46C1-8A8E-34706C639400 -可空Guid值( NullableGuidValue ) -NullableGuidValue -1625758168 -Xiadao -1625758209 -Xiadao -可空Guid值 -uniqueidentifier - - -9F7697FB-9C08-4961-AC14-03E7A887E810 -布尔值( BoolValue ) -BoolValue -1625761946 -Xiadao -1625761986 -Xiadao -布尔值 -bit - - -13C8246B-030B-4929-ADAF-DF548AF4F82C -可空布尔值( NullableBoolValue ) -NullableBoolValue -1625761955 -Xiadao -1625762042 -Xiadao -可空布尔值 -bit - - -4B7969F3-FBBF-4D61-AC5D-8EB53CAD71B5 -Float类型值( FloatValue ) -FloatValue -1625807474 -Xiadao -1625808138 -Xiadao -Float类型值 -decimal(6,2) -6 -2 - - -1D826AA0-8623-47AA-97C8-42194B3AAC5A -可空Float类型值( NullableFloatValue ) -NullableFloatValue -1625807501 -Xiadao -1625808177 -Xiadao -可空Float类型值 -decimal(6,2) -6 -2 - - -0F2BF198-6CAD-461C-B0A2-22DEF2F11702 -Double类型值( DoubleValue ) -DoubleValue -1625808087 -Xiadao -1625808252 -Xiadao -Double类型值 -decimal(10,2) -10 -2 - - -52628F06-F40A-40B2-813E-4D0450CAB7C1 -可空Double类型值( NullableDoubleValue ) -NullableDoubleValue -1625808189 -Xiadao -1625808340 -Xiadao -可空Double类型值 -decimal(10,2) -10 -2 - - -9D7E2288-0B05-4266-BC31-1F5A422C1FBB -Decimal类型值( DecimalValue ) -DecimalValue -1625808317 -Xiadao -1625808409 -Xiadao -Decimal类型值 -decimal(18,2) -18 -2 - - -2EA0032B-D7DF-4400-9C55-0B78485C2C24 -可空Decimal类型值( NullableDecimalValue ) -NullableDecimalValue -1625808368 -Xiadao -1625808513 -Xiadao -可空Decimal类型值 -decimal(18,2) -18 -2 - - -1AC443F7-9DDF-4F3D-9DD0-F34751130003 -日期值( DateTimeValue ) -DateTimeValue -1625813374 -Xiadao -1625813477 -Xiadao -日期值 -datetime - - -A200D0F5-6515-4DAE-B746-AF9F93A7C40C -可空日期值( NullableDateTimeValue ) -NullableDateTimeValue -1625813382 -Xiadao -1625813615 -Xiadao -可空日期值 -datetime - - -ED06EEF6-48FA-461A-A0D8-188F81824B6B -是否删除( IsDeleted ) -IsDeleted -1625384268 -Xiadao -1625384268 -Xiadao -是否删除 -bit -1 - - -26135B4E-C152-4366-AA96-2752F5D6C195 -版本号( Version ) -Version -1625384268 -Xiadao -1625384268 -Xiadao -版本号 -timestamp - - - - -E61F4AF7-53EE-42D7-BCD9-D2C33917044E -Key_1 -Key_1 -1625384268 -Xiadao -1625384268 -Xiadao - - - - - - - - - - - - - -85C2885C-6163-4D07-9F34-16EC2B672F9A -测试_02_1( Test_02_1 ) -Test_02_1 -1625641883 -Xiadao -1629976764 -Xiadao -测试_02_1 - - - -1DDD3CBF-DFE5-4946-B7A9-7A2750D5CF9D -测试标识( TestId ) -TestId -1625641883 -Xiadao -1625641883 -Xiadao -测试标识 -uniqueidentifier -1 - - -72294AE2-1A16-4F92-9AFF-94E6888B491C -字符串值( StringValue ) -StringValue -1625641883 -Xiadao -1625641883 -Xiadao -字符串值 -nvarchar(200) -200 - - -551C30A8-0238-42C1-8ABE-55A4D4446226 -是否删除( IsDeleted ) -IsDeleted -1625641883 -Xiadao -1625641883 -Xiadao -是否删除 -bit -1 - - -09C0E454-0C0F-40CF-AA21-F2205320F66B -版本号( Version ) -Version -1625641883 -Xiadao -1625641883 -Xiadao -版本号 -timestamp - - - - -145A09A4-174E-4E22-884F-3058EF41E66B -Key_1 -Key_1 -1625641883 -Xiadao -1625641883 -Xiadao - - - - - - - - - - - - - -9BE7BBD0-F492-409F-A5C5-EAA52DE959C7 -测试_02_2( Test_02_2 ) -Test_02_2 -1625643974 -Xiadao -1629976764 -Xiadao -测试_02_2 - - - -62614651-555E-411C-BD3D-50B39CE09519 -测试标识( TestId ) -TestId -1625643974 -Xiadao -1625644021 -Xiadao -测试标识 -int -1 -1 - - -9705FC9E-7BB9-42DF-B714-EAB5003DAFCB -字符串值( StringValue ) -StringValue -1625643974 -Xiadao -1625643974 -Xiadao -字符串值 -nvarchar(200) -200 - - -BC5E95DD-59A3-47C0-9E13-FE5F65EC00D3 -是否删除( IsDeleted ) -IsDeleted -1625643974 -Xiadao -1625643974 -Xiadao -是否删除 -bit -1 - - -8621A90B-AAEB-4D1F-A34C-3E1E4AC52878 -版本号( Version ) -Version -1625643974 -Xiadao -1625643974 -Xiadao -版本号 -timestamp - - - - -A03D5F69-AD63-4F06-9F41-6AE74D941595 -Key_1 -Key_1 -1625643974 -Xiadao -1625643974 -Xiadao - - - - - - - - - - - - - -36435A44-E741-470A-B4E2-75727584D6DF -测试_02_3( Test_02_3 ) -Test_02_3 -1625645031 -Xiadao -1629976764 -Xiadao -测试_02_3 - - - -4C4E9141-7D92-4351-AC22-09672129AE64 -测试标识( TestId ) -TestId -1625645031 -Xiadao -1625645064 -Xiadao -测试标识 -nvarchar(50) -50 -1 - - -182304E9-5E2E-436E-97C3-194BCAA273DB -字符串值( StringValue ) -StringValue -1625645031 -Xiadao -1625645031 -Xiadao -字符串值 -nvarchar(200) -200 - - -1BE996FB-0C7E-42B9-BA64-E380FBF9CB43 -是否删除( IsDeleted ) -IsDeleted -1625645031 -Xiadao -1625645031 -Xiadao -是否删除 -bit -1 - - -6391D967-BAD3-410E-B903-CF0D9B96C09C -版本号( Version ) -Version -1625645031 -Xiadao -1625645031 -Xiadao -版本号 -timestamp - - - - -8FDCCA80-2028-4A81-94B5-9FEC46B1F18B -Key_1 -Key_1 -1625645031 -Xiadao -1625645031 -Xiadao - - - - - - - - - - - - - - - -4CD0ACF6-CD47-4391-B0FC-4B4C438DC549 -PUBLIC -PUBLIC -1621773500 -Xiadao -1634474813 -Xiadao - - - - - - - - - - - -7B0C4DC9-5999-4989-98A6-E5851A4E1E49 -Microsoft SQL Server 2014 -MSSQLSRV2014 -1621773500 -Xiadao -1402992778 -Xiadao -file:///%[XDB]%/sqlsv2014.xdb -49106F9E-F946-45DB-871A-64C75D3FA370 -4BA9F647-DAB1-11D1-9944-006097355D9B -1402992778 - - - - - -DBD7197E-E726-4C1B-94CE-17D88F90AAB6 -Util_Data_EF_Test_SqlServer -Util_Data_EF_Test_SqlServer -1631785959 -Xiadao -1634476877 -Xiadao -file:///. -BD608590-48FF-4C8E-8926-A4C7815777DB -CDE44E21-9669-11D1-9914-006097355D9B -1634479459 - - - - - - - - - - - \ No newline at end of file diff --git a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Document/PowerDesigner/Util_Data_EF_Test_SqlServer.pdm b/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Document/PowerDesigner/Util_Data_EF_Test_SqlServer.pdm deleted file mode 100644 index 383e2da2..00000000 --- a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Document/PowerDesigner/Util_Data_EF_Test_SqlServer.pdm +++ /dev/null @@ -1,7792 +0,0 @@ - - - - - - - -00000000-0000-0000-0000-000000000000 - - -BD608590-48FF-4C8E-8926-A4C7815777DB -Util_Data_EF_Test_SqlServer -Util_Data_EF_Test_SqlServer -1621773501 -Xiadao -1634474813 -Xiadao -[FolderOptions] - -[FolderOptions\Physical Objects] -GenerationCheckModel=Yes -GenerationPath= -GenerationOptions= -GenerationTasks= -GenerationTargets= -GenerationSelections= -RevPkey=Yes -RevFkey=Yes -RevAkey=Yes -RevCheck=Yes -RevIndx=Yes -RevOpts=Yes -RevViewAsTabl=No -RevViewOpts=Yes -RevSystAsTabl=Yes -RevTablPerm=No -RevViewPerm=No -RevProcPerm=No -RevDbpkPerm=No -RevSqncPerm=No -RevAdtPerm=No -RevUserPriv=No -RevUserOpts=No -RevGrpePriv=No -RevRolePriv=No -RevDtbsOpts=Yes -RevDtbsPerm=No -RevViewIndx=Yes -RevJidxOpts=Yes -RevStats=No -RevTspcPerm=No -RevCaseSensitive=No -GenTrgrStdMsg=Yes -GenTrgrMsgTab= -GenTrgrMsgNo= -GenTrgrMsgTxt= -TrgrPreserve=No -TrgrIns=Yes -TrgrUpd=Yes -TrgrDel=Yes -TrgrC2Ins=Yes -TrgrC2Upd=Yes -TrgrC3=Yes -TrgrC4=Yes -TrgrC5=Yes -TrgrC6=Yes -TrgrC7=Yes -TrgrC8=Yes -TrgrC9=Yes -TrgrC10=Yes -TrgrC11=Yes -TrgrC1=Yes -TrgrC12Ins=Yes -TrgrC12Upd=Yes -TrgrC13=Yes -UpdateTableStatistics=Yes -UpdateColumnStatistics=Yes -DeploymentMode=REP - -[FolderOptions\Physical Objects\Database Generation] -GenScriptName=crebas -GenScriptName0= -GenScriptName1= -GenScriptName2= -GenScriptName3= -GenScriptName4= -GenScriptName5= -GenScriptName6= -GenScriptName7= -GenScriptName8= -GenScriptName9= -GenPathName= -GenSingleFile=Yes -GenODBC=No -GenCheckModel=Yes -GenScriptPrev=Yes -GenArchiveModel=No -GenUseSync=No -GenSyncChoice=0 -GenSyncArch= -GenSyncRmg=0 - -[FolderOptions\Physical Objects\Database Generation\Format] -GenScriptTitle=Yes -GenScriptNamLabl=No -GenScriptQDtbs=No -GenScriptQOwnr=Yes -GenScriptCase=0 -GenScriptEncoding=ANSI -GenScriptNAcct=No -IdentifierDelimiter=" - -[FolderOptions\Physical Objects\Database Generation\Database] -Create=Yes -Open=Yes -Close=Yes -Drop=Yes -Permission=No - -[FolderOptions\Physical Objects\Database Generation\Database\Create] -Physical Options=Yes -Header=Yes -Footer=Yes - -[FolderOptions\Physical Objects\Database Generation\Tablespace] -Create=Yes -Drop=Yes -Comment=Yes -Permission=No - -[FolderOptions\Physical Objects\Database Generation\Tablespace\Create] -Header=Yes -Footer=Yes - -[FolderOptions\Physical Objects\Database Generation\Storage] -Create=Yes -Drop=Yes -Comment=Yes - -[FolderOptions\Physical Objects\Database Generation\User] -Create=Yes -Drop=Yes -Comment=Yes -Privilege=No - -[FolderOptions\Physical Objects\Database Generation\User\Create] -Physical Options=No - -[FolderOptions\Physical Objects\Database Generation\Group] -Create=Yes -Drop=Yes -Comment=Yes -Privilege=No - -[FolderOptions\Physical Objects\Database Generation\Role] -Create=Yes -Drop=Yes -Privilege=No - -[FolderOptions\Physical Objects\Database Generation\UserDefinedDataType] -Create=Yes -Comment=Yes -Drop=Yes - -[FolderOptions\Physical Objects\Database Generation\UserDefinedDataType\Create] -Default value=Yes -Check=Yes - -[FolderOptions\Physical Objects\Database Generation\AbstractDataType] -Create=Yes -Header=Yes -Footer=Yes -Drop=Yes -Comment=Yes -Install JAVA class=Yes -Remove JAVA class=Yes -Permission=No - -[FolderOptions\Physical Objects\Database Generation\Rule] -Create=Yes -Drop=Yes -Comment=Yes - -[FolderOptions\Physical Objects\Database Generation\Default] -Create=Yes -Comment=Yes -Drop=Yes - -[FolderOptions\Physical Objects\Database Generation\Sequence] -Create=Yes -Drop=Yes -Comment=Yes -Permission=No - -[FolderOptions\Physical Objects\Database Generation\Table&&Column] - -[FolderOptions\Physical Objects\Database Generation\Table&&Column\Table] -Create=Yes -Drop=Yes -Comment=Yes -Permission=No - -[FolderOptions\Physical Objects\Database Generation\Table&&Column\Table\Create] -Check=Yes -Physical Options=Yes -Header=Yes -Footer=Yes - -[FolderOptions\Physical Objects\Database Generation\Table&&Column\Table\Create\Check] -Constraint declaration=No - -[FolderOptions\Physical Objects\Database Generation\Table&&Column\Column] -User datatype=Yes -Default value=Yes -Check=Yes -Physical Options=Yes -Comment=Yes - -[FolderOptions\Physical Objects\Database Generation\Table&&Column\Column\Check] -Constraint declaration=No - -[FolderOptions\Physical Objects\Database Generation\Table&&Column\Key] - -[FolderOptions\Physical Objects\Database Generation\Table&&Column\Key\Primary key] -Create=Yes -Drop=Yes -Comment=Yes - -[FolderOptions\Physical Objects\Database Generation\Table&&Column\Key\Primary key\Create] -Constraint declaration=No -Physical Options=Yes - -[FolderOptions\Physical Objects\Database Generation\Table&&Column\Key\Alternate key] -Create=Yes -Drop=Yes -Comment=Yes - -[FolderOptions\Physical Objects\Database Generation\Table&&Column\Key\Alternate key\Create] -Constraint declaration=No -Physical Options=Yes - -[FolderOptions\Physical Objects\Database Generation\Table&&Column\Foreign key] -Create=Yes -Drop=Yes -Comment=Yes - -[FolderOptions\Physical Objects\Database Generation\Table&&Column\Foreign key\Create] -Constraint declaration=Yes - -[FolderOptions\Physical Objects\Database Generation\Table&&Column\Index] -Create=Yes -Drop=Yes -Comment=Yes - -[FolderOptions\Physical Objects\Database Generation\Table&&Column\Index\Create] -Constraint declaration=Yes -Physical Options=Yes - -[FolderOptions\Physical Objects\Database Generation\Table&&Column\Index\Filter] -Primary key=No -Foreign key=Yes -Alternate key=No -Cluster=Yes -Other=Yes - -[FolderOptions\Physical Objects\Database Generation\Table&&Column\Trigger] -Create=Yes -Drop=Yes -Comment=Yes - -[FolderOptions\Physical Objects\Database Generation\Table&&Column\Trigger\Filter] -For insert=Yes -For update=Yes -For delete=Yes -For other=Yes - -[FolderOptions\Physical Objects\Database Generation\View] -Create=Yes -Drop=Yes -Comment=Yes -Permission=No - -[FolderOptions\Physical Objects\Database Generation\View\Create] -Force Column list=No -Physical Options=Yes -Header=Yes -Footer=Yes - -[FolderOptions\Physical Objects\Database Generation\View\ViewColumn] -Comment=Yes - -[FolderOptions\Physical Objects\Database Generation\View\ViewIndex] -Create=Yes -Drop=Yes -Comment=Yes - -[FolderOptions\Physical Objects\Database Generation\View\ViewIndex\Create] -Physical Options=Yes - -[FolderOptions\Physical Objects\Database Generation\View\ViewIndex\Filter] -Cluster=Yes -Other=Yes - -[FolderOptions\Physical Objects\Database Generation\View\Trigger] -Create=Yes -Drop=Yes -Comment=Yes - -[FolderOptions\Physical Objects\Database Generation\View\Trigger\Filter] -For insert=Yes -For update=Yes -For delete=Yes -For other=Yes - -[FolderOptions\Physical Objects\Database Generation\DBMSTrigger] -Create=Yes -Drop=Yes -Comment=Yes - -[FolderOptions\Physical Objects\Database Generation\Synonym] -Create=Yes -Drop=Yes - -[FolderOptions\Physical Objects\Database Generation\Synonym\Filter] -Table=Yes -View=Yes -Proc=Yes -Synonym=Yes -Database Package=Yes -Sequence=Yes - -[FolderOptions\Physical Objects\Database Generation\JoinIndex] -Create=Yes -Drop=Yes -Comment=Yes - -[FolderOptions\Physical Objects\Database Generation\JoinIndex\Create] -Physical Options=Yes -Header=Yes -Footer=Yes - -[FolderOptions\Physical Objects\Database Generation\Procedure] -Create=Yes -Drop=Yes -Comment=Yes -Permission=No - -[FolderOptions\Physical Objects\Database Generation\Procedure\Create] -Header=Yes -Footer=Yes - -[FolderOptions\Physical Objects\Database Generation\DatabasePackage] -Create=Yes -Drop=Yes -Permission=No - -[FolderOptions\Physical Objects\Database Generation\WebService] -Create=Yes -Drop=Yes -Comment=Yes - -[FolderOptions\Physical Objects\Database Generation\Dimension] -Create=Yes -Drop=Yes - -[FolderOptions\Physical Objects\Database Generation\Synchronization] -GenBackupTabl=1 -GenKeepBackTabl=1 -GenTmpTablDrop=No -GenKeepTablOpts=No - -[FolderOptions\Physical Objects\Database Generation\User <<Schema>>] -Create=Yes -Drop=Yes -Comment=Yes - -[FolderOptions\Physical Objects\Database Generation\User <<User>>] -Create=Yes -Drop=Yes -Comment=Yes -Privilege=No - -[FolderOptions\Physical Objects\Database Generation\ExtendedObject <<Aggregate>>] -Create=Yes -Drop=Yes - -[FolderOptions\Physical Objects\Database Generation\ExtendedObject <<Aggregate>>\ExtendedSubObject <<AggregateParameter>>] -Create=Yes - -[FolderOptions\Physical Objects\Database Generation\ExtendedObject <<Assembly>>] -Create=Yes -Drop=Yes - -[FolderOptions\Physical Objects\Database Generation\ExtendedObject <<AsymmetricKey>>] -Create=Yes -Drop=Yes - -[FolderOptions\Physical Objects\Database Generation\ExtendedObject <<Certificate>>] -Create=Yes -Drop=Yes - -[FolderOptions\Physical Objects\Database Generation\ExtendedObject <<Contract>>] -Create=Yes -Drop=Yes - -[FolderOptions\Physical Objects\Database Generation\ExtendedObject <<EndPoint>>] -Create=Yes -Drop=Yes - -[FolderOptions\Physical Objects\Database Generation\ExtendedObject <<EventNotification>>] -Create=Yes -Drop=Yes - -[FolderOptions\Physical Objects\Database Generation\ExtendedObject <<FullTextCatalog>>] -Create=Yes -Drop=Yes - -[FolderOptions\Physical Objects\Database Generation\ExtendedObject <<MessageType>>] -Create=Yes -Drop=Yes - -[FolderOptions\Physical Objects\Database Generation\ExtendedObject <<PartitionFunction>>] -Create=Yes -Drop=Yes - -[FolderOptions\Physical Objects\Database Generation\ExtendedObject <<PartitionScheme>>] -Create=Yes -Drop=Yes - -[FolderOptions\Physical Objects\Database Generation\ExtendedObject <<Queue>>] -Create=Yes -Drop=Yes - -[FolderOptions\Physical Objects\Database Generation\ExtendedObject <<RemoteServiceBinding>>] -Create=Yes -Drop=Yes - -[FolderOptions\Physical Objects\Database Generation\ExtendedObject <<ResourcePool>>] -Create=Yes -Drop=Yes - -[FolderOptions\Physical Objects\Database Generation\ExtendedObject <<Route>>] -Create=Yes -Drop=Yes - -[FolderOptions\Physical Objects\Database Generation\ExtendedObject <<Service>>] -Create=Yes -Drop=Yes - -[FolderOptions\Physical Objects\Database Generation\ExtendedObject <<SymmetricKey>>] -Create=Yes -Drop=Yes - -[FolderOptions\Physical Objects\Database Generation\ExtendedObject <<WorkloadGroup>>] -Create=Yes -Drop=Yes - -[FolderOptions\Physical Objects\Database Generation\ExtendedObject <<XMLSchemaCollection>>] -Create=Yes -Drop=Yes - -[FolderOptions\Physical Objects\Test Data] -GenDataPathName= -GenDataSinglefile=Yes -GenDataScriptName=testdata -GenDataScriptName0= -GenDataScriptName1= -GenDataScriptName2= -GenDataScriptName3= -GenDataScriptName4= -GenDataScriptName5= -GenDataScriptName6= -GenDataScriptName7= -GenDataScriptName8= -GenDataScriptName9= -GenDataOdbc=0 -GenDataDelOld=No -GenDataTitle=No -GenDataDefNumRows=20 -GenDataCommit=0 -GenDataPacket=0 -GenDataOwner=No -GenDataProfNumb= -GenDataProfChar= -GenDataProfDate= -GenDataCSVSeparator=, -GenDataFileFormat=CSV -GenDataUseWizard=No - -[FolderOptions\Pdm] -IndxIQName=%COLUMN%_%INDEXTYPE% -IndxPK=Yes -IndxFK=Yes -IndxAK=Yes -IndxPKName=%TABLE%_PK -IndxFKName=%REFR%_FK -IndxAKName=%AKEY%_AK -IndxPreserve=No -IndxThreshold=0 -IndxStats=No -RefrPreserve=No -JidxPreserve=No -RbldMultiFact=Yes -RbldMultiDim=Yes -RbldMultiJidx=Yes -CubePreserve=No -TablStProcPreserve=No -ProcDepPreserve=Yes -TrgrDepPreserve=Yes -CubeScriptPath= -CubeScriptCase=0 -CubeScriptEncoding=ANSI -CubeScriptNacct=No -CubeScriptHeader=No -CubeScriptExt=csv -CubeScriptExt0=txt -CubeScriptExt1= -CubeScriptExt2= -CubeScriptSep=, -CubeScriptDeli=" -EstimationYears=0 -DfltDomnName=D_%.U:VALUE% -DfltColnName=D_%.U:VALUE% -DfltReuse=Yes -DfltDrop=Yes -[ModelOptions] - -[ModelOptions\Physical Objects] -CaseSensitive=No -DisplayName=Yes -EnableTrans=No -UseTerm=No -EnableRequirements=No -EnableFullShortcut=Yes -SynchroCode=Yes -DefaultDttp= -IgnoreOwner=No -RebuildTrigger=Yes -RefrUnique=No -RefrAutoMigrate=Yes -RefrMigrateReuse=Yes -RefrMigrateDomain=Yes -RefrMigrateCheck=Yes -RefrMigrateRule=Yes -RefrMigrateExtd=No -RefrMigrDefaultLink=No -RefrDfltImpl=D -RefrPrgtColn=No -RefrMigrateToEnd=No -RebuildTriggerDep=No -ColnFKName=%.3:PARENT%_%COLUMN% -ColnFKNameUse=No -DomnCopyDttp=Yes -DomnCopyChck=No -DomnCopyRule=No -DomnCopyMand=No -DomnCopyExtd=No -DomnCopyProf=No -Notation=0 -DomnDefaultMandatory=No -ColnDefaultMandatory=No -TablDefaultOwner= -ViewDefaultOwner= -TrgrDefaultOwnerTabl= -TrgrDefaultOwnerView= -IdxDefaultOwnerTabl= -IdxDefaultOwnerView= -JdxDefaultOwner= -DBPackDefaultOwner= -SeqDefaultOwner= -ProcDefaultOwner= -DBMSTrgrDefaultOwner= -Currency=USD -RefrDeleteConstraint=0 -RefrUpdateConstraint=0 -RefrParentMandatory=No -RefrParentChangeAllow=Yes -RefrCheckOnCommit=No - -[ModelOptions\Physical Objects\NamingOptionsTemplates] - -[ModelOptions\Physical Objects\ClssNamingOptions] - -[ModelOptions\Physical Objects\ClssNamingOptions\PDMPCKG] - -[ModelOptions\Physical Objects\ClssNamingOptions\PDMPCKG\Name] -Template= -MaxLen=254 -Case=M -ValidChar= -InvldChar= -AllValid=Yes -NoAccent=No -DefaultChar= -Script= -ConvTable= -ConvTablePath=%_HOME%\Resource Files\Conversion Tables - -[ModelOptions\Physical Objects\ClssNamingOptions\PDMPCKG\Code] -Template= -MaxLen=254 -Case=M -ValidChar= -InvldChar= -AllValid=Yes -NoAccent=No -DefaultChar= -Script= -ConvTable= -ConvTablePath=%_HOME%\Resource Files\Conversion Tables - -[ModelOptions\Physical Objects\ClssNamingOptions\PDMDOMN] - -[ModelOptions\Physical Objects\ClssNamingOptions\PDMDOMN\Name] -Template= -MaxLen=254 -Case=M -ValidChar= -InvldChar= -AllValid=Yes -NoAccent=No -DefaultChar= -Script= -ConvTable= -ConvTablePath=%_HOME%\Resource Files\Conversion Tables - -[ModelOptions\Physical Objects\ClssNamingOptions\PDMDOMN\Code] -Template= -MaxLen=128 -Case=M -ValidChar= -InvldChar= -AllValid=Yes -NoAccent=No -DefaultChar= -Script= -ConvTable= -ConvTablePath=%_HOME%\Resource Files\Conversion Tables - -[ModelOptions\Physical Objects\ClssNamingOptions\TABL] - -[ModelOptions\Physical Objects\ClssNamingOptions\TABL\Name] -Template= -MaxLen=254 -Case=M -ValidChar= -InvldChar= -AllValid=Yes -NoAccent=No -DefaultChar= -Script= -ConvTable= -ConvTablePath=%_HOME%\Resource Files\Conversion Tables - -[ModelOptions\Physical Objects\ClssNamingOptions\TABL\Code] -Template= -MaxLen=128 -Case=M -ValidChar= -InvldChar= -AllValid=Yes -NoAccent=No -DefaultChar= -Script= -ConvTable= -ConvTablePath=%_HOME%\Resource Files\Conversion Tables - -[ModelOptions\Physical Objects\ClssNamingOptions\COLN] - -[ModelOptions\Physical Objects\ClssNamingOptions\COLN\Name] -Template= -MaxLen=254 -Case=M -ValidChar= -InvldChar= -AllValid=Yes -NoAccent=No -DefaultChar= -Script= -ConvTable= -ConvTablePath=%_HOME%\Resource Files\Conversion Tables - -[ModelOptions\Physical Objects\ClssNamingOptions\COLN\Code] -Template= -MaxLen=128 -Case=M -ValidChar= -InvldChar= -AllValid=Yes -NoAccent=No -DefaultChar= -Script= -ConvTable= -ConvTablePath=%_HOME%\Resource Files\Conversion Tables - -[ModelOptions\Physical Objects\ClssNamingOptions\INDX] - -[ModelOptions\Physical Objects\ClssNamingOptions\INDX\Name] -Template= -MaxLen=254 -Case=M -ValidChar= -InvldChar= -AllValid=Yes -NoAccent=No -DefaultChar= -Script= -ConvTable= -ConvTablePath=%_HOME%\Resource Files\Conversion Tables - -[ModelOptions\Physical Objects\ClssNamingOptions\INDX\Code] -Template= -MaxLen=254 -Case=M -ValidChar= -InvldChar= -AllValid=Yes -NoAccent=No -DefaultChar= -Script= -ConvTable= -ConvTablePath=%_HOME%\Resource Files\Conversion Tables - -[ModelOptions\Physical Objects\ClssNamingOptions\REFR] - -[ModelOptions\Physical Objects\ClssNamingOptions\REFR\Name] -Template= -MaxLen=254 -Case=M -ValidChar= -InvldChar= -AllValid=Yes -NoAccent=No -DefaultChar= -Script= -ConvTable= -ConvTablePath=%_HOME%\Resource Files\Conversion Tables - -[ModelOptions\Physical Objects\ClssNamingOptions\REFR\Code] -Template= -MaxLen=254 -Case=M -ValidChar= -InvldChar= -AllValid=Yes -NoAccent=No -DefaultChar= -Script= -ConvTable= -ConvTablePath=%_HOME%\Resource Files\Conversion Tables - -[ModelOptions\Physical Objects\ClssNamingOptions\VREF] - -[ModelOptions\Physical Objects\ClssNamingOptions\VREF\Name] -Template= -MaxLen=254 -Case=M -ValidChar= -InvldChar= -AllValid=Yes -NoAccent=No -DefaultChar= -Script= -ConvTable= -ConvTablePath=%_HOME%\Resource Files\Conversion Tables - -[ModelOptions\Physical Objects\ClssNamingOptions\VREF\Code] -Template= -MaxLen=254 -Case=M -ValidChar= -InvldChar= -AllValid=Yes -NoAccent=No -DefaultChar= -Script= -ConvTable= -ConvTablePath=%_HOME%\Resource Files\Conversion Tables - -[ModelOptions\Physical Objects\ClssNamingOptions\VIEW] - -[ModelOptions\Physical Objects\ClssNamingOptions\VIEW\Name] -Template= -MaxLen=254 -Case=M -ValidChar= -InvldChar= -AllValid=Yes -NoAccent=No -DefaultChar= -Script= -ConvTable= -ConvTablePath=%_HOME%\Resource Files\Conversion Tables - -[ModelOptions\Physical Objects\ClssNamingOptions\VIEW\Code] -Template= -MaxLen=128 -Case=M -ValidChar= -InvldChar= -AllValid=Yes -NoAccent=No -DefaultChar= -Script= -ConvTable= -ConvTablePath=%_HOME%\Resource Files\Conversion Tables - -[ModelOptions\Physical Objects\ClssNamingOptions\VIEWC] - -[ModelOptions\Physical Objects\ClssNamingOptions\VIEWC\Name] -Template= -MaxLen=254 -Case=M -ValidChar= -InvldChar= -AllValid=Yes -NoAccent=No -DefaultChar= -Script= -ConvTable= -ConvTablePath=%_HOME%\Resource Files\Conversion Tables - -[ModelOptions\Physical Objects\ClssNamingOptions\VIEWC\Code] -Template= -MaxLen=254 -Case=M -ValidChar= -InvldChar= -AllValid=Yes -NoAccent=No -DefaultChar= -Script= -ConvTable= -ConvTablePath=%_HOME%\Resource Files\Conversion Tables - -[ModelOptions\Physical Objects\ClssNamingOptions\WEBSERV] - -[ModelOptions\Physical Objects\ClssNamingOptions\WEBSERV\Name] -Template= -MaxLen=254 -Case=M -ValidChar= -InvldChar= -AllValid=Yes -NoAccent=No -DefaultChar= -Script= -ConvTable= -ConvTablePath=%_HOME%\Resource Files\Conversion Tables - -[ModelOptions\Physical Objects\ClssNamingOptions\WEBSERV\Code] -Template= -MaxLen=254 -Case=M -ValidChar='a'-'z','A'-'Z','0'-'9',"/-_.!~*'()" -InvldChar= -AllValid=Yes -NoAccent=No -DefaultChar= -Script= -ConvTable= -ConvTablePath=%_HOME%\Resource Files\Conversion Tables - -[ModelOptions\Physical Objects\ClssNamingOptions\WEBOP] - -[ModelOptions\Physical Objects\ClssNamingOptions\WEBOP\Name] -Template= -MaxLen=254 -Case=M -ValidChar= -InvldChar= -AllValid=Yes -NoAccent=No -DefaultChar= -Script= -ConvTable= -ConvTablePath=%_HOME%\Resource Files\Conversion Tables - -[ModelOptions\Physical Objects\ClssNamingOptions\WEBOP\Code] -Template= -MaxLen=254 -Case=M -ValidChar='a'-'z','A'-'Z','0'-'9',"/-_.!~*'()" -InvldChar= -AllValid=Yes -NoAccent=No -DefaultChar= -Script= -ConvTable= -ConvTablePath=%_HOME%\Resource Files\Conversion Tables - -[ModelOptions\Physical Objects\ClssNamingOptions\WPARAM] - -[ModelOptions\Physical Objects\ClssNamingOptions\WPARAM\Name] -Template= -MaxLen=254 -Case=M -ValidChar= -InvldChar= -AllValid=Yes -NoAccent=No -DefaultChar= -Script= -ConvTable= -ConvTablePath=%_HOME%\Resource Files\Conversion Tables - -[ModelOptions\Physical Objects\ClssNamingOptions\WPARAM\Code] -Template= -MaxLen=254 -Case=M -ValidChar= -InvldChar= -AllValid=Yes -NoAccent=No -DefaultChar= -Script= -ConvTable= -ConvTablePath=%_HOME%\Resource Files\Conversion Tables - -[ModelOptions\Physical Objects\ClssNamingOptions\FACT] - -[ModelOptions\Physical Objects\ClssNamingOptions\FACT\Name] -Template= -MaxLen=254 -Case=M -ValidChar= -InvldChar= -AllValid=Yes -NoAccent=No -DefaultChar= -Script= -ConvTable= -ConvTablePath=%_HOME%\Resource Files\Conversion Tables - -[ModelOptions\Physical Objects\ClssNamingOptions\FACT\Code] -Template= -MaxLen=254 -Case=M -ValidChar= -InvldChar= -AllValid=Yes -NoAccent=No -DefaultChar= -Script= -ConvTable= -ConvTablePath=%_HOME%\Resource Files\Conversion Tables - -[ModelOptions\Physical Objects\ClssNamingOptions\DIMN] - -[ModelOptions\Physical Objects\ClssNamingOptions\DIMN\Name] -Template= -MaxLen=254 -Case=M -ValidChar= -InvldChar= -AllValid=Yes -NoAccent=No -DefaultChar= -Script= -ConvTable= -ConvTablePath=%_HOME%\Resource Files\Conversion Tables - -[ModelOptions\Physical Objects\ClssNamingOptions\DIMN\Code] -Template= -MaxLen=254 -Case=M -ValidChar= -InvldChar= -AllValid=Yes -NoAccent=No -DefaultChar= -Script= -ConvTable= -ConvTablePath=%_HOME%\Resource Files\Conversion Tables - -[ModelOptions\Physical Objects\ClssNamingOptions\MEAS] - -[ModelOptions\Physical Objects\ClssNamingOptions\MEAS\Name] -Template= -MaxLen=254 -Case=M -ValidChar= -InvldChar= -AllValid=Yes -NoAccent=No -DefaultChar= -Script= -ConvTable= -ConvTablePath=%_HOME%\Resource Files\Conversion Tables - -[ModelOptions\Physical Objects\ClssNamingOptions\MEAS\Code] -Template= -MaxLen=254 -Case=M -ValidChar= -InvldChar= -AllValid=Yes -NoAccent=No -DefaultChar= -Script= -ConvTable= -ConvTablePath=%_HOME%\Resource Files\Conversion Tables - -[ModelOptions\Physical Objects\ClssNamingOptions\DATTR] - -[ModelOptions\Physical Objects\ClssNamingOptions\DATTR\Name] -Template= -MaxLen=254 -Case=M -ValidChar= -InvldChar= -AllValid=Yes -NoAccent=No -DefaultChar= -Script= -ConvTable= -ConvTablePath=%_HOME%\Resource Files\Conversion Tables - -[ModelOptions\Physical Objects\ClssNamingOptions\DATTR\Code] -Template= -MaxLen=254 -Case=M -ValidChar= -InvldChar= -AllValid=Yes -NoAccent=No -DefaultChar= -Script= -ConvTable= -ConvTablePath=%_HOME%\Resource Files\Conversion Tables - -[ModelOptions\Physical Objects\ClssNamingOptions\FILO] - -[ModelOptions\Physical Objects\ClssNamingOptions\FILO\Name] -Template= -MaxLen=254 -Case=M -ValidChar= -InvldChar= -AllValid=Yes -NoAccent=No -DefaultChar= -Script= -ConvTable= -ConvTablePath=%_HOME%\Resource Files\Conversion Tables - -[ModelOptions\Physical Objects\ClssNamingOptions\FILO\Code] -Template= -MaxLen=254 -Case=M -ValidChar= -InvldChar= -AllValid=Yes -NoAccent=No -DefaultChar= -Script= -ConvTable= -ConvTablePath=%_HOME%\Resource Files\Conversion Tables - -[ModelOptions\Physical Objects\ClssNamingOptions\FRMEOBJ] - -[ModelOptions\Physical Objects\ClssNamingOptions\FRMEOBJ\Name] -Template= -MaxLen=254 -Case=M -ValidChar= -InvldChar= -AllValid=Yes -NoAccent=No -DefaultChar= -Script= -ConvTable= -ConvTablePath=%_HOME%\Resource Files\Conversion Tables - -[ModelOptions\Physical Objects\ClssNamingOptions\FRMEOBJ\Code] -Template= -MaxLen=254 -Case=M -ValidChar= -InvldChar= -AllValid=Yes -NoAccent=No -DefaultChar= -Script= -ConvTable= -ConvTablePath=%_HOME%\Resource Files\Conversion Tables - -[ModelOptions\Physical Objects\ClssNamingOptions\FRMELNK] - -[ModelOptions\Physical Objects\ClssNamingOptions\FRMELNK\Name] -Template= -MaxLen=254 -Case=M -ValidChar= -InvldChar= -AllValid=Yes -NoAccent=No -DefaultChar= -Script= -ConvTable= -ConvTablePath=%_HOME%\Resource Files\Conversion Tables - -[ModelOptions\Physical Objects\ClssNamingOptions\FRMELNK\Code] -Template= -MaxLen=254 -Case=M -ValidChar= -InvldChar= -AllValid=Yes -NoAccent=No -DefaultChar= -Script= -ConvTable= -ConvTablePath=%_HOME%\Resource Files\Conversion Tables - -[ModelOptions\Physical Objects\ClssNamingOptions\AREA] - -[ModelOptions\Physical Objects\ClssNamingOptions\AREA\Name] -Template= -MaxLen=254 -Case=M -ValidChar= -InvldChar= -AllValid=Yes -NoAccent=No -DefaultChar= -Script= -ConvTable= -ConvTablePath=%_HOME%\Resource Files\Conversion Tables - -[ModelOptions\Physical Objects\ClssNamingOptions\AREA\Code] -Template= -MaxLen=254 -Case=M -ValidChar= -InvldChar= -AllValid=Yes -NoAccent=No -DefaultChar= -Script= -ConvTable= -ConvTablePath=%_HOME%\Resource Files\Conversion Tables - -[ModelOptions\Physical Objects\ClssNamingOptions\DefaultClass] - -[ModelOptions\Physical Objects\ClssNamingOptions\DefaultClass\Name] -Template= -MaxLen=254 -Case=M -ValidChar= -InvldChar= -AllValid=Yes -NoAccent=No -DefaultChar= -Script= -ConvTable= -ConvTablePath=%_HOME%\Resource Files\Conversion Tables - -[ModelOptions\Physical Objects\ClssNamingOptions\DefaultClass\Code] -Template= -MaxLen=254 -Case=M -ValidChar= -InvldChar= -AllValid=Yes -NoAccent=No -DefaultChar= -Script= -ConvTable= -ConvTablePath=%_HOME%\Resource Files\Conversion Tables - -[ModelOptions\Connection] - -[ModelOptions\Pdm] - -[ModelOptions\Generate] - -[ModelOptions\Generate\Xsm] -GenRootElement=Yes -GenComplexType=No -GenAttribute=Yes -CheckModel=Yes -SaveLinks=Yes -ORMapping=No -NameToCode=No - -[ModelOptions\Generate\Pdm] -RRMapping=No - -[ModelOptions\Generate\Cdm] -CheckModel=Yes -SaveLinks=Yes -NameToCode=No -Notation=2 - -[ModelOptions\Generate\Oom] -CheckModel=Yes -SaveLinks=Yes -ORMapping=No -NameToCode=Yes -ClassPrefix= - -[ModelOptions\Generate\Ldm] -CheckModel=Yes -SaveLinks=Yes -NameToCode=No - -[ModelOptions\Default Opts] - -[ModelOptions\Default Opts\TABL] -PhysOpts= - -[ModelOptions\Default Opts\COLN] -PhysOpts= - -[ModelOptions\Default Opts\INDX] -PhysOpts= - -[ModelOptions\Default Opts\AKEY] -PhysOpts= - -[ModelOptions\Default Opts\PKEY] -PhysOpts= - -[ModelOptions\Default Opts\STOR] -PhysOpts= - -[ModelOptions\Default Opts\TSPC] -PhysOpts= - -[ModelOptions\Default Opts\SQNC] -PhysOpts= - -[ModelOptions\Default Opts\DTBS] -PhysOpts= - -[ModelOptions\Default Opts\USER] -PhysOpts= - -[ModelOptions\Default Opts\JIDX] -PhysOpts= - -[ModelOptions\Default Opts\FRMEOBJ<<ResourcePool>>] -PhysOpts= - -[ModelOptions\Default Opts\FRMEOBJ<<WorkloadGroup>>] -PhysOpts= - -[ModelOptions\Default Opts\FRMESOB<<ResourcePool>>] -PhysOpts= - -[ModelOptions\Default Opts\FRMESOB<<WorkloadGroup>>] -PhysOpts= -D:\Util\util-v5\test\Util.Data.EntityFrameworkCore.SqlServer.Tests\Document\PowerDesigner\Util_Data_EF_Test_SqlServer.pdm - - -A3B2D737-907D-4CA0-A2C1-04B156933B64 -Microsoft SQL Server 2014 -MSSQLSRV2014 -1621773500 -Xiadao -1621773500 -Xiadao - -49106F9E-F946-45DB-871A-64C75D3FA370 -4BA9F647-DAB1-11D1-9944-006097355D9B - - - - -C56CB1A6-55BD-4ED3-A5CA-5072B8B00F10 -main -main -1621773501 -Xiadao -1628408459 -Xiadao -[DisplayPreferences] - -[DisplayPreferences\PDM] - -[DisplayPreferences\General] -Adjust to text=Yes -Snap Grid=No -Constrain Labels=Yes -Display Grid=No -Show Page Delimiter=Yes -Show Links intersections=Yes -Activate automatic link routing=Yes -Grid size=800 -Graphic unit=2 -Window color=255 255 255 -Background image= -Background mode=8 -Watermark image= -Watermark mode=8 -Show watermark on screen=No -Gradient mode=0 -Gradient end color=255 255 255 -Show Swimlane=No -SwimlaneVert=Yes -TreeVert=No -CompDark=0 - -[DisplayPreferences\Object] -Show Icon=No -Mode=2 -Trunc Length=40 -Word Length=40 -Word Text=!"#$%&')*+,-./:;=>?@\]^_`|}~ -Shortcut IntIcon=Yes -Shortcut IntLoct=Yes -Shortcut IntFullPath=No -Shortcut IntLastPackage=Yes -Shortcut ExtIcon=Yes -Shortcut ExtLoct=No -Shortcut ExtFullPath=No -Shortcut ExtLastPackage=Yes -Shortcut ExtIncludeModl=Yes -Area.IconPicture=Yes -Area.Stereotype=Yes -Area.Comment=No -Area.TextStyle=No -Area.SubSymbols=Yes -Area_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Architecture Area Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <Separator Name="Separator" />[CRLF] <StandardAttribute Name="Comment" Attribute="Comment" Prefix="" Suffix="" Alignment="LEFT" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -EObjShowStrn=Yes -ExtendedObject.Comment=No -ExtendedObject.IconPicture=No -ExtendedObject.TextStyle=No -ExtendedObject_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Object Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <Separator Name="Separator" />[CRLF] <StandardAttribute Name="Comment" Attribute="Comment" Prefix="" Suffix="" Alignment="LEFT" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -ELnkShowStrn=Yes -ELnkShowName=Yes -ExtendedLink_SymbolLayout=<Form>[CRLF] <Form Name="Center" >[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] </Form>[CRLF] <Form Name="Source" >[CRLF] </Form>[CRLF] <Form Name="Destination" >[CRLF] </Form>[CRLF]</Form> -ExtDpdShowStrn=Yes -ExtendedDependency_SymbolLayout=<Form>[CRLF] <Form Name="Center" >[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Caption="" Mandatory="No" />[CRLF] </Form>[CRLF] <Form Name="Source" >[CRLF] </Form>[CRLF] <Form Name="Destination" >[CRLF] </Form>[CRLF]</Form> -FileObject.Stereotype=No -FileObject.DisplayName=Yes -FileObject.LocationOrName=No -FileObject.IconPicture=No -FileObject.TextStyle=No -FileObject.IconMode=Yes -FileObject_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <ExclusiveChoice Name="Exclusive Choice" Mandatory="Yes" Display="HorizontalRadios" >[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Location" Attribute="LocationOrName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] </ExclusiveChoice>[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -Package.Stereotype=Yes -Package.Comment=No -Package.IconPicture=No -Package.TextStyle=No -Package_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <Separator Name="Separator" />[CRLF] <StandardAttribute Name="Comment" Attribute="Comment" Prefix="" Suffix="" Alignment="LEFT" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -Display Model Version=Yes -Table.Stereotype=Yes -Table.DisplayName=Yes -Table.OwnerDisplayName=No -Table.Columns=Yes -Table.Columns._Filter="All Columns" PDMCOLNALL -Table.Columns._Columns=Stereotype DataType KeyIndicator -Table.Columns._Limit=-5 -Table.Keys=No -Table.Keys._Columns=Stereotype Indicator -Table.Indexes=No -Table.Indexes._Columns=Stereotype -Table.Triggers=No -Table.Triggers._Columns=Stereotype -Table.Comment=No -Table.IconPicture=No -Table.TextStyle=No -Table_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <ExclusiveChoice Name="Exclusive Choice" Mandatory="Yes" Display="HorizontalRadios" >[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Owner and Name" Attribute="OwnerDisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] </ExclusiveChoice>[CRLF] <Separator Name="Separator" />[CRLF] <StandardCollection Name="Columns" Collection="Columns" Columns="Stereotype No\r\nDisplayName Yes\r\nDataType No\r\nSymbolDataType No &quot;Domain or Data type&quot;\r\nDomain No\r\nKeyIndicator No\r\nIndexIndicator No\r\nNullStatus No" Filters="&quot;All Columns&quot; PDMCOLNALL &quot;&quot;\r\n&quot;PK Columns&quot; PDMCOLNPK &quot;\&quot;PRIM \&quot;TRUE\&quot; TRUE\&quot;&quot;\r\n&quot;Key Columns&quot; PDMCOLNKEY &quot;\&quot;KEYS \&quot;TRUE\&quot; TRUE\&quot;&quot;" HasLimit="Yes" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardCollection Name="Keys" Collection="Keys" Columns="Stereotype No\r\nDisplayName Yes\r\nIndicator No" HasLimit="No" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardCollection Name="Indexes" Collection="Indexes" Columns="Stereotype No\r\nDisplayName Yes\r\nIndicator No" HasLimit="No" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardCollection Name="Triggers" Collection="Triggers" Columns="Stereotype No\r\nDisplayName Yes" HasLimit="No" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Comment" Attribute="Comment" Prefix="" Suffix="" Alignment="LEFT" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -View.Stereotype=Yes -View.DisplayName=Yes -View.OwnerDisplayName=No -View.Columns=Yes -View.Columns._Columns=DisplayName -View.Columns._Limit=-5 -View.TemporaryVTables=Yes -View.Indexes=No -View.Comment=No -View.IconPicture=No -View.TextStyle=No -View_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <ExclusiveChoice Name="Exclusive Choice" Mandatory="Yes" Display="HorizontalRadios" >[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Owner and Name" Attribute="OwnerDisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] </ExclusiveChoice>[CRLF] <Separator Name="Separator" />[CRLF] <StandardCollection Name="Columns" Collection="Columns" Columns="DisplayName No\r\nExpression No\r\nDataType No\r\nSymbolDataType No &quot;Domain or Data type&quot;\r\nIndexIndicator No" HasLimit="Yes" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardCollection Name="Tables" Collection="TemporaryVTables" Columns="Name Yes" HasLimit="No" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardCollection Name="Indexes" Collection="Indexes" Columns="DisplayName Yes" HasLimit="No" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Comment" Attribute="Comment" Prefix="" Suffix="" Alignment="LEFT" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -Procedure.Stereotype=No -Procedure.DisplayName=Yes -Procedure.OwnerDisplayName=No -Procedure.Comment=No -Procedure.IconPicture=No -Procedure.TextStyle=No -Procedure_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <ExclusiveChoice Name="Exclusive Choice" Mandatory="Yes" Display="HorizontalRadios" >[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Owner and Name" Attribute="OwnerDisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] </ExclusiveChoice>[CRLF] <Separator Name="Separator" />[CRLF] <StandardAttribute Name="Comment" Attribute="Comment" Prefix="" Suffix="" Alignment="LEFT" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -Reference.Cardinality=No -Reference.ImplementationType=No -Reference.ChildRole=Yes -Reference.Stereotype=Yes -Reference.DisplayName=No -Reference.ForeignKeyConstraintName=No -Reference.JoinExpression=No -Reference.Integrity=No -Reference.ParentRole=Yes -Reference_SymbolLayout=<Form>[CRLF] <Form Name="Source" >[CRLF] <StandardAttribute Name="Cardinality" Attribute="Cardinality" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Implementation" Attribute="ImplementationType" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Child Role" Attribute="ChildRole" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] </Form>[CRLF] <Form Name="Center" >[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Caption="" Mandatory="No" />[CRLF] <ExclusiveChoice Name="Exclusive Choice" Mandatory="No" Display="HorizontalRadios" >[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Cons&amp;traint Name" Attribute="ForeignKeyConstraintName" Prefix="" Suffix="" Caption="Cons&amp;traint Name" Mandatory="No" />[CRLF] <StandardAttribute Name="Join" Attribute="JoinExpression" Prefix="" Suffix="" Caption="Join" Mandatory="No" />[CRLF] </ExclusiveChoice>[CRLF] <StandardAttribute Name="Referential integrity" Attribute="Integrity" Prefix="" Suffix="" Caption="Referential integrity" Mandatory="No" />[CRLF] </Form>[CRLF] <Form Name="Destination" >[CRLF] <StandardAttribute Name="Parent Role" Attribute="ParentRole" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] </Form>[CRLF]</Form> -ViewReference.ChildRole=Yes -ViewReference.Stereotype=Yes -ViewReference.DisplayName=No -ViewReference.JoinExpression=No -ViewReference.ParentRole=Yes -ViewReference_SymbolLayout=<Form>[CRLF] <Form Name="Source" >[CRLF] <StandardAttribute Name="Child Role" Attribute="ChildRole" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] </Form>[CRLF] <Form Name="Center" >[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Caption="" Mandatory="No" />[CRLF] <ExclusiveChoice Name="Exclusive Choice" Mandatory="No" Display="HorizontalRadios" >[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Join Expression" Attribute="JoinExpression" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] </ExclusiveChoice>[CRLF] </Form>[CRLF] <Form Name="Destination" >[CRLF] <StandardAttribute Name="Parent Role" Attribute="ParentRole" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] </Form>[CRLF]</Form> - -[DisplayPreferences\Symbol] - -[DisplayPreferences\Symbol\AREA] -STRNFont=新宋体,8,N -STRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -LABLFont=新宋体,8,N -LABLFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=9600 -Height=8000 -Brush color=253 249 234 -Fill Color=Yes -Brush style=6 -Brush bitmap mode=12 -Brush gradient mode=16 -Brush gradient color=245 230 173 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 121 98 6 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\FRMEOBJ] -STRNFont=新宋体,8,N -STRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -LABLFont=新宋体,8,N -LABLFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=6000 -Height=2000 -Brush color=255 255 255 -Fill Color=Yes -Brush style=6 -Brush bitmap mode=12 -Brush gradient mode=64 -Brush gradient color=192 192 192 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 255 128 128 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\FRMELNK] -CENTERFont=新宋体,8,N -CENTERFont color=0 0 0 -Line style=1 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Brush color=255 255 255 -Fill Color=Yes -Brush style=1 -Brush bitmap mode=12 -Brush gradient mode=0 -Brush gradient color=118 118 118 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 128 128 255 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\USRDEPD] -CENTERFont=新宋体,8,N -CENTERFont color=0 0 0 -Line style=1 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Brush color=255 255 255 -Fill Color=Yes -Brush style=1 -Brush bitmap mode=12 -Brush gradient mode=0 -Brush gradient color=118 118 118 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=2 0 128 128 255 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\FILO] -OBJSTRNFont=新宋体,8,N -OBJSTRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -LCNMFont=新宋体,8,N -LCNMFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=4800 -Height=3600 -Brush color=255 255 255 -Fill Color=Yes -Brush style=1 -Brush bitmap mode=12 -Brush gradient mode=0 -Brush gradient color=118 118 118 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 0 0 255 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\PDMPCKG] -STRNFont=新宋体,8,N -STRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -LABLFont=新宋体,8,N -LABLFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=4800 -Height=4000 -Brush color=255 255 192 -Fill Color=Yes -Brush style=6 -Brush bitmap mode=12 -Brush gradient mode=65 -Brush gradient color=255 255 255 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 178 178 178 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\TABL] -STRNFont=新宋体,8,N -STRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -OWNRDISPNAMEFont=新宋体,8,N -OWNRDISPNAMEFont color=0 0 0 -ColumnsFont=新宋体,8,N -ColumnsFont color=0 0 0 -TablePkColumnsFont=新宋体,8,U -TablePkColumnsFont color=0 0 0 -TableFkColumnsFont=新宋体,8,N -TableFkColumnsFont color=0 0 0 -KeysFont=新宋体,8,N -KeysFont color=0 0 0 -IndexesFont=新宋体,8,N -IndexesFont color=0 0 0 -TriggersFont=新宋体,8,N -TriggersFont color=0 0 0 -LABLFont=新宋体,8,N -LABLFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=4800 -Height=4000 -Brush color=178 214 252 -Fill Color=Yes -Brush style=6 -Brush bitmap mode=12 -Brush gradient mode=65 -Brush gradient color=255 255 255 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 0 128 192 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\VIEW] -STRNFont=新宋体,8,N -STRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -OWNRDISPNAMEFont=新宋体,8,N -OWNRDISPNAMEFont color=0 0 0 -ColumnsFont=新宋体,8,N -ColumnsFont color=0 0 0 -TablePkColumnsFont=新宋体,8,U -TablePkColumnsFont color=0 0 0 -TableFkColumnsFont=新宋体,8,N -TableFkColumnsFont color=0 0 0 -TemporaryVTablesFont=新宋体,8,N -TemporaryVTablesFont color=0 0 0 -IndexesFont=新宋体,8,N -IndexesFont color=0 0 0 -LABLFont=新宋体,8,N -LABLFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=4800 -Height=4000 -Brush color=208 208 255 -Fill Color=Yes -Brush style=6 -Brush bitmap mode=12 -Brush gradient mode=65 -Brush gradient color=255 255 255 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 128 128 192 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\PROC] -STRNFont=新宋体,8,N -STRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -OWNRDISPNAMEFont=新宋体,8,N -OWNRDISPNAMEFont color=0 0 0 -LABLFont=新宋体,8,N -LABLFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=4000 -Height=1000 -Brush color=255 255 192 -Fill Color=Yes -Brush style=6 -Brush bitmap mode=12 -Brush gradient mode=65 -Brush gradient color=255 255 255 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 128 108 0 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\REFR] -SOURCEFont=新宋体,8,N -SOURCEFont color=0 0 0 -CENTERFont=新宋体,8,N -CENTERFont color=0 0 0 -DESTINATIONFont=新宋体,8,N -DESTINATIONFont color=0 0 0 -Line style=1 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Brush color=255 255 255 -Fill Color=Yes -Brush style=1 -Brush bitmap mode=12 -Brush gradient mode=0 -Brush gradient color=118 118 118 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 0 128 192 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\VREF] -SOURCEFont=新宋体,8,N -SOURCEFont color=0 0 0 -CENTERFont=新宋体,8,N -CENTERFont color=0 0 0 -DESTINATIONFont=新宋体,8,N -DESTINATIONFont color=0 0 0 -Line style=1 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Brush color=255 255 255 -Fill Color=Yes -Brush style=1 -Brush bitmap mode=12 -Brush gradient mode=0 -Brush gradient color=118 118 118 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 128 128 192 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\Free Symbol] -Free TextFont=新宋体,8,N -Free TextFont color=0 0 0 -Line style=0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Brush color=255 255 255 -Fill Color=Yes -Brush style=1 -Brush bitmap mode=12 -Brush gradient mode=0 -Brush gradient color=118 118 118 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 0 0 255 -Shadow color=192 192 192 -Shadow=0 -(8268, 11693) -((315,354), (433,354)) -1 -15 - - - - -5B174033-3747-4F4B-AC04-DF359F148251 -01-系统 -01-系统 -1628409272 -Xiadao -1629975739 -Xiadao - - -A446ED61-03A1-4E6B-A725-E0FB09EC3A5F -01-日志 -01-日志 -1628409272 -Xiadao -1629975739 -Xiadao -[DisplayPreferences] - -[DisplayPreferences\PDM] - -[DisplayPreferences\General] -Adjust to text=Yes -Snap Grid=No -Constrain Labels=Yes -Display Grid=No -Show Page Delimiter=Yes -Show Links intersections=Yes -Activate automatic link routing=Yes -Grid size=800 -Graphic unit=2 -Window color=255 255 255 -Background image= -Background mode=8 -Watermark image= -Watermark mode=8 -Show watermark on screen=No -Gradient mode=0 -Gradient end color=255 255 255 -Show Swimlane=No -SwimlaneVert=Yes -TreeVert=No -CompDark=0 - -[DisplayPreferences\Object] -Show Icon=No -Mode=2 -Trunc Length=40 -Word Length=40 -Word Text=!"#$%&')*+,-./:;=>?@\]^_`|}~ -Shortcut IntIcon=Yes -Shortcut IntLoct=Yes -Shortcut IntFullPath=No -Shortcut IntLastPackage=Yes -Shortcut ExtIcon=Yes -Shortcut ExtLoct=No -Shortcut ExtFullPath=No -Shortcut ExtLastPackage=Yes -Shortcut ExtIncludeModl=Yes -Area.IconPicture=Yes -Area.Stereotype=Yes -Area.Comment=No -Area.TextStyle=No -Area.SubSymbols=Yes -Area_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Architecture Area Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <Separator Name="Separator" />[CRLF] <StandardAttribute Name="Comment" Attribute="Comment" Prefix="" Suffix="" Alignment="LEFT" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -EObjShowStrn=Yes -ExtendedObject.Comment=No -ExtendedObject.IconPicture=No -ExtendedObject.TextStyle=No -ExtendedObject_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Object Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <Separator Name="Separator" />[CRLF] <StandardAttribute Name="Comment" Attribute="Comment" Prefix="" Suffix="" Alignment="LEFT" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -ELnkShowStrn=Yes -ELnkShowName=Yes -ExtendedLink_SymbolLayout=<Form>[CRLF] <Form Name="Center" >[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] </Form>[CRLF] <Form Name="Source" >[CRLF] </Form>[CRLF] <Form Name="Destination" >[CRLF] </Form>[CRLF]</Form> -ExtDpdShowStrn=Yes -ExtendedDependency_SymbolLayout=<Form>[CRLF] <Form Name="Center" >[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Caption="" Mandatory="No" />[CRLF] </Form>[CRLF] <Form Name="Source" >[CRLF] </Form>[CRLF] <Form Name="Destination" >[CRLF] </Form>[CRLF]</Form> -FileObject.Stereotype=No -FileObject.DisplayName=Yes -FileObject.LocationOrName=No -FileObject.IconPicture=No -FileObject.TextStyle=No -FileObject.IconMode=Yes -FileObject_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <ExclusiveChoice Name="Exclusive Choice" Mandatory="Yes" Display="HorizontalRadios" >[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Location" Attribute="LocationOrName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] </ExclusiveChoice>[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -Package.Stereotype=Yes -Package.Comment=No -Package.IconPicture=No -Package.TextStyle=No -Package_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <Separator Name="Separator" />[CRLF] <StandardAttribute Name="Comment" Attribute="Comment" Prefix="" Suffix="" Alignment="LEFT" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -Display Model Version=Yes -Table.Stereotype=Yes -Table.DisplayName=Yes -Table.OwnerDisplayName=No -Table.Columns=Yes -Table.Columns._Filter="All Columns" PDMCOLNALL -Table.Columns._Columns=Stereotype DataType KeyIndicator -Table.Columns._Limit=-5 -Table.Keys=No -Table.Keys._Columns=Stereotype Indicator -Table.Indexes=No -Table.Indexes._Columns=Stereotype -Table.Triggers=No -Table.Triggers._Columns=Stereotype -Table.Comment=No -Table.IconPicture=No -Table.TextStyle=No -Table_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <ExclusiveChoice Name="Exclusive Choice" Mandatory="Yes" Display="HorizontalRadios" >[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Owner and Name" Attribute="OwnerDisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] </ExclusiveChoice>[CRLF] <Separator Name="Separator" />[CRLF] <StandardCollection Name="Columns" Collection="Columns" Columns="Stereotype No\r\nDisplayName Yes\r\nDataType No\r\nSymbolDataType No &quot;Domain or Data type&quot;\r\nDomain No\r\nKeyIndicator No\r\nIndexIndicator No\r\nNullStatus No" Filters="&quot;All Columns&quot; PDMCOLNALL &quot;&quot;\r\n&quot;PK Columns&quot; PDMCOLNPK &quot;\&quot;PRIM \&quot;TRUE\&quot; TRUE\&quot;&quot;\r\n&quot;Key Columns&quot; PDMCOLNKEY &quot;\&quot;KEYS \&quot;TRUE\&quot; TRUE\&quot;&quot;" HasLimit="Yes" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardCollection Name="Keys" Collection="Keys" Columns="Stereotype No\r\nDisplayName Yes\r\nIndicator No" HasLimit="No" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardCollection Name="Indexes" Collection="Indexes" Columns="Stereotype No\r\nDisplayName Yes\r\nIndicator No" HasLimit="No" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardCollection Name="Triggers" Collection="Triggers" Columns="Stereotype No\r\nDisplayName Yes" HasLimit="No" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Comment" Attribute="Comment" Prefix="" Suffix="" Alignment="LEFT" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -View.Stereotype=Yes -View.DisplayName=Yes -View.OwnerDisplayName=No -View.Columns=Yes -View.Columns._Columns=DisplayName -View.Columns._Limit=-5 -View.TemporaryVTables=Yes -View.Indexes=No -View.Comment=No -View.IconPicture=No -View.TextStyle=No -View_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <ExclusiveChoice Name="Exclusive Choice" Mandatory="Yes" Display="HorizontalRadios" >[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Owner and Name" Attribute="OwnerDisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] </ExclusiveChoice>[CRLF] <Separator Name="Separator" />[CRLF] <StandardCollection Name="Columns" Collection="Columns" Columns="DisplayName No\r\nExpression No\r\nDataType No\r\nSymbolDataType No &quot;Domain or Data type&quot;\r\nIndexIndicator No" HasLimit="Yes" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardCollection Name="Tables" Collection="TemporaryVTables" Columns="Name Yes" HasLimit="No" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardCollection Name="Indexes" Collection="Indexes" Columns="DisplayName Yes" HasLimit="No" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Comment" Attribute="Comment" Prefix="" Suffix="" Alignment="LEFT" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -Procedure.Stereotype=No -Procedure.DisplayName=Yes -Procedure.OwnerDisplayName=No -Procedure.Comment=No -Procedure.IconPicture=No -Procedure.TextStyle=No -Procedure_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <ExclusiveChoice Name="Exclusive Choice" Mandatory="Yes" Display="HorizontalRadios" >[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Owner and Name" Attribute="OwnerDisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] </ExclusiveChoice>[CRLF] <Separator Name="Separator" />[CRLF] <StandardAttribute Name="Comment" Attribute="Comment" Prefix="" Suffix="" Alignment="LEFT" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -Reference.Cardinality=No -Reference.ImplementationType=No -Reference.ChildRole=Yes -Reference.Stereotype=Yes -Reference.DisplayName=No -Reference.ForeignKeyConstraintName=No -Reference.JoinExpression=No -Reference.Integrity=No -Reference.ParentRole=Yes -Reference_SymbolLayout=<Form>[CRLF] <Form Name="Source" >[CRLF] <StandardAttribute Name="Cardinality" Attribute="Cardinality" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Implementation" Attribute="ImplementationType" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Child Role" Attribute="ChildRole" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] </Form>[CRLF] <Form Name="Center" >[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Caption="" Mandatory="No" />[CRLF] <ExclusiveChoice Name="Exclusive Choice" Mandatory="No" Display="HorizontalRadios" >[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Cons&amp;traint Name" Attribute="ForeignKeyConstraintName" Prefix="" Suffix="" Caption="Cons&amp;traint Name" Mandatory="No" />[CRLF] <StandardAttribute Name="Join" Attribute="JoinExpression" Prefix="" Suffix="" Caption="Join" Mandatory="No" />[CRLF] </ExclusiveChoice>[CRLF] <StandardAttribute Name="Referential integrity" Attribute="Integrity" Prefix="" Suffix="" Caption="Referential integrity" Mandatory="No" />[CRLF] </Form>[CRLF] <Form Name="Destination" >[CRLF] <StandardAttribute Name="Parent Role" Attribute="ParentRole" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] </Form>[CRLF]</Form> -ViewReference.ChildRole=Yes -ViewReference.Stereotype=Yes -ViewReference.DisplayName=No -ViewReference.JoinExpression=No -ViewReference.ParentRole=Yes -ViewReference_SymbolLayout=<Form>[CRLF] <Form Name="Source" >[CRLF] <StandardAttribute Name="Child Role" Attribute="ChildRole" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] </Form>[CRLF] <Form Name="Center" >[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Caption="" Mandatory="No" />[CRLF] <ExclusiveChoice Name="Exclusive Choice" Mandatory="No" Display="HorizontalRadios" >[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Join Expression" Attribute="JoinExpression" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] </ExclusiveChoice>[CRLF] </Form>[CRLF] <Form Name="Destination" >[CRLF] <StandardAttribute Name="Parent Role" Attribute="ParentRole" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] </Form>[CRLF]</Form> - -[DisplayPreferences\Symbol] - -[DisplayPreferences\Symbol\AREA] -STRNFont=新宋体,8,N -STRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -LABLFont=新宋体,8,N -LABLFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=9600 -Height=8000 -Brush color=253 249 234 -Fill Color=Yes -Brush style=6 -Brush bitmap mode=12 -Brush gradient mode=16 -Brush gradient color=245 230 173 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 121 98 6 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\FRMEOBJ] -STRNFont=新宋体,8,N -STRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -LABLFont=新宋体,8,N -LABLFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=6000 -Height=2000 -Brush color=255 255 255 -Fill Color=Yes -Brush style=6 -Brush bitmap mode=12 -Brush gradient mode=64 -Brush gradient color=192 192 192 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 255 128 128 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\FRMELNK] -CENTERFont=新宋体,8,N -CENTERFont color=0 0 0 -Line style=1 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Brush color=255 255 255 -Fill Color=Yes -Brush style=1 -Brush bitmap mode=12 -Brush gradient mode=0 -Brush gradient color=118 118 118 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 128 128 255 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\USRDEPD] -CENTERFont=新宋体,8,N -CENTERFont color=0 0 0 -Line style=1 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Brush color=255 255 255 -Fill Color=Yes -Brush style=1 -Brush bitmap mode=12 -Brush gradient mode=0 -Brush gradient color=118 118 118 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=2 0 128 128 255 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\FILO] -OBJSTRNFont=新宋体,8,N -OBJSTRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -LCNMFont=新宋体,8,N -LCNMFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=4800 -Height=3600 -Brush color=255 255 255 -Fill Color=Yes -Brush style=1 -Brush bitmap mode=12 -Brush gradient mode=0 -Brush gradient color=118 118 118 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 0 0 255 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\PDMPCKG] -STRNFont=新宋体,8,N -STRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -LABLFont=新宋体,8,N -LABLFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=4800 -Height=4000 -Brush color=255 255 192 -Fill Color=Yes -Brush style=6 -Brush bitmap mode=12 -Brush gradient mode=65 -Brush gradient color=255 255 255 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 178 178 178 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\TABL] -STRNFont=新宋体,8,N -STRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -OWNRDISPNAMEFont=新宋体,8,N -OWNRDISPNAMEFont color=0 0 0 -ColumnsFont=新宋体,8,N -ColumnsFont color=0 0 0 -TablePkColumnsFont=新宋体,8,U -TablePkColumnsFont color=0 0 0 -TableFkColumnsFont=新宋体,8,N -TableFkColumnsFont color=0 0 0 -KeysFont=新宋体,8,N -KeysFont color=0 0 0 -IndexesFont=新宋体,8,N -IndexesFont color=0 0 0 -TriggersFont=新宋体,8,N -TriggersFont color=0 0 0 -LABLFont=新宋体,8,N -LABLFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=4800 -Height=4000 -Brush color=178 214 252 -Fill Color=Yes -Brush style=6 -Brush bitmap mode=12 -Brush gradient mode=65 -Brush gradient color=255 255 255 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 0 128 192 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\VIEW] -STRNFont=新宋体,8,N -STRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -OWNRDISPNAMEFont=新宋体,8,N -OWNRDISPNAMEFont color=0 0 0 -ColumnsFont=新宋体,8,N -ColumnsFont color=0 0 0 -TablePkColumnsFont=新宋体,8,U -TablePkColumnsFont color=0 0 0 -TableFkColumnsFont=新宋体,8,N -TableFkColumnsFont color=0 0 0 -TemporaryVTablesFont=新宋体,8,N -TemporaryVTablesFont color=0 0 0 -IndexesFont=新宋体,8,N -IndexesFont color=0 0 0 -LABLFont=新宋体,8,N -LABLFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=4800 -Height=4000 -Brush color=208 208 255 -Fill Color=Yes -Brush style=6 -Brush bitmap mode=12 -Brush gradient mode=65 -Brush gradient color=255 255 255 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 128 128 192 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\PROC] -STRNFont=新宋体,8,N -STRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -OWNRDISPNAMEFont=新宋体,8,N -OWNRDISPNAMEFont color=0 0 0 -LABLFont=新宋体,8,N -LABLFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=4000 -Height=1000 -Brush color=255 255 192 -Fill Color=Yes -Brush style=6 -Brush bitmap mode=12 -Brush gradient mode=65 -Brush gradient color=255 255 255 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 128 108 0 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\REFR] -SOURCEFont=新宋体,8,N -SOURCEFont color=0 0 0 -CENTERFont=新宋体,8,N -CENTERFont color=0 0 0 -DESTINATIONFont=新宋体,8,N -DESTINATIONFont color=0 0 0 -Line style=1 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Brush color=255 255 255 -Fill Color=Yes -Brush style=1 -Brush bitmap mode=12 -Brush gradient mode=0 -Brush gradient color=118 118 118 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 0 128 192 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\VREF] -SOURCEFont=新宋体,8,N -SOURCEFont color=0 0 0 -CENTERFont=新宋体,8,N -CENTERFont color=0 0 0 -DESTINATIONFont=新宋体,8,N -DESTINATIONFont color=0 0 0 -Line style=1 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Brush color=255 255 255 -Fill Color=Yes -Brush style=1 -Brush bitmap mode=12 -Brush gradient mode=0 -Brush gradient color=118 118 118 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 128 128 192 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\Free Symbol] -Free TextFont=新宋体,8,N -Free TextFont color=0 0 0 -Line style=0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Brush color=255 255 255 -Fill Color=Yes -Brush style=1 -Brush bitmap mode=12 -Brush gradient mode=0 -Brush gradient color=118 118 118 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 0 0 255 -Shadow color=192 192 192 -Shadow=0 -(8268, 11693) -((315,354), (433,354)) -1 -15 - - -1629975622 -1630311342 --1 -((-7982,10396), (11754,18244)) -0 -12615680 -16570034 -12632256 -STRN 0 新宋体,8,N -DISPNAME 0 新宋体,8,N -OWNRDISPNAME 0 新宋体,8,N -Columns 0 新宋体,8,N -TablePkColumns 0 新宋体,8,U -TableFkColumns 0 新宋体,8,N -Keys 0 新宋体,8,N -Indexes 0 新宋体,8,N -Triggers 0 新宋体,8,N -LABL 0 新宋体,8,N -6 -65 -16777215 -1 - - - - - - - - - - - - -949A22D1-AB0B-4C02-820B-205FBF277B88 -操作日志( OperationLog ) -OperationLog -1629975622 -Xiadao -1630311339 -Xiadao -操作日志 - - - -C8213067-897B-474A-AFD2-9F0A1600A3A2 -操作标识( LogId ) -LogId -1629975622 -Xiadao -1632131121 -Xiadao -操作标识 -bigint -1 -1 - - -E89DAF52-EBB1-44DB-AA5A-C8073BB431A4 -日志名称( LogName ) -LogName -1629975622 -Xiadao -1630311265 -Xiadao -日志名称 -nvarchar(50) -50 -1 - - -4800B877-CF81-40F2-B59C-C55FFF19E93A -操作时间( OperationTime ) -OperationTime -1629975622 -Xiadao -1630311280 -Xiadao -操作时间 -datetime - - -9E39A0DE-079C-4551-9A28-C59EC2F333C0 -标题( Caption ) -Caption -1629975622 -Xiadao -1629975622 -Xiadao -标题 -nvarchar(200) -200 - - -5B4B72EA-85F3-460F-9C1A-9E8B1DB9E30C -内容( Content ) -Content -1629975622 -Xiadao -1629975622 -Xiadao -内容 -nvarchar(MAX) - - -6FDCFFAE-E6A4-4BF8-B5C0-BFBAB701123D -版本号( Version ) -Version -1629975622 -Xiadao -1629975622 -Xiadao -版本号 -timestamp - - - - -582657C8-71B5-4F31-B217-003C571715CB -Key_1 -Key_1 -1629975622 -Xiadao -1629975622 -Xiadao - - - - - - - -638A3E2A-3249-48D9-B9A7-2F187B061389 -cls_idx_operationtime -cls_idx_operationtime -1629975622 -Xiadao -1629975892 -Xiadao - - -5C29C73F-8823-419C-851E-07105BA3DECD -1629975622 -Xiadao -1629975622 -Xiadao - - - - - - - - - - - - - - - - - - - - - - - - - - -42F88B7C-14FB-49BA-90CD-C8D1EB1ADAE1 -03 - 商品 -03 - 商品 -1630573249 -Xiadao -1633533744 -Xiadao - - -87C3BEB1-BEE0-4859-B685-17CFFF11B062 -02 - 产品 -02 - 产品 -1630573249 -Xiadao -1633533744 -Xiadao -[DisplayPreferences] - -[DisplayPreferences\PDM] - -[DisplayPreferences\General] -Adjust to text=Yes -Snap Grid=No -Constrain Labels=Yes -Display Grid=No -Show Page Delimiter=Yes -Show Links intersections=Yes -Activate automatic link routing=Yes -Grid size=800 -Graphic unit=2 -Window color=255 255 255 -Background image= -Background mode=8 -Watermark image= -Watermark mode=8 -Show watermark on screen=No -Gradient mode=0 -Gradient end color=255 255 255 -Show Swimlane=No -SwimlaneVert=Yes -TreeVert=No -CompDark=0 - -[DisplayPreferences\Object] -Show Icon=No -Mode=2 -Trunc Length=40 -Word Length=40 -Word Text=!"#$%&')*+,-./:;=>?@\]^_`|}~ -Shortcut IntIcon=Yes -Shortcut IntLoct=Yes -Shortcut IntFullPath=No -Shortcut IntLastPackage=Yes -Shortcut ExtIcon=Yes -Shortcut ExtLoct=No -Shortcut ExtFullPath=No -Shortcut ExtLastPackage=Yes -Shortcut ExtIncludeModl=Yes -Area.IconPicture=Yes -Area.Stereotype=Yes -Area.Comment=No -Area.TextStyle=No -Area.SubSymbols=Yes -Area_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Architecture Area Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <Separator Name="Separator" />[CRLF] <StandardAttribute Name="Comment" Attribute="Comment" Prefix="" Suffix="" Alignment="LEFT" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -EObjShowStrn=Yes -ExtendedObject.Comment=No -ExtendedObject.IconPicture=No -ExtendedObject.TextStyle=No -ExtendedObject_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Object Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <Separator Name="Separator" />[CRLF] <StandardAttribute Name="Comment" Attribute="Comment" Prefix="" Suffix="" Alignment="LEFT" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -ELnkShowStrn=Yes -ELnkShowName=Yes -ExtendedLink_SymbolLayout=<Form>[CRLF] <Form Name="Center" >[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] </Form>[CRLF] <Form Name="Source" >[CRLF] </Form>[CRLF] <Form Name="Destination" >[CRLF] </Form>[CRLF]</Form> -ExtDpdShowStrn=Yes -ExtendedDependency_SymbolLayout=<Form>[CRLF] <Form Name="Center" >[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Caption="" Mandatory="No" />[CRLF] </Form>[CRLF] <Form Name="Source" >[CRLF] </Form>[CRLF] <Form Name="Destination" >[CRLF] </Form>[CRLF]</Form> -FileObject.Stereotype=No -FileObject.DisplayName=Yes -FileObject.LocationOrName=No -FileObject.IconPicture=No -FileObject.TextStyle=No -FileObject.IconMode=Yes -FileObject_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <ExclusiveChoice Name="Exclusive Choice" Mandatory="Yes" Display="HorizontalRadios" >[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Location" Attribute="LocationOrName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] </ExclusiveChoice>[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -Package.Stereotype=Yes -Package.Comment=No -Package.IconPicture=No -Package.TextStyle=No -Package_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <Separator Name="Separator" />[CRLF] <StandardAttribute Name="Comment" Attribute="Comment" Prefix="" Suffix="" Alignment="LEFT" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -Display Model Version=Yes -Table.Stereotype=Yes -Table.DisplayName=Yes -Table.OwnerDisplayName=No -Table.Columns=Yes -Table.Columns._Filter="All Columns" PDMCOLNALL -Table.Columns._Columns=Stereotype DataType KeyIndicator -Table.Columns._Limit=-5 -Table.Keys=No -Table.Keys._Columns=Stereotype Indicator -Table.Indexes=No -Table.Indexes._Columns=Stereotype -Table.Triggers=No -Table.Triggers._Columns=Stereotype -Table.Comment=No -Table.IconPicture=No -Table.TextStyle=No -Table_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <ExclusiveChoice Name="Exclusive Choice" Mandatory="Yes" Display="HorizontalRadios" >[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Owner and Name" Attribute="OwnerDisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] </ExclusiveChoice>[CRLF] <Separator Name="Separator" />[CRLF] <StandardCollection Name="Columns" Collection="Columns" Columns="Stereotype No\r\nDisplayName Yes\r\nDataType No\r\nSymbolDataType No &quot;Domain or Data type&quot;\r\nDomain No\r\nKeyIndicator No\r\nIndexIndicator No\r\nNullStatus No" Filters="&quot;All Columns&quot; PDMCOLNALL &quot;&quot;\r\n&quot;PK Columns&quot; PDMCOLNPK &quot;\&quot;PRIM \&quot;TRUE\&quot; TRUE\&quot;&quot;\r\n&quot;Key Columns&quot; PDMCOLNKEY &quot;\&quot;KEYS \&quot;TRUE\&quot; TRUE\&quot;&quot;" HasLimit="Yes" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardCollection Name="Keys" Collection="Keys" Columns="Stereotype No\r\nDisplayName Yes\r\nIndicator No" HasLimit="No" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardCollection Name="Indexes" Collection="Indexes" Columns="Stereotype No\r\nDisplayName Yes\r\nIndicator No" HasLimit="No" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardCollection Name="Triggers" Collection="Triggers" Columns="Stereotype No\r\nDisplayName Yes" HasLimit="No" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Comment" Attribute="Comment" Prefix="" Suffix="" Alignment="LEFT" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -View.Stereotype=Yes -View.DisplayName=Yes -View.OwnerDisplayName=No -View.Columns=Yes -View.Columns._Columns=DisplayName -View.Columns._Limit=-5 -View.TemporaryVTables=Yes -View.Indexes=No -View.Comment=No -View.IconPicture=No -View.TextStyle=No -View_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <ExclusiveChoice Name="Exclusive Choice" Mandatory="Yes" Display="HorizontalRadios" >[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Owner and Name" Attribute="OwnerDisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] </ExclusiveChoice>[CRLF] <Separator Name="Separator" />[CRLF] <StandardCollection Name="Columns" Collection="Columns" Columns="DisplayName No\r\nExpression No\r\nDataType No\r\nSymbolDataType No &quot;Domain or Data type&quot;\r\nIndexIndicator No" HasLimit="Yes" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardCollection Name="Tables" Collection="TemporaryVTables" Columns="Name Yes" HasLimit="No" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardCollection Name="Indexes" Collection="Indexes" Columns="DisplayName Yes" HasLimit="No" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Comment" Attribute="Comment" Prefix="" Suffix="" Alignment="LEFT" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -Procedure.Stereotype=No -Procedure.DisplayName=Yes -Procedure.OwnerDisplayName=No -Procedure.Comment=No -Procedure.IconPicture=No -Procedure.TextStyle=No -Procedure_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <ExclusiveChoice Name="Exclusive Choice" Mandatory="Yes" Display="HorizontalRadios" >[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Owner and Name" Attribute="OwnerDisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] </ExclusiveChoice>[CRLF] <Separator Name="Separator" />[CRLF] <StandardAttribute Name="Comment" Attribute="Comment" Prefix="" Suffix="" Alignment="LEFT" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -Reference.Cardinality=No -Reference.ImplementationType=No -Reference.ChildRole=Yes -Reference.Stereotype=Yes -Reference.DisplayName=No -Reference.ForeignKeyConstraintName=No -Reference.JoinExpression=No -Reference.Integrity=No -Reference.ParentRole=Yes -Reference_SymbolLayout=<Form>[CRLF] <Form Name="Source" >[CRLF] <StandardAttribute Name="Cardinality" Attribute="Cardinality" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Implementation" Attribute="ImplementationType" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Child Role" Attribute="ChildRole" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] </Form>[CRLF] <Form Name="Center" >[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Caption="" Mandatory="No" />[CRLF] <ExclusiveChoice Name="Exclusive Choice" Mandatory="No" Display="HorizontalRadios" >[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Cons&amp;traint Name" Attribute="ForeignKeyConstraintName" Prefix="" Suffix="" Caption="Cons&amp;traint Name" Mandatory="No" />[CRLF] <StandardAttribute Name="Join" Attribute="JoinExpression" Prefix="" Suffix="" Caption="Join" Mandatory="No" />[CRLF] </ExclusiveChoice>[CRLF] <StandardAttribute Name="Referential integrity" Attribute="Integrity" Prefix="" Suffix="" Caption="Referential integrity" Mandatory="No" />[CRLF] </Form>[CRLF] <Form Name="Destination" >[CRLF] <StandardAttribute Name="Parent Role" Attribute="ParentRole" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] </Form>[CRLF]</Form> -ViewReference.ChildRole=Yes -ViewReference.Stereotype=Yes -ViewReference.DisplayName=No -ViewReference.JoinExpression=No -ViewReference.ParentRole=Yes -ViewReference_SymbolLayout=<Form>[CRLF] <Form Name="Source" >[CRLF] <StandardAttribute Name="Child Role" Attribute="ChildRole" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] </Form>[CRLF] <Form Name="Center" >[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Caption="" Mandatory="No" />[CRLF] <ExclusiveChoice Name="Exclusive Choice" Mandatory="No" Display="HorizontalRadios" >[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Join Expression" Attribute="JoinExpression" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] </ExclusiveChoice>[CRLF] </Form>[CRLF] <Form Name="Destination" >[CRLF] <StandardAttribute Name="Parent Role" Attribute="ParentRole" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] </Form>[CRLF]</Form> - -[DisplayPreferences\Symbol] - -[DisplayPreferences\Symbol\AREA] -STRNFont=新宋体,8,N -STRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -LABLFont=新宋体,8,N -LABLFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=9600 -Height=8000 -Brush color=253 249 234 -Fill Color=Yes -Brush style=6 -Brush bitmap mode=12 -Brush gradient mode=16 -Brush gradient color=245 230 173 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 121 98 6 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\FRMEOBJ] -STRNFont=新宋体,8,N -STRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -LABLFont=新宋体,8,N -LABLFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=6000 -Height=2000 -Brush color=255 255 255 -Fill Color=Yes -Brush style=6 -Brush bitmap mode=12 -Brush gradient mode=64 -Brush gradient color=192 192 192 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 255 128 128 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\FRMELNK] -CENTERFont=新宋体,8,N -CENTERFont color=0 0 0 -Line style=1 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Brush color=255 255 255 -Fill Color=Yes -Brush style=1 -Brush bitmap mode=12 -Brush gradient mode=0 -Brush gradient color=118 118 118 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 128 128 255 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\USRDEPD] -CENTERFont=新宋体,8,N -CENTERFont color=0 0 0 -Line style=1 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Brush color=255 255 255 -Fill Color=Yes -Brush style=1 -Brush bitmap mode=12 -Brush gradient mode=0 -Brush gradient color=118 118 118 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=2 0 128 128 255 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\FILO] -OBJSTRNFont=新宋体,8,N -OBJSTRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -LCNMFont=新宋体,8,N -LCNMFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=4800 -Height=3600 -Brush color=255 255 255 -Fill Color=Yes -Brush style=1 -Brush bitmap mode=12 -Brush gradient mode=0 -Brush gradient color=118 118 118 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 0 0 255 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\PDMPCKG] -STRNFont=新宋体,8,N -STRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -LABLFont=新宋体,8,N -LABLFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=4800 -Height=4000 -Brush color=255 255 192 -Fill Color=Yes -Brush style=6 -Brush bitmap mode=12 -Brush gradient mode=65 -Brush gradient color=255 255 255 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 178 178 178 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\TABL] -STRNFont=新宋体,8,N -STRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -OWNRDISPNAMEFont=新宋体,8,N -OWNRDISPNAMEFont color=0 0 0 -ColumnsFont=新宋体,8,N -ColumnsFont color=0 0 0 -TablePkColumnsFont=新宋体,8,U -TablePkColumnsFont color=0 0 0 -TableFkColumnsFont=新宋体,8,N -TableFkColumnsFont color=0 0 0 -KeysFont=新宋体,8,N -KeysFont color=0 0 0 -IndexesFont=新宋体,8,N -IndexesFont color=0 0 0 -TriggersFont=新宋体,8,N -TriggersFont color=0 0 0 -LABLFont=新宋体,8,N -LABLFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=4800 -Height=4000 -Brush color=178 214 252 -Fill Color=Yes -Brush style=6 -Brush bitmap mode=12 -Brush gradient mode=65 -Brush gradient color=255 255 255 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 0 128 192 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\VIEW] -STRNFont=新宋体,8,N -STRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -OWNRDISPNAMEFont=新宋体,8,N -OWNRDISPNAMEFont color=0 0 0 -ColumnsFont=新宋体,8,N -ColumnsFont color=0 0 0 -TablePkColumnsFont=新宋体,8,U -TablePkColumnsFont color=0 0 0 -TableFkColumnsFont=新宋体,8,N -TableFkColumnsFont color=0 0 0 -TemporaryVTablesFont=新宋体,8,N -TemporaryVTablesFont color=0 0 0 -IndexesFont=新宋体,8,N -IndexesFont color=0 0 0 -LABLFont=新宋体,8,N -LABLFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=4800 -Height=4000 -Brush color=208 208 255 -Fill Color=Yes -Brush style=6 -Brush bitmap mode=12 -Brush gradient mode=65 -Brush gradient color=255 255 255 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 128 128 192 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\PROC] -STRNFont=新宋体,8,N -STRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -OWNRDISPNAMEFont=新宋体,8,N -OWNRDISPNAMEFont color=0 0 0 -LABLFont=新宋体,8,N -LABLFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=4000 -Height=1000 -Brush color=255 255 192 -Fill Color=Yes -Brush style=6 -Brush bitmap mode=12 -Brush gradient mode=65 -Brush gradient color=255 255 255 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 128 108 0 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\REFR] -SOURCEFont=新宋体,8,N -SOURCEFont color=0 0 0 -CENTERFont=新宋体,8,N -CENTERFont color=0 0 0 -DESTINATIONFont=新宋体,8,N -DESTINATIONFont color=0 0 0 -Line style=1 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Brush color=255 255 255 -Fill Color=Yes -Brush style=1 -Brush bitmap mode=12 -Brush gradient mode=0 -Brush gradient color=118 118 118 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 0 128 192 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\VREF] -SOURCEFont=新宋体,8,N -SOURCEFont color=0 0 0 -CENTERFont=新宋体,8,N -CENTERFont color=0 0 0 -DESTINATIONFont=新宋体,8,N -DESTINATIONFont color=0 0 0 -Line style=1 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Brush color=255 255 255 -Fill Color=Yes -Brush style=1 -Brush bitmap mode=12 -Brush gradient mode=0 -Brush gradient color=118 118 118 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 128 128 192 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\Free Symbol] -Free TextFont=新宋体,8,N -Free TextFont color=0 0 0 -Line style=0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Brush color=255 255 255 -Fill Color=Yes -Brush style=1 -Brush bitmap mode=12 -Brush gradient mode=0 -Brush gradient color=118 118 118 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 0 0 255 -Shadow color=192 192 192 -Shadow=0 -(8268, 11693) -((315,354), (433,354)) -1 -15 - - -1633533744 -1633533744 -((-837,16780), (413,21922)) -((-212,17180),(-212,21522)) -1 -1 -12615680 -12632256 -CENTER 0 新宋体,8,N -SOURCE 0 新宋体,8,N -DESTINATION 0 新宋体,8,N - - - - - - - - - - - -1630573318 -1633533747 --1 -((-13007,3856), (13007,17180)) -0 -12615680 -16570034 -12632256 -STRN 0 新宋体,8,N -DISPNAME 0 新宋体,8,N -OWNRDISPNAME 0 新宋体,8,N -Columns 0 新宋体,8,N -TablePkColumns 0 新宋体,8,U -TableFkColumns 0 新宋体,8,N -Keys 0 新宋体,8,N -Indexes 0 新宋体,8,N -Triggers 0 新宋体,8,N -LABL 0 新宋体,8,N -6 -65 -16777215 -1 - - - - - -1633533736 -1633533739 --1 -((-12920,21522), (12496,35554)) -0 -12615680 -16570034 -12632256 -STRN 0 新宋体,8,N -DISPNAME 0 新宋体,8,N -OWNRDISPNAME 0 新宋体,8,N -Columns 0 新宋体,8,N -TablePkColumns 0 新宋体,8,U -TableFkColumns 0 新宋体,8,N -Keys 0 新宋体,8,N -Indexes 0 新宋体,8,N -Triggers 0 新宋体,8,N -LABL 0 新宋体,8,N -6 -65 -16777215 -1 - - - - - - - -C398C3C5-829A-40BE-95F9-939CE009E188 -01 - 商品分类 -01 - 商品分类 -1633532812 -Xiadao -1633533722 -Xiadao -[DisplayPreferences] - -[DisplayPreferences\PDM] - -[DisplayPreferences\General] -Adjust to text=Yes -Snap Grid=No -Constrain Labels=Yes -Display Grid=No -Show Page Delimiter=Yes -Show Links intersections=Yes -Activate automatic link routing=Yes -Grid size=800 -Graphic unit=2 -Window color=255 255 255 -Background image= -Background mode=8 -Watermark image= -Watermark mode=8 -Show watermark on screen=No -Gradient mode=0 -Gradient end color=255 255 255 -Show Swimlane=No -SwimlaneVert=Yes -TreeVert=No -CompDark=0 - -[DisplayPreferences\Object] -Show Icon=No -Mode=2 -Trunc Length=40 -Word Length=40 -Word Text=!"#$%&')*+,-./:;=>?@\]^_`|}~ -Shortcut IntIcon=Yes -Shortcut IntLoct=Yes -Shortcut IntFullPath=No -Shortcut IntLastPackage=Yes -Shortcut ExtIcon=Yes -Shortcut ExtLoct=No -Shortcut ExtFullPath=No -Shortcut ExtLastPackage=Yes -Shortcut ExtIncludeModl=Yes -Area.IconPicture=Yes -Area.Stereotype=Yes -Area.Comment=No -Area.TextStyle=No -Area.SubSymbols=Yes -Area_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Architecture Area Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <Separator Name="Separator" />[CRLF] <StandardAttribute Name="Comment" Attribute="Comment" Prefix="" Suffix="" Alignment="LEFT" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -EObjShowStrn=Yes -ExtendedObject.Comment=No -ExtendedObject.IconPicture=No -ExtendedObject.TextStyle=No -ExtendedObject_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Object Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <Separator Name="Separator" />[CRLF] <StandardAttribute Name="Comment" Attribute="Comment" Prefix="" Suffix="" Alignment="LEFT" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -ELnkShowStrn=Yes -ELnkShowName=Yes -ExtendedLink_SymbolLayout=<Form>[CRLF] <Form Name="Center" >[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] </Form>[CRLF] <Form Name="Source" >[CRLF] </Form>[CRLF] <Form Name="Destination" >[CRLF] </Form>[CRLF]</Form> -ExtDpdShowStrn=Yes -ExtendedDependency_SymbolLayout=<Form>[CRLF] <Form Name="Center" >[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Caption="" Mandatory="No" />[CRLF] </Form>[CRLF] <Form Name="Source" >[CRLF] </Form>[CRLF] <Form Name="Destination" >[CRLF] </Form>[CRLF]</Form> -FileObject.Stereotype=No -FileObject.DisplayName=Yes -FileObject.LocationOrName=No -FileObject.IconPicture=No -FileObject.TextStyle=No -FileObject.IconMode=Yes -FileObject_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <ExclusiveChoice Name="Exclusive Choice" Mandatory="Yes" Display="HorizontalRadios" >[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Location" Attribute="LocationOrName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] </ExclusiveChoice>[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -Package.Stereotype=Yes -Package.Comment=No -Package.IconPicture=No -Package.TextStyle=No -Package_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <Separator Name="Separator" />[CRLF] <StandardAttribute Name="Comment" Attribute="Comment" Prefix="" Suffix="" Alignment="LEFT" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -Display Model Version=Yes -Table.Stereotype=Yes -Table.DisplayName=Yes -Table.OwnerDisplayName=No -Table.Columns=Yes -Table.Columns._Filter="All Columns" PDMCOLNALL -Table.Columns._Columns=Stereotype DataType KeyIndicator -Table.Columns._Limit=-5 -Table.Keys=No -Table.Keys._Columns=Stereotype Indicator -Table.Indexes=No -Table.Indexes._Columns=Stereotype -Table.Triggers=No -Table.Triggers._Columns=Stereotype -Table.Comment=No -Table.IconPicture=No -Table.TextStyle=No -Table_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <ExclusiveChoice Name="Exclusive Choice" Mandatory="Yes" Display="HorizontalRadios" >[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Owner and Name" Attribute="OwnerDisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] </ExclusiveChoice>[CRLF] <Separator Name="Separator" />[CRLF] <StandardCollection Name="Columns" Collection="Columns" Columns="Stereotype No\r\nDisplayName Yes\r\nDataType No\r\nSymbolDataType No &quot;Domain or Data type&quot;\r\nDomain No\r\nKeyIndicator No\r\nIndexIndicator No\r\nNullStatus No" Filters="&quot;All Columns&quot; PDMCOLNALL &quot;&quot;\r\n&quot;PK Columns&quot; PDMCOLNPK &quot;\&quot;PRIM \&quot;TRUE\&quot; TRUE\&quot;&quot;\r\n&quot;Key Columns&quot; PDMCOLNKEY &quot;\&quot;KEYS \&quot;TRUE\&quot; TRUE\&quot;&quot;" HasLimit="Yes" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardCollection Name="Keys" Collection="Keys" Columns="Stereotype No\r\nDisplayName Yes\r\nIndicator No" HasLimit="No" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardCollection Name="Indexes" Collection="Indexes" Columns="Stereotype No\r\nDisplayName Yes\r\nIndicator No" HasLimit="No" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardCollection Name="Triggers" Collection="Triggers" Columns="Stereotype No\r\nDisplayName Yes" HasLimit="No" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Comment" Attribute="Comment" Prefix="" Suffix="" Alignment="LEFT" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -View.Stereotype=Yes -View.DisplayName=Yes -View.OwnerDisplayName=No -View.Columns=Yes -View.Columns._Columns=DisplayName -View.Columns._Limit=-5 -View.TemporaryVTables=Yes -View.Indexes=No -View.Comment=No -View.IconPicture=No -View.TextStyle=No -View_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <ExclusiveChoice Name="Exclusive Choice" Mandatory="Yes" Display="HorizontalRadios" >[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Owner and Name" Attribute="OwnerDisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] </ExclusiveChoice>[CRLF] <Separator Name="Separator" />[CRLF] <StandardCollection Name="Columns" Collection="Columns" Columns="DisplayName No\r\nExpression No\r\nDataType No\r\nSymbolDataType No &quot;Domain or Data type&quot;\r\nIndexIndicator No" HasLimit="Yes" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardCollection Name="Tables" Collection="TemporaryVTables" Columns="Name Yes" HasLimit="No" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardCollection Name="Indexes" Collection="Indexes" Columns="DisplayName Yes" HasLimit="No" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Comment" Attribute="Comment" Prefix="" Suffix="" Alignment="LEFT" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -Procedure.Stereotype=No -Procedure.DisplayName=Yes -Procedure.OwnerDisplayName=No -Procedure.Comment=No -Procedure.IconPicture=No -Procedure.TextStyle=No -Procedure_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <ExclusiveChoice Name="Exclusive Choice" Mandatory="Yes" Display="HorizontalRadios" >[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Owner and Name" Attribute="OwnerDisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] </ExclusiveChoice>[CRLF] <Separator Name="Separator" />[CRLF] <StandardAttribute Name="Comment" Attribute="Comment" Prefix="" Suffix="" Alignment="LEFT" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -Reference.Cardinality=No -Reference.ImplementationType=No -Reference.ChildRole=Yes -Reference.Stereotype=Yes -Reference.DisplayName=No -Reference.ForeignKeyConstraintName=No -Reference.JoinExpression=No -Reference.Integrity=No -Reference.ParentRole=Yes -Reference_SymbolLayout=<Form>[CRLF] <Form Name="Source" >[CRLF] <StandardAttribute Name="Cardinality" Attribute="Cardinality" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Implementation" Attribute="ImplementationType" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Child Role" Attribute="ChildRole" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] </Form>[CRLF] <Form Name="Center" >[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Caption="" Mandatory="No" />[CRLF] <ExclusiveChoice Name="Exclusive Choice" Mandatory="No" Display="HorizontalRadios" >[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Cons&amp;traint Name" Attribute="ForeignKeyConstraintName" Prefix="" Suffix="" Caption="Cons&amp;traint Name" Mandatory="No" />[CRLF] <StandardAttribute Name="Join" Attribute="JoinExpression" Prefix="" Suffix="" Caption="Join" Mandatory="No" />[CRLF] </ExclusiveChoice>[CRLF] <StandardAttribute Name="Referential integrity" Attribute="Integrity" Prefix="" Suffix="" Caption="Referential integrity" Mandatory="No" />[CRLF] </Form>[CRLF] <Form Name="Destination" >[CRLF] <StandardAttribute Name="Parent Role" Attribute="ParentRole" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] </Form>[CRLF]</Form> -ViewReference.ChildRole=Yes -ViewReference.Stereotype=Yes -ViewReference.DisplayName=No -ViewReference.JoinExpression=No -ViewReference.ParentRole=Yes -ViewReference_SymbolLayout=<Form>[CRLF] <Form Name="Source" >[CRLF] <StandardAttribute Name="Child Role" Attribute="ChildRole" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] </Form>[CRLF] <Form Name="Center" >[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Caption="" Mandatory="No" />[CRLF] <ExclusiveChoice Name="Exclusive Choice" Mandatory="No" Display="HorizontalRadios" >[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Join Expression" Attribute="JoinExpression" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] </ExclusiveChoice>[CRLF] </Form>[CRLF] <Form Name="Destination" >[CRLF] <StandardAttribute Name="Parent Role" Attribute="ParentRole" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] </Form>[CRLF]</Form> - -[DisplayPreferences\Symbol] - -[DisplayPreferences\Symbol\AREA] -STRNFont=新宋体,8,N -STRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -LABLFont=新宋体,8,N -LABLFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=9600 -Height=8000 -Brush color=253 249 234 -Fill Color=Yes -Brush style=6 -Brush bitmap mode=12 -Brush gradient mode=16 -Brush gradient color=245 230 173 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 121 98 6 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\FRMEOBJ] -STRNFont=新宋体,8,N -STRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -LABLFont=新宋体,8,N -LABLFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=6000 -Height=2000 -Brush color=255 255 255 -Fill Color=Yes -Brush style=6 -Brush bitmap mode=12 -Brush gradient mode=64 -Brush gradient color=192 192 192 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 255 128 128 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\FRMELNK] -CENTERFont=新宋体,8,N -CENTERFont color=0 0 0 -Line style=1 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Brush color=255 255 255 -Fill Color=Yes -Brush style=1 -Brush bitmap mode=12 -Brush gradient mode=0 -Brush gradient color=118 118 118 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 128 128 255 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\USRDEPD] -CENTERFont=新宋体,8,N -CENTERFont color=0 0 0 -Line style=1 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Brush color=255 255 255 -Fill Color=Yes -Brush style=1 -Brush bitmap mode=12 -Brush gradient mode=0 -Brush gradient color=118 118 118 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=2 0 128 128 255 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\FILO] -OBJSTRNFont=新宋体,8,N -OBJSTRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -LCNMFont=新宋体,8,N -LCNMFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=4800 -Height=3600 -Brush color=255 255 255 -Fill Color=Yes -Brush style=1 -Brush bitmap mode=12 -Brush gradient mode=0 -Brush gradient color=118 118 118 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 0 0 255 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\PDMPCKG] -STRNFont=新宋体,8,N -STRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -LABLFont=新宋体,8,N -LABLFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=4800 -Height=4000 -Brush color=255 255 192 -Fill Color=Yes -Brush style=6 -Brush bitmap mode=12 -Brush gradient mode=65 -Brush gradient color=255 255 255 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 178 178 178 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\TABL] -STRNFont=新宋体,8,N -STRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -OWNRDISPNAMEFont=新宋体,8,N -OWNRDISPNAMEFont color=0 0 0 -ColumnsFont=新宋体,8,N -ColumnsFont color=0 0 0 -TablePkColumnsFont=新宋体,8,U -TablePkColumnsFont color=0 0 0 -TableFkColumnsFont=新宋体,8,N -TableFkColumnsFont color=0 0 0 -KeysFont=新宋体,8,N -KeysFont color=0 0 0 -IndexesFont=新宋体,8,N -IndexesFont color=0 0 0 -TriggersFont=新宋体,8,N -TriggersFont color=0 0 0 -LABLFont=新宋体,8,N -LABLFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=4800 -Height=4000 -Brush color=178 214 252 -Fill Color=Yes -Brush style=6 -Brush bitmap mode=12 -Brush gradient mode=65 -Brush gradient color=255 255 255 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 0 128 192 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\VIEW] -STRNFont=新宋体,8,N -STRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -OWNRDISPNAMEFont=新宋体,8,N -OWNRDISPNAMEFont color=0 0 0 -ColumnsFont=新宋体,8,N -ColumnsFont color=0 0 0 -TablePkColumnsFont=新宋体,8,U -TablePkColumnsFont color=0 0 0 -TableFkColumnsFont=新宋体,8,N -TableFkColumnsFont color=0 0 0 -TemporaryVTablesFont=新宋体,8,N -TemporaryVTablesFont color=0 0 0 -IndexesFont=新宋体,8,N -IndexesFont color=0 0 0 -LABLFont=新宋体,8,N -LABLFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=4800 -Height=4000 -Brush color=208 208 255 -Fill Color=Yes -Brush style=6 -Brush bitmap mode=12 -Brush gradient mode=65 -Brush gradient color=255 255 255 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 128 128 192 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\PROC] -STRNFont=新宋体,8,N -STRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -OWNRDISPNAMEFont=新宋体,8,N -OWNRDISPNAMEFont color=0 0 0 -LABLFont=新宋体,8,N -LABLFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=4000 -Height=1000 -Brush color=255 255 192 -Fill Color=Yes -Brush style=6 -Brush bitmap mode=12 -Brush gradient mode=65 -Brush gradient color=255 255 255 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 128 108 0 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\REFR] -SOURCEFont=新宋体,8,N -SOURCEFont color=0 0 0 -CENTERFont=新宋体,8,N -CENTERFont color=0 0 0 -DESTINATIONFont=新宋体,8,N -DESTINATIONFont color=0 0 0 -Line style=1 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Brush color=255 255 255 -Fill Color=Yes -Brush style=1 -Brush bitmap mode=12 -Brush gradient mode=0 -Brush gradient color=118 118 118 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 0 128 192 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\VREF] -SOURCEFont=新宋体,8,N -SOURCEFont color=0 0 0 -CENTERFont=新宋体,8,N -CENTERFont color=0 0 0 -DESTINATIONFont=新宋体,8,N -DESTINATIONFont color=0 0 0 -Line style=1 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Brush color=255 255 255 -Fill Color=Yes -Brush style=1 -Brush bitmap mode=12 -Brush gradient mode=0 -Brush gradient color=118 118 118 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 128 128 192 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\Free Symbol] -Free TextFont=新宋体,8,N -Free TextFont color=0 0 0 -Line style=0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Brush color=255 255 255 -Fill Color=Yes -Brush style=1 -Brush bitmap mode=12 -Brush gradient mode=0 -Brush gradient color=118 118 118 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 0 0 255 -Shadow color=192 192 192 -Shadow=0 -(8268, 11693) -((315,354), (433,354)) -1 -15 - - -1633532827 -1633533177 --1 -((-12708,-5713), (12708,8319)) -0 -12615680 -16570034 -12632256 -STRN 0 新宋体,8,N -DISPNAME 0 新宋体,8,N -OWNRDISPNAME 0 新宋体,8,N -Columns 0 新宋体,8,N -TablePkColumns 0 新宋体,8,U -TableFkColumns 0 新宋体,8,N -Keys 0 新宋体,8,N -Indexes 0 新宋体,8,N -Triggers 0 新宋体,8,N -LABL 0 新宋体,8,N -6 -65 -16777215 -1 - - - - - - - - - - - - -2E6FA781-2BB6-4E53-8EE0-A2A7D9DBE25F -产品( Product ) -Product -1630573318 -Xiadao -1633533744 -Xiadao -产品 - - - -0DD9B87E-220F-42B9-B413-36A8A1F4B1EE -产品标识( ProductId ) -ProductId -1630573318 -Xiadao -1632130941 -Xiadao -产品标识 -uniqueidentifier -1 - - -BE7ECC82-51E4-472F-B342-D4CC23017A5E -商品分类标识( CategoryId ) -CategoryId -1633533744 -Xiadao -1633533744 -Xiadao -商品分类标识 -uniqueidentifier -1 - - -5F17AE72-B38B-47B3-9B46-1F84BA2989BA -产品编码( Code ) -Code -1630573318 -Xiadao -1630573457 -Xiadao -产品编码 -nvarchar(50) -50 -1 - - -42290B46-1FB2-4848-A0AC-B2024D188B5A -产品名称( Name ) -Name -1630573318 -Xiadao -1630573451 -Xiadao -产品名称 -nvarchar(500) -500 -1 - - -63B017CF-FF55-4386-ADAC-7FB9456F607B -价格( Price ) -Price -1630574746 -Xiadao -1630575791 -Xiadao -价格 -decimal(12,2) -12 -2 -1 - - -BC9C2BB4-685B-414C-8291-D2E5BBA68B28 -描述( Description ) -Description -1630573318 -Xiadao -1630573318 -Xiadao -描述 -nvarchar(max) - - -13AF1493-B069-43CB-BF04-5DD8B2E18A7F -启用( Enabled ) -Enabled -1630573318 -Xiadao -1630573318 -Xiadao -启用 -bit -1 - - -845EAFE3-41A0-40E6-95C9-8D70C497A413 -创建时间( CreationTime ) -CreationTime -1630573318 -Xiadao -1630573318 -Xiadao -创建时间 -datetime - - -084AE8C8-3B07-4E96-B8A4-32B5B7019A7F -创建人( CreatorId ) -CreatorId -1630573318 -Xiadao -1630573318 -Xiadao -创建人 -uniqueidentifier - - -9762DFFF-C9CD-4E75-90E7-1BAB83A0DBE3 -最后修改时间( LastModificationTime ) -LastModificationTime -1630573318 -Xiadao -1630573318 -Xiadao -最后修改时间 -datetime - - -5CBEDA96-F634-494C-859C-08B453CE7EAE -最后修改人( LastModifierId ) -LastModifierId -1630573318 -Xiadao -1630573318 -Xiadao -最后修改人 -uniqueidentifier - - -F9BCB29D-0D82-4C2F-9CEB-C161DB09575B -是否删除( IsDeleted ) -IsDeleted -1630573318 -Xiadao -1630573318 -Xiadao -是否删除 -bit -1 - - -C9E864FE-4E4F-4F81-9575-65956CDDB38D -版本号( Version ) -Version -1630573318 -Xiadao -1630573318 -Xiadao -版本号 -timestamp - - - - -11966CCA-4A4A-4A22-A805-B1F6B86FD532 -Key_1 -Key_1 -1630573318 -Xiadao -1630573318 -Xiadao - - - - - - - -87EDE0C9-D4D2-497E-81AA-2F02A6665502 -clus_idx_creationtime -clus_idx_creationtime -1630573318 -Xiadao -1630573318 -Xiadao - - -5C2306EF-091F-42C1-A571-5BB4A923DADC -1630573318 -Xiadao -1630573318 -Xiadao - - - - - - - - - - - - - - - - - - - - - -68A8C690-3BAD-4989-A402-6E78036C39DD -商品分类( Category ) -Category -1633532827 -Xiadao -1633533174 -Xiadao -商品分类 - - - -8EDCBA7E-22C9-48D5-B4B6-6C5806A44CAD -商品分类标识( CategoryId ) -CategoryId -1633532827 -Xiadao -1633533086 -Xiadao -商品分类标识 -uniqueidentifier -1 - - -80258690-088B-4A72-A925-9E9D1828DEC2 -商品分类编码( Code ) -Code -1633532827 -Xiadao -1633533106 -Xiadao -商品分类编码 -nvarchar(50) -50 -1 - - -BDC48015-9EC6-474B-BD0E-F9B534283F40 -商品分类名称( Name ) -Name -1633532827 -Xiadao -1633533122 -Xiadao -商品分类名称 -nvarchar(500) -500 -1 - - -6D18CC60-6A06-4F0B-BE91-6E4615AD3A61 -父标识( ParentId ) -ParentId -1633532827 -Xiadao -1633533142 -Xiadao -父标识 -uniqueidentifier - - -73A570E0-37FF-4B5C-9553-50CEB1AAE744 -路径( Path ) -Path -1633532827 -Xiadao -1633532827 -Xiadao -路径 -nvarchar(800) -800 -1 - - -0B42DC52-73C0-4719-A9D6-972BFE5B6B27 -层级( Level ) -Level -1633532827 -Xiadao -1633533156 -Xiadao -层级 -int -1 - - -B248AA93-2559-47C3-9B03-457AD81DBF57 -启用( Enabled ) -Enabled -1633532827 -Xiadao -1633532827 -Xiadao -启用 -bit -1 - - -2620C75C-873F-4693-B100-EA0C48AE487C -排序号 ( SortId ) -SortId -1633532827 -Xiadao -1633532827 -Xiadao -排序号 -int -1 - - -37786EB3-5BCE-44DD-85EB-9BAEFDBF6FDE -创建时间( CreationTime ) -CreationTime -1633532827 -Xiadao -1633532827 -Xiadao -创建时间 -datetime - - -52665D94-4A1F-48AA-806A-798675E955D8 -创建人( CreatorId ) -CreatorId -1633532827 -Xiadao -1633532827 -Xiadao -创建人 -uniqueidentifier - - -D05FFB71-CA2D-47D0-A25F-2E4CAF8931FA -最后修改时间( LastModificationTime ) -LastModificationTime -1633532827 -Xiadao -1633532827 -Xiadao -最后修改时间 -datetime - - -D67FBC03-A2C4-451F-AD75-B2886D351F80 -最后修改人( LastModifierId ) -LastModifierId -1633532827 -Xiadao -1633532827 -Xiadao -最后修改人 -uniqueidentifier - - -DDF20537-59FF-4FF7-A0E4-2F0A816C91FD -是否删除( IsDeleted ) -IsDeleted -1633532827 -Xiadao -1633532827 -Xiadao -是否删除 -bit -1 - - -2AF37E8E-34EE-4CC9-AA3B-060E8B273BB8 -版本号( Version ) -Version -1633532827 -Xiadao -1633532827 -Xiadao -版本号 -timestamp - - - - -2018F823-DCD9-49BE-AC2A-AC1E5FFDC83E -Key_1 -Key_1 -1633532827 -Xiadao -1633532827 -Xiadao - - - - - - - -2CABB6DB-BB9D-436F-BCEE-61F7C68AFBFB -clus_idx_creationtime -clus_idx_creationtime -1633532827 -Xiadao -1633532827 -Xiadao - - -4C99862B-E21E-4365-BE20-174BDDF08D84 -1633532827 -Xiadao -1633532827 -Xiadao - - - - - - - - - - - - - - - - - - - - - - - - - - -1F0AC123-FCDF-4573-824E-3AFF39254A6C -Reference_1 -Reference_1 -1633533744 -Xiadao -1633533744 -Xiadao -0..* - - - - - - - - - - - -C42734EF-BD87-467D-B189-EFECE817845F -1633533744 -Xiadao -1633533744 -Xiadao - - - - - - - - - - - - -8FF613F9-EF5E-4C61-8D3F-AA347DBDEAE9 -04 - 订单 -04 - 订单 -1631776163 -Xiadao -1634469208 -Xiadao - - -A7854049-DB95-46D3-BCC9-EE9A705D71C8 -01 - 订单 -01 - 订单 -1631776163 -Xiadao -1634469208 -Xiadao -[DisplayPreferences] - -[DisplayPreferences\PDM] - -[DisplayPreferences\General] -Adjust to text=Yes -Snap Grid=No -Constrain Labels=Yes -Display Grid=No -Show Page Delimiter=Yes -Show Links intersections=Yes -Activate automatic link routing=Yes -Grid size=800 -Graphic unit=2 -Window color=255 255 255 -Background image= -Background mode=8 -Watermark image= -Watermark mode=8 -Show watermark on screen=No -Gradient mode=0 -Gradient end color=255 255 255 -Show Swimlane=No -SwimlaneVert=Yes -TreeVert=No -CompDark=0 - -[DisplayPreferences\Object] -Show Icon=No -Mode=2 -Trunc Length=40 -Word Length=40 -Word Text=!"#$%&')*+,-./:;=>?@\]^_`|}~ -Shortcut IntIcon=Yes -Shortcut IntLoct=Yes -Shortcut IntFullPath=No -Shortcut IntLastPackage=Yes -Shortcut ExtIcon=Yes -Shortcut ExtLoct=No -Shortcut ExtFullPath=No -Shortcut ExtLastPackage=Yes -Shortcut ExtIncludeModl=Yes -Area.IconPicture=Yes -Area.Stereotype=Yes -Area.Comment=No -Area.TextStyle=No -Area.SubSymbols=Yes -Area_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Architecture Area Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <Separator Name="Separator" />[CRLF] <StandardAttribute Name="Comment" Attribute="Comment" Prefix="" Suffix="" Alignment="LEFT" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -EObjShowStrn=Yes -ExtendedObject.Comment=No -ExtendedObject.IconPicture=No -ExtendedObject.TextStyle=No -ExtendedObject_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Object Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <Separator Name="Separator" />[CRLF] <StandardAttribute Name="Comment" Attribute="Comment" Prefix="" Suffix="" Alignment="LEFT" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -ELnkShowStrn=Yes -ELnkShowName=Yes -ExtendedLink_SymbolLayout=<Form>[CRLF] <Form Name="Center" >[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] </Form>[CRLF] <Form Name="Source" >[CRLF] </Form>[CRLF] <Form Name="Destination" >[CRLF] </Form>[CRLF]</Form> -ExtDpdShowStrn=Yes -ExtendedDependency_SymbolLayout=<Form>[CRLF] <Form Name="Center" >[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Caption="" Mandatory="No" />[CRLF] </Form>[CRLF] <Form Name="Source" >[CRLF] </Form>[CRLF] <Form Name="Destination" >[CRLF] </Form>[CRLF]</Form> -FileObject.Stereotype=No -FileObject.DisplayName=Yes -FileObject.LocationOrName=No -FileObject.IconPicture=No -FileObject.TextStyle=No -FileObject.IconMode=Yes -FileObject_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <ExclusiveChoice Name="Exclusive Choice" Mandatory="Yes" Display="HorizontalRadios" >[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Location" Attribute="LocationOrName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] </ExclusiveChoice>[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -Package.Stereotype=Yes -Package.Comment=No -Package.IconPicture=No -Package.TextStyle=No -Package_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <Separator Name="Separator" />[CRLF] <StandardAttribute Name="Comment" Attribute="Comment" Prefix="" Suffix="" Alignment="LEFT" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -Display Model Version=Yes -Table.Stereotype=Yes -Table.DisplayName=Yes -Table.OwnerDisplayName=No -Table.Columns=Yes -Table.Columns._Filter="All Columns" PDMCOLNALL -Table.Columns._Columns=Stereotype DataType KeyIndicator -Table.Columns._Limit=-5 -Table.Keys=No -Table.Keys._Columns=Stereotype Indicator -Table.Indexes=No -Table.Indexes._Columns=Stereotype -Table.Triggers=No -Table.Triggers._Columns=Stereotype -Table.Comment=No -Table.IconPicture=No -Table.TextStyle=No -Table_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <ExclusiveChoice Name="Exclusive Choice" Mandatory="Yes" Display="HorizontalRadios" >[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Owner and Name" Attribute="OwnerDisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] </ExclusiveChoice>[CRLF] <Separator Name="Separator" />[CRLF] <StandardCollection Name="Columns" Collection="Columns" Columns="Stereotype No\r\nDisplayName Yes\r\nDataType No\r\nSymbolDataType No &quot;Domain or Data type&quot;\r\nDomain No\r\nKeyIndicator No\r\nIndexIndicator No\r\nNullStatus No" Filters="&quot;All Columns&quot; PDMCOLNALL &quot;&quot;\r\n&quot;PK Columns&quot; PDMCOLNPK &quot;\&quot;PRIM \&quot;TRUE\&quot; TRUE\&quot;&quot;\r\n&quot;Key Columns&quot; PDMCOLNKEY &quot;\&quot;KEYS \&quot;TRUE\&quot; TRUE\&quot;&quot;" HasLimit="Yes" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardCollection Name="Keys" Collection="Keys" Columns="Stereotype No\r\nDisplayName Yes\r\nIndicator No" HasLimit="No" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardCollection Name="Indexes" Collection="Indexes" Columns="Stereotype No\r\nDisplayName Yes\r\nIndicator No" HasLimit="No" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardCollection Name="Triggers" Collection="Triggers" Columns="Stereotype No\r\nDisplayName Yes" HasLimit="No" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Comment" Attribute="Comment" Prefix="" Suffix="" Alignment="LEFT" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -View.Stereotype=Yes -View.DisplayName=Yes -View.OwnerDisplayName=No -View.Columns=Yes -View.Columns._Columns=DisplayName -View.Columns._Limit=-5 -View.TemporaryVTables=Yes -View.Indexes=No -View.Comment=No -View.IconPicture=No -View.TextStyle=No -View_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <ExclusiveChoice Name="Exclusive Choice" Mandatory="Yes" Display="HorizontalRadios" >[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Owner and Name" Attribute="OwnerDisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] </ExclusiveChoice>[CRLF] <Separator Name="Separator" />[CRLF] <StandardCollection Name="Columns" Collection="Columns" Columns="DisplayName No\r\nExpression No\r\nDataType No\r\nSymbolDataType No &quot;Domain or Data type&quot;\r\nIndexIndicator No" HasLimit="Yes" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardCollection Name="Tables" Collection="TemporaryVTables" Columns="Name Yes" HasLimit="No" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardCollection Name="Indexes" Collection="Indexes" Columns="DisplayName Yes" HasLimit="No" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Comment" Attribute="Comment" Prefix="" Suffix="" Alignment="LEFT" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -Procedure.Stereotype=No -Procedure.DisplayName=Yes -Procedure.OwnerDisplayName=No -Procedure.Comment=No -Procedure.IconPicture=No -Procedure.TextStyle=No -Procedure_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <ExclusiveChoice Name="Exclusive Choice" Mandatory="Yes" Display="HorizontalRadios" >[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Owner and Name" Attribute="OwnerDisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] </ExclusiveChoice>[CRLF] <Separator Name="Separator" />[CRLF] <StandardAttribute Name="Comment" Attribute="Comment" Prefix="" Suffix="" Alignment="LEFT" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -Reference.Cardinality=No -Reference.ImplementationType=No -Reference.ChildRole=Yes -Reference.Stereotype=Yes -Reference.DisplayName=No -Reference.ForeignKeyConstraintName=No -Reference.JoinExpression=No -Reference.Integrity=No -Reference.ParentRole=Yes -Reference_SymbolLayout=<Form>[CRLF] <Form Name="Source" >[CRLF] <StandardAttribute Name="Cardinality" Attribute="Cardinality" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Implementation" Attribute="ImplementationType" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Child Role" Attribute="ChildRole" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] </Form>[CRLF] <Form Name="Center" >[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Caption="" Mandatory="No" />[CRLF] <ExclusiveChoice Name="Exclusive Choice" Mandatory="No" Display="HorizontalRadios" >[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Cons&amp;traint Name" Attribute="ForeignKeyConstraintName" Prefix="" Suffix="" Caption="Cons&amp;traint Name" Mandatory="No" />[CRLF] <StandardAttribute Name="Join" Attribute="JoinExpression" Prefix="" Suffix="" Caption="Join" Mandatory="No" />[CRLF] </ExclusiveChoice>[CRLF] <StandardAttribute Name="Referential integrity" Attribute="Integrity" Prefix="" Suffix="" Caption="Referential integrity" Mandatory="No" />[CRLF] </Form>[CRLF] <Form Name="Destination" >[CRLF] <StandardAttribute Name="Parent Role" Attribute="ParentRole" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] </Form>[CRLF]</Form> -ViewReference.ChildRole=Yes -ViewReference.Stereotype=Yes -ViewReference.DisplayName=No -ViewReference.JoinExpression=No -ViewReference.ParentRole=Yes -ViewReference_SymbolLayout=<Form>[CRLF] <Form Name="Source" >[CRLF] <StandardAttribute Name="Child Role" Attribute="ChildRole" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] </Form>[CRLF] <Form Name="Center" >[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Caption="" Mandatory="No" />[CRLF] <ExclusiveChoice Name="Exclusive Choice" Mandatory="No" Display="HorizontalRadios" >[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Join Expression" Attribute="JoinExpression" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] </ExclusiveChoice>[CRLF] </Form>[CRLF] <Form Name="Destination" >[CRLF] <StandardAttribute Name="Parent Role" Attribute="ParentRole" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] </Form>[CRLF]</Form> - -[DisplayPreferences\Symbol] - -[DisplayPreferences\Symbol\AREA] -STRNFont=新宋体,8,N -STRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -LABLFont=新宋体,8,N -LABLFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=9600 -Height=8000 -Brush color=253 249 234 -Fill Color=Yes -Brush style=6 -Brush bitmap mode=12 -Brush gradient mode=16 -Brush gradient color=245 230 173 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 121 98 6 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\FRMEOBJ] -STRNFont=新宋体,8,N -STRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -LABLFont=新宋体,8,N -LABLFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=6000 -Height=2000 -Brush color=255 255 255 -Fill Color=Yes -Brush style=6 -Brush bitmap mode=12 -Brush gradient mode=64 -Brush gradient color=192 192 192 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 255 128 128 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\FRMELNK] -CENTERFont=新宋体,8,N -CENTERFont color=0 0 0 -Line style=1 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Brush color=255 255 255 -Fill Color=Yes -Brush style=1 -Brush bitmap mode=12 -Brush gradient mode=0 -Brush gradient color=118 118 118 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 128 128 255 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\USRDEPD] -CENTERFont=新宋体,8,N -CENTERFont color=0 0 0 -Line style=1 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Brush color=255 255 255 -Fill Color=Yes -Brush style=1 -Brush bitmap mode=12 -Brush gradient mode=0 -Brush gradient color=118 118 118 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=2 0 128 128 255 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\FILO] -OBJSTRNFont=新宋体,8,N -OBJSTRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -LCNMFont=新宋体,8,N -LCNMFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=4800 -Height=3600 -Brush color=255 255 255 -Fill Color=Yes -Brush style=1 -Brush bitmap mode=12 -Brush gradient mode=0 -Brush gradient color=118 118 118 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 0 0 255 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\PDMPCKG] -STRNFont=新宋体,8,N -STRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -LABLFont=新宋体,8,N -LABLFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=4800 -Height=4000 -Brush color=255 255 192 -Fill Color=Yes -Brush style=6 -Brush bitmap mode=12 -Brush gradient mode=65 -Brush gradient color=255 255 255 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 178 178 178 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\TABL] -STRNFont=新宋体,8,N -STRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -OWNRDISPNAMEFont=新宋体,8,N -OWNRDISPNAMEFont color=0 0 0 -ColumnsFont=新宋体,8,N -ColumnsFont color=0 0 0 -TablePkColumnsFont=新宋体,8,U -TablePkColumnsFont color=0 0 0 -TableFkColumnsFont=新宋体,8,N -TableFkColumnsFont color=0 0 0 -KeysFont=新宋体,8,N -KeysFont color=0 0 0 -IndexesFont=新宋体,8,N -IndexesFont color=0 0 0 -TriggersFont=新宋体,8,N -TriggersFont color=0 0 0 -LABLFont=新宋体,8,N -LABLFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=4800 -Height=4000 -Brush color=178 214 252 -Fill Color=Yes -Brush style=6 -Brush bitmap mode=12 -Brush gradient mode=65 -Brush gradient color=255 255 255 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 0 128 192 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\VIEW] -STRNFont=新宋体,8,N -STRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -OWNRDISPNAMEFont=新宋体,8,N -OWNRDISPNAMEFont color=0 0 0 -ColumnsFont=新宋体,8,N -ColumnsFont color=0 0 0 -TablePkColumnsFont=新宋体,8,U -TablePkColumnsFont color=0 0 0 -TableFkColumnsFont=新宋体,8,N -TableFkColumnsFont color=0 0 0 -TemporaryVTablesFont=新宋体,8,N -TemporaryVTablesFont color=0 0 0 -IndexesFont=新宋体,8,N -IndexesFont color=0 0 0 -LABLFont=新宋体,8,N -LABLFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=4800 -Height=4000 -Brush color=208 208 255 -Fill Color=Yes -Brush style=6 -Brush bitmap mode=12 -Brush gradient mode=65 -Brush gradient color=255 255 255 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 128 128 192 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\PROC] -STRNFont=新宋体,8,N -STRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -OWNRDISPNAMEFont=新宋体,8,N -OWNRDISPNAMEFont color=0 0 0 -LABLFont=新宋体,8,N -LABLFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=4000 -Height=1000 -Brush color=255 255 192 -Fill Color=Yes -Brush style=6 -Brush bitmap mode=12 -Brush gradient mode=65 -Brush gradient color=255 255 255 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 128 108 0 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\REFR] -SOURCEFont=新宋体,8,N -SOURCEFont color=0 0 0 -CENTERFont=新宋体,8,N -CENTERFont color=0 0 0 -DESTINATIONFont=新宋体,8,N -DESTINATIONFont color=0 0 0 -Line style=1 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Brush color=255 255 255 -Fill Color=Yes -Brush style=1 -Brush bitmap mode=12 -Brush gradient mode=0 -Brush gradient color=118 118 118 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 0 128 192 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\VREF] -SOURCEFont=新宋体,8,N -SOURCEFont color=0 0 0 -CENTERFont=新宋体,8,N -CENTERFont color=0 0 0 -DESTINATIONFont=新宋体,8,N -DESTINATIONFont color=0 0 0 -Line style=1 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Brush color=255 255 255 -Fill Color=Yes -Brush style=1 -Brush bitmap mode=12 -Brush gradient mode=0 -Brush gradient color=118 118 118 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 128 128 192 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\Free Symbol] -Free TextFont=新宋体,8,N -Free TextFont color=0 0 0 -Line style=0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Brush color=255 255 255 -Fill Color=Yes -Brush style=1 -Brush bitmap mode=12 -Brush gradient mode=0 -Brush gradient color=118 118 118 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 0 0 255 -Shadow color=192 192 192 -Shadow=0 -(8268, 11693) -((315,354), (433,354)) -1 -15 - - -1631785980 -1631786175 -((-7856,-17298), (-6606,-11748)) -((-7231,-12148),(-7231,-16898)) -1 -1 -12615680 -12632256 -CENTER 0 新宋体,8,N -SOURCE 0 新宋体,8,N -DESTINATION 0 新宋体,8,N -3 - - - - - - - - - - - -1631786394 -1631786394 -((-7742,-5806), (-6492,-1775)) -((-7117,-5406),(-7117,-2175)) -1 -1 -12615680 -12632256 -CENTER 0 新宋体,8,N -SOURCE 0 新宋体,8,N -DESTINATION 0 新宋体,8,N - - - - - - - - - - - -1634469208 -1634469208 -((-6802,7545), (-5552,12659)) -((-6177,7945),(-6177,12259)) -1 -1 -12615680 -12632256 -CENTER 0 新宋体,8,N -SOURCE 0 新宋体,8,N -DESTINATION 0 新宋体,8,N - - - - - - - - - - - -1631776192 -1631786172 --1 -((-18140,-2175), (3906,7945)) -0 -12615680 -16570034 -12632256 -STRN 0 新宋体,8,N -DISPNAME 0 新宋体,8,N -OWNRDISPNAME 0 新宋体,8,N -Columns 0 新宋体,8,N -TablePkColumns 0 新宋体,8,U -TableFkColumns 0 新宋体,8,N -Keys 0 新宋体,8,N -Indexes 0 新宋体,8,N -Triggers 0 新宋体,8,N -LABL 0 新宋体,8,N -6 -65 -16777215 -1 - - - - - -1631776209 -1631786169 --1 -((-18310,-12148), (4922,-5406)) -0 -12615680 -16570034 -12632256 -STRN 0 新宋体,8,N -DISPNAME 0 新宋体,8,N -OWNRDISPNAME 0 新宋体,8,N -Columns 0 新宋体,8,N -TablePkColumns 0 新宋体,8,U -TableFkColumns 0 新宋体,8,N -Keys 0 新宋体,8,N -Indexes 0 新宋体,8,N -Triggers 0 新宋体,8,N -LABL 0 新宋体,8,N -6 -65 -16777215 -1 - - - - - -1631785959 -1631785966 --1 -((-17412,-30179), (9034,-16841)) -0 -12615680 -16570034 -12632256 -STRN 0 新宋体,8,N -DISPNAME 0 新宋体,8,N -OWNRDISPNAME 0 新宋体,8,N -Columns 0 新宋体,8,N -TablePkColumns 0 新宋体,8,U -TableFkColumns 0 新宋体,8,N -Keys 0 新宋体,8,N -Indexes 0 新宋体,8,N -Triggers 0 新宋体,8,N -LABL 0 新宋体,8,N -6 -65 -16777215 -1 - - - - - -1634469187 -1634469214 --1 -((-17663,12259), (5309,28103)) -0 -12615680 -16570034 -12632256 -STRN 0 新宋体,8,N -DISPNAME 0 新宋体,8,N -OWNRDISPNAME 0 新宋体,8,N -Columns 0 新宋体,8,N -TablePkColumns 0 新宋体,8,U -TableFkColumns 0 新宋体,8,N -Keys 0 新宋体,8,N -Indexes 0 新宋体,8,N -Triggers 0 新宋体,8,N -LABL 0 新宋体,8,N -6 -65 -16777215 -1 - - - - - - - - - - - - -CD94F13A-7AC3-404B-8C30-07349EB77FFC -订单( Order ) -Order -1631776192 -Xiadao -1634469988 -Xiadao -订单 - - - -F832F242-7A0F-416D-8D03-DB9FA0B93497 -订单标识( OrderId ) -OrderId -1631776192 -Xiadao -1632130976 -Xiadao -订单标识 -nvarchar(256) -256 -1 - - -E99D2B7D-948B-4F31-B2DF-98CBC8EF9599 -客户标识( CustomerId ) -CustomerId -1634469208 -Xiadao -1634469233 -Xiadao -客户标识 -int -1 -1 - - -777BE324-C260-497E-BE0B-C699CB638F6E -客户名称( CustomerName ) -CustomerName -1631776192 -Xiadao -1631776192 -Xiadao -客户名称 -nvarchar(200) -200 - - -5393A178-F4BF-4A32-96B2-FB371880E49F -金额( Amount ) -Amount -1631776192 -Xiadao -1631786241 -Xiadao -金额 -decimal(15,2) -15 -2 -1 - - -0F11D2A5-36F2-440C-9EC8-2008E3760849 -下单时间( PlaceOrderTime ) -PlaceOrderTime -1631776192 -Xiadao -1631776192 -Xiadao -下单时间 -datetime -1 - - -D8F68ED7-51B4-4B1B-9671-E84B258BF14B -订单状态( State ) -State -1631776192 -Xiadao -1631776192 -Xiadao -订单状态 -int -1 - - -6B467CE5-C50D-496E-8DD5-1D297B64FCE1 -是否删除( IsDeleted ) -IsDeleted -1631776192 -Xiadao -1631776192 -Xiadao -是否删除 -bit -1 - - -0953EE6D-44A5-4A38-8A5F-FF29C368DCD5 -版本号( Version ) -Version -1631776192 -Xiadao -1631776192 -Xiadao -版本号 -timestamp - - - - -4D3D59AA-84F6-42AA-A57F-B7BBF76F7A52 -Key_1 -Key_1 -1631776192 -Xiadao -1631776192 -Xiadao - - - - - - - -337371E1-6706-499E-898F-4734CED5264D -clus_idx_placetime -clus_idx_placetime -1631776192 -Xiadao -1631776192 -Xiadao - - -DAFF9F3A-32AD-45DF-A817-C526ACDF629D -1631776192 -Xiadao -1631776192 -Xiadao - - - - - - - - - - - - - - - - - - - - - -28D8BD2F-1F80-4EFE-97E4-33992A0636C7 -订单明细( OrderItem ) -OrderItem -1631776209 -Xiadao -1631786407 -Xiadao -订单明细 - - - -E8EBFC5B-F75B-41D2-865D-84697FA961E5 -订单明细标识( OrderItemId ) -OrderItemId -1631776209 -Xiadao -1632130998 -Xiadao -订单明细标识 -uniqueidentifier -1 - - -199BF524-5555-404A-840B-B1AE6C69F24E -订单标识( OrderId ) -OrderId -1631786394 -Xiadao -1632131006 -Xiadao -订单标识 -nvarchar(256) -256 -1 -1 - - -EA92698D-332D-4912-A000-AEDC558F968C -产品标识( ProductId ) -ProductId -1631785980 -Xiadao -1632131014 -Xiadao -产品标识 -uniqueidentifier -1 - - -F41E0B62-8456-4A76-8F6B-FC8DBA4DA214 -产品名称( ProductName ) -ProductName -1631776209 -Xiadao -1631786137 -Xiadao -产品名称 -nvarchar(500) -500 -1 - - -7EEB28F6-5976-4306-A1B1-A8B67D2A138A -单价( Price ) -Price -1631776209 -Xiadao -1631786154 -Xiadao -单价 -decimal(12,2) -12 -2 -1 - - -68CE9F04-BF44-435D-A44B-ABBF790C2261 -数量( Quantity ) -Quantity -1631776209 -Xiadao -1631776209 -Xiadao -数量 -int -1 - - - - -8C1ED9AC-57EE-4F0F-A886-931AD5EABE52 -clus_idx_orderitemid -clus_idx_orderitemid -1631776209 -Xiadao -1631776209 -Xiadao - - - - - - - - - - - - - - - - -9487E398-F6C4-48D5-998D-197532328D09 -产品( Product ) -Product -1631785959 -Xiadao -1631785959 -Xiadao - -2E6FA781-2BB6-4E53-8EE0-A2A7D9DBE25F -380BAA40-0042-11D2-BD28-00A02478ECC9 -<Model>::03 - 商品 - - -59E00B00-F3C8-47DB-935E-F1E23E284FAD -客户( Customer ) -Customer -1634469187 -Xiadao -1634469187 -Xiadao - -BD102691-5783-434C-9D80-CC022FC53A38 -380BAA40-0042-11D2-BD28-00A02478ECC9 -<Model>::02- 客户 - - - - -D3B1007E-23E8-4F7C-847C-D05BC6C5A03A -Reference_2 -Reference_2 -1631785980 -Xiadao -1631785980 -Xiadao -0..* - - - - - - - - - - - -4DE26E79-A278-4115-8750-404DB4A2FA5B -1631785980 -Xiadao -1631785980 -Xiadao - - - - - - - - - - -E891B7D4-9C5D-47BE-9C74-2ADDFFABD5EF -Reference_3 -Reference_3 -1631786394 -Xiadao -1631786394 -Xiadao -0..* - - - - - - - - - - - -E86F9047-6AE9-412B-9155-E33141187310 -1631786394 -Xiadao -1631786394 -Xiadao - - - - - - - - - - -43FDC985-84BF-458E-A19B-D9D29E34C66A -Reference_4 -Reference_4 -1634469208 -Xiadao -1634469208 -Xiadao -0..* - - - - - - - - - - - -AB93EA2F-DB82-4A48-8A24-EFED2909DB39 -1634469208 -Xiadao -1634469208 -Xiadao - - - - - - - - - - - - -787E9839-BD38-4DAF-907E-4CC09AC6C353 -02- 客户 -02- 客户 -1631784514 -Xiadao -1631784626 -Xiadao - - -4E4FADC5-9A54-47F8-AD0B-8399B8F0B4AA -01 - 客户 -01 - 客户 -1631784514 -Xiadao -1631784626 -Xiadao -[DisplayPreferences] - -[DisplayPreferences\PDM] - -[DisplayPreferences\General] -Adjust to text=Yes -Snap Grid=No -Constrain Labels=Yes -Display Grid=No -Show Page Delimiter=Yes -Show Links intersections=Yes -Activate automatic link routing=Yes -Grid size=800 -Graphic unit=2 -Window color=255 255 255 -Background image= -Background mode=8 -Watermark image= -Watermark mode=8 -Show watermark on screen=No -Gradient mode=0 -Gradient end color=255 255 255 -Show Swimlane=No -SwimlaneVert=Yes -TreeVert=No -CompDark=0 - -[DisplayPreferences\Object] -Show Icon=No -Mode=2 -Trunc Length=40 -Word Length=40 -Word Text=!"#$%&')*+,-./:;=>?@\]^_`|}~ -Shortcut IntIcon=Yes -Shortcut IntLoct=Yes -Shortcut IntFullPath=No -Shortcut IntLastPackage=Yes -Shortcut ExtIcon=Yes -Shortcut ExtLoct=No -Shortcut ExtFullPath=No -Shortcut ExtLastPackage=Yes -Shortcut ExtIncludeModl=Yes -Area.IconPicture=Yes -Area.Stereotype=Yes -Area.Comment=No -Area.TextStyle=No -Area.SubSymbols=Yes -Area_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Architecture Area Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <Separator Name="Separator" />[CRLF] <StandardAttribute Name="Comment" Attribute="Comment" Prefix="" Suffix="" Alignment="LEFT" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -EObjShowStrn=Yes -ExtendedObject.Comment=No -ExtendedObject.IconPicture=No -ExtendedObject.TextStyle=No -ExtendedObject_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Object Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <Separator Name="Separator" />[CRLF] <StandardAttribute Name="Comment" Attribute="Comment" Prefix="" Suffix="" Alignment="LEFT" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -ELnkShowStrn=Yes -ELnkShowName=Yes -ExtendedLink_SymbolLayout=<Form>[CRLF] <Form Name="Center" >[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] </Form>[CRLF] <Form Name="Source" >[CRLF] </Form>[CRLF] <Form Name="Destination" >[CRLF] </Form>[CRLF]</Form> -ExtDpdShowStrn=Yes -ExtendedDependency_SymbolLayout=<Form>[CRLF] <Form Name="Center" >[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Caption="" Mandatory="No" />[CRLF] </Form>[CRLF] <Form Name="Source" >[CRLF] </Form>[CRLF] <Form Name="Destination" >[CRLF] </Form>[CRLF]</Form> -FileObject.Stereotype=No -FileObject.DisplayName=Yes -FileObject.LocationOrName=No -FileObject.IconPicture=No -FileObject.TextStyle=No -FileObject.IconMode=Yes -FileObject_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <ExclusiveChoice Name="Exclusive Choice" Mandatory="Yes" Display="HorizontalRadios" >[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Location" Attribute="LocationOrName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] </ExclusiveChoice>[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -Package.Stereotype=Yes -Package.Comment=No -Package.IconPicture=No -Package.TextStyle=No -Package_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <Separator Name="Separator" />[CRLF] <StandardAttribute Name="Comment" Attribute="Comment" Prefix="" Suffix="" Alignment="LEFT" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -Display Model Version=Yes -Table.Stereotype=Yes -Table.DisplayName=Yes -Table.OwnerDisplayName=No -Table.Columns=Yes -Table.Columns._Filter="All Columns" PDMCOLNALL -Table.Columns._Columns=Stereotype DataType KeyIndicator -Table.Columns._Limit=-5 -Table.Keys=No -Table.Keys._Columns=Stereotype Indicator -Table.Indexes=No -Table.Indexes._Columns=Stereotype -Table.Triggers=No -Table.Triggers._Columns=Stereotype -Table.Comment=No -Table.IconPicture=No -Table.TextStyle=No -Table_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <ExclusiveChoice Name="Exclusive Choice" Mandatory="Yes" Display="HorizontalRadios" >[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Owner and Name" Attribute="OwnerDisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] </ExclusiveChoice>[CRLF] <Separator Name="Separator" />[CRLF] <StandardCollection Name="Columns" Collection="Columns" Columns="Stereotype No\r\nDisplayName Yes\r\nDataType No\r\nSymbolDataType No &quot;Domain or Data type&quot;\r\nDomain No\r\nKeyIndicator No\r\nIndexIndicator No\r\nNullStatus No" Filters="&quot;All Columns&quot; PDMCOLNALL &quot;&quot;\r\n&quot;PK Columns&quot; PDMCOLNPK &quot;\&quot;PRIM \&quot;TRUE\&quot; TRUE\&quot;&quot;\r\n&quot;Key Columns&quot; PDMCOLNKEY &quot;\&quot;KEYS \&quot;TRUE\&quot; TRUE\&quot;&quot;" HasLimit="Yes" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardCollection Name="Keys" Collection="Keys" Columns="Stereotype No\r\nDisplayName Yes\r\nIndicator No" HasLimit="No" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardCollection Name="Indexes" Collection="Indexes" Columns="Stereotype No\r\nDisplayName Yes\r\nIndicator No" HasLimit="No" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardCollection Name="Triggers" Collection="Triggers" Columns="Stereotype No\r\nDisplayName Yes" HasLimit="No" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Comment" Attribute="Comment" Prefix="" Suffix="" Alignment="LEFT" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -View.Stereotype=Yes -View.DisplayName=Yes -View.OwnerDisplayName=No -View.Columns=Yes -View.Columns._Columns=DisplayName -View.Columns._Limit=-5 -View.TemporaryVTables=Yes -View.Indexes=No -View.Comment=No -View.IconPicture=No -View.TextStyle=No -View_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <ExclusiveChoice Name="Exclusive Choice" Mandatory="Yes" Display="HorizontalRadios" >[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Owner and Name" Attribute="OwnerDisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] </ExclusiveChoice>[CRLF] <Separator Name="Separator" />[CRLF] <StandardCollection Name="Columns" Collection="Columns" Columns="DisplayName No\r\nExpression No\r\nDataType No\r\nSymbolDataType No &quot;Domain or Data type&quot;\r\nIndexIndicator No" HasLimit="Yes" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardCollection Name="Tables" Collection="TemporaryVTables" Columns="Name Yes" HasLimit="No" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardCollection Name="Indexes" Collection="Indexes" Columns="DisplayName Yes" HasLimit="No" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Comment" Attribute="Comment" Prefix="" Suffix="" Alignment="LEFT" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -Procedure.Stereotype=No -Procedure.DisplayName=Yes -Procedure.OwnerDisplayName=No -Procedure.Comment=No -Procedure.IconPicture=No -Procedure.TextStyle=No -Procedure_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <ExclusiveChoice Name="Exclusive Choice" Mandatory="Yes" Display="HorizontalRadios" >[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Owner and Name" Attribute="OwnerDisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] </ExclusiveChoice>[CRLF] <Separator Name="Separator" />[CRLF] <StandardAttribute Name="Comment" Attribute="Comment" Prefix="" Suffix="" Alignment="LEFT" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -Reference.Cardinality=No -Reference.ImplementationType=No -Reference.ChildRole=Yes -Reference.Stereotype=Yes -Reference.DisplayName=No -Reference.ForeignKeyConstraintName=No -Reference.JoinExpression=No -Reference.Integrity=No -Reference.ParentRole=Yes -Reference_SymbolLayout=<Form>[CRLF] <Form Name="Source" >[CRLF] <StandardAttribute Name="Cardinality" Attribute="Cardinality" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Implementation" Attribute="ImplementationType" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Child Role" Attribute="ChildRole" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] </Form>[CRLF] <Form Name="Center" >[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Caption="" Mandatory="No" />[CRLF] <ExclusiveChoice Name="Exclusive Choice" Mandatory="No" Display="HorizontalRadios" >[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Cons&amp;traint Name" Attribute="ForeignKeyConstraintName" Prefix="" Suffix="" Caption="Cons&amp;traint Name" Mandatory="No" />[CRLF] <StandardAttribute Name="Join" Attribute="JoinExpression" Prefix="" Suffix="" Caption="Join" Mandatory="No" />[CRLF] </ExclusiveChoice>[CRLF] <StandardAttribute Name="Referential integrity" Attribute="Integrity" Prefix="" Suffix="" Caption="Referential integrity" Mandatory="No" />[CRLF] </Form>[CRLF] <Form Name="Destination" >[CRLF] <StandardAttribute Name="Parent Role" Attribute="ParentRole" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] </Form>[CRLF]</Form> -ViewReference.ChildRole=Yes -ViewReference.Stereotype=Yes -ViewReference.DisplayName=No -ViewReference.JoinExpression=No -ViewReference.ParentRole=Yes -ViewReference_SymbolLayout=<Form>[CRLF] <Form Name="Source" >[CRLF] <StandardAttribute Name="Child Role" Attribute="ChildRole" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] </Form>[CRLF] <Form Name="Center" >[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Caption="" Mandatory="No" />[CRLF] <ExclusiveChoice Name="Exclusive Choice" Mandatory="No" Display="HorizontalRadios" >[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Join Expression" Attribute="JoinExpression" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] </ExclusiveChoice>[CRLF] </Form>[CRLF] <Form Name="Destination" >[CRLF] <StandardAttribute Name="Parent Role" Attribute="ParentRole" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] </Form>[CRLF]</Form> - -[DisplayPreferences\Symbol] - -[DisplayPreferences\Symbol\AREA] -STRNFont=新宋体,8,N -STRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -LABLFont=新宋体,8,N -LABLFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=9600 -Height=8000 -Brush color=253 249 234 -Fill Color=Yes -Brush style=6 -Brush bitmap mode=12 -Brush gradient mode=16 -Brush gradient color=245 230 173 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 121 98 6 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\FRMEOBJ] -STRNFont=新宋体,8,N -STRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -LABLFont=新宋体,8,N -LABLFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=6000 -Height=2000 -Brush color=255 255 255 -Fill Color=Yes -Brush style=6 -Brush bitmap mode=12 -Brush gradient mode=64 -Brush gradient color=192 192 192 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 255 128 128 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\FRMELNK] -CENTERFont=新宋体,8,N -CENTERFont color=0 0 0 -Line style=1 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Brush color=255 255 255 -Fill Color=Yes -Brush style=1 -Brush bitmap mode=12 -Brush gradient mode=0 -Brush gradient color=118 118 118 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 128 128 255 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\USRDEPD] -CENTERFont=新宋体,8,N -CENTERFont color=0 0 0 -Line style=1 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Brush color=255 255 255 -Fill Color=Yes -Brush style=1 -Brush bitmap mode=12 -Brush gradient mode=0 -Brush gradient color=118 118 118 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=2 0 128 128 255 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\FILO] -OBJSTRNFont=新宋体,8,N -OBJSTRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -LCNMFont=新宋体,8,N -LCNMFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=4800 -Height=3600 -Brush color=255 255 255 -Fill Color=Yes -Brush style=1 -Brush bitmap mode=12 -Brush gradient mode=0 -Brush gradient color=118 118 118 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 0 0 255 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\PDMPCKG] -STRNFont=新宋体,8,N -STRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -LABLFont=新宋体,8,N -LABLFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=4800 -Height=4000 -Brush color=255 255 192 -Fill Color=Yes -Brush style=6 -Brush bitmap mode=12 -Brush gradient mode=65 -Brush gradient color=255 255 255 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 178 178 178 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\TABL] -STRNFont=新宋体,8,N -STRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -OWNRDISPNAMEFont=新宋体,8,N -OWNRDISPNAMEFont color=0 0 0 -ColumnsFont=新宋体,8,N -ColumnsFont color=0 0 0 -TablePkColumnsFont=新宋体,8,U -TablePkColumnsFont color=0 0 0 -TableFkColumnsFont=新宋体,8,N -TableFkColumnsFont color=0 0 0 -KeysFont=新宋体,8,N -KeysFont color=0 0 0 -IndexesFont=新宋体,8,N -IndexesFont color=0 0 0 -TriggersFont=新宋体,8,N -TriggersFont color=0 0 0 -LABLFont=新宋体,8,N -LABLFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=4800 -Height=4000 -Brush color=178 214 252 -Fill Color=Yes -Brush style=6 -Brush bitmap mode=12 -Brush gradient mode=65 -Brush gradient color=255 255 255 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 0 128 192 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\VIEW] -STRNFont=新宋体,8,N -STRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -OWNRDISPNAMEFont=新宋体,8,N -OWNRDISPNAMEFont color=0 0 0 -ColumnsFont=新宋体,8,N -ColumnsFont color=0 0 0 -TablePkColumnsFont=新宋体,8,U -TablePkColumnsFont color=0 0 0 -TableFkColumnsFont=新宋体,8,N -TableFkColumnsFont color=0 0 0 -TemporaryVTablesFont=新宋体,8,N -TemporaryVTablesFont color=0 0 0 -IndexesFont=新宋体,8,N -IndexesFont color=0 0 0 -LABLFont=新宋体,8,N -LABLFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=4800 -Height=4000 -Brush color=208 208 255 -Fill Color=Yes -Brush style=6 -Brush bitmap mode=12 -Brush gradient mode=65 -Brush gradient color=255 255 255 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 128 128 192 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\PROC] -STRNFont=新宋体,8,N -STRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -OWNRDISPNAMEFont=新宋体,8,N -OWNRDISPNAMEFont color=0 0 0 -LABLFont=新宋体,8,N -LABLFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=4000 -Height=1000 -Brush color=255 255 192 -Fill Color=Yes -Brush style=6 -Brush bitmap mode=12 -Brush gradient mode=65 -Brush gradient color=255 255 255 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 128 108 0 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\REFR] -SOURCEFont=新宋体,8,N -SOURCEFont color=0 0 0 -CENTERFont=新宋体,8,N -CENTERFont color=0 0 0 -DESTINATIONFont=新宋体,8,N -DESTINATIONFont color=0 0 0 -Line style=1 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Brush color=255 255 255 -Fill Color=Yes -Brush style=1 -Brush bitmap mode=12 -Brush gradient mode=0 -Brush gradient color=118 118 118 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 0 128 192 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\VREF] -SOURCEFont=新宋体,8,N -SOURCEFont color=0 0 0 -CENTERFont=新宋体,8,N -CENTERFont color=0 0 0 -DESTINATIONFont=新宋体,8,N -DESTINATIONFont color=0 0 0 -Line style=1 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Brush color=255 255 255 -Fill Color=Yes -Brush style=1 -Brush bitmap mode=12 -Brush gradient mode=0 -Brush gradient color=118 118 118 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 128 128 192 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\Free Symbol] -Free TextFont=新宋体,8,N -Free TextFont color=0 0 0 -Line style=0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Brush color=255 255 255 -Fill Color=Yes -Brush style=1 -Brush bitmap mode=12 -Brush gradient mode=0 -Brush gradient color=118 118 118 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 0 0 255 -Shadow color=192 192 192 -Shadow=0 -(8268, 11693) -((315,354), (433,354)) -1 -15 - - -1631784563 -1631788824 --1 -((-13248,-17405), (9724,-2855)) -0 -12615680 -16570034 -12632256 -STRN 0 新宋体,8,N -DISPNAME 0 新宋体,8,N -OWNRDISPNAME 0 新宋体,8,N -Columns 0 新宋体,8,N -TablePkColumns 0 新宋体,8,U -TableFkColumns 0 新宋体,8,N -Keys 0 新宋体,8,N -Indexes 0 新宋体,8,N -Triggers 0 新宋体,8,N -LABL 0 新宋体,8,N -6 -65 -16777215 -1 - - - - - - - - - - - - -BD102691-5783-434C-9D80-CC022FC53A38 -客户( Customer ) -Customer -1631784563 -Xiadao -1631788821 -Xiadao -客户 - - - -35488561-5B22-4184-93DE-8614D1B5EAB0 -客户标识( CustomerId ) -CustomerId -1631784592 -Xiadao -1631785156 -Xiadao -客户标识 -int -1 -1 - - -E2C97AB7-BD0D-4CD7-8889-BF08061515F0 -编码( Code ) -Code -1631784563 -Xiadao -1631784563 -Xiadao -编码 -nvarchar(100) -100 - - -8BA50C63-275A-4011-9C70-1EA831837025 -姓名( Name ) -Name -1631784563 -Xiadao -1631784563 -Xiadao -姓名 -nvarchar(200) -200 - - -9803F730-D585-4692-8FE0-D406D9591166 -昵称( Nickname ) -Nickname -1631784563 -Xiadao -1631784563 -Xiadao -昵称 -nvarchar(50) -50 - - -C2DD58A8-0910-44E4-8B40-4C0D5BCF8422 -性别( Gender ) -Gender -1631784563 -Xiadao -1631784563 -Xiadao -性别 -int - - -25AE0B51-33E9-4700-AAC7-C511A8BA098B -出生日期( Birthday ) -Birthday -1631784563 -Xiadao -1631784563 -Xiadao -出生日期 -datetime - - -5B340712-D0DA-4152-954C-A44FAA83AAB9 -民族( Nation ) -Nation -1631784563 -Xiadao -1631784563 -Xiadao -民族 -int - - -A8A2CD10-A1E0-465F-A0DE-FC956E3EE09A -手机号( Phone ) -Phone -1631784563 -Xiadao -1631784563 -Xiadao -手机号 -nvarchar(50) -50 - - -83D69016-E2AC-43D6-86E7-9DF60ACCF899 -电子邮件( Email ) -Email -1631784563 -Xiadao -1631784563 -Xiadao -电子邮件 -nvarchar(500) -500 - - -C3288051-E1C4-436F-8791-E3B8CBC59592 -创建时间( CreationTime ) -CreationTime -1631784563 -Xiadao -1631784563 -Xiadao -创建时间 -datetime - - -38087254-9712-4E05-8556-484658221223 -创建人( CreatorId ) -CreatorId -1631784563 -Xiadao -1631784563 -Xiadao -创建人 -uniqueidentifier - - -630E284E-442F-47C7-9CE7-72A50715BE6B -最后修改时间( LastModificationTime ) -LastModificationTime -1631784563 -Xiadao -1631784563 -Xiadao -最后修改时间 -datetime - - -1D7D1D1E-7EF6-41C1-9C2F-C26083508E09 -最后修改人( LastModifierId ) -LastModifierId -1631784563 -Xiadao -1631784563 -Xiadao -最后修改人 -uniqueidentifier - - -E75E55F0-A608-458C-9743-4950D71F6DA0 -是否删除( IsDeleted ) -IsDeleted -1631784563 -Xiadao -1631784563 -Xiadao -是否删除 -bit -1 - - -D2CBCEDE-4263-49E5-A0E2-F3D3AD7D4BA5 -版本号( Version ) -Version -1631784563 -Xiadao -1631784563 -Xiadao -版本号 -timestamp - - - - -B1C30BB8-8AE2-4E41-ACEC-1FD073EED22B -Key_1 -Key_1 -1631784563 -Xiadao -1631785156 -Xiadao - - - - - - - - - - - - - - - - - - -BF4ED0CA-69B4-4DE1-996C-34192084F70D -05 - 博客 -05 - 博客 -1634474081 -Xiadao -1634479459 -Xiadao - - -7294C4E9-50EA-443A-861F-4ABD810E34DC -01 - 贴子 -01 - 贴子 -1634474081 -Xiadao -1634479459 -Xiadao -[DisplayPreferences] - -[DisplayPreferences\PDM] - -[DisplayPreferences\General] -Adjust to text=Yes -Snap Grid=No -Constrain Labels=Yes -Display Grid=No -Show Page Delimiter=Yes -Show Links intersections=Yes -Activate automatic link routing=Yes -Grid size=800 -Graphic unit=2 -Window color=255 255 255 -Background image= -Background mode=8 -Watermark image= -Watermark mode=8 -Show watermark on screen=No -Gradient mode=0 -Gradient end color=255 255 255 -Show Swimlane=No -SwimlaneVert=Yes -TreeVert=No -CompDark=0 - -[DisplayPreferences\Object] -Show Icon=No -Mode=2 -Trunc Length=40 -Word Length=40 -Word Text=!"#$%&')*+,-./:;=>?@\]^_`|}~ -Shortcut IntIcon=Yes -Shortcut IntLoct=Yes -Shortcut IntFullPath=No -Shortcut IntLastPackage=Yes -Shortcut ExtIcon=Yes -Shortcut ExtLoct=No -Shortcut ExtFullPath=No -Shortcut ExtLastPackage=Yes -Shortcut ExtIncludeModl=Yes -Area.IconPicture=Yes -Area.Stereotype=Yes -Area.Comment=No -Area.TextStyle=No -Area.SubSymbols=Yes -Area_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Architecture Area Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <Separator Name="Separator" />[CRLF] <StandardAttribute Name="Comment" Attribute="Comment" Prefix="" Suffix="" Alignment="LEFT" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -EObjShowStrn=Yes -ExtendedObject.Comment=No -ExtendedObject.IconPicture=No -ExtendedObject.TextStyle=No -ExtendedObject_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Object Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <Separator Name="Separator" />[CRLF] <StandardAttribute Name="Comment" Attribute="Comment" Prefix="" Suffix="" Alignment="LEFT" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -ELnkShowStrn=Yes -ELnkShowName=Yes -ExtendedLink_SymbolLayout=<Form>[CRLF] <Form Name="Center" >[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] </Form>[CRLF] <Form Name="Source" >[CRLF] </Form>[CRLF] <Form Name="Destination" >[CRLF] </Form>[CRLF]</Form> -ExtDpdShowStrn=Yes -ExtendedDependency_SymbolLayout=<Form>[CRLF] <Form Name="Center" >[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Caption="" Mandatory="No" />[CRLF] </Form>[CRLF] <Form Name="Source" >[CRLF] </Form>[CRLF] <Form Name="Destination" >[CRLF] </Form>[CRLF]</Form> -FileObject.Stereotype=No -FileObject.DisplayName=Yes -FileObject.LocationOrName=No -FileObject.IconPicture=No -FileObject.TextStyle=No -FileObject.IconMode=Yes -FileObject_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <ExclusiveChoice Name="Exclusive Choice" Mandatory="Yes" Display="HorizontalRadios" >[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Location" Attribute="LocationOrName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] </ExclusiveChoice>[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -Package.Stereotype=Yes -Package.Comment=No -Package.IconPicture=No -Package.TextStyle=No -Package_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <Separator Name="Separator" />[CRLF] <StandardAttribute Name="Comment" Attribute="Comment" Prefix="" Suffix="" Alignment="LEFT" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -Display Model Version=Yes -Table.Stereotype=Yes -Table.DisplayName=Yes -Table.OwnerDisplayName=No -Table.Columns=Yes -Table.Columns._Filter="All Columns" PDMCOLNALL -Table.Columns._Columns=Stereotype DataType KeyIndicator -Table.Columns._Limit=-5 -Table.Keys=No -Table.Keys._Columns=Stereotype Indicator -Table.Indexes=No -Table.Indexes._Columns=Stereotype -Table.Triggers=No -Table.Triggers._Columns=Stereotype -Table.Comment=No -Table.IconPicture=No -Table.TextStyle=No -Table_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <ExclusiveChoice Name="Exclusive Choice" Mandatory="Yes" Display="HorizontalRadios" >[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Owner and Name" Attribute="OwnerDisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] </ExclusiveChoice>[CRLF] <Separator Name="Separator" />[CRLF] <StandardCollection Name="Columns" Collection="Columns" Columns="Stereotype No\r\nDisplayName Yes\r\nDataType No\r\nSymbolDataType No &quot;Domain or Data type&quot;\r\nDomain No\r\nKeyIndicator No\r\nIndexIndicator No\r\nNullStatus No" Filters="&quot;All Columns&quot; PDMCOLNALL &quot;&quot;\r\n&quot;PK Columns&quot; PDMCOLNPK &quot;\&quot;PRIM \&quot;TRUE\&quot; TRUE\&quot;&quot;\r\n&quot;Key Columns&quot; PDMCOLNKEY &quot;\&quot;KEYS \&quot;TRUE\&quot; TRUE\&quot;&quot;" HasLimit="Yes" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardCollection Name="Keys" Collection="Keys" Columns="Stereotype No\r\nDisplayName Yes\r\nIndicator No" HasLimit="No" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardCollection Name="Indexes" Collection="Indexes" Columns="Stereotype No\r\nDisplayName Yes\r\nIndicator No" HasLimit="No" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardCollection Name="Triggers" Collection="Triggers" Columns="Stereotype No\r\nDisplayName Yes" HasLimit="No" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Comment" Attribute="Comment" Prefix="" Suffix="" Alignment="LEFT" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -View.Stereotype=Yes -View.DisplayName=Yes -View.OwnerDisplayName=No -View.Columns=Yes -View.Columns._Columns=DisplayName -View.Columns._Limit=-5 -View.TemporaryVTables=Yes -View.Indexes=No -View.Comment=No -View.IconPicture=No -View.TextStyle=No -View_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <ExclusiveChoice Name="Exclusive Choice" Mandatory="Yes" Display="HorizontalRadios" >[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Owner and Name" Attribute="OwnerDisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] </ExclusiveChoice>[CRLF] <Separator Name="Separator" />[CRLF] <StandardCollection Name="Columns" Collection="Columns" Columns="DisplayName No\r\nExpression No\r\nDataType No\r\nSymbolDataType No &quot;Domain or Data type&quot;\r\nIndexIndicator No" HasLimit="Yes" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardCollection Name="Tables" Collection="TemporaryVTables" Columns="Name Yes" HasLimit="No" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardCollection Name="Indexes" Collection="Indexes" Columns="DisplayName Yes" HasLimit="No" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Comment" Attribute="Comment" Prefix="" Suffix="" Alignment="LEFT" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -Procedure.Stereotype=No -Procedure.DisplayName=Yes -Procedure.OwnerDisplayName=No -Procedure.Comment=No -Procedure.IconPicture=No -Procedure.TextStyle=No -Procedure_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <ExclusiveChoice Name="Exclusive Choice" Mandatory="Yes" Display="HorizontalRadios" >[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Owner and Name" Attribute="OwnerDisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] </ExclusiveChoice>[CRLF] <Separator Name="Separator" />[CRLF] <StandardAttribute Name="Comment" Attribute="Comment" Prefix="" Suffix="" Alignment="LEFT" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -Reference.Cardinality=No -Reference.ImplementationType=No -Reference.ChildRole=Yes -Reference.Stereotype=Yes -Reference.DisplayName=No -Reference.ForeignKeyConstraintName=No -Reference.JoinExpression=No -Reference.Integrity=No -Reference.ParentRole=Yes -Reference_SymbolLayout=<Form>[CRLF] <Form Name="Source" >[CRLF] <StandardAttribute Name="Cardinality" Attribute="Cardinality" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Implementation" Attribute="ImplementationType" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Child Role" Attribute="ChildRole" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] </Form>[CRLF] <Form Name="Center" >[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Caption="" Mandatory="No" />[CRLF] <ExclusiveChoice Name="Exclusive Choice" Mandatory="No" Display="HorizontalRadios" >[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Cons&amp;traint Name" Attribute="ForeignKeyConstraintName" Prefix="" Suffix="" Caption="Cons&amp;traint Name" Mandatory="No" />[CRLF] <StandardAttribute Name="Join" Attribute="JoinExpression" Prefix="" Suffix="" Caption="Join" Mandatory="No" />[CRLF] </ExclusiveChoice>[CRLF] <StandardAttribute Name="Referential integrity" Attribute="Integrity" Prefix="" Suffix="" Caption="Referential integrity" Mandatory="No" />[CRLF] </Form>[CRLF] <Form Name="Destination" >[CRLF] <StandardAttribute Name="Parent Role" Attribute="ParentRole" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] </Form>[CRLF]</Form> -ViewReference.ChildRole=Yes -ViewReference.Stereotype=Yes -ViewReference.DisplayName=No -ViewReference.JoinExpression=No -ViewReference.ParentRole=Yes -ViewReference_SymbolLayout=<Form>[CRLF] <Form Name="Source" >[CRLF] <StandardAttribute Name="Child Role" Attribute="ChildRole" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] </Form>[CRLF] <Form Name="Center" >[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Caption="" Mandatory="No" />[CRLF] <ExclusiveChoice Name="Exclusive Choice" Mandatory="No" Display="HorizontalRadios" >[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Join Expression" Attribute="JoinExpression" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] </ExclusiveChoice>[CRLF] </Form>[CRLF] <Form Name="Destination" >[CRLF] <StandardAttribute Name="Parent Role" Attribute="ParentRole" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] </Form>[CRLF]</Form> - -[DisplayPreferences\Symbol] - -[DisplayPreferences\Symbol\AREA] -STRNFont=新宋体,8,N -STRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -LABLFont=新宋体,8,N -LABLFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=9600 -Height=8000 -Brush color=253 249 234 -Fill Color=Yes -Brush style=6 -Brush bitmap mode=12 -Brush gradient mode=16 -Brush gradient color=245 230 173 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 121 98 6 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\FRMEOBJ] -STRNFont=新宋体,8,N -STRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -LABLFont=新宋体,8,N -LABLFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=6000 -Height=2000 -Brush color=255 255 255 -Fill Color=Yes -Brush style=6 -Brush bitmap mode=12 -Brush gradient mode=64 -Brush gradient color=192 192 192 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 255 128 128 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\FRMELNK] -CENTERFont=新宋体,8,N -CENTERFont color=0 0 0 -Line style=1 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Brush color=255 255 255 -Fill Color=Yes -Brush style=1 -Brush bitmap mode=12 -Brush gradient mode=0 -Brush gradient color=118 118 118 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 128 128 255 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\USRDEPD] -CENTERFont=新宋体,8,N -CENTERFont color=0 0 0 -Line style=1 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Brush color=255 255 255 -Fill Color=Yes -Brush style=1 -Brush bitmap mode=12 -Brush gradient mode=0 -Brush gradient color=118 118 118 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=2 0 128 128 255 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\FILO] -OBJSTRNFont=新宋体,8,N -OBJSTRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -LCNMFont=新宋体,8,N -LCNMFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=4800 -Height=3600 -Brush color=255 255 255 -Fill Color=Yes -Brush style=1 -Brush bitmap mode=12 -Brush gradient mode=0 -Brush gradient color=118 118 118 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 0 0 255 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\PDMPCKG] -STRNFont=新宋体,8,N -STRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -LABLFont=新宋体,8,N -LABLFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=4800 -Height=4000 -Brush color=255 255 192 -Fill Color=Yes -Brush style=6 -Brush bitmap mode=12 -Brush gradient mode=65 -Brush gradient color=255 255 255 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 178 178 178 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\TABL] -STRNFont=新宋体,8,N -STRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -OWNRDISPNAMEFont=新宋体,8,N -OWNRDISPNAMEFont color=0 0 0 -ColumnsFont=新宋体,8,N -ColumnsFont color=0 0 0 -TablePkColumnsFont=新宋体,8,U -TablePkColumnsFont color=0 0 0 -TableFkColumnsFont=新宋体,8,N -TableFkColumnsFont color=0 0 0 -KeysFont=新宋体,8,N -KeysFont color=0 0 0 -IndexesFont=新宋体,8,N -IndexesFont color=0 0 0 -TriggersFont=新宋体,8,N -TriggersFont color=0 0 0 -LABLFont=新宋体,8,N -LABLFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=4800 -Height=4000 -Brush color=178 214 252 -Fill Color=Yes -Brush style=6 -Brush bitmap mode=12 -Brush gradient mode=65 -Brush gradient color=255 255 255 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 0 128 192 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\VIEW] -STRNFont=新宋体,8,N -STRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -OWNRDISPNAMEFont=新宋体,8,N -OWNRDISPNAMEFont color=0 0 0 -ColumnsFont=新宋体,8,N -ColumnsFont color=0 0 0 -TablePkColumnsFont=新宋体,8,U -TablePkColumnsFont color=0 0 0 -TableFkColumnsFont=新宋体,8,N -TableFkColumnsFont color=0 0 0 -TemporaryVTablesFont=新宋体,8,N -TemporaryVTablesFont color=0 0 0 -IndexesFont=新宋体,8,N -IndexesFont color=0 0 0 -LABLFont=新宋体,8,N -LABLFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=4800 -Height=4000 -Brush color=208 208 255 -Fill Color=Yes -Brush style=6 -Brush bitmap mode=12 -Brush gradient mode=65 -Brush gradient color=255 255 255 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 128 128 192 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\PROC] -STRNFont=新宋体,8,N -STRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -OWNRDISPNAMEFont=新宋体,8,N -OWNRDISPNAMEFont color=0 0 0 -LABLFont=新宋体,8,N -LABLFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=4000 -Height=1000 -Brush color=255 255 192 -Fill Color=Yes -Brush style=6 -Brush bitmap mode=12 -Brush gradient mode=65 -Brush gradient color=255 255 255 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 128 108 0 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\REFR] -SOURCEFont=新宋体,8,N -SOURCEFont color=0 0 0 -CENTERFont=新宋体,8,N -CENTERFont color=0 0 0 -DESTINATIONFont=新宋体,8,N -DESTINATIONFont color=0 0 0 -Line style=1 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Brush color=255 255 255 -Fill Color=Yes -Brush style=1 -Brush bitmap mode=12 -Brush gradient mode=0 -Brush gradient color=118 118 118 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 0 128 192 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\VREF] -SOURCEFont=新宋体,8,N -SOURCEFont color=0 0 0 -CENTERFont=新宋体,8,N -CENTERFont color=0 0 0 -DESTINATIONFont=新宋体,8,N -DESTINATIONFont color=0 0 0 -Line style=1 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Brush color=255 255 255 -Fill Color=Yes -Brush style=1 -Brush bitmap mode=12 -Brush gradient mode=0 -Brush gradient color=118 118 118 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 128 128 192 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\Free Symbol] -Free TextFont=新宋体,8,N -Free TextFont color=0 0 0 -Line style=0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Brush color=255 255 255 -Fill Color=Yes -Brush style=1 -Brush bitmap mode=12 -Brush gradient mode=0 -Brush gradient color=118 118 118 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 0 0 255 -Shadow color=192 192 192 -Shadow=0 -(8268, 11693) -((315,354), (433,354)) -1 -15 - - -1634479458 -1634479458 -((2264,-5792), (3514,-872)) -((2889,-5392),(2889,-1272)) -1 -1 -12615680 -12632256 -CENTER 0 新宋体,8,N -SOURCE 0 新宋体,8,N -DESTINATION 0 新宋体,8,N - - - - - - - - - - - -1634479459 -1634479459 -((1862,-13883), (3112,-8992)) -((2487,-9392),(2487,-13483)) -1 -1 -12615680 -12632256 -CENTER 0 新宋体,8,N -SOURCE 0 新宋体,8,N -DESTINATION 0 新宋体,8,N - - - - - - - - - - - -1634474232 -1634475107 --1 -((-8597,-1272), (14375,8596)) -0 -12615680 -16570034 -12632256 -STRN 0 新宋体,8,N -DISPNAME 0 新宋体,8,N -OWNRDISPNAME 0 新宋体,8,N -Columns 0 新宋体,8,N -TablePkColumns 0 新宋体,8,U -TableFkColumns 0 新宋体,8,N -Keys 0 新宋体,8,N -Indexes 0 新宋体,8,N -Triggers 0 新宋体,8,N -LABL 0 新宋体,8,N -6 -65 -16777215 -1 - - - - - -1634479401 -1634479404 --1 -((-8999,-23351), (13973,-13483)) -0 -12615680 -16570034 -12632256 -STRN 0 新宋体,8,N -DISPNAME 0 新宋体,8,N -OWNRDISPNAME 0 新宋体,8,N -Columns 0 新宋体,8,N -TablePkColumns 0 新宋体,8,U -TableFkColumns 0 新宋体,8,N -Keys 0 新宋体,8,N -Indexes 0 新宋体,8,N -Triggers 0 新宋体,8,N -LABL 0 新宋体,8,N -6 -65 -16777215 -1 - - - - - -1634479425 -1634479430 --1 -((-8486,-9392), (14443,-5392)) -0 -12615680 -16570034 -12632256 -STRN 0 新宋体,8,N -DISPNAME 0 新宋体,8,N -OWNRDISPNAME 0 新宋体,8,N -Columns 0 新宋体,8,N -TablePkColumns 0 新宋体,8,U -TableFkColumns 0 新宋体,8,N -Keys 0 新宋体,8,N -Indexes 0 新宋体,8,N -Triggers 0 新宋体,8,N -LABL 0 新宋体,8,N -6 -65 -16777215 -1 - - - - - - - -BAF8B5BF-7B38-492B-8881-67DE30E29196 -02 - 标签 -02 - 标签 -1634474204 -Xiadao -1634476877 -Xiadao -[DisplayPreferences] - -[DisplayPreferences\PDM] - -[DisplayPreferences\General] -Adjust to text=Yes -Snap Grid=No -Constrain Labels=Yes -Display Grid=No -Show Page Delimiter=Yes -Show Links intersections=Yes -Activate automatic link routing=Yes -Grid size=800 -Graphic unit=2 -Window color=255 255 255 -Background image= -Background mode=8 -Watermark image= -Watermark mode=8 -Show watermark on screen=No -Gradient mode=0 -Gradient end color=255 255 255 -Show Swimlane=No -SwimlaneVert=Yes -TreeVert=No -CompDark=0 - -[DisplayPreferences\Object] -Show Icon=No -Mode=2 -Trunc Length=40 -Word Length=40 -Word Text=!"#$%&')*+,-./:;=>?@\]^_`|}~ -Shortcut IntIcon=Yes -Shortcut IntLoct=Yes -Shortcut IntFullPath=No -Shortcut IntLastPackage=Yes -Shortcut ExtIcon=Yes -Shortcut ExtLoct=No -Shortcut ExtFullPath=No -Shortcut ExtLastPackage=Yes -Shortcut ExtIncludeModl=Yes -Area.IconPicture=Yes -Area.Stereotype=Yes -Area.Comment=No -Area.TextStyle=No -Area.SubSymbols=Yes -Area_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Architecture Area Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <Separator Name="Separator" />[CRLF] <StandardAttribute Name="Comment" Attribute="Comment" Prefix="" Suffix="" Alignment="LEFT" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -EObjShowStrn=Yes -ExtendedObject.Comment=No -ExtendedObject.IconPicture=No -ExtendedObject.TextStyle=No -ExtendedObject_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Object Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <Separator Name="Separator" />[CRLF] <StandardAttribute Name="Comment" Attribute="Comment" Prefix="" Suffix="" Alignment="LEFT" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -ELnkShowStrn=Yes -ELnkShowName=Yes -ExtendedLink_SymbolLayout=<Form>[CRLF] <Form Name="Center" >[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] </Form>[CRLF] <Form Name="Source" >[CRLF] </Form>[CRLF] <Form Name="Destination" >[CRLF] </Form>[CRLF]</Form> -ExtDpdShowStrn=Yes -ExtendedDependency_SymbolLayout=<Form>[CRLF] <Form Name="Center" >[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Caption="" Mandatory="No" />[CRLF] </Form>[CRLF] <Form Name="Source" >[CRLF] </Form>[CRLF] <Form Name="Destination" >[CRLF] </Form>[CRLF]</Form> -FileObject.Stereotype=No -FileObject.DisplayName=Yes -FileObject.LocationOrName=No -FileObject.IconPicture=No -FileObject.TextStyle=No -FileObject.IconMode=Yes -FileObject_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <ExclusiveChoice Name="Exclusive Choice" Mandatory="Yes" Display="HorizontalRadios" >[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Location" Attribute="LocationOrName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] </ExclusiveChoice>[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -Package.Stereotype=Yes -Package.Comment=No -Package.IconPicture=No -Package.TextStyle=No -Package_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <Separator Name="Separator" />[CRLF] <StandardAttribute Name="Comment" Attribute="Comment" Prefix="" Suffix="" Alignment="LEFT" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -Display Model Version=Yes -Table.Stereotype=Yes -Table.DisplayName=Yes -Table.OwnerDisplayName=No -Table.Columns=Yes -Table.Columns._Filter="All Columns" PDMCOLNALL -Table.Columns._Columns=Stereotype DataType KeyIndicator -Table.Columns._Limit=-5 -Table.Keys=No -Table.Keys._Columns=Stereotype Indicator -Table.Indexes=No -Table.Indexes._Columns=Stereotype -Table.Triggers=No -Table.Triggers._Columns=Stereotype -Table.Comment=No -Table.IconPicture=No -Table.TextStyle=No -Table_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <ExclusiveChoice Name="Exclusive Choice" Mandatory="Yes" Display="HorizontalRadios" >[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Owner and Name" Attribute="OwnerDisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] </ExclusiveChoice>[CRLF] <Separator Name="Separator" />[CRLF] <StandardCollection Name="Columns" Collection="Columns" Columns="Stereotype No\r\nDisplayName Yes\r\nDataType No\r\nSymbolDataType No &quot;Domain or Data type&quot;\r\nDomain No\r\nKeyIndicator No\r\nIndexIndicator No\r\nNullStatus No" Filters="&quot;All Columns&quot; PDMCOLNALL &quot;&quot;\r\n&quot;PK Columns&quot; PDMCOLNPK &quot;\&quot;PRIM \&quot;TRUE\&quot; TRUE\&quot;&quot;\r\n&quot;Key Columns&quot; PDMCOLNKEY &quot;\&quot;KEYS \&quot;TRUE\&quot; TRUE\&quot;&quot;" HasLimit="Yes" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardCollection Name="Keys" Collection="Keys" Columns="Stereotype No\r\nDisplayName Yes\r\nIndicator No" HasLimit="No" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardCollection Name="Indexes" Collection="Indexes" Columns="Stereotype No\r\nDisplayName Yes\r\nIndicator No" HasLimit="No" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardCollection Name="Triggers" Collection="Triggers" Columns="Stereotype No\r\nDisplayName Yes" HasLimit="No" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Comment" Attribute="Comment" Prefix="" Suffix="" Alignment="LEFT" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -View.Stereotype=Yes -View.DisplayName=Yes -View.OwnerDisplayName=No -View.Columns=Yes -View.Columns._Columns=DisplayName -View.Columns._Limit=-5 -View.TemporaryVTables=Yes -View.Indexes=No -View.Comment=No -View.IconPicture=No -View.TextStyle=No -View_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <ExclusiveChoice Name="Exclusive Choice" Mandatory="Yes" Display="HorizontalRadios" >[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Owner and Name" Attribute="OwnerDisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] </ExclusiveChoice>[CRLF] <Separator Name="Separator" />[CRLF] <StandardCollection Name="Columns" Collection="Columns" Columns="DisplayName No\r\nExpression No\r\nDataType No\r\nSymbolDataType No &quot;Domain or Data type&quot;\r\nIndexIndicator No" HasLimit="Yes" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardCollection Name="Tables" Collection="TemporaryVTables" Columns="Name Yes" HasLimit="No" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardCollection Name="Indexes" Collection="Indexes" Columns="DisplayName Yes" HasLimit="No" HideEmpty="No" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Comment" Attribute="Comment" Prefix="" Suffix="" Alignment="LEFT" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -Procedure.Stereotype=No -Procedure.DisplayName=Yes -Procedure.OwnerDisplayName=No -Procedure.Comment=No -Procedure.IconPicture=No -Procedure.TextStyle=No -Procedure_SymbolLayout=<Form>[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <ExclusiveChoice Name="Exclusive Choice" Mandatory="Yes" Display="HorizontalRadios" >[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Owner and Name" Attribute="OwnerDisplayName" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="No" />[CRLF] </ExclusiveChoice>[CRLF] <Separator Name="Separator" />[CRLF] <StandardAttribute Name="Comment" Attribute="Comment" Prefix="" Suffix="" Alignment="LEFT" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Icon" Attribute="IconPicture" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF] <StandardAttribute Name="Force top align" Attribute="TextStyle" Prefix="" Suffix="" Alignment="CNTR" Caption="" Mandatory="Yes" />[CRLF]</Form> -Reference.Cardinality=No -Reference.ImplementationType=No -Reference.ChildRole=Yes -Reference.Stereotype=Yes -Reference.DisplayName=No -Reference.ForeignKeyConstraintName=No -Reference.JoinExpression=No -Reference.Integrity=No -Reference.ParentRole=Yes -Reference_SymbolLayout=<Form>[CRLF] <Form Name="Source" >[CRLF] <StandardAttribute Name="Cardinality" Attribute="Cardinality" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Implementation" Attribute="ImplementationType" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Child Role" Attribute="ChildRole" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] </Form>[CRLF] <Form Name="Center" >[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Caption="" Mandatory="No" />[CRLF] <ExclusiveChoice Name="Exclusive Choice" Mandatory="No" Display="HorizontalRadios" >[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Cons&amp;traint Name" Attribute="ForeignKeyConstraintName" Prefix="" Suffix="" Caption="Cons&amp;traint Name" Mandatory="No" />[CRLF] <StandardAttribute Name="Join" Attribute="JoinExpression" Prefix="" Suffix="" Caption="Join" Mandatory="No" />[CRLF] </ExclusiveChoice>[CRLF] <StandardAttribute Name="Referential integrity" Attribute="Integrity" Prefix="" Suffix="" Caption="Referential integrity" Mandatory="No" />[CRLF] </Form>[CRLF] <Form Name="Destination" >[CRLF] <StandardAttribute Name="Parent Role" Attribute="ParentRole" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] </Form>[CRLF]</Form> -ViewReference.ChildRole=Yes -ViewReference.Stereotype=Yes -ViewReference.DisplayName=No -ViewReference.JoinExpression=No -ViewReference.ParentRole=Yes -ViewReference_SymbolLayout=<Form>[CRLF] <Form Name="Source" >[CRLF] <StandardAttribute Name="Child Role" Attribute="ChildRole" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] </Form>[CRLF] <Form Name="Center" >[CRLF] <StandardAttribute Name="Stereotype" Attribute="Stereotype" Prefix="&lt;&lt;" Suffix="&gt;&gt;" Caption="" Mandatory="No" />[CRLF] <ExclusiveChoice Name="Exclusive Choice" Mandatory="No" Display="HorizontalRadios" >[CRLF] <StandardAttribute Name="Name" Attribute="DisplayName" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] <StandardAttribute Name="Join Expression" Attribute="JoinExpression" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] </ExclusiveChoice>[CRLF] </Form>[CRLF] <Form Name="Destination" >[CRLF] <StandardAttribute Name="Parent Role" Attribute="ParentRole" Prefix="" Suffix="" Caption="" Mandatory="No" />[CRLF] </Form>[CRLF]</Form> - -[DisplayPreferences\Symbol] - -[DisplayPreferences\Symbol\AREA] -STRNFont=新宋体,8,N -STRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -LABLFont=新宋体,8,N -LABLFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=9600 -Height=8000 -Brush color=253 249 234 -Fill Color=Yes -Brush style=6 -Brush bitmap mode=12 -Brush gradient mode=16 -Brush gradient color=245 230 173 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 121 98 6 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\FRMEOBJ] -STRNFont=新宋体,8,N -STRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -LABLFont=新宋体,8,N -LABLFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=6000 -Height=2000 -Brush color=255 255 255 -Fill Color=Yes -Brush style=6 -Brush bitmap mode=12 -Brush gradient mode=64 -Brush gradient color=192 192 192 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 255 128 128 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\FRMELNK] -CENTERFont=新宋体,8,N -CENTERFont color=0 0 0 -Line style=1 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Brush color=255 255 255 -Fill Color=Yes -Brush style=1 -Brush bitmap mode=12 -Brush gradient mode=0 -Brush gradient color=118 118 118 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 128 128 255 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\USRDEPD] -CENTERFont=新宋体,8,N -CENTERFont color=0 0 0 -Line style=1 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Brush color=255 255 255 -Fill Color=Yes -Brush style=1 -Brush bitmap mode=12 -Brush gradient mode=0 -Brush gradient color=118 118 118 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=2 0 128 128 255 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\FILO] -OBJSTRNFont=新宋体,8,N -OBJSTRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -LCNMFont=新宋体,8,N -LCNMFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=4800 -Height=3600 -Brush color=255 255 255 -Fill Color=Yes -Brush style=1 -Brush bitmap mode=12 -Brush gradient mode=0 -Brush gradient color=118 118 118 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 0 0 255 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\PDMPCKG] -STRNFont=新宋体,8,N -STRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -LABLFont=新宋体,8,N -LABLFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=4800 -Height=4000 -Brush color=255 255 192 -Fill Color=Yes -Brush style=6 -Brush bitmap mode=12 -Brush gradient mode=65 -Brush gradient color=255 255 255 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 178 178 178 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\TABL] -STRNFont=新宋体,8,N -STRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -OWNRDISPNAMEFont=新宋体,8,N -OWNRDISPNAMEFont color=0 0 0 -ColumnsFont=新宋体,8,N -ColumnsFont color=0 0 0 -TablePkColumnsFont=新宋体,8,U -TablePkColumnsFont color=0 0 0 -TableFkColumnsFont=新宋体,8,N -TableFkColumnsFont color=0 0 0 -KeysFont=新宋体,8,N -KeysFont color=0 0 0 -IndexesFont=新宋体,8,N -IndexesFont color=0 0 0 -TriggersFont=新宋体,8,N -TriggersFont color=0 0 0 -LABLFont=新宋体,8,N -LABLFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=4800 -Height=4000 -Brush color=178 214 252 -Fill Color=Yes -Brush style=6 -Brush bitmap mode=12 -Brush gradient mode=65 -Brush gradient color=255 255 255 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 0 128 192 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\VIEW] -STRNFont=新宋体,8,N -STRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -OWNRDISPNAMEFont=新宋体,8,N -OWNRDISPNAMEFont color=0 0 0 -ColumnsFont=新宋体,8,N -ColumnsFont color=0 0 0 -TablePkColumnsFont=新宋体,8,U -TablePkColumnsFont color=0 0 0 -TableFkColumnsFont=新宋体,8,N -TableFkColumnsFont color=0 0 0 -TemporaryVTablesFont=新宋体,8,N -TemporaryVTablesFont color=0 0 0 -IndexesFont=新宋体,8,N -IndexesFont color=0 0 0 -LABLFont=新宋体,8,N -LABLFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=4800 -Height=4000 -Brush color=208 208 255 -Fill Color=Yes -Brush style=6 -Brush bitmap mode=12 -Brush gradient mode=65 -Brush gradient color=255 255 255 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 128 128 192 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\PROC] -STRNFont=新宋体,8,N -STRNFont color=0 0 0 -DISPNAMEFont=新宋体,8,N -DISPNAMEFont color=0 0 0 -OWNRDISPNAMEFont=新宋体,8,N -OWNRDISPNAMEFont color=0 0 0 -LABLFont=新宋体,8,N -LABLFont color=0 0 0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Width=4000 -Height=1000 -Brush color=255 255 192 -Fill Color=Yes -Brush style=6 -Brush bitmap mode=12 -Brush gradient mode=65 -Brush gradient color=255 255 255 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 128 108 0 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\REFR] -SOURCEFont=新宋体,8,N -SOURCEFont color=0 0 0 -CENTERFont=新宋体,8,N -CENTERFont color=0 0 0 -DESTINATIONFont=新宋体,8,N -DESTINATIONFont color=0 0 0 -Line style=1 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Brush color=255 255 255 -Fill Color=Yes -Brush style=1 -Brush bitmap mode=12 -Brush gradient mode=0 -Brush gradient color=118 118 118 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 0 128 192 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\VREF] -SOURCEFont=新宋体,8,N -SOURCEFont color=0 0 0 -CENTERFont=新宋体,8,N -CENTERFont color=0 0 0 -DESTINATIONFont=新宋体,8,N -DESTINATIONFont color=0 0 0 -Line style=1 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Brush color=255 255 255 -Fill Color=Yes -Brush style=1 -Brush bitmap mode=12 -Brush gradient mode=0 -Brush gradient color=118 118 118 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 128 128 192 -Shadow color=192 192 192 -Shadow=0 - -[DisplayPreferences\Symbol\Free Symbol] -Free TextFont=新宋体,8,N -Free TextFont color=0 0 0 -Line style=0 -AutoAdjustToText=Yes -Keep aspect=No -Keep center=No -Keep size=No -Brush color=255 255 255 -Fill Color=Yes -Brush style=1 -Brush bitmap mode=12 -Brush gradient mode=0 -Brush gradient color=118 118 118 -Brush background image= -Custom shape= -Custom text mode=0 -Pen=1 0 0 0 255 -Shadow color=192 192 192 -Shadow=0 -(8268, 11693) -((315,354), (433,354)) -1 -15 - - -1634476877 -1634476877 --1 -((-11486,-4934), (11486,4934)) -0 -12615680 -16570034 -12632256 -STRN 0 新宋体,8,N -DISPNAME 0 新宋体,8,N -OWNRDISPNAME 0 新宋体,8,N -Columns 0 新宋体,8,N -TablePkColumns 0 新宋体,8,U -TableFkColumns 0 新宋体,8,N -Keys 0 新宋体,8,N -Indexes 0 新宋体,8,N -Triggers 0 新宋体,8,N -LABL 0 新宋体,8,N -6 -65 -16777215 -1 - - - - - - - - - - - - -AD5D38BE-D347-4730-9E27-61B07401B54F -贴子( Post ) -Post -1634474232 -Xiadao -1634475057 -Xiadao -贴子 - - - -9C6B17C1-0BC3-4E5A-9BFE-DA9EB826215B -贴子标识( PostId ) -PostId -1634474232 -Xiadao -1634474886 -Xiadao -贴子标识 -uniqueidentifier -1 - - -24A86E90-D048-47AB-8494-8B710CEF76B2 -标题( Title ) -Title -1634475012 -Xiadao -1634475050 -Xiadao -标题 -nvarchar(200) -200 - - -9E716B3E-83C9-48FA-8653-7A3CBF1D830F -内容( Content ) -Content -1634475024 -Xiadao -1634475098 -Xiadao -内容 -nvarchar(max) - - -0817F3C5-C814-4EEB-AF12-FC7011041E4C -创建时间( CreationTime ) -CreationTime -1634474232 -Xiadao -1634474232 -Xiadao -创建时间 -datetime - - -12CE5BFA-2E78-4BCF-AB26-7A385A929A04 -创建人( CreatorId ) -CreatorId -1634474232 -Xiadao -1634474232 -Xiadao -创建人 -uniqueidentifier - - -7D319909-9F8D-4E1A-8D56-E2610BB9965F -最后修改时间( LastModificationTime ) -LastModificationTime -1634474232 -Xiadao -1634474232 -Xiadao -最后修改时间 -datetime - - -53467064-BC0C-4E59-950B-D315922DF76A -最后修改人( LastModifierId ) -LastModifierId -1634474232 -Xiadao -1634474232 -Xiadao -最后修改人 -uniqueidentifier - - -517E8891-2178-486D-ADF1-C5C97CE2EA73 -是否删除( IsDeleted ) -IsDeleted -1634474232 -Xiadao -1634474232 -Xiadao -是否删除 -bit -1 - - -7F85AB0F-4461-4CF5-8B88-DD31DA801207 -版本号( Version ) -Version -1634474232 -Xiadao -1634474232 -Xiadao -版本号 -timestamp - - - - -BC4763C8-712B-4794-BA5E-60E44783C441 -Key_1 -Key_1 -1634474232 -Xiadao -1634474232 -Xiadao - - - - - - - - - - - - - - - - -59F96735-771C-4357-ADD4-2320DD4DEC35 -标签( Tag ) -Tag -1634476877 -Xiadao -1634479393 -Xiadao -标签 - - - -86DF057E-2824-43ED-BA24-A0DC217C0AE3 -标签标识( TagId ) -TagId -1634476877 -Xiadao -1634477808 -Xiadao -标签标识 -uniqueidentifier -1 - - -E737B960-5739-4FBD-A17A-15A05F628EE7 -标签名称( Name ) -Name -1634476877 -Xiadao -1634479390 -Xiadao -标签名称 -nvarchar(200) -200 - - -E8080B7D-AC52-4AE9-915D-3F9833507F0F -创建时间( CreationTime ) -CreationTime -1634476877 -Xiadao -1634476877 -Xiadao -创建时间 -datetime - - -D864B12A-89CB-455D-992D-73C4C8B0F8CF -创建人( CreatorId ) -CreatorId -1634476877 -Xiadao -1634476877 -Xiadao -创建人 -uniqueidentifier - - -B7D6FEDF-E506-4E72-B07E-9E43CA7586B8 -最后修改时间( LastModificationTime ) -LastModificationTime -1634476877 -Xiadao -1634476877 -Xiadao -最后修改时间 -datetime - - -9BF7A667-53B0-4C14-AFE3-2BDC35E6D98D -最后修改人( LastModifierId ) -LastModifierId -1634476877 -Xiadao -1634476877 -Xiadao -最后修改人 -uniqueidentifier - - -CC86B34B-17D4-4646-9083-67CB26C9BCB6 -是否删除( IsDeleted ) -IsDeleted -1634476877 -Xiadao -1634476877 -Xiadao -是否删除 -bit -1 - - -917F88C5-D945-4985-88AC-F9E7EEF26A20 -版本号( Version ) -Version -1634476877 -Xiadao -1634476877 -Xiadao -版本号 -timestamp - - - - -9FEC9F44-352A-417D-BF86-0E0B7B0CD479 -Key_1 -Key_1 -1634476877 -Xiadao -1634476877 -Xiadao - - - - - - - - - - - - - - - - -EE018CC5-5B90-4B18-812F-23CF6A62CEB8 -贴子标签( PostTag ) -PostTag -1634479425 -Xiadao -1634479678 -Xiadao -贴子标签 - - - -AB478AEC-D7B9-41A0-89D4-7105B613005E -贴子标识( PostId ) -PostId -1634479458 -Xiadao -1634479466 -Xiadao -贴子标识 -uniqueidentifier -1 -1 - - -1A893A25-070C-4021-8586-54F8184DE82B -标签标识( TagId ) -TagId -1634479459 -Xiadao -1634479466 -Xiadao -标签标识 -uniqueidentifier -1 -1 - - - - -77A13292-0F54-4E5F-A383-FDCBC1365C4B -Key_1 -Key_1 -1634479461 -Xiadao -1634479466 -Xiadao - - - - - - - - - - - - - - - - - - - -D5309618-C047-447B-8DE9-E414DAAE10E6 -Reference_5 -Reference_5 -1634479458 -Xiadao -1634479458 -Xiadao -0..* - - - - - - - - - - - -970BA17E-3EB3-4216-B9FF-60F8F48FCFB2 -1634479458 -Xiadao -1634479458 -Xiadao - - - - - - - - - - -692D0A36-D763-4AE5-B8FA-8C44E75FF676 -Reference_6 -Reference_6 -1634479459 -Xiadao -1634479459 -Xiadao -0..* - - - - - - - - - - - -BE5EE49E-8AC3-4876-AC26-C89DA2B1E8C7 -1634479459 -Xiadao -1634479459 -Xiadao - - - - - - - - - - - - - - - - - -89128D3A-55E9-4B29-B560-E400E18B70B1 -客户( Customers ) -Customers -1631784547 -Xiadao -1634474807 -Xiadao -Schema - - -915433E0-4A0F-426D-BC0E-C0359F88BF04 -销售( Sales ) -Sales -1631776192 -Xiadao -1631776192 -Xiadao -Schema - - -1DEAC531-1773-4DDC-BEAE-B1A35BEBE14C -商品( Products ) -Products -1630573318 -Xiadao -1630573931 -Xiadao -Schema - - -0CF6239F-4164-45DF-8938-51466B41925C -系统( Systems ) -Systems -1628410313 -Xiadao -1630573931 -Xiadao -Schema - - -AF2EB7EE-8810-4EE5-B730-9398534C9C6D -博客( Blogs ) -Blogs -1634474809 -Xiadao -1634479678 -Xiadao -Schema - - - - -A23AC743-1D1E-443A-B485-E4B2622424BD -测试_01_1( Test_01_1 ) -Test_01_1 -1625384268 -Xiadao -1629976764 -Xiadao -测试_01_1 - - - -DD65CB8E-9805-46DC-AAFD-C7A11369E2BA -测试标识( TestId ) -TestId -1625384268 -Xiadao -1625384268 -Xiadao -测试标识 -uniqueidentifier -1 - - -9BBDB808-B190-4EB1-AC90-0D5427AE2D47 -字符串值( StringValue ) -StringValue -1625384268 -Xiadao -1625384268 -Xiadao -字符串值 -nvarchar(200) -200 - - -9C8F3B63-4EAC-4C61-96AB-8F67CBEB9B6E -整型值( IntValue ) -IntValue -1625733148 -Xiadao -1625738048 -Xiadao -整型值 -int - - -F21FBB89-DA2A-4AFF-910E-E36B4661291E -可空整型值( NullableIntValue ) -NullableIntValue -1625754273 -Xiadao -1625754399 -Xiadao -可空整型值 -int - - -35A58EB3-7253-49EB-9B1D-945C918A94B0 -长整型值( LongValue ) -LongValue -1625763436 -Xiadao -1625763483 -Xiadao -长整型值 -bigint - - -B10CEFAD-3CE3-4DE9-95F1-A680A1DF9656 -可空长整型值( NullableLongValue ) -NullableLongValue -1625763450 -Xiadao -1625763544 -Xiadao -可空长整型值 -bigint - - -84A19594-775B-473D-BA0E-DBBF37305BDC -Guid值( GuidValue ) -GuidValue -1625757818 -Xiadao -1625757888 -Xiadao -Guid值 -uniqueidentifier - - -E9A1F657-BD25-46C1-8A8E-34706C639400 -可空Guid值( NullableGuidValue ) -NullableGuidValue -1625758168 -Xiadao -1625758209 -Xiadao -可空Guid值 -uniqueidentifier - - -9F7697FB-9C08-4961-AC14-03E7A887E810 -布尔值( BoolValue ) -BoolValue -1625761946 -Xiadao -1625761986 -Xiadao -布尔值 -bit - - -13C8246B-030B-4929-ADAF-DF548AF4F82C -可空布尔值( NullableBoolValue ) -NullableBoolValue -1625761955 -Xiadao -1625762042 -Xiadao -可空布尔值 -bit - - -4B7969F3-FBBF-4D61-AC5D-8EB53CAD71B5 -Float类型值( FloatValue ) -FloatValue -1625807474 -Xiadao -1625808138 -Xiadao -Float类型值 -decimal(6,2) -6 -2 - - -1D826AA0-8623-47AA-97C8-42194B3AAC5A -可空Float类型值( NullableFloatValue ) -NullableFloatValue -1625807501 -Xiadao -1625808177 -Xiadao -可空Float类型值 -decimal(6,2) -6 -2 - - -0F2BF198-6CAD-461C-B0A2-22DEF2F11702 -Double类型值( DoubleValue ) -DoubleValue -1625808087 -Xiadao -1625808252 -Xiadao -Double类型值 -decimal(10,2) -10 -2 - - -52628F06-F40A-40B2-813E-4D0450CAB7C1 -可空Double类型值( NullableDoubleValue ) -NullableDoubleValue -1625808189 -Xiadao -1625808340 -Xiadao -可空Double类型值 -decimal(10,2) -10 -2 - - -9D7E2288-0B05-4266-BC31-1F5A422C1FBB -Decimal类型值( DecimalValue ) -DecimalValue -1625808317 -Xiadao -1625808409 -Xiadao -Decimal类型值 -decimal(18,2) -18 -2 - - -2EA0032B-D7DF-4400-9C55-0B78485C2C24 -可空Decimal类型值( NullableDecimalValue ) -NullableDecimalValue -1625808368 -Xiadao -1625808513 -Xiadao -可空Decimal类型值 -decimal(18,2) -18 -2 - - -1AC443F7-9DDF-4F3D-9DD0-F34751130003 -日期值( DateTimeValue ) -DateTimeValue -1625813374 -Xiadao -1625813477 -Xiadao -日期值 -datetime - - -A200D0F5-6515-4DAE-B746-AF9F93A7C40C -可空日期值( NullableDateTimeValue ) -NullableDateTimeValue -1625813382 -Xiadao -1625813615 -Xiadao -可空日期值 -datetime - - -ED06EEF6-48FA-461A-A0D8-188F81824B6B -是否删除( IsDeleted ) -IsDeleted -1625384268 -Xiadao -1625384268 -Xiadao -是否删除 -bit -1 - - -26135B4E-C152-4366-AA96-2752F5D6C195 -版本号( Version ) -Version -1625384268 -Xiadao -1625384268 -Xiadao -版本号 -timestamp - - - - -E61F4AF7-53EE-42D7-BCD9-D2C33917044E -Key_1 -Key_1 -1625384268 -Xiadao -1625384268 -Xiadao - - - - - - - - - - - - - -85C2885C-6163-4D07-9F34-16EC2B672F9A -测试_02_1( Test_02_1 ) -Test_02_1 -1625641883 -Xiadao -1629976764 -Xiadao -测试_02_1 - - - -1DDD3CBF-DFE5-4946-B7A9-7A2750D5CF9D -测试标识( TestId ) -TestId -1625641883 -Xiadao -1625641883 -Xiadao -测试标识 -uniqueidentifier -1 - - -72294AE2-1A16-4F92-9AFF-94E6888B491C -字符串值( StringValue ) -StringValue -1625641883 -Xiadao -1625641883 -Xiadao -字符串值 -nvarchar(200) -200 - - -551C30A8-0238-42C1-8ABE-55A4D4446226 -是否删除( IsDeleted ) -IsDeleted -1625641883 -Xiadao -1625641883 -Xiadao -是否删除 -bit -1 - - -09C0E454-0C0F-40CF-AA21-F2205320F66B -版本号( Version ) -Version -1625641883 -Xiadao -1625641883 -Xiadao -版本号 -timestamp - - - - -145A09A4-174E-4E22-884F-3058EF41E66B -Key_1 -Key_1 -1625641883 -Xiadao -1625641883 -Xiadao - - - - - - - - - - - - - -9BE7BBD0-F492-409F-A5C5-EAA52DE959C7 -测试_02_2( Test_02_2 ) -Test_02_2 -1625643974 -Xiadao -1629976764 -Xiadao -测试_02_2 - - - -62614651-555E-411C-BD3D-50B39CE09519 -测试标识( TestId ) -TestId -1625643974 -Xiadao -1625644021 -Xiadao -测试标识 -int -1 -1 - - -9705FC9E-7BB9-42DF-B714-EAB5003DAFCB -字符串值( StringValue ) -StringValue -1625643974 -Xiadao -1625643974 -Xiadao -字符串值 -nvarchar(200) -200 - - -BC5E95DD-59A3-47C0-9E13-FE5F65EC00D3 -是否删除( IsDeleted ) -IsDeleted -1625643974 -Xiadao -1625643974 -Xiadao -是否删除 -bit -1 - - -8621A90B-AAEB-4D1F-A34C-3E1E4AC52878 -版本号( Version ) -Version -1625643974 -Xiadao -1625643974 -Xiadao -版本号 -timestamp - - - - -A03D5F69-AD63-4F06-9F41-6AE74D941595 -Key_1 -Key_1 -1625643974 -Xiadao -1625643974 -Xiadao - - - - - - - - - - - - - -36435A44-E741-470A-B4E2-75727584D6DF -测试_02_3( Test_02_3 ) -Test_02_3 -1625645031 -Xiadao -1629976764 -Xiadao -测试_02_3 - - - -4C4E9141-7D92-4351-AC22-09672129AE64 -测试标识( TestId ) -TestId -1625645031 -Xiadao -1625645064 -Xiadao -测试标识 -nvarchar(50) -50 -1 - - -182304E9-5E2E-436E-97C3-194BCAA273DB -字符串值( StringValue ) -StringValue -1625645031 -Xiadao -1625645031 -Xiadao -字符串值 -nvarchar(200) -200 - - -1BE996FB-0C7E-42B9-BA64-E380FBF9CB43 -是否删除( IsDeleted ) -IsDeleted -1625645031 -Xiadao -1625645031 -Xiadao -是否删除 -bit -1 - - -6391D967-BAD3-410E-B903-CF0D9B96C09C -版本号( Version ) -Version -1625645031 -Xiadao -1625645031 -Xiadao -版本号 -timestamp - - - - -8FDCCA80-2028-4A81-94B5-9FEC46B1F18B -Key_1 -Key_1 -1625645031 -Xiadao -1625645031 -Xiadao - - - - - - - - - - - - - - - -4CD0ACF6-CD47-4391-B0FC-4B4C438DC549 -PUBLIC -PUBLIC -1621773500 -Xiadao -1634474813 -Xiadao - - - - - - - - - - - -7B0C4DC9-5999-4989-98A6-E5851A4E1E49 -Microsoft SQL Server 2014 -MSSQLSRV2014 -1621773500 -Xiadao -1402992778 -Xiadao -file:///%[XDB]%/sqlsv2014.xdb -49106F9E-F946-45DB-871A-64C75D3FA370 -4BA9F647-DAB1-11D1-9944-006097355D9B -1402992778 - - - - - -DBD7197E-E726-4C1B-94CE-17D88F90AAB6 -Util_Data_EF_Test_SqlServer -Util_Data_EF_Test_SqlServer -1631785959 -Xiadao -1634479459 -Xiadao -file:///. -BD608590-48FF-4C8E-8926-A4C7815777DB -CDE44E21-9669-11D1-9914-006097355D9B -1634479678 - - - - - - - - - - - \ No newline at end of file diff --git a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Fakes/CustomerFakeService.cs b/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Fakes/CustomerFakeService.cs deleted file mode 100644 index 796d330b..00000000 --- a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Fakes/CustomerFakeService.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using AutoBogus; -using Util.Data.EntityFrameworkCore.Models; - -namespace Util.Data.EntityFrameworkCore.Fakes { - /// - /// 客户模拟数据服务 - /// - public static class CustomerFakeService { - /// - /// 获取客户 - /// - public static Customer GetCustomer() { - return GetCustomers( 1 ).First(); - } - - /// - /// 获取客户列表 - /// - /// 行数 - public static List GetCustomers( int count ) { - return new AutoFaker() - .RuleFor( t => t.Code, t => t.Random.String2( 1, 100 ) ) - .RuleFor( t => t.Name, t => t.Random.String2( 1, 200 ) ) - .RuleFor( t => t.Nickname, t => t.Random.String2( 1, 50 ) ) - .RuleFor( t => t.Phone, t => t.Random.String2( 1, 50 ) ) - .RuleFor( t => t.Email, t => t.Random.String2( 1, 500 ) ) - .RuleFor( t => t.IsDeleted, false ) - .Generate( count ); - } - } -} \ No newline at end of file diff --git a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Fakes/OperationLogFakeService.cs b/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Fakes/OperationLogFakeService.cs deleted file mode 100644 index 150f3ba3..00000000 --- a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Fakes/OperationLogFakeService.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using AutoBogus; -using Util.Data.EntityFrameworkCore.Models; - -namespace Util.Data.EntityFrameworkCore.Fakes { - /// - /// 操作日志模拟数据服务 - /// - public static class OperationLogFakeService { - /// - /// 获取操作日志 - /// - public static OperationLog GetOperationLog() { - return GetOperationLogs( 1 ).First(); - } - - /// - /// 获取操作日志列表 - /// - /// 行数 - public static List GetOperationLogs( int count ) { - return new AutoFaker() - .Generate( count ); - } - } -} \ No newline at end of file diff --git a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Fakes/OrderItemFakeService.cs b/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Fakes/OrderItemFakeService.cs deleted file mode 100644 index c0629669..00000000 --- a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Fakes/OrderItemFakeService.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using AutoBogus; -using Util.Data.EntityFrameworkCore.Models; - -namespace Util.Data.EntityFrameworkCore.Fakes { - /// - /// 订单明细模拟数据服务 - /// - public static class OrderItemFakeService { - /// - /// 获取订单明细 - /// - public static OrderItem GetOrderItem() { - return GetOrderItems( 1 ).First(); - } - - /// - /// 获取订单明细列表 - /// - /// 行数 - public static List GetOrderItems( int count ) { - return new AutoFaker() - .Ignore( t => t.Order ) - .Generate( count ); - } - } -} \ No newline at end of file diff --git a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Fakes/ProductFakeService.cs b/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Fakes/ProductFakeService.cs deleted file mode 100644 index c9ee7992..00000000 --- a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Fakes/ProductFakeService.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using AutoBogus; -using Util.Data.EntityFrameworkCore.Models; - -namespace Util.Data.EntityFrameworkCore.Fakes { - /// - /// 产品模拟数据服务 - /// - public static class ProductFakeService { - /// - /// 获取产品 - /// - public static Product GetProduct() { - return GetProducts( 1 ).First(); - } - - /// - /// 获取产品列表 - /// - /// 行数 - public static List GetProducts( int count ) { - return new AutoFaker() - .RuleFor( t => t.Code, t => t.Random.String2( 1, 50 ) ) - .RuleFor( t => t.Name, t => t.Random.String2( 1, 500 ) ) - .RuleFor( t => t.IsDeleted, false ) - .Ignore( t => t.TestProperty1 ) - .Generate( count ); - } - } -} \ No newline at end of file diff --git a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Infrastructure/TestBase.cs b/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Infrastructure/TestBase.cs deleted file mode 100644 index 618c8b7d..00000000 --- a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Infrastructure/TestBase.cs +++ /dev/null @@ -1,18 +0,0 @@ -namespace Util.Data.EntityFrameworkCore.Infrastructure { - /// - /// 测试基类 - /// - public abstract class TestBase { - /// - /// 测试初始化 - /// - protected TestBase( IUnitOfWork unitOfWork ) { - UnitOfWork = unitOfWork; - } - - /// - /// 工作单元 - /// - protected IUnitOfWork UnitOfWork { get; } - } -} \ No newline at end of file diff --git a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Models/Customer.cs b/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Models/Customer.cs deleted file mode 100644 index 964790ed..00000000 --- a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Models/Customer.cs +++ /dev/null @@ -1,116 +0,0 @@ -using System; -using System.ComponentModel; -using System.ComponentModel.DataAnnotations; -using Util.Domain; -using Util.Domain.Biz.Enums; -using Util.Domain.Entities; - -namespace Util.Data.EntityFrameworkCore.Models { - /// - /// 客户 - /// - [Description( "客户" )] - public class Customer : AggregateRoot,IDelete { - /// - /// 初始化客户 - /// - public Customer() : this( 0 ) { - } - - /// - /// 初始化客户 - /// - /// 客户标识 - public Customer( int id ) : base( id ) { - } - - /// - /// 编码 - /// - [Description( "编码" )] - [MaxLength( 100 )] - public string Code { get; set; } - /// - /// 姓名 - /// - [Description( "姓名" )] - [MaxLength( 200 )] - public string Name { get; set; } - /// - /// 昵称 - /// - [Description( "昵称" )] - [MaxLength( 50 )] - public string Nickname { get; set; } - /// - /// 性别 - /// - [Description( "性别" )] - public Gender? Gender { get; set; } - /// - /// 出生日期 - /// - [Description( "出生日期" )] - public DateTime? Birthday { get; set; } - /// - /// 民族 - /// - [Description( "民族" )] - public Nation? Nation { get; set; } - /// - /// 手机号 - /// - [Description( "手机号" )] - [MaxLength( 50 )] - public string Phone { get; set; } - /// - /// 电子邮件 - /// - [Description( "电子邮件" )] - [MaxLength( 500 )] - public string Email { get; set; } - /// - /// 创建时间 - /// - [Description( "创建时间" )] - public DateTime? CreationTime { get; set; } - /// - /// 创建人 - /// - [Description( "创建人" )] - public Guid? CreatorId { get; set; } - /// - /// 最后修改时间 - /// - [Description( "最后修改时间" )] - public DateTime? LastModificationTime { get; set; } - /// - /// 最后修改人 - /// - [Description( "最后修改人" )] - public Guid? LastModifierId { get; set; } - /// - /// 是否删除 - /// - [Description( "是否删除" )] - public bool IsDeleted { get; set; } - - /// - /// 添加变更列表 - /// - protected override void AddChanges( Customer other ) { - AddChange( t => t.Code, other.Code ); - AddChange( t => t.Name, other.Name ); - AddChange( t => t.Nickname, other.Nickname ); - AddChange( t => t.Gender, other.Gender ); - AddChange( t => t.Birthday, other.Birthday ); - AddChange( t => t.Nation, other.Nation ); - AddChange( t => t.Phone, other.Phone ); - AddChange( t => t.Email, other.Email ); - AddChange( t => t.CreationTime, other.CreationTime ); - AddChange( t => t.CreatorId, other.CreatorId ); - AddChange( t => t.LastModificationTime, other.LastModificationTime ); - AddChange( t => t.LastModifierId, other.LastModifierId ); - } - } -} \ No newline at end of file diff --git a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Models/Order.cs b/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Models/Order.cs deleted file mode 100644 index 725f6e9e..00000000 --- a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Models/Order.cs +++ /dev/null @@ -1,80 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.ComponentModel.DataAnnotations; -using Util.Domain; -using Util.Domain.Entities; - -namespace Util.Data.EntityFrameworkCore.Models { - /// - /// 订单 - /// - [Description( "订单" )] - public class Order : AggregateRoot, IDelete { - /// - /// 初始化订单 - /// - public Order() : this( string.Empty ) { - } - - /// - /// 初始化订单 - /// - /// 订单标识 - public Order( string id ) : base( id ) { - OrderItems = new List(); - } - - /// - /// 客户标识 - /// - [Description( "客户标识" )] - [Required( ErrorMessage = "客户标识不能为空" )] - public int CustomerId { get; set; } - /// - /// 客户名称 - /// - [Description( "客户名称" )] - [MaxLength( 200 )] - public string CustomerName { get; set; } - /// - /// 金额 - /// - [Description( "金额" )] - [Required( ErrorMessage = "金额不能为空" )] - public decimal Amount { get; set; } - /// - /// 下单时间 - /// - [Description( "下单时间" )] - [Required( ErrorMessage = "下单时间不能为空" )] - public DateTime PlaceOrderTime { get; set; } - /// - /// 订单状态 - /// - [Description( "订单状态" )] - [Required( ErrorMessage = "订单状态不能为空" )] - public int State { get; set; } - /// - /// 是否删除 - /// - [Description( "是否删除" )] - public bool IsDeleted { get; set; } - - /// - /// 订单项列表 - /// - public ICollection OrderItems { get; set; } - - /// - /// 添加变更列表 - /// - protected override void AddChanges( Order other ) { - AddChange( t => t.CustomerId, other.CustomerId ); - AddChange( t => t.CustomerName, other.CustomerName ); - AddChange( t => t.Amount, other.Amount ); - AddChange( t => t.PlaceOrderTime, other.PlaceOrderTime ); - AddChange( t => t.State, other.State ); - } - } -} \ No newline at end of file diff --git a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Models/OrderItem.cs b/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Models/OrderItem.cs deleted file mode 100644 index c1f86a25..00000000 --- a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Models/OrderItem.cs +++ /dev/null @@ -1,71 +0,0 @@ -using System; -using System.ComponentModel; -using System.ComponentModel.DataAnnotations; -using Util.Domain.Entities; - -namespace Util.Data.EntityFrameworkCore.Models { - /// - /// 订单明细 - /// - [Description( "订单明细" )] - public class OrderItem : EntityBase { - /// - /// 初始化订单明细 - /// - public OrderItem() : this( Guid.Empty ) { - } - - /// - /// 初始化订单明细 - /// - /// 订单明细标识 - public OrderItem( Guid id ) : base( id ) { - } - - /// - /// 订单标识 - /// - [Description( "订单标识" )] - [Required( ErrorMessage = "订单标识不能为空" )] - [MaxLength( 256 )] - public string OrderId { get; set; } - /// - /// 产品标识 - /// - [Description( "产品标识" )] - public Guid? ProductId { get; set; } - /// - /// 产品名称 - /// - [Description( "产品名称" )] - [Required( ErrorMessage = "产品名称不能为空" )] - [MaxLength( 500 )] - public string ProductName { get; set; } - /// - /// 单价 - /// - [Description( "单价" )] - public decimal Price { get; set; } - /// - /// 数量 - /// - [Description( "数量" )] - public int Quantity { get; set; } - - /// - /// 订单 - /// - public Order Order { get; set; } - - /// - /// 添加变更列表 - /// - protected override void AddChanges( OrderItem other ) { - AddChange( t => t.OrderId, other.OrderId ); - AddChange( t => t.ProductId, other.ProductId ); - AddChange( t => t.ProductName, other.ProductName ); - AddChange( t => t.Price, other.Price ); - AddChange( t => t.Quantity, other.Quantity ); - } - } -} \ No newline at end of file diff --git a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Models/Product.cs b/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Models/Product.cs deleted file mode 100644 index 098d95b5..00000000 --- a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Models/Product.cs +++ /dev/null @@ -1,149 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.ComponentModel.DataAnnotations; -using System.ComponentModel.DataAnnotations.Schema; -using Util.Domain; -using Util.Domain.Auditing; -using Util.Domain.Entities; -using Util.Domain.Extending; - -namespace Util.Data.EntityFrameworkCore.Models { - /// - /// 产品 - /// - [Description( "产品" )] - public class Product : AggregateRoot, IDelete, IAudited, IExtraProperties { - /// - /// 初始化产品 - /// - public Product() : this( Guid.Empty ) { - } - - /// - /// 初始化产品 - /// - /// 产品标识 - public Product( Guid id ) : base( id ) { - TestProperty2 = new ProductItem(); - TestProperty4 = new ProductItem2(); - TestProperties = new List(); - } - - /// - /// 产品编码 - /// - [Description( "产品编码" )] - [MaxLength( 50 )] - public string Code { get; set; } - /// - /// 产品名称 - /// - [Description( "产品名称" )] - [MaxLength( 500 )] - public string Name { get; set; } - /// - /// 价格 - /// - [Description( "价格" )] - public decimal Price { get; set; } - /// - /// 描述 - /// - [Description( "描述" )] - public string Description { get; set; } - /// - /// 启用 - /// - [Description( "启用" )] - public bool Enabled { get; set; } - /// - /// 创建时间 - /// - [Description( "创建时间" )] - public DateTime? CreationTime { get; set; } - /// - /// 创建人 - /// - [Description( "创建人" )] - public Guid? CreatorId { get; set; } - /// - /// 最后修改时间 - /// - [Description( "最后修改时间" )] - public DateTime? LastModificationTime { get; set; } - /// - /// 最后修改人 - /// - [Description( "最后修改人" )] - public Guid? LastModifierId { get; set; } - /// - /// 是否删除 - /// - [Description( "是否删除" )] - public bool IsDeleted { get; set; } - - /// - /// 简单扩展属性 - /// - [NotMapped] - public string TestProperty1 { - get => ExtraProperties.GetProperty( nameof( TestProperty1 ) ); - set => ExtraProperties.SetProperty( nameof(TestProperty1), value ); - } - - private readonly ExtraProperty _property2 = new(nameof( TestProperty2 ) ); - /// - /// 对象扩展属性 - /// - [NotMapped] - public ProductItem TestProperty2 { - get => _property2.GetProperty( ExtraProperties ); - set => _property2.SetProperty( ExtraProperties,value ); - } - - /// - /// 枚举扩展属性 - /// - [NotMapped] - public ProductEnum? TestProperty3 { - get => ExtraProperties.GetProperty( nameof( TestProperty3 ) ); - set => ExtraProperties.SetProperty( nameof( TestProperty3 ), value ); - } - - private readonly ExtraProperty _property4 = new( nameof( TestProperty4 ) ); - /// - /// 不可变对象扩展属性 - /// - [NotMapped] - public ProductItem2 TestProperty4 { - get => _property4.GetProperty( ExtraProperties ); - set => _property4.SetProperty( ExtraProperties, value ); - } - - private readonly ExtraProperty> _properties = new( nameof( TestProperties ) ); - /// - /// 对象集合扩展属性 - /// - [NotMapped] - public List TestProperties { - get => _properties.GetProperty( ExtraProperties ); - set => _properties.SetProperty( ExtraProperties,value ); - } - - /// - /// 添加变更列表 - /// - protected override void AddChanges( Product other ) { - AddChange( t => t.Code, other.Code ); - AddChange( t => t.Name, other.Name ); - AddChange( t => t.Price, other.Price ); - AddChange( t => t.Description, other.Description ); - AddChange( t => t.Enabled, other.Enabled ); - AddChange( t => t.CreationTime, other.CreationTime ); - AddChange( t => t.CreatorId, other.CreatorId ); - AddChange( t => t.LastModificationTime, other.LastModificationTime ); - AddChange( t => t.LastModifierId, other.LastModifierId ); - } - } -} \ No newline at end of file diff --git a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Models/ProductEnum.cs b/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Models/ProductEnum.cs deleted file mode 100644 index 0b41f04e..00000000 --- a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Models/ProductEnum.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Util.Data.EntityFrameworkCore.Models { - /// - /// 用于测试枚举扩展属性 - /// - public enum ProductEnum { - Hello, - World - } -} diff --git a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Repositories/ICustomerRepository.cs b/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Repositories/ICustomerRepository.cs deleted file mode 100644 index f7b64097..00000000 --- a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Repositories/ICustomerRepository.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Util.Data.EntityFrameworkCore.Models; -using Util.Domain.Repositories; - -namespace Util.Data.EntityFrameworkCore.Repositories { - /// - /// 客户仓储 - /// - public interface ICustomerRepository : IRepository { - } -} \ No newline at end of file diff --git a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Repositories/IProductRepository.cs b/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Repositories/IProductRepository.cs deleted file mode 100644 index 900cd862..00000000 --- a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Repositories/IProductRepository.cs +++ /dev/null @@ -1,15 +0,0 @@ -using Util.Data.EntityFrameworkCore.Models; -using Util.Domain.Repositories; - -namespace Util.Data.EntityFrameworkCore.Repositories { - /// - /// 产品仓储 - /// - public interface IProductRepository : IRepository { - /// - /// 更新产品 - /// - /// 产品 - public void UpdateProduct( Product product ); - } -} \ No newline at end of file diff --git a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/UnitOfWorks/ISqlServerUnitOfWork.cs b/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/UnitOfWorks/ISqlServerUnitOfWork.cs deleted file mode 100644 index 407c1a99..00000000 --- a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/UnitOfWorks/ISqlServerUnitOfWork.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Util.Data.EntityFrameworkCore.UnitOfWorks { - /// - /// 工作单元 - /// - public interface ISqlServerUnitOfWork : IUnitOfWork { - } -} \ No newline at end of file diff --git a/test/Util.Data.EntityFrameworkCore.Sqlite.Tests.Integration/Filters/DeleteFilterTest.cs b/test/Util.Data.EntityFrameworkCore.Sqlite.Tests.Integration/Filters/DeleteFilterTest.cs new file mode 100644 index 00000000..e589e106 --- /dev/null +++ b/test/Util.Data.EntityFrameworkCore.Sqlite.Tests.Integration/Filters/DeleteFilterTest.cs @@ -0,0 +1,81 @@ +using Util.Tests.Models; +using Xunit; +using Xunit.Abstractions; + +namespace Util.Data.EntityFrameworkCore.Filters { + /// + /// 逻辑删除过滤器测试 + /// + public class DeleteFilterTest { + /// + /// 测试消息输出 + /// + private readonly ITestOutputHelper _testOutputHelper; + /// + /// 逻辑删除过滤器 + /// + private readonly DeleteFilter _filter; + + /// + /// 测试初始化 + /// + public DeleteFilterTest( ITestOutputHelper testOutputHelper ) { + _testOutputHelper = testOutputHelper; + _filter = new DeleteFilter(); + } + + /// + /// 测试是否启用 + /// + [Fact] + public void TestIsEnabled() { + //默认值为启用 + Assert.True( _filter.IsEnabled ); + + //禁用过滤器 + _filter.Disable(); + Assert.False( _filter.IsEnabled ); + + //启用过滤器 + _filter.Enable(); + Assert.True( _filter.IsEnabled ); + } + + /// + /// 测试禁用 + /// + [Fact] + public void TestDisable() { + //默认值为启用 + Assert.True( _filter.IsEnabled ); + + //禁用过滤器 + using( _filter.Disable() ) { + Assert.False( _filter.IsEnabled ); + } + + //恢复启用状态 + Assert.True( _filter.IsEnabled ); + } + + /// + /// 测试实体是否启用过滤器 + /// + [Fact] + public void TestIsEntityEnabled() { + Assert.False( _filter.IsEntityEnabled() ); + Assert.True( _filter.IsEntityEnabled() ); + } + + /// + /// 测试获取表达式 + /// + [Fact] + public void TestGetExpression() { + var expression = _filter.GetExpression(); + var result = "entity => Not(Property(entity, \"IsDeleted\"))"; + _testOutputHelper.WriteLine( expression.ToString() ); + Assert.Equal( result,expression.ToString() ); + } + } +} diff --git a/test/Util.Data.EntityFrameworkCore.Sqlite.Tests.Integration/Filters/FilterManagerTest.cs b/test/Util.Data.EntityFrameworkCore.Sqlite.Tests.Integration/Filters/FilterManagerTest.cs new file mode 100644 index 00000000..4ac4609d --- /dev/null +++ b/test/Util.Data.EntityFrameworkCore.Sqlite.Tests.Integration/Filters/FilterManagerTest.cs @@ -0,0 +1,101 @@ +using Util.Data.Filters; +using Util.Domain; +using Util.Tests.Models; +using Xunit; + +namespace Util.Data.EntityFrameworkCore.Filters { + /// + /// 数据过滤器管理器测试 + /// + public class FilterManagerTest { + /// + /// 数据过滤器管理器 + /// + private readonly IFilterManager _filterManager; + + /// + /// 测试初始化 + /// + public FilterManagerTest( IFilterManager filterManager ) { + _filterManager = filterManager; + } + + /// + /// 测试获取过滤器 - 泛型 + /// + [Fact] + public void TestGetFilter_1() { + //逻辑删除过滤器已默认加载 + var filter = _filterManager.GetFilter(); + Assert.NotNull( filter ); + Assert.True( filter.IsEnabled ); + } + + /// + /// 测试获取过滤器 - 非泛型 + /// + [Fact] + public void TestGetFilter_2() { + //逻辑删除过滤器已默认加载 + var filter = _filterManager.GetFilter(typeof( IDelete ) ); + Assert.NotNull( filter ); + } + + /// + /// 测试禁用过滤器 + /// + [Fact] + public void TestDisableFilter_1() { + _filterManager.DisableFilter(); + var filter = _filterManager.GetFilter(); + Assert.False( filter.IsEnabled ); + } + + /// + /// 测试禁用过滤器 - 使用using + /// + [Fact] + public void TestDisableFilter_2() { + var filter = _filterManager.GetFilter(); + using ( _filterManager.DisableFilter() ) { + Assert.False( filter.IsEnabled ); + } + Assert.True( filter.IsEnabled ); + } + + /// + /// 测试启用过滤器 + /// + [Fact] + public void TestEnableFilter() { + var filter = _filterManager.GetFilter(); + + //禁用 + _filterManager.DisableFilter(); + Assert.False( filter.IsEnabled ); + + //启用 + _filterManager.EnableFilter(); + Assert.True( filter.IsEnabled ); + } + + /// + /// 测试实体是否启用过滤器 + /// + [Fact] + public void TestIsEntityEnabled() { + Assert.False( _filterManager.IsEntityEnabled() ); + Assert.True( _filterManager.IsEntityEnabled() ); + } + + /// + /// 测试过滤器是否启用 + /// + [Fact] + public void TestIsEnabled() { + Assert.True( _filterManager.IsEnabled() ); + Assert.False( _filterManager.IsEnabled() ); + } + } +} + diff --git a/test/Util.Data.EntityFrameworkCore.Sqlite.Tests.Integration/Startup.cs b/test/Util.Data.EntityFrameworkCore.Sqlite.Tests.Integration/Startup.cs new file mode 100644 index 00000000..afe2e7e6 --- /dev/null +++ b/test/Util.Data.EntityFrameworkCore.Sqlite.Tests.Integration/Startup.cs @@ -0,0 +1,53 @@ +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using Util.Aop; +using Util.Helpers; +using Util.Sessions; +using Util.Tests.Infrastructure; +using Util.Tests.UnitOfWorks; +using Xunit.DependencyInjection; +using Xunit.DependencyInjection.Logging; + +namespace Util.Data.EntityFrameworkCore { + /// + /// Æô¶¯ÅäÖà + /// + public class Startup { + /// + /// ÅäÖÃÖ÷»ú + /// + public void ConfigureHost( IHostBuilder hostBuilder ) { + hostBuilder.ConfigureDefaults( null ) + .AddUtil( options => { + Environment.SetDevelopment(); + options.UseAop() + .UseSqliteUnitOfWork( Config.GetConnectionString( "connection" ) ); + } ); + } + + /// + /// ÅäÖ÷þÎñ + /// + public void ConfigureServices( IServiceCollection services ) { + services.AddSingleton(); + InitDatabase( services ); + } + + /// + /// ³õʼ»¯Êý¾ݿâ + /// + private void InitDatabase( IServiceCollection services ) { + var unitOfWork = services.BuildServiceProvider().GetService(); + unitOfWork.EnsureDeleted(); + unitOfWork.EnsureCreated(); + } + + /// + /// ÅäÖÃÈÕ־Ìṩ³ÌÐò + /// + public void Configure( ILoggerFactory loggerFactory, ITestOutputHelperAccessor accessor ) { + loggerFactory.AddProvider( new XunitTestOutputLoggerProvider( accessor, ( s, logLevel ) => logLevel >= LogLevel.Trace ) ); + } + } +} diff --git a/test/Util.Data.EntityFrameworkCore.Sqlite.Tests.Integration/Tests/CustomerRepositoryTest.cs b/test/Util.Data.EntityFrameworkCore.Sqlite.Tests.Integration/Tests/CustomerRepositoryTest.cs new file mode 100644 index 00000000..2f43c378 --- /dev/null +++ b/test/Util.Data.EntityFrameworkCore.Sqlite.Tests.Integration/Tests/CustomerRepositoryTest.cs @@ -0,0 +1,604 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore; +using Util.Data.Queries; +using Util.Tests.Fakes; +using Util.Tests.Infrastructure; +using Util.Tests.Models; +using Util.Tests.Repositories; +using Util.Tests.UnitOfWorks; +using Xunit; + +namespace Util.Data.EntityFrameworkCore.Tests { + /// + /// 客户仓储测试 + /// 说明: + /// 1. 测试自增长int类型标识 + /// 2. 测试日期范围查询 + /// 3. 测试分页查询 + /// 4. 测试Utc日期 + /// + public class CustomerRepositoryTest : TestBase { + + #region 测试初始化 + + /// + /// 仓储 + /// + private readonly ICustomerRepository _repository; + + /// + /// 测试初始化 + /// + public CustomerRepositoryTest( ICustomerRepository repository, ITestUnitOfWork unitOfWork ) : base( unitOfWork ) { + _repository = repository; + } + + #endregion + + #region 辅助操作 + + /// + /// 添加实体列表 + /// + /// 添加数量 + /// 客户名称 + private async Task> AddCustomersAsync( int count = 2, string name = null ) { + var customers = CustomerFakeService.GetCustomers( count ); + customers.ForEach( customer => { + if ( name != null ) + customer.Name = name; + customer.CreationTime = null; + } ); + await _repository.AddAsync( customers ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + return customers.OrderBy( t => t.Code ).ToList(); + } + + #endregion + + #region Between + + /// + /// 测试添加范围查询条件 - 日期带时间 + /// + [Fact] + public async Task TestBetween_DateTime_1() { + //常量 + var name = "TestBetween_DateTime_1"; + var birthday = "2005-5-5 05:05:05".ToDateTime(); + var minBirthday = "2005-5-6 06:05:05".ToDateTime(); + var maxBirthday = "2005-5-8 06:05:05".ToDateTime(); + + //添加实体列表 + await AddCustomersAsync(); + var customers = CustomerFakeService.GetCustomers( 5 ); + customers.ForEach( customer => { + customer.Name = name; + customer.Birthday = birthday; + birthday = birthday.AddDays( 1 ); + } ); + await _repository.AddAsync( customers ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //查询 + var result = await _repository.Find().Where( t => t.Name == name ).Between( t => t.Birthday, minBirthday, maxBirthday ).ToListAsync(); + + //验证 + Assert.Equal( 2, result.Count ); + } + + /// + /// 测试添加范围查询条件 - 日期带时间 - 包含左边界 + /// + [Fact] + public async Task TestBetween_DateTime_2() { + //常量 + var name = "TestBetween_DateTime_2"; + var birthday = "2005-5-5 05:05:05".ToDateTime(); + var minBirthday = "2005-5-6 05:05:05".ToDateTime(); + var maxBirthday = "2005-5-8 05:05:05".ToDateTime(); + + //添加实体列表 + await AddCustomersAsync(); + var customers = CustomerFakeService.GetCustomers( 5 ); + customers.ForEach( customer => { + customer.Name = name; + customer.Birthday = birthday; + birthday = birthday.AddDays( 1 ); + } ); + await _repository.AddAsync( customers ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //查询 + var result = await _repository.Find().Where( t => t.Name == name ).Between( t => t.Birthday, minBirthday, maxBirthday, boundary: Boundary.Left ).ToListAsync(); + + //验证 + Assert.Equal( 2, result.Count ); + } + + /// + /// 测试添加范围查询条件 - 日期带时间 - 包含右边界 + /// + [Fact] + public async Task TestBetween_DateTime_3() { + //常量 + var name = "TestBetween_DateTime_3"; + var birthday = "2005-5-5 05:05:05".ToDateTime(); + var minBirthday = "2005-5-6 05:05:05".ToDateTime(); + var maxBirthday = "2005-5-8 05:05:05".ToDateTime(); + + //添加实体列表 + await AddCustomersAsync(); + var customers = CustomerFakeService.GetCustomers( 5 ); + customers.ForEach( customer => { + customer.Name = name; + customer.Birthday = birthday; + birthday = birthday.AddDays( 1 ); + } ); + await _repository.AddAsync( customers ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //查询 + var result = await _repository.Find().Where( t => t.Name == name ).Between( t => t.Birthday, minBirthday, maxBirthday, boundary: Boundary.Right ).ToListAsync(); + + //验证 + Assert.Equal( 2, result.Count ); + } + + /// + /// 测试添加范围查询条件 - 日期带时间 - 包含两边 + /// + [Fact] + public async Task TestBetween_DateTime_4() { + //常量 + var name = "TestBetween_DateTime_4"; + var birthday = "2005-5-5 05:05:05".ToDateTime(); + var minBirthday = "2005-5-6 05:05:05".ToDateTime(); + var maxBirthday = "2005-5-8 05:05:05".ToDateTime(); + + //添加实体列表 + await AddCustomersAsync(); + var customers = CustomerFakeService.GetCustomers( 5 ); + customers.ForEach( customer => { + customer.Name = name; + customer.Birthday = birthday; + birthday = birthday.AddDays( 1 ); + } ); + await _repository.AddAsync( customers ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //查询 + var result = await _repository.Find().Where( t => t.Name == name ).Between( t => t.Birthday, minBirthday, maxBirthday, boundary: Boundary.Both ).ToListAsync(); + + //验证 + Assert.Equal( 3, result.Count ); + } + + /// + /// 测试添加范围查询条件 - 日期带时间 - 不包含边界 + /// + [Fact] + public async Task TestBetween_DateTime_5() { + //常量 + var name = "TestBetween_DateTime_5"; + var birthday = "2005-5-5 05:05:05".ToDateTime(); + var minBirthday = "2005-5-6 05:05:05".ToDateTime(); + var maxBirthday = "2005-5-8 05:05:05".ToDateTime(); + + //添加实体列表 + await AddCustomersAsync(); + var customers = CustomerFakeService.GetCustomers( 5 ); + customers.ForEach( customer => { + customer.Name = name; + customer.Birthday = birthday; + birthday = birthday.AddDays( 1 ); + } ); + await _repository.AddAsync( customers ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //查询 + var result = await _repository.Find().Where( t => t.Name == name ).Between( t => t.Birthday, minBirthday, maxBirthday, boundary: Boundary.Neither ).ToListAsync(); + + //验证 + Assert.Single( result ); + } + + /// + /// 测试添加范围查询条件 - 日期带时间 - 最大值为空 + /// + [Fact] + public async Task TestBetween_DateTime_6() { + //常量 + var name = "TestBetween_DateTime_6"; + var birthday = "2005-5-5 05:05:05".ToDateTime(); + var minBirthday = "2005-5-6 05:05:05".ToDateTime(); + + //添加实体列表 + await AddCustomersAsync(); + var customers = CustomerFakeService.GetCustomers( 5 ); + customers.ForEach( customer => { + customer.Name = name; + customer.Birthday = birthday; + birthday = birthday.AddDays( 1 ); + } ); + await _repository.AddAsync( customers ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //查询 + var result = await _repository.Find().Where( t => t.Name == name ).Between( t => t.Birthday, minBirthday, null, boundary: Boundary.Both ).ToListAsync(); + + //验证 + Assert.Equal( 4, result.Count ); + } + + /// + /// 测试添加范围查询条件 - 日期带时间 - 最小值为空 + /// + [Fact] + public async Task TestBetween_DateTime_7() { + //常量 + var name = "TestBetween_DateTime_7"; + var birthday = "2005-5-5 05:05:05".ToDateTime(); + var maxBirthday = "2005-5-8 05:05:05".ToDateTime(); + + //添加实体列表 + await AddCustomersAsync(); + var customers = CustomerFakeService.GetCustomers( 5 ); + customers.ForEach( customer => { + customer.Name = name; + customer.Birthday = birthday; + birthday = birthday.AddDays( 1 ); + } ); + await _repository.AddAsync( customers ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //查询 + var result = await _repository.Find().Where( t => t.Name == name ).Between( t => t.Birthday, null, maxBirthday, boundary: Boundary.Both ).ToListAsync(); + + //验证 + Assert.Equal( 4, result.Count ); + } + + /// + /// 测试添加范围查询条件 - 日期不带时间 - 包含左边界 + /// + [Fact] + public async Task TestBetween_Date_1() { + //常量 + var name = "TestBetween_Date_1"; + var birthday = "2005-5-5 05:05:05".ToDateTime(); + var minBirthday = "2005-5-6".ToDateTime(); + var maxBirthday = "2005-5-8".ToDateTime(); + + //添加实体列表 + await AddCustomersAsync(); + var customers = CustomerFakeService.GetCustomers( 5 ); + customers.ForEach( customer => { + customer.Name = name; + customer.Birthday = birthday; + birthday = birthday.AddDays( 1 ); + } ); + await _repository.AddAsync( customers ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //查询 + var result = await _repository.Find() + .Where( t => t.Name == name ) + .Between( t => t.Birthday, minBirthday, maxBirthday, false, Boundary.Left ) + .OrderBy( t => t.Birthday ) + .ToListAsync(); + + //验证 + Assert.Equal( 2, result.Count ); + Assert.Equal( 6, result[0].Birthday.SafeValue().Day ); + Assert.Equal( 7, result[1].Birthday.SafeValue().Day ); + } + + /// + /// 测试添加范围查询条件 - 日期不带时间 - 包含右边界 + /// + [Fact] + public async Task TestBetween_Date_2() { + //常量 + var name = "TestBetween_Date_2"; + var birthday = "2005-5-5 05:05:05".ToDateTime(); + var minBirthday = "2005-5-6".ToDateTime(); + var maxBirthday = "2005-5-8".ToDateTime(); + + //添加实体列表 + await AddCustomersAsync(); + var customers = CustomerFakeService.GetCustomers( 5 ); + customers.ForEach( customer => { + customer.Name = name; + customer.Birthday = birthday; + birthday = birthday.AddDays( 1 ); + } ); + await _repository.AddAsync( customers ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //查询 + var result = await _repository.Find() + .Where( t => t.Name == name ) + .Between( t => t.Birthday, minBirthday, maxBirthday, false, Boundary.Right ) + .OrderBy( t => t.Birthday ) + .ToListAsync(); + + //验证 + Assert.Equal( 2, result.Count ); + Assert.Equal( 7, result[0].Birthday.SafeValue().Day ); + Assert.Equal( 8, result[1].Birthday.SafeValue().Day ); + } + + /// + /// 测试添加范围查询条件 - 日期不带时间 - 包含两边 + /// + [Fact] + public async Task TestBetween_Date_3() { + //常量 + var name = "TestBetween_Date_3"; + var birthday = "2005-5-5 05:05:05".ToDateTime(); + var minBirthday = "2005-5-6".ToDateTime(); + var maxBirthday = "2005-5-8".ToDateTime(); + + //添加实体列表 + await AddCustomersAsync(); + var customers = CustomerFakeService.GetCustomers( 5 ); + customers.ForEach( customer => { + customer.Name = name; + customer.Birthday = birthday; + birthday = birthday.AddDays( 1 ); + } ); + await _repository.AddAsync( customers ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //查询 + var result = await _repository.Find() + .Where( t => t.Name == name ) + .Between( t => t.Birthday, minBirthday, maxBirthday, false, Boundary.Both ) + .OrderBy( t => t.Birthday ) + .ToListAsync(); + + //验证 + Assert.Equal( 3, result.Count ); + Assert.Equal( 6, result[0].Birthday.SafeValue().Day ); + Assert.Equal( 7, result[1].Birthday.SafeValue().Day ); + Assert.Equal( 8, result[2].Birthday.SafeValue().Day ); + } + + /// + /// 测试添加范围查询条件 - 日期不带时间 - 不包含边界 + /// + [Fact] + public async Task TestBetween_Date_4() { + //常量 + var name = "TestBetween_Date_4"; + var birthday = "2005-5-5 05:05:05".ToDateTime(); + var minBirthday = "2005-5-6".ToDateTime(); + var maxBirthday = "2005-5-8".ToDateTime(); + + //添加实体列表 + await AddCustomersAsync(); + var customers = CustomerFakeService.GetCustomers( 5 ); + customers.ForEach( customer => { + customer.Name = name; + customer.Birthday = birthday; + birthday = birthday.AddDays( 1 ); + } ); + await _repository.AddAsync( customers ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //查询 + var result = await _repository.Find() + .Where( t => t.Name == name ) + .Between( t => t.Birthday, minBirthday, maxBirthday, false, Boundary.Neither ) + .ToListAsync(); + + //验证 + Assert.Single( result ); + Assert.Equal( 7, result[0].Birthday.SafeValue().Day ); + } + + /// + /// 测试添加范围查询条件 - 日期不带时间 - 最大值为空 + /// + [Fact] + public async Task TestBetween_Date_5() { + //常量 + var name = "TestBetween_Date_5"; + var birthday = "2005-5-5 05:05:05".ToDateTime(); + var minBirthday = "2005-5-6".ToDateTime(); + + //添加实体列表 + await AddCustomersAsync(); + var customers = CustomerFakeService.GetCustomers( 5 ); + customers.ForEach( customer => { + customer.Nickname = name; + customer.Name = name; + customer.Birthday = birthday; + birthday = birthday.AddDays( 1 ); + } ); + await _repository.AddAsync( customers ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //查询 + var result = await _repository.Find() + .Where( t => t.Name == name ) + .Between( t => t.Birthday, minBirthday, null, false ) + .OrderBy( t => t.Birthday ) + .ToListAsync(); + + //验证 + Assert.Equal( 4, result.Count ); + Assert.Equal( 6, result[0].Birthday.SafeValue().Day ); + } + + /// + /// 测试添加范围查询条件 - 日期不带时间 - 最小值为空 + /// + [Fact] + public async Task TestBetween_Date_6() { + //常量 + var name = "TestBetween_Date_6"; + var birthday = "2005-5-5 05:05:05".ToDateTime(); + var maxBirthday = "2005-5-8".ToDateTime(); + + //添加实体列表 + await AddCustomersAsync(); + var customers = CustomerFakeService.GetCustomers( 5 ); + customers.ForEach( customer => { + customer.Name = name; + customer.Birthday = birthday; + birthday = birthday.AddDays( 1 ); + } ); + await _repository.AddAsync( customers ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //查询 + var result = await _repository.Find() + .Where( t => t.Name == name ) + .Between( t => t.Birthday, null, maxBirthday, false ) + .ToListAsync(); + + //验证 + Assert.Equal( 4, result.Count ); + } + + #endregion + + #region ToPageList + + /// + /// 测试获取分页列表 + /// + [Fact] + public async Task TestToPageList_1() { + //常量 + var name = "TestToPageList_1"; + + //添加实体列表 + var customers = await AddCustomersAsync( 10, name ); + + //创建查询参数 + var parameter = new QueryParameter { PageSize = 3, Page = 1, Order = "Code" }; + + //查询 + var result = _repository.Find().Where( t => t.Name == name ).ToPageList( parameter ); + + //验证 + Assert.Equal( 4, result.PageCount ); + Assert.Equal( 1, result.Page ); + Assert.Equal( 3, result.PageSize ); + Assert.Equal( 10, result.Total ); + Assert.Equal( 3, result.Data.Count ); + Assert.Equal( customers[0].Id, result.Data[0].Id ); + Assert.Equal( customers[1].Id, result.Data[1].Id ); + Assert.Equal( customers[2].Id, result.Data[2].Id ); + } + + /// + /// 测试获取分页列表 - 第二页 + /// + [Fact] + public async Task TestToPageList_2() { + //常量 + var name = "TestToPageList_2"; + + //添加实体列表 + var customers = await AddCustomersAsync( 10, name ); + + //创建查询参数 + var parameter = new QueryParameter { PageSize = 3, Page = 2, Order = "Code" }; + + //查询 + var result = _repository.Find().Where( t => t.Name == name ).ToPageList( parameter ); + + //验证 + Assert.Equal( 4, result.PageCount ); + Assert.Equal( 2, result.Page ); + Assert.Equal( 3, result.PageSize ); + Assert.Equal( 10, result.Total ); + Assert.Equal( 3, result.Data.Count ); + Assert.Equal( customers[3].Id, result.Data[0].Id ); + Assert.Equal( customers[4].Id, result.Data[1].Id ); + Assert.Equal( customers[5].Id, result.Data[2].Id ); + } + + /// + /// 测试获取分页列表 - Queryable设置排序 + /// + [Fact] + public async Task TestToPageList_3() { + //常量 + var name = "TestToPageList_3"; + + //添加实体列表 + var customers = await AddCustomersAsync( 10, name ); + + //创建查询参数 + var parameter = new QueryParameter { PageSize = 3, Page = 2 }; + + //查询 + var result = _repository.Find().Where( t => t.Name == name ).OrderBy( t => t.Code ).ToPageList( parameter ); + + //验证 + Assert.Equal( 4, result.PageCount ); + Assert.Equal( 2, result.Page ); + Assert.Equal( 3, result.PageSize ); + Assert.Equal( 10, result.Total ); + Assert.Equal( 3, result.Data.Count ); + Assert.Equal( customers[3].Id, result.Data[0].Id ); + Assert.Equal( customers[4].Id, result.Data[1].Id ); + Assert.Equal( customers[5].Id, result.Data[2].Id ); + } + + #endregion + + #region ToPageListAsync + + /// + /// 测试获取分页列表 + /// + [Fact] + public async Task TestToPageListAsync() { + //常量 + var name = "TestToPageListAsync"; + + //添加实体列表 + var customers = await AddCustomersAsync( 10, name ); + + //创建查询参数 + var parameter = new QueryParameter { PageSize = 3, Page = 2, Order = "Code" }; + + //查询 + var result = await _repository.Find().Where( t => t.Name == name ).ToPageListAsync( parameter ); + + //验证 + Assert.Equal( 4, result.PageCount ); + Assert.Equal( 2, result.Page ); + Assert.Equal( 3, result.PageSize ); + Assert.Equal( 10, result.Total ); + Assert.Equal( 3, result.Data.Count ); + Assert.Equal( customers[3].Id, result.Data[0].Id ); + Assert.Equal( customers[4].Id, result.Data[1].Id ); + Assert.Equal( customers[5].Id, result.Data[2].Id ); + } + + #endregion + } +} \ No newline at end of file diff --git a/test/Util.Data.EntityFrameworkCore.Sqlite.Tests.Integration/Tests/EntityEventsTest.cs b/test/Util.Data.EntityFrameworkCore.Sqlite.Tests.Integration/Tests/EntityEventsTest.cs new file mode 100644 index 00000000..b4e62e8c --- /dev/null +++ b/test/Util.Data.EntityFrameworkCore.Sqlite.Tests.Integration/Tests/EntityEventsTest.cs @@ -0,0 +1,211 @@ +using System.Threading.Tasks; +using Util.Tests.EventHandlers; +using Util.Tests.Fakes; +using Util.Tests.Infrastructure; +using Util.Tests.Repositories; +using Util.Tests.UnitOfWorks; +using Xunit; +using Xunit.Abstractions; + +namespace Util.Data.EntityFrameworkCore.Tests { + /// + /// 实体事件测试 + /// + public class EntityEventsTest : TestBase { + + #region 测试初始化 + + /// + /// 测试输出 + /// + private readonly ITestOutputHelper _testOutputHelper; + /// + /// 产品仓储 + /// + private readonly IProductRepository _productRepository; + /// + /// 操作日志仓储 + /// + private readonly IOperationLogRepository _operationLogRepository; + + /// + /// 测试初始化 + /// + public EntityEventsTest( ITestOutputHelper testOutputHelper, IProductRepository productRepository, + IOperationLogRepository operationLogRepository, ITestUnitOfWork unitOfWork ) :base(unitOfWork){ + _testOutputHelper = testOutputHelper; + _productRepository = productRepository; + _operationLogRepository = operationLogRepository; + } + + #endregion + + #region 实体创建事件 + + /// + /// 测试实体创建事件 + /// + [Fact] + public async Task TestEntityCreatedEvent() { + //添加实体 + var entity = ProductFakeService.GetProduct(); + entity.Init(); + entity.Name = "EntityCreatedEvent"; + await _productRepository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); + + //验证 + Assert.True( await _operationLogRepository.ExistsAsync( t => t.Caption == "EntityCreatedEvent" && t.LogName == nameof( ProductCreatedEventHandler ) ) ); + } + + /// + /// 测试实体变更事件 - 创建 + /// + [Fact] + public async Task TestEntityChangedEvent_Created() { + //添加实体 + var entity = ProductFakeService.GetProduct(); + entity.Init(); + entity.Name = "EntityChangedEvent_Created"; + await _productRepository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); + + //验证 + Assert.True( await _operationLogRepository.ExistsAsync( t => t.Caption == "EntityChangedEvent_Created" && t.LogName == nameof( ProductChangedEventHandler ) ) ); + } + + #endregion + + #region 实体修改事件 + + /// + /// 测试实体修改事件 + /// + [Fact] + public async Task TestEntityUpdatedEvent() { + //添加实体 + var entity = ProductFakeService.GetProduct(); + entity.Init(); + await _productRepository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //修改实体 + var product = await _productRepository.FindByIdAsync( entity.Id ); + product.Name = "EntityUpdatedEvent"; + await _productRepository.UpdateAsync( product ); + await UnitOfWork.CommitAsync(); + + //验证 + Assert.True( await _operationLogRepository.ExistsAsync( t => t.Caption == "EntityUpdatedEvent" && t.LogName == nameof( ProductUpdatedEventHandler ) ) ); + } + + /// + /// 测试实体变更事件 - 修改 + /// + [Fact] + public async Task TestEntityChangedEvent_Updated() { + //添加实体 + var entity = ProductFakeService.GetProduct(); + entity.Init(); + await _productRepository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //修改实体 + var product = _productRepository.FindById( entity.Id ); + product.Name = "EntityChangedEvent_Updated"; + await _productRepository.UpdateAsync( product ); + await UnitOfWork.CommitAsync(); + + //验证 + Assert.True( await _operationLogRepository.ExistsAsync( t => t.Caption == "EntityChangedEvent_Updated" && t.LogName == nameof( ProductChangedEventHandler ) ) ); + } + + #endregion + + #region 实体删除事件 + + /// + /// 测试实体删除事件 - 逻辑删除 + /// + [Fact] + public async Task TestEntityDeletedEvent_1() { + //添加实体 + var entity = ProductFakeService.GetProduct(); + entity.Init(); + entity.Name = "EntityDeletedEvent"; + await _productRepository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); + + //删除实体 + await _productRepository.RemoveAsync( entity ); + await UnitOfWork.CommitAsync(); + + //验证 + Assert.True( await _operationLogRepository.ExistsAsync( t => t.Caption == "EntityDeletedEvent" && t.LogName == nameof( ProductDeletedEventHandler ) ) ); + } + + /// + /// 测试实体删除事件 - 物理删除 + /// + [Fact] + public async Task TestEntityDeletedEvent_2() { + //添加实体 + var entity = OperationLogFakeService.GetOperationLog(); + entity.Init(); + entity.LogName = "EntityDeletedEvent"; + await _operationLogRepository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); + + //删除实体 + await _operationLogRepository.RemoveAsync( entity ); + await UnitOfWork.CommitAsync(); + + //验证 + Assert.True( await _operationLogRepository.ExistsAsync( t => t.LogName == "Test" && t.Caption == nameof( OperationLogDeletedEventHandler ) && t.Content == "EntityDeletedEvent" ) ); + } + + /// + /// 测试实体变更事件 - 逻辑删除 + /// + [Fact] + public async Task TestEntityChangedEvent_Deleted_1() { + //添加实体 + var entity = ProductFakeService.GetProduct(); + entity.Init(); + entity.Name = "EntityChangedEvent_Deleted"; + await _productRepository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); + + //删除实体 + await _productRepository.RemoveAsync( entity ); + await UnitOfWork.CommitAsync(); + + //验证 + Assert.True( await _operationLogRepository.ExistsAsync( t => t.Caption == "EntityChangedEvent_Deleted" && t.LogName == nameof( ProductChangedEventHandler ) ) ); + } + + /// + /// 测试实体变更事件 - 物理删除 + /// + [Fact] + public async Task TestEntityChangedEvent_Deleted_2() { + //添加实体 + var entity = OperationLogFakeService.GetOperationLog(); + entity.Init(); + entity.LogName = "EntityChangedEvent_Deleted"; + await _operationLogRepository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); + + //删除实体 + await _operationLogRepository.RemoveAsync( entity ); + await UnitOfWork.CommitAsync(); + + //验证 + Assert.True( await _operationLogRepository.ExistsAsync( t => t.LogName == "Test" && t.Caption == nameof( OperationLogChangedEventHandler ) && t.Content == "EntityChangedEvent_Deleted" ) ); + } + + #endregion + } +} diff --git a/test/Util.Data.EntityFrameworkCore.Sqlite.Tests.Integration/Tests/OperationLogRepositoryTest.cs b/test/Util.Data.EntityFrameworkCore.Sqlite.Tests.Integration/Tests/OperationLogRepositoryTest.cs new file mode 100644 index 00000000..fecbccb7 --- /dev/null +++ b/test/Util.Data.EntityFrameworkCore.Sqlite.Tests.Integration/Tests/OperationLogRepositoryTest.cs @@ -0,0 +1,63 @@ +using System.Threading.Tasks; +using Util.Tests.Fakes; +using Util.Tests.Infrastructure; +using Util.Tests.Repositories; +using Util.Tests.UnitOfWorks; +using Xunit; + +namespace Util.Data.EntityFrameworkCore.Tests { + /// + /// 操作日志仓储测试 + /// 说明: + /// 测试自增长long类型标识 + /// + public class OperationLogRepositoryTest : TestBase { + /// + /// 仓储 + /// + private readonly IOperationLogRepository _repository; + + /// + /// 测试初始化 + /// + public OperationLogRepositoryTest( IOperationLogRepository operationLogRepository, ITestUnitOfWork unitOfWork ) : base( unitOfWork ) { + _repository = operationLogRepository; + } + + /// + /// 测试添加实体 + /// + [Fact] + public async Task TestAdd() { + //添加实体 + var entity = OperationLogFakeService.GetOperationLog(); + await _repository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); + + //验证 + Assert.True( entity.Id > 0 ); + Assert.True( _repository.Exists( t => t.Id == entity.Id ) ); + } + + /// + /// 测试通过标识移除实体 - 物理删除 + /// + [Fact] + public async Task TestRemove_Id() { + //添加实体 + var entity = OperationLogFakeService.GetOperationLog(); + await _repository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //移除实体 + await _repository.RemoveAsync( entity.Id ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //验证 + var result = await _repository.FindByIdAsync( entity.Id ); + Assert.Null( result ); + } + } +} diff --git a/test/Util.Data.EntityFrameworkCore.Sqlite.Tests.Integration/Tests/OrderRepositoryTest.cs b/test/Util.Data.EntityFrameworkCore.Sqlite.Tests.Integration/Tests/OrderRepositoryTest.cs new file mode 100644 index 00000000..076b5bd1 --- /dev/null +++ b/test/Util.Data.EntityFrameworkCore.Sqlite.Tests.Integration/Tests/OrderRepositoryTest.cs @@ -0,0 +1,130 @@ +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore; +using Util.Tests.Fakes; +using Util.Tests.Infrastructure; +using Util.Tests.Models; +using Util.Tests.Repositories; +using Util.Tests.UnitOfWorks; +using Xunit; + +namespace Util.Data.EntityFrameworkCore.Tests { + /// + /// 订单仓储测试 + /// 说明: + /// 1. 测试string类型标识 + /// 2. 测试一对多导航属性 + /// + public class OrderRepositoryTest : TestBase { + + #region 测试初始化 + + /// + /// 仓储 + /// + private readonly IOrderRepository _repository; + + /// + /// 测试初始化 + /// + public OrderRepositoryTest( IOrderRepository repository, ITestUnitOfWork unitOfWork ) : base( unitOfWork ) { + _repository = repository; + } + + #endregion + + #region 辅助方法 + + /// + /// 添加订单 + /// + private async Task AddOrderAsync() { + var order = OrderFakeService.GetOrder(); + order.Init(); + order.OrderItems.Add( CreateOrderItem() ); + order.OrderItems.Add( CreateOrderItem() ); + await _repository.AddAsync( order ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + return order; + } + + /// + /// 创建订单项 + /// + private OrderItem CreateOrderItem() { + var item = OrderItemFakeService.GetOrderItem(); + item.Init(); + return item; + } + + #endregion + + #region Single + + /// + /// 测试查找单个实体 + /// + [Fact] + public async Task TestSingle_1() { + //添加实体 + var entity = await AddOrderAsync(); + + //查找单个实体 + var result = await _repository.SingleAsync( t => t.Id == entity.Id ); + + //验证 + Assert.Empty( result.OrderItems ); + } + + /// + /// 测试查找单个实体 - 使用Include包含子实体集合 + /// + [Fact] + public async Task TestSingle_2() { + //添加实体 + var entity = await AddOrderAsync(); + + //查找单个实体 + var result = await _repository.SingleAsync( t => t.Id == entity.Id, queryable => queryable.Include( t => t.OrderItems ) ); + + //验证 + Assert.Equal( 2, result.OrderItems.Count ); + } + + #endregion + + #region SingleAsync + + /// + /// 测试查找单个实体 + /// + [Fact] + public async Task TestSingleAsync_1() { + //添加实体 + var entity = await AddOrderAsync(); + + //查找单个实体 + var result = await _repository.SingleAsync( t => t.Id == entity.Id ); + + //验证 + Assert.Empty( result.OrderItems ); + } + + /// + /// 测试查找单个实体 - 使用Include包含子实体集合 + /// + [Fact] + public async Task TestSingleAsync_2() { + //添加实体 + var entity = await AddOrderAsync(); + + //查找单个实体 + var result = await _repository.SingleAsync( t => t.Id == entity.Id, queryable => queryable.Include( t => t.OrderItems ) ); + + //验证 + Assert.Equal( 2, result.OrderItems.Count ); + } + + #endregion + } +} \ No newline at end of file diff --git a/test/Util.Data.EntityFrameworkCore.Sqlite.Tests.Integration/Tests/PostRepositoryTest.cs b/test/Util.Data.EntityFrameworkCore.Sqlite.Tests.Integration/Tests/PostRepositoryTest.cs new file mode 100644 index 00000000..c238dde1 --- /dev/null +++ b/test/Util.Data.EntityFrameworkCore.Sqlite.Tests.Integration/Tests/PostRepositoryTest.cs @@ -0,0 +1,54 @@ +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore; +using Util.Tests.Fakes; +using Util.Tests.Infrastructure; +using Util.Tests.Repositories; +using Util.Tests.UnitOfWorks; +using Xunit; + +namespace Util.Data.EntityFrameworkCore.Tests { + /// + /// 贴子仓储测试 + /// 说明: + /// 1. 测试多对多 + /// + public class PostRepositoryTest : TestBase { + /// + /// 仓储 + /// + private readonly IPostRepository _repository; + + /// + /// 测试初始化 + /// + public PostRepositoryTest(IPostRepository repository, ITestUnitOfWork unitOfWork ) : base(unitOfWork){ + _repository = repository; + } + + /// + /// 测试添加实体 + /// + [Fact] + public async Task TestAddAsync() { + //添加实体 + var post = PostFakeService.GetPost(); + post.Init(); + var tag1 = TagFakeService.GetTag(); + tag1.Init(); + post.Tags.Add( tag1 ); + + var tag2 = TagFakeService.GetTag(); + tag2.Init(); + post.Tags.Add( tag2 ); + + await _repository.AddAsync( post ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //验证 + var result = await _repository.SingleAsync( t => t.Id == post.Id, queryable => queryable.Include( t => t.Tags ) ); + Assert.NotNull( result ); + Assert.Equal( 2,result.Tags.Count ); + } + } +} \ No newline at end of file diff --git a/test/Util.Data.EntityFrameworkCore.Sqlite.Tests.Integration/Tests/ProductRepositoryTest.Queryable.cs b/test/Util.Data.EntityFrameworkCore.Sqlite.Tests.Integration/Tests/ProductRepositoryTest.Queryable.cs new file mode 100644 index 00000000..e03ea9c5 --- /dev/null +++ b/test/Util.Data.EntityFrameworkCore.Sqlite.Tests.Integration/Tests/ProductRepositoryTest.Queryable.cs @@ -0,0 +1,390 @@ +using System; +using System.Linq; +using System.Threading.Tasks; +using Util.Data.Queries; +using Util.Tests.Conditions; +using Util.Tests.Fakes; +using Xunit; + +namespace Util.Data.EntityFrameworkCore.Tests { + /// + /// 产品仓储测试 - 查询测试 + /// + public partial class ProductRepositoryTest { + + #region Where + + /// + /// 测试设置查询条件 - 添加查询条件对象 + /// + [Fact] + public async Task TestWhere() { + //常量 + var name = "TestWhere"; + + //添加实体列表 + await AddProductsAsync(); + var products = await AddProductsAsync( name: name ); + + //创建查询条件 + var condition = new ProductNameCondition( name ); + + //查询 + var result = _repository.Find().Where( condition ).ToList(); + + //验证 + Assert.Equal( products.Count, result.Count ); + Assert.True( result.TrueForAll( t => products.Any( p => p.Id == t.Id ) ) ); + } + + #endregion + + #region WhereIf + + /// + /// 测试设置查询条件 - IQueryable添加WhereIf扩展 - true + /// + [Fact] + public async Task TestWhereIf_True() { + //常量 + var name = "TestWhereIf_True"; + + //添加实体列表 + await AddProductsAsync(); + var products = await AddProductsAsync( name: name ); + + //查询 + var result = _repository.Find().WhereIf( t => t.Name == name, true ).ToList(); + + //验证 + Assert.Equal( products.Count, result.Count ); + } + + /// + /// 测试设置查询条件 - IQueryable添加WhereIf扩展 - false + /// + [Fact] + public async Task TestWhereIf_False() { + //常量 + var name = "TestWhereIf_False"; + + //添加实体列表 + await AddProductsAsync(); + var products = await AddProductsAsync( name: name ); + + //查询 + var result = _repository.Find().WhereIf( t => t.Name == name, false ).ToList(); + + //验证 + Assert.NotEqual( products.Count, result.Count ); + } + + #endregion + + #region WhereIfNotEmpty + + /// + /// 测试设置查询条件 - IQueryable添加WhereIfNotEmpty扩展 - 有效条件 + /// + [Fact] + public async Task TestWhereIfNotEmpty_Valid() { + //常量 + var name = "TestWhereIfNotEmpty_Valid"; + + //添加实体列表 + await AddProductsAsync(); + var products = await AddProductsAsync( name: name ); + + //查询 + var result = _repository.Find().WhereIfNotEmpty( t => t.Name == name ).ToList(); + + //验证 + Assert.Equal( products.Count, result.Count ); + } + + /// + /// 测试设置查询条件 - IQueryable添加WhereIfNotEmpty扩展 - 忽略条件 + /// + [Fact] + public async Task TestWhereIfNotEmpty_Ignore() { + //常量 + var name = "TestWhereIfNotEmpty_Ignore"; + + //添加实体列表 + await AddProductsAsync(); + var products = await AddProductsAsync( name: name ); + + //查询 + var result = _repository.Find().Where( t => t.Name == name ).WhereIfNotEmpty( t => t.Code == "" ).ToList(); + + //验证 + Assert.Equal( products.Count, result.Count ); + } + + /// + /// 测试设置查询条件 - IQueryable添加WhereIfNotEmpty扩展 - 无效条件,抛出异常 + /// + [Fact] + public async Task TestWhereIfNotEmpty_Invalid() { + //添加实体列表 + await AddProductsAsync(); + + //查询 + Assert.Throws( () => { + _repository.Find().WhereIfNotEmpty( t => t.Name == "a" && t.Code == "b" ); + } ); + } + + #endregion + + #region OrIfNotEmpty + + /// + /// 测试设置查询条件 - IQueryable添加OrIfNotEmpty扩展 - 有效条件 + /// + [Fact] + public async Task TestOrIfNotEmpty_Valid() { + //常量 + var name1 = "TestOrIfNotEmpty_Valid_1"; + var name2 = "TestOrIfNotEmpty_Valid_2"; + var name3 = "TestOrIfNotEmpty_Valid_3"; + + //添加实体列表 + await AddProductsAsync(); + await AddProductsAsync( 2, name1 ); + await AddProductsAsync( 3, name2 ); + await AddProductsAsync( 4, name3 ); + + //查询 + var result = _repository.Find().OrIfNotEmpty( t => t.Name == name1,t => t.Name == name2, t => t.Name == name3 ).ToList(); + + //验证 + Assert.Equal( 9, result.Count ); + } + + /// + /// 测试设置查询条件 - IQueryable添加OrIfNotEmpty扩展 - 忽略条件 + /// + [Fact] + public async Task TestOrIfNotEmpty_Ignore() { + //常量 + var name1 = "TestOrIfNotEmpty_Ignore_1"; + var name2 = "TestOrIfNotEmpty_Ignore_2"; + var name3 = "TestOrIfNotEmpty_Ignore_3"; + + //添加实体列表 + await AddProductsAsync(); + await AddProductsAsync( 2, name1 ); + await AddProductsAsync( 3, name2 ); + await AddProductsAsync( 4, name3 ); + + //查询 + var result = _repository.Find().OrIfNotEmpty( t => t.Name == name1, t => t.Name == name2, t => t.Name == "" ).ToList(); + + //验证 + Assert.Equal( 5, result.Count ); + } + + #endregion + + #region Between + + /// + /// 测试添加范围查询条件 + /// + [Fact] + public async Task TestBetween_1() { + //常量 + var name = "TestBetween_1"; + var price = 10.1M; + + //添加实体列表 + await AddProductsAsync(); + var products = ProductFakeService.GetProducts( 5 ); + products.ForEach( product => { + product.Init(); + product.Name = name; + product.Price = price++; + } ); + await _repository.AddAsync( products ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //查询 + var result = _repository.Find().Where( t => t.Name == name ).Between( t => t.Price,11.5M,13.5M ).ToList(); + + //验证 + Assert.Equal( 2, result.Count ); + } + + /// + /// 测试添加范围查询条件 - 包含左边界 + /// + [Fact] + public async Task TestBetween_2() { + //常量 + var name = "TestBetween_2"; + var price = 10.1M; + + //添加实体列表 + await AddProductsAsync(); + var products = ProductFakeService.GetProducts( 5 ); + products.ForEach( product => { + product.Init(); + product.Name = name; + product.Price = price++; + } ); + await _repository.AddAsync( products ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //查询 + var result = _repository.Find().Where( t => t.Name == name ).Between( t => t.Price, 11.1M, 13.1M,Boundary.Left ).ToList(); + + //验证 + Assert.Equal( 2, result.Count ); + } + + /// + /// 测试添加范围查询条件 - 包含右边界 + /// + [Fact] + public async Task TestBetween_3() { + //常量 + var name = "TestBetween_3"; + var price = 10.1M; + + //添加实体列表 + await AddProductsAsync(); + var products = ProductFakeService.GetProducts( 5 ); + products.ForEach( product => { + product.Init(); + product.Name = name; + product.Price = price++; + } ); + await _repository.AddAsync( products ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //查询 + var result = _repository.Find().Where( t => t.Name == name ).Between( t => t.Price, 11.1M, 13.1M, Boundary.Right ).ToList(); + + //验证 + Assert.Equal( 2, result.Count ); + } + + /// + /// 测试添加范围查询条件 - 包含两边 + /// + [Fact] + public async Task TestBetween_4() { + //常量 + var name = "TestBetween_4"; + var price = 10.1M; + + //添加实体列表 + await AddProductsAsync(); + var products = ProductFakeService.GetProducts( 5 ); + products.ForEach( product => { + product.Init(); + product.Name = name; + product.Price = price++; + } ); + await _repository.AddAsync( products ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //查询 + var result = _repository.Find().Where( t => t.Name == name ).Between( t => t.Price, 11.1M, 13.1M ).ToList(); + + //验证 + Assert.Equal( 3, result.Count ); + } + + /// + /// 测试添加范围查询条件 - 不包含边界 + /// + [Fact] + public async Task TestBetween_5() { + //常量 + var name = "TestBetween_5"; + var price = 10.1M; + + //添加实体列表 + await AddProductsAsync(); + var products = ProductFakeService.GetProducts( 5 ); + products.ForEach( product => { + product.Init(); + product.Name = name; + product.Price = price++; + } ); + await _repository.AddAsync( products ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //查询 + var result = _repository.Find().Where( t => t.Name == name ).Between( t => t.Price, 11.1M, 13.1M,Boundary.Neither ).ToList(); + + //验证 + Assert.Single( result ); + } + + /// + /// 测试添加范围查询条件 - 最大值为空 + /// + [Fact] + public async Task TestBetween_6() { + //常量 + var name = "TestBetween_6"; + var price = 10.1M; + + //添加实体列表 + await AddProductsAsync(); + var products = ProductFakeService.GetProducts( 5 ); + products.ForEach( product => { + product.Init(); + product.Name = name; + product.Price = price++; + } ); + await _repository.AddAsync( products ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //查询 + var result = _repository.Find().Where( t => t.Name == name ).Between( t => t.Price, 9.5M, null ).ToList(); + + //验证 + Assert.Equal( 5, result.Count ); + } + + /// + /// 测试添加范围查询条件 - 最小值为空 + /// + [Fact] + public async Task TestBetween_7() { + //常量 + var name = "TestBetween_7"; + var price = 10.1M; + + //添加实体列表 + await AddProductsAsync(); + var products = ProductFakeService.GetProducts( 5 ); + products.ForEach( product => { + product.Init(); + product.Name = name; + product.Price = price++; + } ); + await _repository.AddAsync( products ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //查询 + var result = _repository.Find().Where( t => t.Name == name ).Between( t => t.Price, null, 15.5M ).ToList(); + + //验证 + Assert.Equal( 5, result.Count ); + } + + #endregion + } +} diff --git a/test/Util.Data.EntityFrameworkCore.Sqlite.Tests.Integration/Tests/ProductRepositoryTest.cs b/test/Util.Data.EntityFrameworkCore.Sqlite.Tests.Integration/Tests/ProductRepositoryTest.cs new file mode 100644 index 00000000..4f939e57 --- /dev/null +++ b/test/Util.Data.EntityFrameworkCore.Sqlite.Tests.Integration/Tests/ProductRepositoryTest.cs @@ -0,0 +1,1408 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Util.Exceptions; +using Util.Tests.Fakes; +using Util.Tests.Infrastructure; +using Util.Tests.Models; +using Util.Tests.Repositories; +using Util.Tests.UnitOfWorks; +using Xunit; +using Xunit.Abstractions; +using Xunit.DependencyInjection; + +namespace Util.Data.EntityFrameworkCore.Tests { + /// + /// 产品仓储测试 + /// 说明: + /// 1. 测试Guid类型标识 + /// 2. 测试仓储基础方法 + /// 3. 测试扩展属性 + /// + public partial class ProductRepositoryTest : TestBase { + + #region 测试初始化 + + /// + /// 日志消息 + /// + private readonly ITestOutputHelper _log; + /// + /// 仓储 + /// + private readonly IProductRepository _repository; + + /// + /// 测试初始化 + /// + public ProductRepositoryTest( ITestOutputHelperAccessor accessor, IProductRepository repository, ITestUnitOfWork unitOfWork ) :base(unitOfWork) { + _log = accessor.Output; + _repository = repository; + } + + #endregion + + #region 辅助方法 + + /// + /// 添加产品 + /// + private async Task AddProductAsync( string name = null ) { + var entity = ProductFakeService.GetProduct(); + entity.Init(); + if( name != null ) + entity.Name = name; + await _repository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); + return entity; + } + + /// + /// 添加实体列表 + /// + /// 添加数量 + /// 产品名称 + private async Task> AddProductsAsync( int count = 2, string name = null ) { + var products = ProductFakeService.GetProducts( count ); + products.ForEach( product => { + product.Init(); + if( name != null ) + product.Name = name; + } ); + await _repository.AddAsync( products ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + return products.OrderBy( t => t.Id ).ToList(); + } + + /// + /// 打印更改跟踪调试信息 + /// + private void WriteTrackerDebug() { + _log.WriteLine( UnitOfWork.GetChangeTrackerDebugView() ); + } + + #endregion + + #region FindById + + /// + /// 测试通过标识查找实体 - 跟踪实体 + /// + [Fact] + public async Task TestFindById_Tracking_1() { + //添加实体 + var entity = await AddProductAsync(); + UnitOfWork.ClearCache(); + + //验证 + var result = _repository.FindById( entity.Id ); + WriteTrackerDebug(); + Assert.Equal( entity.Code, result.Code ); + } + + /// + /// 测试通过标识查找实体 - 跟踪实体 - 字符串标识 + /// + [Fact] + public async Task TestFindById_Tracking_2() { + //添加实体 + var entity = await AddProductAsync(); + UnitOfWork.ClearCache(); + + //验证 + var result = _repository.FindById( entity.Id.ToString() ); + WriteTrackerDebug(); + Assert.Equal( entity.Code, result.Code ); + } + + /// + /// 测试通过标识查找实体 - 不跟踪实体 + /// + [Fact] + public async Task TestFindById_NoTracking() { + //添加实体 + var entity = await AddProductAsync(); + UnitOfWork.ClearCache(); + + //验证 + var result = _repository.NoTracking().FindById( entity.Id ); + WriteTrackerDebug(); + Assert.Equal( entity.Code, result.Code ); + } + + #endregion + + #region FindByIdAsync + + /// + /// 测试通过标识查找实体 - 跟踪 - 异步 + /// + [Fact] + public async Task TestFindByIdAsync_Tracking_1() { + //添加实体 + var entity = await AddProductAsync(); + UnitOfWork.ClearCache(); + + //验证 + var result = await _repository.FindByIdAsync( entity.Id ); + WriteTrackerDebug(); + Assert.Equal( entity.Code, result.Code ); + } + + /// + /// 测试通过标识查找实体 - 跟踪 - 异步 - 字符串标识 + /// + [Fact] + public async Task TestFindByIdAsync_Tracking_2() { + //添加实体 + var entity = await AddProductAsync(); + UnitOfWork.ClearCache(); + + //验证 + var result = await _repository.FindByIdAsync( entity.Id.ToString() ); + WriteTrackerDebug(); + Assert.Equal( entity.Code, result.Code ); + } + + /// + /// 测试通过标识查找实体 - 不跟踪 - 异步 + /// + [Fact] + public async Task TestFindByIdAsync_NoTracking() { + //添加实体 + var entity = await AddProductAsync(); + UnitOfWork.ClearCache(); + + //验证 + var result = await _repository.NoTracking().FindByIdAsync( entity.Id ); + WriteTrackerDebug(); + Assert.Equal( entity.Code, result.Code ); + } + + #endregion + + #region FindByIds + + /// + /// 测试通过标识列表查找实体列表 - 传入逗号分隔的标识列表 + /// + [Fact] + public async Task TestFindByIds_1() { + //常量 + var count = 3; + + //添加实体列表 + var products = ProductFakeService.GetProducts( count ).OrderBy( t => t.Code ).ToList(); + products.ForEach( product => { + product.Init(); + } ); + await _repository.AddAsync( products ); + await UnitOfWork.CommitAsync(); + + //验证 + var result = _repository.FindByIds( products[0].Id, products[1].Id, products[2].Id ).OrderBy( t => t.Code ).ToList(); + Assert.Equal( products[0].Description, result[0].Description ); + Assert.Equal( products[1].Description, result[1].Description ); + Assert.Equal( products[2].Description, result[2].Description ); + } + + /// + /// 测试通过标识列表查找实体列表 - 传入集合 + /// + [Fact] + public async Task TestFindByIds_2() { + //常量 + var count = 3; + + //添加实体列表 + var products = ProductFakeService.GetProducts( count ).OrderBy( t => t.Code ).ToList(); + products.ForEach( product => { + product.Init(); + } ); + await _repository.AddAsync( products ); + await UnitOfWork.CommitAsync(); + + //验证 + var result = _repository.FindByIds( products.Select( t => t.Id ) ).OrderBy( t => t.Code ).ToList(); + Assert.Equal( products[0].Description, result[0].Description ); + Assert.Equal( products[1].Description, result[1].Description ); + Assert.Equal( products[2].Description, result[2].Description ); + } + + /// + /// 测试通过标识列表查找实体列表 - 传入标识列表字符串 + /// + [Fact] + public async Task TestFindByIds_3() { + //常量 + var count = 3; + + //添加实体列表 + var products = ProductFakeService.GetProducts( count ).OrderBy( t => t.Code ).ToList(); + products.ForEach( product => { + product.Init(); + } ); + await _repository.AddAsync( products ); + await UnitOfWork.CommitAsync(); + + //验证 + var result = _repository.FindByIds( products.Select( t => t.Id ).Join() ).OrderBy( t => t.Code ).ToList(); + Assert.Equal( products[0].Description, result[0].Description ); + Assert.Equal( products[1].Description, result[1].Description ); + Assert.Equal( products[2].Description, result[2].Description ); + } + + #endregion + + #region FindByIdsAsync + + /// + /// 测试通过标识列表查找实体列表 - 传入逗号分隔的标识列表 - 异步 + /// + [Fact] + public async Task TestFindByIdsAsync_1() { + //常量 + var count = 3; + + //添加实体列表 + var products = ProductFakeService.GetProducts( count ).OrderBy( t => t.Code ).ToList(); + products.ForEach( product => { + product.Init(); + } ); + await _repository.AddAsync( products ); + await UnitOfWork.CommitAsync(); + + //验证 + var result = ( await _repository.FindByIdsAsync( products[0].Id, products[1].Id, products[2].Id ) ).OrderBy( t => t.Code ).ToList(); + Assert.Equal( products[0].Description, result[0].Description ); + Assert.Equal( products[1].Description, result[1].Description ); + Assert.Equal( products[2].Description, result[2].Description ); + } + + /// + /// 测试通过标识列表查找实体列表 - 传入集合 - 异步 + /// + [Fact] + public async Task TestFindByIdsAsync_2() { + //常量 + var count = 3; + + //添加实体列表 + var products = ProductFakeService.GetProducts( count ).OrderBy( t => t.Code ).ToList(); + products.ForEach( product => { + product.Init(); + } ); + await _repository.AddAsync( products ); + await UnitOfWork.CommitAsync(); + + //验证 + var result = ( await _repository.FindByIdsAsync( products.Select( t => t.Id ) ) ).OrderBy( t => t.Code ).ToList(); + Assert.Equal( products[0].Description, result[0].Description ); + Assert.Equal( products[1].Description, result[1].Description ); + Assert.Equal( products[2].Description, result[2].Description ); + } + + /// + /// 测试通过标识列表查找实体列表 - 传入标识列表字符串 - 异步 + /// + [Fact] + public async Task TestFindByIdsAsync_3() { + //常量 + var count = 3; + + //添加实体列表 + var products = ProductFakeService.GetProducts( count ).OrderBy( t => t.Code ).ToList(); + products.ForEach( product => { + product.Init(); + } ); + await _repository.AddAsync( products ); + await UnitOfWork.CommitAsync(); + + //验证 + var result = ( await _repository.FindByIdsAsync( products.Select( t => t.Id ).Join() ) ).OrderBy( t => t.Code ).ToList(); + Assert.Equal( products[0].Description, result[0].Description ); + Assert.Equal( products[1].Description, result[1].Description ); + Assert.Equal( products[2].Description, result[2].Description ); + } + + #endregion + + #region Single + + /// + /// 测试查找单个实体 + /// + [Fact] + public async Task TestSingle_1() { + //常量 + var name = "TestSingle"; + + //添加实体 + var entity = await AddProductAsync( name ); + UnitOfWork.ClearCache(); + + //验证 + var result = _repository.Single( t => t.Name == name ); + Assert.Equal( entity.Code, result.Code ); + } + + #endregion + + #region SingleAsync + + /// + /// 测试查找单个实体 - 异步 + /// + [Fact] + public async Task TestSingleAsync() { + //常量 + var name = "TestSingleAsync"; + + //添加实体 + var entity = await AddProductAsync( name ); + UnitOfWork.ClearCache(); + + //验证 + var result = await _repository.SingleAsync( t => t.Name == name ); + Assert.Equal( entity.Code, result.Code ); + } + + #endregion + + #region Exists + + /// + /// 测试判断是否存在 + /// + [Fact] + public async Task TestExists() { + //添加实体 + var entity = await AddProductAsync(); + UnitOfWork.ClearCache(); + + //验证 + Assert.True( _repository.Exists( t => t.Id == entity.Id ) ); + } + + #endregion + + #region ExistsAsync + + /// + /// 测试判断是否存在 - 异步 + /// + [Fact] + public async Task TestExistsAsync() { + //添加实体 + var entity = await AddProductAsync(); + UnitOfWork.ClearCache(); + + //验证 + Assert.True( await _repository.ExistsAsync( t => t.Id == entity.Id ) ); + } + + #endregion + + #region Count + + /// + /// 测试查找数量 + /// + [Fact] + public async Task TestCount() { + //常量 + var name = "TestCount"; + var count = 3; + + //添加实体列表 + var products = ProductFakeService.GetProducts( count ); + products.ForEach( product => { + product.Init(); + product.Name = name; + } ); + await _repository.AddAsync( products ); + await UnitOfWork.CommitAsync(); + + //验证 + var result = _repository.Count( t => t.Name == name ); + Assert.Equal( count, result ); + } + + #endregion + + #region CountAsync + + /// + /// 测试查找数量 - 异步 + /// + [Fact] + public async Task TestCountAsync() { + //常量 + var name = "TestCountAsync"; + var count = 3; + + //添加实体列表 + var products = ProductFakeService.GetProducts( count ); + products.ForEach( product => { + product.Init(); + product.Name = name; + } ); + await _repository.AddAsync( products ); + await UnitOfWork.CommitAsync(); + + //验证 + var result = await _repository.CountAsync( t => t.Name == name ); + Assert.Equal( count, result ); + } + + #endregion + + #region Update + + /// + /// 测试更新方法1 - 查找并修改实体,直接提交工作单元 + /// + [Fact] + public async Task TestUpdate_1() { + //常量 + var code = "TestUpdate_1_Code"; + + //添加实体 + var entity = await AddProductAsync(); + UnitOfWork.ClearCache(); + + //查找实体并修改 + var product = await _repository.FindByIdAsync( entity.Id ); + product.Code = code; + + //直接提交工作单元 + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //验证 + var result = await _repository.FindByIdAsync( entity.Id ); + Assert.Equal( code, result.Code ); + } + + /// + /// 测试更新并发 - 使用更新方法1 + /// 更新方法1的缺陷: 通过赋值的方式更新查找实体的版本号,无法触发乐观锁 + /// + [Fact] + public async Task TestUpdate_1_Concurrency() { + //常量 + var code = "TestUpdate_1_Concurrency_Code"; + var description = "TestUpdate_1_Concurrency_Description"; + + //添加实体 + var entity = await AddProductAsync(); + UnitOfWork.ClearCache(); + + //此处模拟用户1打开表单并修改,但尚未提交,这将保存旧实体 + var product = await _repository.FindByIdAsync( entity.Id ); + product.Code = code; + UnitOfWork.ClearCache(); + + //此处模拟用户2更新该实体,这将导致版本号变化 + var product2 = await _repository.FindByIdAsync( entity.Id ); + product2.Description = description; + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //此处模拟用户1提交表单,查找实体,并进行赋值 + var result = _repository.FindById( entity.Id ); + result.Code = product.Code; + result.Description = product.Description; + result.Version = product.Version; + //提交工作单元,由于版本号变化,预期应触发乐观锁,但实际未触发 + await UnitOfWork.CommitAsync(); + + //结果:用户1覆盖了用户2设置的Description属性 + Assert.Equal( code, result.Code ); + Assert.NotEqual( description, result.Description ); + } + + /// + /// 测试更新方法2 - 创建未跟踪实体,调用dbcontext.Update方法 + /// + [Fact] + public async Task TestUpdate_2() { + //常量 + var code = "TestUpdate_2_Code"; + + //添加实体 + var entity = await AddProductAsync(); + UnitOfWork.ClearCache(); + + //创建未跟踪实体 + var product = entity.MapTo(); + product.Code = code; + //调用dbcontext.Update方法更新实体 + _repository.UpdateProduct( product ); + //提交工作单元 + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //验证 + var result = await _repository.FindByIdAsync( entity.Id ); + Assert.Equal( code, result.Code ); + } + + /// + /// 测试更新方法2的陷阱 + /// 如果在创建未跟踪实体并调用dbcontext.Update方法之前,从dbcontext中已查找出该实体,将发生异常 + /// + [Fact] + public async Task TestUpdate_2_InvalidOperation() { + //常量 + var code = "TestUpdate_2_InvalidOperation_Code"; + + //添加实体 + var entity = await AddProductAsync(); + UnitOfWork.ClearCache(); + + //模拟更新之前无意中已查找出该实体 + await _repository.FindByIdAsync( entity.Id ); + + //创建未跟踪实体 + var product = entity.MapTo(); + product.Code = code; + + //由于实体已被跟踪,调用dbcontext.Update方法更新实体将触发异常 + Assert.Throws( () => { + _repository.UpdateProduct( product ); + } ); + } + + /// + /// 测试更新并发 - 使用更新方法2 + /// + [Fact] + public async Task TestUpdate_2_Concurrency() { + //常量 + var code = "TestUpdate_2_Concurrency_Code"; + var description = "TestUpdate_2_Concurrency_Description"; + + //添加实体 + var entity = await AddProductAsync(); + UnitOfWork.ClearCache(); + + //此处模拟用户1打开表单并修改,但尚未提交,这将保存旧实体 + var product = await _repository.FindByIdAsync( entity.Id ); + product.Code = code; + UnitOfWork.ClearCache(); + + //此处模拟用户2更新该实体,这将导致版本号变化 + var product2 = await _repository.FindByIdAsync( entity.Id ); + product2.Description = description; + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //此处模拟用户1提交表单,创建一个新的实体,并赋值 + var result = product.MapTo(); + + //调用dbcontext.Update方法更新实体 + _repository.UpdateProduct( result ); + + //提交工作单元,由于版本号变化,触发乐观锁 + await Assert.ThrowsAsync( async () => { + await UnitOfWork.CommitAsync(); + } ); + } + + /// + /// 测试Util Update更新方法 - 查找并修改实体,提交工作单元 + /// + [Fact] + public async Task TestUpdate_3_1() { + //常量 + var code = "TestUpdate_3_1_Code"; + + //添加实体 + var entity = await AddProductAsync(); + UnitOfWork.ClearCache(); + + //查找实体并修改 + var product = await _repository.FindByIdAsync( entity.Id ); + product.Code = code; + + //调用Update方法 + await _repository.UpdateAsync( product ); + + //提交工作单元 + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //验证 + var result = _repository.FindById( entity.Id ); + Assert.Equal( code, result.Code ); + } + + /// + /// 测试Util Update更新方法 - 创建未跟踪实体,调用Update方法 + /// + [Fact] + public async Task TestUpdate_3_2() { + //常量 + var code = "TestUpdate_3_2_Code"; + + //添加实体 + var entity = await AddProductAsync(); + UnitOfWork.ClearCache(); + + //创建未跟踪实体 + var product = entity.MapTo(); + product.Code = code; + + //调用Update方法更新实体 + await _repository.UpdateAsync( product ); + + //提交工作单元 + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //验证 + var result = await _repository.FindByIdAsync( entity.Id ); + Assert.Equal( code, result.Code ); + } + + /// + /// 测试Util Update更新方法 - 允许在创建未跟踪实体并调用Update方法之前查找实体,不会发生异常 + /// + [Fact] + public async Task TestUpdate_3_3() { + //常量 + var code = "TestUpdate_3_3_InvalidOperation_Code"; + + //添加实体 + var entity = await AddProductAsync(); + UnitOfWork.ClearCache(); + + //模拟更新之前无意中已查找出该实体 + await _repository.FindByIdAsync( entity.Id ); + + //创建未跟踪实体 + var product = entity.MapTo(); + product.Code = code; + + //调用Update方法更新实体 + await _repository.UpdateAsync( product ); + + //提交工作单元 + _log.WriteLine( UnitOfWork.GetChangeTrackerDebugView() ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //验证 + var result = _repository.FindById( entity.Id ); + Assert.Equal( code, result.Code ); + } + + /// + /// 测试更新并发 - 使用Util Update更新方法 + /// 通过赋值的方式更新查找实体的版本号,触发乐观锁 + /// + [Fact] + public async Task TestUpdate_3_Concurrency_1() { + //常量 + var code = "TestUpdate_3_Concurrency_1_Code"; + var description = "TestUpdate_3_Concurrency_1_Description"; + + //添加实体 + var entity = await AddProductAsync(); + UnitOfWork.ClearCache(); + + //此处模拟用户1打开表单并修改,但尚未提交,这将保存旧实体 + var product = await _repository.FindByIdAsync( entity.Id ); + product.Code = code; + UnitOfWork.ClearCache(); + + //此处模拟用户2更新该实体,这将导致版本号变化 + var product2 = await _repository.FindByIdAsync( entity.Id ); + product2.Description = description; + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //此处模拟用户1提交表单,查找实体,并进行赋值 + var result = await _repository.FindByIdAsync( entity.Id ); + result.Code = product.Code; + result.Description = product.Description; + result.Version = product.Version; + + //调用Update方法更新实体时触发乐观锁 + await Assert.ThrowsAsync( async () => { + await _repository.UpdateAsync( result ); + } ); + } + + /// + /// 测试更新并发 - 使用Util Update更新方法 + /// 更新未跟踪实体触发乐观锁 + /// + [Fact] + public async Task TestUpdate_3_Concurrency_2() { + //常量 + var code = "TestUpdate_3_Concurrency_2_Code"; + var description = "TestUpdate_3_Concurrency_2_Description"; + + //添加实体 + var entity = await AddProductAsync(); + UnitOfWork.ClearCache(); + + //此处模拟用户1打开表单并修改,但尚未提交,这将保存旧实体 + var product = await _repository.FindByIdAsync( entity.Id ); + product.Code = code; + UnitOfWork.ClearCache(); + + //此处模拟用户2更新该实体,这将导致版本号变化 + var product2 = await _repository.FindByIdAsync( entity.Id ); + product2.Description = description; + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //此处模拟用户1提交表单,创建一个新的实体,并赋值 + var result = product.MapTo(); + + //调用Update方法更新实体 + await _repository.UpdateAsync( result ); + + //提交工作单元,由于版本号变化,触发乐观锁 + await Assert.ThrowsAsync( async () => { + await UnitOfWork.CommitAsync(); + } ); + } + + /// + /// 测试更新集合 + /// + [Fact] + public async Task TestUpdate_4() { + //常量 + var count = 3; + var code = "TestUpdate_4_Code"; + + //添加实体列表 + var entities = ProductFakeService.GetProducts( count ); + entities.ForEach( product => { + product.Init(); + } ); + await _repository.AddAsync( entities ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //查找实体,赋值,调用Update方法,提交工作单元 + var products = await _repository.FindByIdsAsync( entities.Select( t => t.Id ) ); + products.ForEach( product => product.Code = code ); + await _repository.UpdateAsync( products ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //验证 + var result = await _repository.FindByIdsAsync( entities.Select( t => t.Id ) ); + Assert.Equal( code, result[0].Code ); + Assert.Equal( code, result[1].Code ); + Assert.Equal( code, result[2].Code ); + } + + #endregion + + #region Remove + + /// + /// 测试通过标识移除实体 - 逻辑删除 + /// + [Fact] + public async Task TestRemoveAsync_Id_1() { + //添加实体 + var entity = await AddProductAsync(); + UnitOfWork.ClearCache(); + + //移除实体 + await _repository.RemoveAsync( entity.Id ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //验证 + var result = await _repository.FindByIdAsync( entity.Id ); + Assert.Null( result ); + } + + /// + /// 测试通过标识移除实体 - 逻辑删除 - 使用工作单元禁用逻辑删除过滤器 + /// + [Fact] + public async Task TestRemoveAsync_Id_2() { + //添加实体 + var entity = await AddProductAsync(); + UnitOfWork.ClearCache(); + + //移除实体 + await _repository.RemoveAsync( entity.Id ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //使用工作单元禁用逻辑删除过滤器,可以查出 + using( UnitOfWork.DisableDeleteFilter() ) { + var product = await _repository.FindByIdAsync( entity.Id ); + Assert.True( product.IsDeleted ); + Assert.Equal( entity.Code, product.Code ); + } + UnitOfWork.ClearCache(); + + //逻辑删除过滤器已启用,无法查出 + var result = await _repository.FindByIdAsync( entity.Id ); + Assert.Null( result ); + } + + /// + /// 测试通过标识移除实体 - 逻辑删除 - 使用仓储禁用逻辑删除过滤器 + /// + [Fact] + public async Task TestRemoveAsync_Id_3() { + //添加实体 + var entity = await AddProductAsync(); + UnitOfWork.ClearCache(); + + //移除实体 + await _repository.RemoveAsync( entity.Id ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //使用仓储禁用逻辑删除过滤器,可以查出 + using( _repository.DisableDeleteFilter() ) { + var product = await _repository.FindByIdAsync( entity.Id ); + Assert.True( product.IsDeleted ); + Assert.Equal( entity.Code, product.Code ); + } + UnitOfWork.ClearCache(); + + //逻辑删除过滤器已启用,无法查出 + var result = await _repository.FindByIdAsync( entity.Id ); + Assert.Null( result ); + } + + /// + /// 测试移除实体 - 逻辑删除 + /// + [Fact] + public async Task TestRemoveAsync_Entity() { + //添加实体 + var entity = await AddProductAsync(); + UnitOfWork.ClearCache(); + + //移除实体 + await _repository.RemoveAsync( entity ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //验证 + var result = await _repository.FindByIdAsync( entity.Id ); + Assert.Null( result ); + } + + /// + /// 测试移除实体集合 - 逻辑删除 - 通过标识列表 + /// + [Fact] + public async Task TestRemoveAsync_Entities_1() { + //常量 + var count = 3; + + //添加实体列表 + var products = ProductFakeService.GetProducts( count ).ToList(); + products.ForEach( product => { + product.Init(); + } ); + await _repository.AddAsync( products ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //移除实体集合 + var ids = products.Select( t => t.Id ).ToList(); + await _repository.RemoveAsync( ids ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //验证 + using( _repository.DisableDeleteFilter() ) { + var result = await _repository.FindByIdsAsync( ids ); + Assert.Equal( count, result.Count ); + result.ForEach( t => Assert.True( t.IsDeleted ) ); + } + } + + /// + /// 测试移除实体集合 - 逻辑删除 - 通过实体列表 + /// + [Fact] + public async Task TestRemoveAsync_Entities_2() { + //常量 + var count = 3; + + //添加实体列表 + var products = ProductFakeService.GetProducts( count ).ToList(); + products.ForEach( product => { + product.Init(); + } ); + await _repository.AddAsync( products ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //移除实体集合 + await _repository.RemoveAsync( products ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //验证 + using( _repository.DisableDeleteFilter() ) { + var result = await _repository.FindByIdsAsync( products.Select( t => t.Id ) ); + Assert.Equal( count, result.Count ); + result.ForEach( t => Assert.True( t.IsDeleted ) ); + } + } + + #endregion + + #region Audit + + /// + /// 测试设置创建审计属性 + /// + [Fact] + public async Task TestCreationAudit() { + var entity = ProductFakeService.GetProduct(); + entity.Init(); + await _repository.AddAsync( entity ); + Assert.NotEqual( TestSession.TestUserId, entity.CreatorId ); + await UnitOfWork.CommitAsync(); + Assert.Equal( TestSession.TestUserId, entity.CreatorId ); + Assert.Equal( TestSession.TestUserId, entity.LastModifierId ); + } + + /// + /// 测试设置修改审计属性 + /// + [Fact] + public async Task TestModificationAudit() { + //工作单元 + var unitOfWork = (SqliteUnitOfWork)UnitOfWork; + + //常量 + var code = "TestModificationAudit"; + + //添加实体 + var entity = await AddProductAsync(); + unitOfWork.ClearCache(); + + //修改 + var product = entity.MapTo(); + product.Code = code; + await _repository.UpdateAsync( product ); + unitOfWork.SetSession( new TestSession { UserId = TestSession.TestUserId2.ToString() } ); + + //验证修改前审计属性 + Assert.Equal( TestSession.TestUserId, product.CreatorId ); + Assert.Equal( TestSession.TestUserId, product.LastModifierId ); + + //提交 + await unitOfWork.CommitAsync(); + + //验证修改后审计属性 + Assert.Equal( TestSession.TestUserId, product.CreatorId ); + Assert.Equal( TestSession.TestUserId2, product.LastModifierId ); + } + + #endregion + + #region ExtraProperties + + /// + /// 测试扩展属性 - 添加简单扩展属性 + /// + [Fact] + public async Task TestExtraProperties_1() { + //常量 + var value = "TestExtraProperties_1"; + + //添加实体 + var entity = new Product(); + entity.Init(); + entity.TestProperty1 = value; + await _repository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //验证 + var result = await _repository.FindByIdAsync( entity.Id ); + Assert.Equal( value, result.TestProperty1 ); + } + + /// + /// 测试扩展属性 - 修改简单扩展属性 + /// + [Fact] + public async Task TestExtraProperties_2() { + //常量 + var oldValue = "TestExtraProperties_2_1"; + var newValue = "TestExtraProperties_2_2"; + + //添加实体 + var entity = new Product(); + entity.Init(); + entity.TestProperty1 = oldValue; + await _repository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //验证 + var oldEntity = await _repository.FindByIdAsync( entity.Id ); + Assert.Equal( oldValue, oldEntity.TestProperty1 ); + + //修改实体 + oldEntity.TestProperty1 = newValue; + await _repository.UpdateAsync( oldEntity ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //验证 + var result = await _repository.FindByIdAsync( entity.Id ); + Assert.Equal( newValue, result.TestProperty1 ); + } + + /// + /// 测试扩展属性 - 添加对象扩展属性 + /// + [Fact] + public async Task TestExtraProperties_3() { + //常量 + var code = 2; + var name = "TestExtraProperties_3"; + var enumValue = ProductEnum.World; + + //添加实体 + var entity = new Product(); + entity.Init(); + entity.TestProperty2.Code = code; + entity.TestProperty2.Name = name; + entity.TestProperty2.EnumValue = enumValue; + await _repository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //验证 + var result = _repository.FindById( entity.Id ); + Assert.Equal( code, result.TestProperty2.Code ); + Assert.Equal( name, result.TestProperty2.Name ); + Assert.Equal( enumValue, result.TestProperty2.EnumValue ); + } + + /// + /// 测试扩展属性 - 修改对象扩展属性 + /// + [Fact] + public async Task TestExtraProperties_4() { + //常量 + var code = 2; + var oldName = "TestExtraProperties_4_1"; + var newName = "TestExtraProperties_4_2"; + var oldEnumValue = ProductEnum.Hello; + var newEnumValue = ProductEnum.World; + + //添加实体 + var entity = new Product(); + entity.Init(); + entity.TestProperty2.Code = code; + entity.TestProperty2.Name = oldName; + entity.TestProperty2.EnumValue = oldEnumValue; + await _repository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //验证 + var oldEntity = await _repository.FindByIdAsync( entity.Id ); + Assert.Equal( code, oldEntity.TestProperty2.Code ); + Assert.Equal( oldName, oldEntity.TestProperty2.Name ); + Assert.Equal( oldEnumValue, oldEntity.TestProperty2.EnumValue ); + + //修改实体 + oldEntity.TestProperty2.Name = newName; + oldEntity.TestProperty2.EnumValue = newEnumValue; + WriteTrackerDebug(); + await _repository.UpdateAsync( oldEntity ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //验证 + var result = await _repository.FindByIdAsync( entity.Id ); + Assert.Equal( newName, result.TestProperty2.Name ); + Assert.Equal( newEnumValue, result.TestProperty2.EnumValue ); + } + + /// + /// 测试扩展属性 - 添加对象集合扩展属性 + /// + [Fact] + public async Task TestExtraProperties_5() { + //常量 + var code = 1; + var name1 = "TestExtraProperties_5_1"; + var name2 = "TestExtraProperties_5_2"; + + //添加实体 + var entity = new Product(); + entity.Init(); + entity.TestProperties.Add( new ProductItem { Code = code, Name = name1 } ); + entity.TestProperties.Add( new ProductItem { Code = code, Name = name2 } ); + await _repository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //验证 + var result = await _repository.FindByIdAsync( entity.Id ); + Assert.Equal( 2, result.TestProperties.Count ); + Assert.Equal( code, result.TestProperties[0].Code ); + Assert.Equal( name1, result.TestProperties[0].Name ); + Assert.Equal( code, result.TestProperties[1].Code ); + Assert.Equal( name2, result.TestProperties[1].Name ); + } + + /// + /// 测试扩展属性 - 修改对象集合扩展属性 + /// + [Fact] + public async Task TestExtraProperties_6() { + //常量 + var code = 1; + var oldName = "TestExtraProperties_6_1"; + var newName = "TestExtraProperties_6_2"; + var name3 = "TestExtraProperties_6_3"; + + //添加实体 + var entity = new Product(); + entity.Init(); + entity.TestProperties.Add( new ProductItem { Code = code, Name = oldName } ); + entity.TestProperties.Add( new ProductItem { Code = code, Name = oldName } ); + await _repository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //验证 + var oldEntity = await _repository.FindByIdAsync( entity.Id ); + Assert.Equal( 2, oldEntity.TestProperties.Count ); + + //修改实体 + oldEntity.TestProperties[0].Name = newName; + oldEntity.TestProperties[1].Name = newName; + oldEntity.TestProperties.Add( new ProductItem { Code = code, Name = name3 } ); + await _repository.UpdateAsync( oldEntity ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //验证 + var result = await _repository.FindByIdAsync( entity.Id ); + Assert.Equal( 3, result.TestProperties.Count ); + Assert.Equal( code, result.TestProperties[0].Code ); + Assert.Equal( newName, result.TestProperties[0].Name ); + Assert.Equal( code, result.TestProperties[1].Code ); + Assert.Equal( newName, result.TestProperties[1].Name ); + Assert.Equal( code, result.TestProperties[2].Code ); + Assert.Equal( name3, result.TestProperties[2].Name ); + } + + /// + /// 测试扩展属性 - 添加多个扩展属性 + /// + [Fact] + public async Task TestExtraProperties_7() { + //常量 + var code = 2; + var name = "TestExtraProperties_7"; + + //添加实体 + var entity = new Product(); + entity.Init(); + entity.TestProperty1 = name; + entity.TestProperty2.Code = code; + entity.TestProperty2.Name = name; + entity.TestProperties.Add( new ProductItem { Code = code, Name = name } ); + entity.TestProperties.Add( new ProductItem { Code = code, Name = name } ); + await _repository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //验证 + var result = await _repository.FindByIdAsync( entity.Id ); + Assert.Equal( name, result.TestProperty1 ); + Assert.Equal( code, result.TestProperty2.Code ); + Assert.Equal( name, result.TestProperty2.Name ); + Assert.Equal( code, result.TestProperties[0].Code ); + Assert.Equal( name, result.TestProperties[0].Name ); + Assert.Equal( code, result.TestProperties[1].Code ); + Assert.Equal( name, result.TestProperties[1].Name ); + } + + /// + /// 测试扩展属性 - 修改多个扩展属性 + /// + [Fact] + public async Task TestExtraProperties_8() { + //常量 + var code = 2; + var oldName = "TestExtraProperties_8_1"; + var newName = "TestExtraProperties_8_2"; + + //添加实体 + var entity = new Product(); + entity.Init(); + entity.TestProperty1 = oldName; + entity.TestProperty2.Code = code; + entity.TestProperty2.Name = oldName; + entity.TestProperties.Add( new ProductItem { Code = code, Name = oldName } ); + entity.TestProperties.Add( new ProductItem { Code = code, Name = oldName } ); + await _repository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //验证 + var oldEntity = await _repository.FindByIdAsync( entity.Id ); + Assert.Equal( oldName, oldEntity.TestProperty1 ); + Assert.Equal( code, oldEntity.TestProperty2.Code ); + Assert.Equal( oldName, oldEntity.TestProperty2.Name ); + Assert.Equal( 2, oldEntity.TestProperties.Count ); + + //修改实体 + oldEntity.TestProperty1 = newName; + oldEntity.TestProperty2.Name = newName; + oldEntity.TestProperties[0].Name = newName; + oldEntity.TestProperties[1].Name = newName; + oldEntity.TestProperties.Add( new ProductItem{ Code = code, Name = newName } ); + await _repository.UpdateAsync( oldEntity ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //验证 + var result = await _repository.FindByIdAsync( entity.Id ); + Assert.Equal( newName, result.TestProperty1 ); + Assert.Equal( newName, result.TestProperty2.Name ); + Assert.Equal( 3, result.TestProperties.Count ); + Assert.Equal( newName, result.TestProperties[0].Name ); + Assert.Equal( newName, result.TestProperties[1].Name ); + Assert.Equal( newName, result.TestProperties[2].Name ); + } + + /// + /// 测试扩展属性 - 添加枚举扩展属性 + /// + [Fact] + public async Task TestExtraProperties_9() { + //常量 + ProductEnum value = ProductEnum.World; + + //添加实体 + var entity = new Product(); + entity.Init(); + entity.TestProperty3 = value; + await _repository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //验证 + var result = await _repository.FindByIdAsync( entity.Id ); + Assert.Equal( value, result.TestProperty3 ); + } + + /// + /// 测试扩展属性 - 修改枚举扩展属性 + /// + [Fact] + public async Task TestExtraProperties_10() { + //常量 + ProductEnum oldValue = ProductEnum.Hello; + ProductEnum newValue = ProductEnum.World; + + //添加实体 + var entity = new Product(); + entity.Init(); + entity.TestProperty3 = oldValue; + await _repository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //验证 + var oldEntity = await _repository.FindByIdAsync( entity.Id ); + Assert.Equal( oldValue, oldEntity.TestProperty3 ); + + //修改实体 + oldEntity.TestProperty3 = newValue; + await _repository.UpdateAsync( oldEntity ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //验证 + var result = await _repository.FindByIdAsync( entity.Id ); + Assert.Equal( newValue, result.TestProperty3 ); + } + + /// + /// 测试扩展属性 - 添加不可变对象扩展属性 + /// + [Fact] + public async Task TestExtraProperties_11() { + //常量 + var code = 2; + var name = "TestExtraProperties_11"; + + //添加实体 + var entity = new Product(); + entity.Init(); + entity.TestProperty4 = new ProductItem2( code, name ); + await _repository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //验证 + var result = await _repository.FindByIdAsync( entity.Id ); + Assert.Equal( code, result.TestProperty4.Code ); + Assert.Equal( name, result.TestProperty4.Name ); + } + + /// + /// 测试扩展属性 - 修改对象扩展属性 + /// + [Fact] + public async Task TestExtraProperties_12() { + //常量 + var code = 2; + var oldName = "TestExtraProperties_12_1"; + var newName = "TestExtraProperties_12_2"; + + //添加实体 + var entity = new Product(); + entity.Init(); + entity.TestProperty4 = new ProductItem2( code, oldName ); + await _repository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //验证 + var oldEntity = await _repository.FindByIdAsync( entity.Id ); + Assert.Equal( code, oldEntity.TestProperty4.Code ); + Assert.Equal( oldName, oldEntity.TestProperty4.Name ); + + //修改实体 + oldEntity.TestProperty4 = new ProductItem2( code, newName ); + WriteTrackerDebug(); + await _repository.UpdateAsync( oldEntity ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //验证 + var result = await _repository.FindByIdAsync( entity.Id ); + Assert.Equal( newName, result.TestProperty4.Name ); + } + + #endregion + } +} \ No newline at end of file diff --git a/test/Util.Data.EntityFrameworkCore.Sqlite.Tests.Integration/Tests/TagRepositoryTest.cs b/test/Util.Data.EntityFrameworkCore.Sqlite.Tests.Integration/Tests/TagRepositoryTest.cs new file mode 100644 index 00000000..3819f129 --- /dev/null +++ b/test/Util.Data.EntityFrameworkCore.Sqlite.Tests.Integration/Tests/TagRepositoryTest.cs @@ -0,0 +1,41 @@ +using System.Threading.Tasks; +using Util.Tests.Fakes; +using Util.Tests.Infrastructure; +using Util.Tests.Repositories; +using Util.Tests.UnitOfWorks; +using Xunit; + +namespace Util.Data.EntityFrameworkCore.Tests { + /// + /// 标签仓储测试 + /// + public class TagRepositoryTest : TestBase { + /// + /// 仓储 + /// + private readonly ITagRepository _repository; + + /// + /// 测试初始化 + /// + public TagRepositoryTest( ITagRepository repository, ITestUnitOfWork unitOfWork ) : base( unitOfWork ) { + _repository = repository; + } + + /// + /// 测试添加实体 + /// + [Fact] + public async Task TestAddAsync() { + //添加实体 + var entity = TagFakeService.GetTag(); + entity.Init(); + await _repository.AddAsync( entity ); + await UnitOfWork.CommitAsync(); + UnitOfWork.ClearCache(); + + //验证 + Assert.True( await _repository.ExistsAsync( t => t.Id == entity.Id ) ); + } + } +} \ No newline at end of file diff --git a/test/Util.Data.EntityFrameworkCore.Sqlite.Tests.Integration/Util.Data.EntityFrameworkCore.Sqlite.Tests.Integration.csproj b/test/Util.Data.EntityFrameworkCore.Sqlite.Tests.Integration/Util.Data.EntityFrameworkCore.Sqlite.Tests.Integration.csproj new file mode 100644 index 00000000..e94458e6 --- /dev/null +++ b/test/Util.Data.EntityFrameworkCore.Sqlite.Tests.Integration/Util.Data.EntityFrameworkCore.Sqlite.Tests.Integration.csproj @@ -0,0 +1,39 @@ + + + + $(NetTargetFramework) + false + Util.Data.EntityFrameworkCore + Util.Data.EntityFrameworkCore.Startup + + + + + Always + + + Always + + + + + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + \ No newline at end of file diff --git a/test/Util.Data.EntityFrameworkCore.Sqlite.Tests.Integration/appsettings.Development.json b/test/Util.Data.EntityFrameworkCore.Sqlite.Tests.Integration/appsettings.Development.json new file mode 100644 index 00000000..0c8f9152 --- /dev/null +++ b/test/Util.Data.EntityFrameworkCore.Sqlite.Tests.Integration/appsettings.Development.json @@ -0,0 +1,11 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Trace", + "Microsoft": "Trace" + } + }, + "ConnectionStrings": { + "connection": "Filename=Util.Data.EntityFrameworkCore.Test.db" + } +} \ No newline at end of file diff --git a/test/Util.Data.EntityFrameworkCore.Sqlite.Tests.Integration/appsettings.json b/test/Util.Data.EntityFrameworkCore.Sqlite.Tests.Integration/appsettings.json new file mode 100644 index 00000000..1e1c1827 --- /dev/null +++ b/test/Util.Data.EntityFrameworkCore.Sqlite.Tests.Integration/appsettings.json @@ -0,0 +1,11 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Error", + "Microsoft": "Error" + } + }, + "ConnectionStrings": { + "connection": "Filename=Util.Data.EntityFrameworkCore.Test.db" + } +} \ No newline at end of file diff --git a/test/Util.Data.Sql.Tests/Builders/Clauses/EndClauseTest.cs b/test/Util.Data.Sql.Tests/Builders/Clauses/EndClauseTest.cs new file mode 100644 index 00000000..1a74e692 --- /dev/null +++ b/test/Util.Data.Sql.Tests/Builders/Clauses/EndClauseTest.cs @@ -0,0 +1,188 @@ +using System.Text; +using Util.Data.Queries; +using Util.Data.Sql.Builders; +using Util.Data.Sql.Builders.Clauses; +using Util.Data.Sql.Builders.Params; +using Util.Data.Sql.Tests.Samples; +using Xunit; + +namespace Util.Data.Sql.Tests.Builders.Clauses { + /// + /// 结束子句测试 + /// + public class EndClauseTest { + + #region 测试初始化 + + /// + /// 参数管理器 + /// + private readonly IParameterManager _parameterManager; + /// + /// 结束子句 + /// + private readonly EndClause _clause; + + /// + /// 测试初始化 + /// + public EndClauseTest() { + _parameterManager = new ParameterManager( TestDialect.Instance ); + _clause = CreateEndClause( TestDialect.Instance ); + } + + /// + /// 创建结束子句 + /// + private EndClause CreateEndClause( IDialect dialect ) { + return new EndClause( new TestSqlBuilder( dialect, parameterManager:_parameterManager ) ); + } + + /// + /// 获取Sql语句 + /// + private string GetSql( IEndClause clause = null ) { + clause ??= _clause; + var builder = new StringBuilder(); + clause.AppendTo( builder ); + return builder.ToString(); + } + + #endregion + + #region Take + + /// + /// 测试设置获取行数 + /// + [Fact] + public void TestTake() { + _clause.Take( 20 ); + Assert.Equal( "Limit @_p_0 OFFSET @_p_1", GetSql() ); + Assert.Equal( 20, _parameterManager.GetValue( "@_p_0" ) ); + Assert.Equal( 0, _parameterManager.GetValue( "@_p_1" ) ); + } + + #endregion + + #region Skip + + /// + /// 测试设置跳过行数 + /// + [Fact] + public void TestSkip() { + _clause.Skip( 80 ); + _clause.Take( 40 ); + Assert.Equal( "Limit @_p_1 OFFSET @_p_0", GetSql() ); + Assert.Equal( 80, _parameterManager.GetValue( "@_p_0" ) ); + Assert.Equal( 40, _parameterManager.GetValue( "@_p_1" ) ); + } + + #endregion + + #region Page + + /// + /// 测试设置分页 + /// + [Fact] + public void TestPage() { + var page = new Pager( 3, 40 ); + _clause.Page( page ); + Assert.Equal( "Limit @_p_1 OFFSET @_p_0", GetSql() ); + Assert.Equal( 80, _parameterManager.GetValue( "@_p_0" ) ); + Assert.Equal( 40, _parameterManager.GetValue( "@_p_1" ) ); + } + + #endregion + + #region AppendSql + + /// + /// 测试添加到结束位置 - 替换[]为特定转义字符 + /// + [Fact] + public void TestAppendSql_1() { + var clause = CreateEndClause( new TestDialect2() ); + clause.AppendSql( "[a].[b]", false ); + Assert.Equal( "$a&.$b&", GetSql( clause ) ); + } + + /// + /// 测试添加到结束位置 - 原样添加 + /// + [Fact] + public void TestAppendSql_2() { + var clause = CreateEndClause( new TestDialect2() ); + clause.AppendSql( "[a].[b]", true ); + Assert.Equal( "[a].[b]", GetSql( clause ) ); + } + + /// + /// 测试添加到结束位置 - 多次调用 + /// + [Fact] + public void TestAppendSql_3() { + var clause = CreateEndClause( new TestDialect2() ); + clause.AppendSql( "[a].", true ); + clause.AppendSql( "[b]", true ); + Assert.Equal( "[a].[b]", GetSql( clause ) ); + } + + #endregion + + #region ClearPage + + /// + /// 测试清理分页 + /// + [Fact] + public void TestClearPage() { + var page = new Pager( 3, 40 ); + _clause.Page( page ); + _clause.ClearPage(); + Assert.Empty( GetSql() ); + } + + #endregion + + #region Clear + + /// + /// 测试清理 + /// + [Fact] + public void TestClear() { + var page = new Pager( 3, 40 ); + _clause.Page( page ); + _clause.AppendSql( "[a].[b]", false ); + _clause.Clear(); + Assert.Empty( GetSql() ); + } + + #endregion + + #region Clone + + /// + /// 测试复制结束子句 + /// + [Fact] + public void TestClone() { + //设置分页 + var page = new Pager( 3, 40 ); + _clause.Page( page ); + + //复制并验证 + var clone = _clause.Clone( new TestSqlBuilder() ); + Assert.Equal( "Limit @_p_1 OFFSET @_p_0", GetSql( clone ) ); + + //修改原始子句,复制子句不应受影响 + _clause.Clear(); + Assert.Equal( "Limit @_p_1 OFFSET @_p_0", GetSql( clone ) ); + } + + #endregion + } +} diff --git a/test/Util.Data.Sql.Tests/Builders/Clauses/FromClauseTest.cs b/test/Util.Data.Sql.Tests/Builders/Clauses/FromClauseTest.cs new file mode 100644 index 00000000..5b60a199 --- /dev/null +++ b/test/Util.Data.Sql.Tests/Builders/Clauses/FromClauseTest.cs @@ -0,0 +1,187 @@ +using System.Text; +using Util.Data.Sql.Builders.Clauses; +using Util.Data.Sql.Tests.Samples; +using Xunit; + +namespace Util.Data.Sql.Tests.Builders.Clauses { + /// + /// From子句测试 + /// + public class FromClauseTest { + + #region 测试初始化 + + /// + /// From子句 + /// + private readonly FromClause _clause; + + /// + /// 测试初始化 + /// + public FromClauseTest() { + _clause = new FromClause( new TestSqlBuilder() ); + } + + /// + /// 获取Sql语句 + /// + private string GetSql( IFromClause clause = null ) { + clause ??= _clause; + var builder = new StringBuilder(); + clause.AppendTo( builder ); + return builder.ToString(); + } + + #endregion + + #region 默认输出 + + /// + /// 默认输出空 + /// + [Fact] + public void TestDefault() { + Assert.Empty( GetSql() ); + } + + #endregion + + #region From + + /// + /// 测试设置简单表 + /// + [Fact] + public void TestFrom_1() { + _clause.From( "a" ); + Assert.Equal( "From [a]", GetSql() ); + } + + /// + /// 测试设置带架构的表 + /// + [Fact] + public void TestFrom_2() { + _clause.From( "a.b" ); + Assert.Equal( "From [a].[b]", GetSql() ); + } + + /// + /// 测试设置带表别名的表 + /// + [Fact] + public void TestFrom_3() { + _clause.From( "a as b" ); + Assert.Equal( "From [a] As [b]", GetSql() ); + } + + /// + /// 测试设置带架构和表别名的表 + /// + [Fact] + public void TestFrom_4() { + _clause.From( "a.b as c" ); + Assert.Equal( "From [a].[b] As [c]", GetSql() ); + } + + /// + /// 测试设置子查询表 + /// + [Fact] + public void TestFrom_5() { + var result = new StringBuilder(); + result.AppendLine( "From (Select [a] " ); + result.Append( "From [b]) As [c]" ); + + var builder = new TestSqlBuilder().Select( "a" ).From( "b" ); + _clause.From( builder, "c" ); + Assert.Equal( result.ToString(), GetSql() ); + } + + /// + /// 测试设置子查询表 - 内嵌表达式 + /// + [Fact] + public void TestFrom_6() { + var result = new StringBuilder(); + result.AppendLine( "From (Select [a] " ); + result.Append( "From [b]) As [c]" ); + + _clause.From( t => t.Select( "a" ).From( "b" ), "c" ); + Assert.Equal( result.ToString(), GetSql() ); + } + + #endregion + + #region AppendSql + + /// + /// 添加到from子句 - 替换[]为特定转义字符 + /// + [Fact] + public void TestAppendSql_1() { + var clause = new FromClause( new TestSqlBuilder( new TestDialect2() ) ); + clause.AppendSql( "[a].[b], c.[D]", false ); + Assert.Equal( "From $a&.$b&, c.$D&", GetSql( clause ) ); + } + + /// + /// 添加到from子句 - 原样添加 + /// + [Fact] + public void TestAppendSql_2() { + var clause = new FromClause( new TestSqlBuilder( new TestDialect2() ) ); + clause.AppendSql( "[a].[b], c.[D]", true ); + Assert.Equal( "From [a].[b], c.[D]", GetSql( clause ) ); + } + + /// + /// 添加到from子句 - 多次调用 + /// + [Fact] + public void TestAppendSql_3() { + var clause = new FromClause( new TestSqlBuilder( new TestDialect2() ) ); + clause.AppendSql( "[a].", true ); + clause.AppendSql( "[b]", true ); + Assert.Equal( "From [a].[b]", GetSql( clause ) ); + } + + #endregion + + #region Clear + + /// + /// 测试清理 + /// + [Fact] + public void TestClear() { + _clause.From( "a" ); + _clause.Clear(); + Assert.Empty( GetSql() ); + } + + #endregion + + #region Clone + + /// + /// 测试复制From子句 + /// + [Fact] + public void TestClone() { + //设置表 + _clause.From( "a" ); + + //复制并验证 + var clone = _clause.Clone( new TestSqlBuilder() ); + Assert.Equal( "From [a]", GetSql( clone ) ); + + //修改原始子句,复制子句不应受影响 + _clause.Clear(); + Assert.Equal( "From [a]", GetSql( clone ) ); + } + + #endregion + } +} diff --git a/test/Util.Data.Sql.Tests/Builders/Clauses/GroupByClauseTest.cs b/test/Util.Data.Sql.Tests/Builders/Clauses/GroupByClauseTest.cs new file mode 100644 index 00000000..ea1d7790 --- /dev/null +++ b/test/Util.Data.Sql.Tests/Builders/Clauses/GroupByClauseTest.cs @@ -0,0 +1,267 @@ +using System.Text; +using Util.Data.Sql.Builders.Clauses; +using Util.Data.Sql.Builders.Params; +using Util.Data.Sql.Tests.Samples; +using Xunit; + +namespace Util.Data.Sql.Tests.Builders.Clauses { + /// + /// Group By子句测试 + /// + public class GroupByClauseTest { + + #region 测试初始化 + + /// + /// 参数管理器 + /// + private readonly IParameterManager _parameterManager; + /// + /// 分组子句 + /// + private readonly GroupByClause _clause; + + /// + /// 测试初始化 + /// + public GroupByClauseTest() { + _parameterManager = new ParameterManager( TestDialect.Instance ); + _clause = new GroupByClause( new TestSqlBuilder(parameterManager: _parameterManager ) ); + } + + /// + /// 获取Sql语句 + /// + private string GetSql( IGroupByClause clause = null ) { + clause ??= _clause; + var builder = new StringBuilder(); + clause.AppendTo( builder ); + return builder.ToString(); + } + + #endregion + + #region 默认输出 + + /// + /// 默认输出 + /// + [Fact] + public void TestDefault() { + Assert.Empty( GetSql() ); + } + + #endregion + + #region GroupBy + + /// + /// 测试添加分组 - 传入空值 + /// + [Fact] + public void TestGroupBy_1() { + _clause.GroupBy( "" ); + Assert.Empty( GetSql() ); + } + + /// + /// 测试添加分组 - 1个列 + /// + [Fact] + public void TestGroupBy_2() { + _clause.GroupBy( "a.B" ); + Assert.Equal( "Group By [a].[B]", GetSql() ); + } + + /// + /// 测试添加分组 - 2个列 + /// + [Fact] + public void TestGroupBy_3() { + _clause.GroupBy( "a.B,c.D" ); + Assert.Equal( "Group By [a].[B],[c].[D]", GetSql() ); + } + + /// + /// 测试添加分组 - 多次调用GroupBy方法 + /// + [Fact] + public void TestGroupBy_4() { + _clause.GroupBy( "a.B" ); + _clause.GroupBy( "c.D" ); + Assert.Equal( "Group By [a].[B],[c].[D]", GetSql() ); + } + + #endregion + + #region Having + + /// + /// 测试添加分组条件 - 未设置GroupBy输出空 + /// + [Fact] + public void TestHaving_1() { + _clause.Having( "a","b" ); + Assert.Empty( GetSql() ); + } + + /// + /// 测试添加分组条件 - 1个条件 + /// + [Fact] + public void TestHaving_2() { + var result = new StringBuilder(); + result.Append( "Group By [a].[B] " ); + result.Append( "Having sum(a)>@_p_0" ); + + _clause.GroupBy( "a.B" ); + _clause.Having( "sum(a)", "1",Operator.Greater ); + Assert.Equal( result.ToString(), GetSql() ); + Assert.Equal( "1", _parameterManager.GetValue( "@_p_0" ) ); + } + + /// + /// 测试添加分组条件 - 2个条件 + /// + [Fact] + public void TestHaving_3() { + var result = new StringBuilder(); + result.Append( "Group By [a].[B] " ); + result.Append( "Having sum(a)>@_p_0 And max(b)<@_p_1" ); + + _clause.GroupBy( "a.B" ); + _clause.Having( "sum(a)", "1", Operator.Greater ); + _clause.Having( "max(b)", 2, Operator.Less ); + Assert.Equal( result.ToString(), GetSql() ); + Assert.Equal( "1", _parameterManager.GetValue( "@_p_0" ) ); + Assert.Equal( 2, _parameterManager.GetValue( "@_p_1" ) ); + } + + #endregion + + #region AppendGroupBy + + /// + /// 测试添加到Group By子句 - 替换[] + /// + [Fact] + public void TestAppendGroupBy_1() { + var result = new StringBuilder(); + result.Append( "Group By $a&.$id&" ); + + var clause = new GroupByClause( new TestSqlBuilder( new TestDialect2(), new TestColumnCache( new TestDialect2() ) ) ); + clause.AppendGroupBy( "[a].[id]", false ); + Assert.Equal( result.ToString(), GetSql( clause ) ); + } + + /// + /// 测试添加到Group By子句 - 原样添加 + /// + [Fact] + public void TestAppendGroupBy_2() { + var result = new StringBuilder(); + result.Append( "Group By [a].[id]" ); + + var clause = new GroupByClause( new TestSqlBuilder( new TestDialect2(), new TestColumnCache( new TestDialect2() ) ) ); + clause.AppendGroupBy( "[a].[id]", true ); + Assert.Equal( result.ToString(), GetSql( clause ) ); + } + + /// + /// 测试添加到Group By子句 - 多次调用 + /// + [Fact] + public void TestAppendGroupBy_3() { + var result = new StringBuilder(); + result.Append( "Group By [a].[id]" ); + + var clause = new GroupByClause( new TestSqlBuilder( new TestDialect2(), new TestColumnCache( new TestDialect2() ) ) ); + clause.AppendGroupBy( "[a].", true ); + clause.AppendGroupBy( "[id]", true ); + Assert.Equal( result.ToString(), GetSql( clause ) ); + } + + #endregion + + #region AppendHaving + + /// + /// 测试添加到Having子句 - 替换[] + /// + [Fact] + public void TestAppendHaving_1() { + var result = new StringBuilder(); + result.Append( "Group By $a1&.$id&,$b1&.$id& " ); + result.Append( "Having Count($a&.$id&)>1 And sum($b&.$id&)=2" ); + + var clause = new GroupByClause( new TestSqlBuilder( new TestDialect2(), new TestColumnCache( new TestDialect2() ) ) ); + clause.GroupBy( "a1.id" ); + clause.GroupBy( "b1.id" ); + clause.AppendHaving( "Count([a].[id])>1", false ); + clause.AppendHaving( "sum([b].[id])=2", false ); + Assert.Equal( result.ToString(), GetSql( clause ) ); + } + + /// + /// 测试添加到Having子句 - 原样添加 + /// + [Fact] + public void TestAppendHaving_2() { + var result = new StringBuilder(); + result.Append( "Group By $a1&.$id&,$b1&.$id& " ); + result.Append( "Having Count([a].[id])>1 And sum([b].[id])=2" ); + + var clause = new GroupByClause( new TestSqlBuilder( new TestDialect2(), new TestColumnCache( new TestDialect2() ) ) ); + clause.GroupBy( "a1.id" ); + clause.GroupBy( "b1.id" ); + clause.AppendHaving( "Count([a].[id])>1", true ); + clause.AppendHaving( "sum([b].[id])=2", true ); + Assert.Equal( result.ToString(), GetSql( clause ) ); + } + + #endregion + + #region Clear + + /// + /// 测试清理 + /// + [Fact] + public void TestClear() { + _clause.GroupBy( "a.B" ); + _clause.Having( "sum(a)", "1", Operator.Greater ); + _clause.Clear(); + Assert.Empty( GetSql() ); + } + + #endregion + + #region Clone + + /// + /// 测试复制Group By子句 + /// + [Fact] + public void TestClone() { + //结果 + var result = new StringBuilder(); + result.Append( "Group By [a].[B] " ); + result.Append( "Having sum(a)>@_p_0" ); + + //设置分组 + _clause.GroupBy( "a.B" ); + _clause.Having( "sum(a)", "1", Operator.Greater ); + + //复制并验证 + var clone = _clause.Clone( new TestSqlBuilder() ); + Assert.Equal( result.ToString(), GetSql( clone ) ); + + //修改原始子句,复制子句不应受影响 + _clause.GroupBy( "c.d" ); + _clause.Having( "sum(e)", "2", Operator.Greater ); + Assert.Equal( result.ToString(), GetSql( clone ) ); + } + + #endregion + } +} diff --git a/test/Util.Data.Sql.Tests/Builders/Clauses/InsertClauseTest.cs b/test/Util.Data.Sql.Tests/Builders/Clauses/InsertClauseTest.cs new file mode 100644 index 00000000..84376faa --- /dev/null +++ b/test/Util.Data.Sql.Tests/Builders/Clauses/InsertClauseTest.cs @@ -0,0 +1,270 @@ +using System.Text; +using Util.Data.Sql.Builders.Clauses; +using Util.Data.Sql.Builders.Params; +using Util.Data.Sql.Tests.Samples; +using Xunit; + +namespace Util.Data.Sql.Tests.Builders.Clauses { + /// + /// 插入子句测试 + /// + public class InsertClauseTest { + + #region 测试初始化 + + /// + /// 参数管理器 + /// + private readonly IParameterManager _parameterManager; + /// + /// Select子句 + /// + private readonly InsertClause _clause; + + /// + /// 测试初始化 + /// + public InsertClauseTest() { + _parameterManager = new ParameterManager( TestDialect.Instance ); + _clause = new InsertClause( new TestSqlBuilder( parameterManager: _parameterManager ) ); + } + + /// + /// 获取Sql语句 + /// + private string GetSql( IInsertClause clause = null ) { + clause ??= _clause; + var builder = new StringBuilder(); + clause.AppendTo( builder ); + return builder.ToString(); + } + + #endregion + + #region Insert + + /// + /// 测试插入一列 - 未设置值 + /// + [Fact] + public void TestInsert_1() { + var result = new StringBuilder(); + result.Append( "Insert Into [t].[c]([a].[b]) " ); + + _clause.Insert( "a.b", "t.c" ); + Assert.Equal( result.ToString(), GetSql() ); + } + + /// + /// 测试插入2列 + /// + [Fact] + public void TestInsert_2() { + var result = new StringBuilder(); + result.AppendLine( "Insert Into [z].[t]([a].[b],[c].[d]) " ); + result.Append( "Values(@_p_0,@_p_1)" ); + + _clause.Insert( "a.b,c.d", "z.t" ); + _clause.Values( 1, "a" ); + Assert.Equal( result.ToString(), GetSql() ); + Assert.Equal( 1, _parameterManager.GetValue( "@_p_0" ) ); + Assert.Equal( "a", _parameterManager.GetValue( "@_p_1" ) ); + } + + /// + /// 测试插入2列 - 多次调用Insert + /// + [Fact] + public void TestInsert_3() { + var result = new StringBuilder(); + result.AppendLine( "Insert Into [z].[t]([a].[b],[c].[d]) " ); + result.Append( "Values(@_p_0,@_p_1)" ); + + _clause.Insert( "a.b", "z.t" ); + _clause.Insert( "c.d" ); + _clause.Values( 1, "a" ); + Assert.Equal( result.ToString(), GetSql() ); + Assert.Equal( 1, _parameterManager.GetValue( "@_p_0" ) ); + Assert.Equal( "a", _parameterManager.GetValue( "@_p_1" ) ); + } + + #endregion + + #region Values + + /// + /// 测试插入一行 + /// + [Fact] + public void TestValues_1() { + var result = new StringBuilder(); + result.AppendLine( "Insert Into [t].[c]([a].[b]) " ); + result.Append( "Values(@_p_0)" ); + + _clause.Insert( "a.b", "t.c" ); + _clause.Values( 1 ); + Assert.Equal( result.ToString(), GetSql() ); + Assert.Equal( 1, _parameterManager.GetValue( "@_p_0" ) ); + } + + /// + /// 测试插入多行 + /// + [Fact] + public void TestValues_2() { + var result = new StringBuilder(); + result.AppendLine( "Insert Into [z].[t]([a].[b],[c].[d]) " ); + result.Append( "Values(@_p_0,@_p_1)," ); + result.Append( "(@_p_2,@_p_3)" ); + + _clause.Insert( "a.b", "z.t" ); + _clause.Insert( "c.d" ); + _clause.Values( 1, "a" ); + _clause.Values( 2, "b" ); + Assert.Equal( result.ToString(), GetSql() ); + Assert.Equal( 1, _parameterManager.GetValue( "@_p_0" ) ); + Assert.Equal( "a", _parameterManager.GetValue( "@_p_1" ) ); + Assert.Equal( 2, _parameterManager.GetValue( "@_p_2" ) ); + Assert.Equal( "b", _parameterManager.GetValue( "@_p_3" ) ); + } + + #endregion + + #region AppendInsert + + /// + /// 测试添加到Insert子句 - 替换[]为特定转义字符 + /// + [Fact] + public void TestAppendInsert_1() { + var result = new StringBuilder(); + result.Append( "Insert Into $t&.$c&($a&.$b&) " ); + + var clause = new InsertClause( new TestSqlBuilder( new TestDialect2(), new TestColumnCache( new TestDialect2() ) ) ); + clause.AppendInsert( "[t].[c]([a].[b])", false ); + Assert.Equal( result.ToString(), GetSql( clause ) ); + } + + /// + /// 测试添加到Insert子句 - 原样添加 + /// + [Fact] + public void TestAppendInsert_2() { + var result = new StringBuilder(); + result.Append( "Insert Into [t].[c]([a].[b]) " ); + + var clause = new InsertClause( new TestSqlBuilder( new TestDialect2(), new TestColumnCache( new TestDialect2() ) ) ); + clause.AppendInsert( "[t].[c]([a].[b])", true ); + Assert.Equal( result.ToString(), GetSql( clause ) ); + } + + /// + /// 测试添加到Insert子句 - 多次调用 + /// + [Fact] + public void TestAppendInsert_3() { + var result = new StringBuilder(); + result.Append( "Insert Into [t].[c]([a].[b],[c].[d]) " ); + + var clause = new InsertClause( new TestSqlBuilder( new TestDialect2(), new TestColumnCache( new TestDialect2() ) ) ); + clause.AppendInsert( "[t].[c]([a].[b],", true ); + clause.AppendInsert( "[c].[d])", true ); + Assert.Equal( result.ToString(), GetSql( clause ) ); + } + + #endregion + + #region AppendValues + + /// + /// 测试添加到Values子句 - 替换[]为特定转义字符 + /// + [Fact] + public void TestAppendValues_1() { + var result = new StringBuilder(); + result.AppendLine( "Insert Into $t&($a&) " ); + result.Append( "Values($c&)" ); + + var clause = new InsertClause( new TestSqlBuilder( new TestDialect2(), new TestColumnCache( new TestDialect2() ) ) ); + clause.Insert( "a", "t" ); + clause.AppendValues( "([c])", false ); + Assert.Equal( result.ToString(), GetSql( clause ) ); + } + + /// + /// 测试添加到Values子句 - 原样添加 + /// + [Fact] + public void TestAppendValues_2() { + var result = new StringBuilder(); + result.AppendLine( "Insert Into $t&($a&) " ); + result.Append( "Values([c])" ); + + var clause = new InsertClause( new TestSqlBuilder( new TestDialect2(), new TestColumnCache( new TestDialect2() ) ) ); + clause.Insert( "a", "t" ); + clause.AppendValues( "([c])", true ); + Assert.Equal( result.ToString(), GetSql( clause ) ); + } + + /// + /// 测试添加到Values子句 - 多次调用 + /// + [Fact] + public void TestAppendValues_3() { + var result = new StringBuilder(); + result.AppendLine( "Insert Into $t&($a&) " ); + result.Append( "Values([c],[d])" ); + + var clause = new InsertClause( new TestSqlBuilder( new TestDialect2(), new TestColumnCache( new TestDialect2() ) ) ); + clause.Insert( "a", "t" ); + clause.AppendValues( "([c]", true ); + clause.AppendValues( ",[d])", true ); + Assert.Equal( result.ToString(), GetSql( clause ) ); + } + + #endregion + + #region Clear + + /// + /// 测试清理 + /// + [Fact] + public void TestClear() { + _clause.Insert( "a.b", "t.c" ); + _clause.Values( 1 ); + _clause.AppendInsert( "[t].[c]([a].[b])", false ); + _clause.Clear(); + Assert.Empty( GetSql() ); + } + + #endregion + + #region Clone + + /// + /// 测试复制Select子句 + /// + [Fact] + public void TestClone() { + //结果 + var result = new StringBuilder(); + result.AppendLine( "Insert Into [t].[c]([a].[b]) " ); + result.Append( "Values(@_p_0)" ); + + //插入数据 + _clause.Insert( "a.b", "t.c" ); + _clause.Values( 1 ); + + //复制并验证 + var clone = _clause.Clone( new TestSqlBuilder() ); + Assert.Equal( result.ToString(), GetSql( clone ) ); + + //修改原始子句,复制子句不应受影响 + _clause.Values( 2 ); + Assert.Equal( result.ToString(), GetSql( clone ) ); + } + + #endregion + } +} diff --git a/test/Util.Data.Sql.Tests/Builders/Clauses/JoinClauseTest.cs b/test/Util.Data.Sql.Tests/Builders/Clauses/JoinClauseTest.cs new file mode 100644 index 00000000..75729a1f --- /dev/null +++ b/test/Util.Data.Sql.Tests/Builders/Clauses/JoinClauseTest.cs @@ -0,0 +1,502 @@ +using System.Text; +using Util.Data.Sql.Builders.Clauses; +using Util.Data.Sql.Builders.Params; +using Util.Data.Sql.Tests.Samples; +using Xunit; + +namespace Util.Data.Sql.Tests.Builders.Clauses { + /// + /// Join子句测试 + /// + public class JoinClauseTest { + + #region 测试初始化 + + /// + /// 参数管理器 + /// + private readonly IParameterManager _parameterManager; + /// + /// Join子句 + /// + private readonly JoinClause _clause; + + /// + /// 测试初始化 + /// + public JoinClauseTest() { + _parameterManager = new ParameterManager( TestDialect.Instance ); + _clause = new JoinClause( new TestSqlBuilder( parameterManager: _parameterManager ) ); + } + + /// + /// 获取Sql语句 + /// + private string GetSql( IJoinClause clause = null ) { + clause ??= _clause; + var builder = new StringBuilder(); + clause.AppendTo( builder ); + return builder.ToString(); + } + + #endregion + + #region 默认输出 + + /// + /// 默认输出 + /// + [Fact] + public void TestDefault() { + Assert.Empty( GetSql() ); + } + + #endregion + + #region On + + /// + /// 测试表连接条件 - 未设置join返回空 + /// + [Fact] + public void TestOn_1() { + _clause.On( "a.id", "b" ); + Assert.Empty( GetSql() ); + } + + #endregion + + #region Join + + /// + /// 测试内连接 + /// + [Fact] + public void TestJoin_1() { + _clause.Join( "a.b as c" ); + Assert.Equal( "Join [a].[b] As [c]", GetSql() ); + } + + /// + /// 测试内连接 - 连接列 + /// + [Fact] + public void TestJoin_2() { + var result = new StringBuilder(); + result.Append( "Join [t] " ); + result.Append( "On [t].[id]=[a].[id]" ); + + _clause.Join( "t" ); + _clause.On( "t.id", "a.id" ); + Assert.Equal( result.ToString(), GetSql() ); + } + + /// + /// 测试内连接 - 2个条件 + /// + [Fact] + public void TestJoin_3() { + var result = new StringBuilder(); + result.Append( "Join [t] " ); + result.Append( "On [t].[id]=[a].[id] And [t].[id]>@_p_0" ); + + _clause.Join( "t" ); + _clause.On( "t.id", "a.id" ); + _clause.On( "t.id", 1, Operator.Greater, true ); + Assert.Equal( result.ToString(), GetSql() ); + Assert.Equal( 1, _parameterManager.GetValue( "@_p_0" ) ); + } + + /// + /// 测试2个内连接 + /// + [Fact] + public void TestJoin_4() { + var result = new StringBuilder(); + result.Append( "Join [b] " ); + result.AppendLine( "On [b].[id]=[a].[id] " ); + result.Append( "Join [c] " ); + result.Append( "On [c].[id]=[b].[id] And [c].[id]>@_p_0" ); + + _clause.Join( "b" ); + _clause.On( "b.id", "a.id" ); + _clause.Join( "c" ); + _clause.On( "c.id", "b.id" ); + _clause.On( "c.id", 1, Operator.Greater, true ); + Assert.Equal( result.ToString(), GetSql() ); + Assert.Equal( 1, _parameterManager.GetValue( "@_p_0" ) ); + } + + /// + /// 测试内连接 - 子查询 + /// + [Fact] + public void TestJoin_5() { + var result = new StringBuilder(); + result.Append( "Join [t] " ); + result.AppendLine( "On [t].[id]=[a].[id] " ); + result.AppendLine( "Join (Select [a] " ); + result.Append( "From [b]) As [c]" ); + + var builder = new TestSqlBuilder().Select( "a" ).From( "b" ); + _clause.Join( "t" ); + _clause.On( "t.id", "a.id" ); + _clause.Join( builder, "c" ); + Assert.Equal( result.ToString(), GetSql() ); + } + + /// + /// 测试内连接 - 子查询 - 内嵌表达式 + /// + [Fact] + public void TestJoin_6() { + var result = new StringBuilder(); + result.Append( "Join [t] " ); + result.AppendLine( "On [t].[id]=[a].[id] " ); + result.AppendLine( "Join (Select [a] " ); + result.Append( "From [b]) As [c]" ); + + _clause.Join( "t" ); + _clause.On( "t.id", "a.id" ); + _clause.Join( t => t.Select( "a" ).From( "b" ), "c" ); + Assert.Equal( result.ToString(), GetSql() ); + } + + #endregion + + #region LeftJoin + + /// + /// 测试左外连接 + /// + [Fact] + public void TestLeftJoin_1() { + _clause.LeftJoin( "a.b as c" ); + Assert.Equal( "Left Join [a].[b] As [c]", GetSql() ); + } + + /// + /// 测试左外连接 - 子查询 + /// + [Fact] + public void TestLeftJoin_2() { + var result = new StringBuilder(); + result.Append( "Join [t] " ); + result.AppendLine( "On [t].[id]=[a].[id] " ); + result.AppendLine( "Left Join (Select [a] " ); + result.Append( "From [b]) As [c]" ); + + var builder = new TestSqlBuilder().Select( "a" ).From( "b" ); + _clause.Join( "t" ); + _clause.On( "t.id", "a.id" ); + _clause.LeftJoin( builder, "c" ); + Assert.Equal( result.ToString(), GetSql() ); + } + + /// + /// 测试左外连接 - 子查询 - 内嵌表达式 + /// + [Fact] + public void TestLeftJoin_3() { + var result = new StringBuilder(); + result.Append( "Join [t] " ); + result.AppendLine( "On [t].[id]=[a].[id] " ); + result.AppendLine( "Left Join (Select [a] " ); + result.Append( "From [b]) As [c]" ); + + _clause.Join( "t" ); + _clause.On( "t.id", "a.id" ); + _clause.LeftJoin( t => t.Select( "a" ).From( "b" ), "c" ); + Assert.Equal( result.ToString(), GetSql() ); + } + + #endregion + + #region RightJoin + + /// + /// 测试右外连接 + /// + [Fact] + public void TestRightJoin_1() { + _clause.RightJoin( "a.b as c" ); + Assert.Equal( "Right Join [a].[b] As [c]", GetSql() ); + } + + /// + /// 测试右外连接 - 子查询 + /// + [Fact] + public void TestRightJoin_2() { + var result = new StringBuilder(); + result.Append( "Join [t] " ); + result.AppendLine( "On [t].[id]=[a].[id] " ); + result.AppendLine( "Right Join (Select [a] " ); + result.Append( "From [b]) As [c]" ); + + var builder = new TestSqlBuilder().Select( "a" ).From( "b" ); + _clause.Join( "t" ); + _clause.On( "t.id", "a.id" ); + _clause.RightJoin( builder, "c" ); + Assert.Equal( result.ToString(), GetSql() ); + } + + /// + /// 测试右外连接 - 子查询 - 内嵌表达式 + /// + [Fact] + public void TestRightJoin_3() { + var result = new StringBuilder(); + result.Append( "Join [t] " ); + result.AppendLine( "On [t].[id]=[a].[id] " ); + result.AppendLine( "Right Join (Select [a] " ); + result.Append( "From [b]) As [c]" ); + + _clause.Join( "t" ); + _clause.On( "t.id", "a.id" ); + _clause.RightJoin( t => t.Select( "a" ).From( "b" ), "c" ); + Assert.Equal( result.ToString(), GetSql() ); + } + + #endregion + + #region AppendJoin + + /// + /// 测试添加到内连接 - 替换[]为特定转义字符 + /// + [Fact] + public void TestAppendJoin_1() { + var clause = new JoinClause( new TestSqlBuilder( new TestDialect2(), new TestColumnCache( new TestDialect2() ),_parameterManager ) ); + clause.AppendJoin( "[a].[b]", false ); + Assert.Equal( "Join $a&.$b&", GetSql( clause ) ); + } + + /// + /// 测试添加到内连接 - 原样添加 + /// + [Fact] + public void TestAppendJoin_2() { + var clause = new JoinClause( new TestSqlBuilder( new TestDialect2(), new TestColumnCache( new TestDialect2() ), _parameterManager ) ); + clause.AppendJoin( "[a].[b] as c", true ); + Assert.Equal( "Join [a].[b] as c", GetSql( clause ) ); + } + + /// + /// 测试添加到内连接 - 先调用select,再调用appendJoin + /// + [Fact] + public void TestAppendJoin_3() { + var result = new StringBuilder(); + result.Append( "Join [t] " ); + result.AppendLine( "On [t].[id]=[a].[id] " ); + result.Append( "Join [a].[b] as c" ); + + _clause.Join( "t" ); + _clause.On( "t.id", "a.id" ); + _clause.AppendJoin( "[a].[b] as c", false ); + Assert.Equal( result.ToString(), GetSql() ); + } + + #endregion + + #region AppendLeftJoin + + /// + /// 测试添加到左外连接 - 替换[]为特定转义字符 + /// + [Fact] + public void TestAppendLeftJoin_1() { + var clause = new JoinClause( new TestSqlBuilder( new TestDialect2(), new TestColumnCache( new TestDialect2() ), _parameterManager ) ); + clause.AppendLeftJoin( "[a].[b]", false ); + Assert.Equal( "Left Join $a&.$b&", GetSql( clause ) ); + } + + /// + /// 测试添加到左外连接 - 原样添加 + /// + [Fact] + public void TestAppendLeftJoin_2() { + var clause = new JoinClause( new TestSqlBuilder( new TestDialect2(), new TestColumnCache( new TestDialect2() ), _parameterManager ) ); + clause.AppendLeftJoin( "[a].[b] as c", true ); + Assert.Equal( "Left Join [a].[b] as c", GetSql( clause ) ); + } + + /// + /// 测试添加到左外连接 - 先调用select,再调用AppendLeftJoin + /// + [Fact] + public void TestAppendLeftJoin_3() { + var result = new StringBuilder(); + result.Append( "Join [t] " ); + result.AppendLine( "On [t].[id]=[a].[id] " ); + result.Append( "Left Join [a].[b] as c" ); + + _clause.Join( "t" ); + _clause.On( "t.id", "a.id" ); + _clause.AppendLeftJoin( "[a].[b] as c", false ); + Assert.Equal( result.ToString(), GetSql() ); + } + + #endregion + + #region AppendRightJoin + + /// + /// 测试添加到右外连接 - 替换[]为特定转义字符 + /// + [Fact] + public void TestAppendRightJoin_1() { + var clause = new JoinClause( new TestSqlBuilder( new TestDialect2(), new TestColumnCache( new TestDialect2() ), _parameterManager ) ); + clause.AppendRightJoin( "[a].[b]", false ); + Assert.Equal( "Right Join $a&.$b&", GetSql( clause ) ); + } + + /// + /// 测试添加到右外连接 - 原样添加 + /// + [Fact] + public void TestAppendRightJoin_2() { + var clause = new JoinClause( new TestSqlBuilder( new TestDialect2(), new TestColumnCache( new TestDialect2() ), _parameterManager ) ); + clause.AppendRightJoin( "[a].[b] as c", true ); + Assert.Equal( "Right Join [a].[b] as c", GetSql( clause ) ); + } + + /// + /// 测试添加到右外连接 - 先调用select,再调用AppendRightJoin + /// + [Fact] + public void TestAppendRightJoin_3() { + var result = new StringBuilder(); + result.Append( "Join [t] " ); + result.AppendLine( "On [t].[id]=[a].[id] " ); + result.Append( "Right Join [a].[b] as c" ); + + _clause.Join( "t" ); + _clause.On( "t.id", "a.id" ); + _clause.AppendRightJoin( "[a].[b] as c", false ); + Assert.Equal( result.ToString(), GetSql() ); + } + + #endregion + + #region AppendOn + + /// + /// 添加到On子句 + /// + [Fact] + public void TestAppendOn_1() { + //结果 + var result = new StringBuilder(); + result.Append( "Join $t& " ); + result.Append( "On $a&.$id&=b.id" ); + + //操作 + var clause = new JoinClause( new TestSqlBuilder( new TestDialect2(), new TestColumnCache( new TestDialect2() ), _parameterManager ) ); + clause.Join( "t" ); + clause.AppendOn( "[a].[id]=b.id", false ); + + + //验证 + Assert.Equal( result.ToString(), GetSql( clause ) ); + } + + /// + /// 添加到On子句 - 先调用On,再调用AppendOn + /// + [Fact] + public void TestAppendOn_2() { + //结果 + var result = new StringBuilder(); + result.Append( "Join $t& " ); + result.Append( "On $a&.$id&=$b&.$id& " ); + result.Append( "And [c].[id]=b.id" ); + + //操作 + var clause = new JoinClause( new TestSqlBuilder( new TestDialect2(), new TestColumnCache( new TestDialect2() ), _parameterManager ) ); + clause.Join( "t" ); + clause.On( "a.id", "b.id" ); + clause.AppendOn( "[c].[id]=b.id", true ); + + + //验证 + Assert.Equal( result.ToString(), GetSql( clause ) ); + } + + /// + /// 添加到On子句 - 综合调用 + /// + [Fact] + public void TestAppendOn_3() { + //结果 + var result = new StringBuilder(); + result.Append( "Join [t] " ); + result.Append( "On [a].[id]=[b].[id] " ); + result.AppendLine( "And [c].[id]=b.id " ); + result.Append( "Join a " ); + result.Append( "On [a].[id2]=[b].[id] " ); + result.Append( "And [c].[id]=[a].[id] " ); + result.Append( "And c.id=b.id" ); + + //操作 + _clause.Join( "t" ); + _clause.On( "a.id", "b.id" ); + _clause.AppendOn( "[c].[id]=b.id", false ); + _clause.AppendJoin( "a", false ); + _clause.AppendOn( "[a].[id2]=[b].[id]", false ); + _clause.On( "c.id", "a.id" ); + _clause.AppendOn( "c.id=b.id", false ); + + + //验证 + Assert.Equal( result.ToString(), GetSql() ); + } + + #endregion + + #region Clear + + /// + /// 测试清理 + /// + [Fact] + public void TestClear() { + _clause.Join( "t" ); + _clause.On( "t.id", "a.id" ); + _clause.Clear(); + Assert.Empty( GetSql() ); + } + + #endregion + + #region Clone + + /// + /// 测试复制Join子句 + /// + [Fact] + public void TestClone() { + //结果 + var result = new StringBuilder(); + result.Append( "Join [t] " ); + result.Append( "On [t].[id]=[a].[id]" ); + + //设置join条件 + _clause.Join( "t" ); + _clause.On( "t.id", "a.id" ); + + + //复制并验证 + var clone = _clause.Clone( new TestSqlBuilder() ); + Assert.Equal( result.ToString(), GetSql( clone ) ); + + //修改原始子句,复制子句不应受影响 + _clause.Join( "t2" ); + _clause.On( "t2.id", "b.id" ); + Assert.Equal( result.ToString(), GetSql( clone ) ); + } + + #endregion + } +} diff --git a/test/Util.Data.Sql.Tests/Builders/Clauses/OrderByClauseTest.cs b/test/Util.Data.Sql.Tests/Builders/Clauses/OrderByClauseTest.cs new file mode 100644 index 00000000..a6a287a1 --- /dev/null +++ b/test/Util.Data.Sql.Tests/Builders/Clauses/OrderByClauseTest.cs @@ -0,0 +1,183 @@ +using System.Text; +using Util.Data.Sql.Builders.Clauses; +using Util.Data.Sql.Tests.Samples; +using Xunit; + +namespace Util.Data.Sql.Tests.Builders.Clauses { + /// + /// Order By子句测试 + /// + public class OrderByClauseTest { + + #region 测试初始化 + + /// + /// 排序子句 + /// + private readonly OrderByClause _clause; + + /// + /// 测试初始化 + /// + public OrderByClauseTest() { + _clause = new OrderByClause( new TestSqlBuilder() ); + } + + /// + /// 获取Sql语句 + /// + private string GetSql( IOrderByClause clause = null ) { + clause ??= _clause; + var builder = new StringBuilder(); + clause.AppendTo( builder ); + return builder.ToString(); + } + + #endregion + + #region 默认输出 + + /// + /// 默认输出 + /// + [Fact] + public void TestDefault() { + Assert.Empty( GetSql() ); + } + + #endregion + + #region OrderBy + + /// + /// 测试排序 - 升序 + /// + [Fact] + public void TestOrderBy_1() { + _clause.OrderBy( "a.B" ); + Assert.Equal( "Order By [a].[B]", GetSql() ); + } + + /// + /// 测试排序 - asc关键字 + /// + [Fact] + public void TestOrderBy_2() { + _clause.OrderBy( "a.B asc" ); + Assert.Equal( "Order By [a].[B]", GetSql() ); + } + + /// + /// 测试排序 - 降序 + /// + [Fact] + public void TestOrderBy_3() { + _clause.OrderBy( "a.B desc" ); + Assert.Equal( "Order By [a].[B] Desc", GetSql() ); + } + + /// + /// 测试排序 - 2个排序列 + /// + [Fact] + public void TestOrderBy_4() { + _clause.OrderBy( "a.B,c.D desc" ); + Assert.Equal( "Order By [a].[B],[c].[D] Desc", GetSql() ); + } + + /// + /// 测试排序 - 2个排序列 - 添加多余空格 + /// + [Fact] + public void TestOrderBy_5() { + _clause.OrderBy( " a .B, c. D desc " ); + Assert.Equal( "Order By [a].[B],[c].[D] Desc", GetSql() ); + } + + /// + /// 测试排序 - 多次调用 + /// + [Fact] + public void TestOrderBy_6() { + _clause.OrderBy( "a.B,c.D desc" ); + _clause.OrderBy( "[e].F ASC,g.H DESC" ); + Assert.Equal( "Order By [a].[B],[c].[D] Desc,[e].[F],[g].[H] Desc", GetSql() ); + } + + #endregion + + #region AppendSql + + /// + /// 测试添加到Order By子句 - 替换[]为特定转义字符 + /// + [Fact] + public void TestAppendSql_1() { + var clause = new OrderByClause( new TestSqlBuilder( new TestDialect2(), new TestColumnCache( new TestDialect2() ) ) ); + clause.AppendSql( "[a].[b]", false ); + Assert.Equal( "Order By $a&.$b&", GetSql( clause ) ); + } + + /// + /// 测试添加到Order By子句 - 原样添加 + /// + [Fact] + public void TestAppendSql_2() { + var clause = new OrderByClause( new TestSqlBuilder( new TestDialect2(), new TestColumnCache( new TestDialect2() ) ) ); + clause.AppendSql( "[a].[b]", true ); + Assert.Equal( "Order By [a].[b]", GetSql( clause ) ); + } + + /// + /// 测试添加到Order By子句 - 多次调用 + /// + [Fact] + public void TestAppendSql_3() { + _clause.OrderBy( "a.b DESC" ); + _clause.OrderBy( "c,D.e desc" ); + _clause.AppendSql( "a", true ); + _clause.AppendSql( "b", true ); + Assert.Equal( "Order By [a].[b] Desc,[c],[D].[e] Desc,ab", GetSql() ); + } + + #endregion + + #region Clear + + /// + /// 测试清理 + /// + [Fact] + public void TestClear() { + _clause.OrderBy( "a.b DESC" ); + _clause.OrderBy( "c,D.e desc" ); + _clause.AppendSql( "a", true ); + _clause.AppendSql( "b", true ); + _clause.Clear(); + Assert.Empty( GetSql() ); + } + + #endregion + + #region Clone + + /// + /// 测试复制Order By子句 + /// + [Fact] + public void TestClone() { + //设置排序 + _clause.OrderBy( "a.B" ); + + //复制并验证 + var clone = _clause.Clone( new TestSqlBuilder() ); + Assert.Equal( "Order By [a].[B]", GetSql( clone ) ); + + //修改原始子句,复制子句不应受影响 + _clause.OrderBy( "c" ); + Assert.Equal( "Order By [a].[B]", GetSql( clone ) ); + } + + #endregion + } +} diff --git a/test/Util.Data.Sql.Tests/Builders/Clauses/SelectClauseTest.cs b/test/Util.Data.Sql.Tests/Builders/Clauses/SelectClauseTest.cs new file mode 100644 index 00000000..cfe72f53 --- /dev/null +++ b/test/Util.Data.Sql.Tests/Builders/Clauses/SelectClauseTest.cs @@ -0,0 +1,297 @@ +using System.Text; +using Util.Data.Sql.Builders.Clauses; +using Util.Data.Sql.Tests.Samples; +using Xunit; + +namespace Util.Data.Sql.Tests.Builders.Clauses { + /// + /// Select子句测试 + /// + public class SelectClauseTest { + + #region 测试初始化 + + /// + /// Select子句 + /// + private readonly SelectClause _clause; + + /// + /// 测试初始化 + /// + public SelectClauseTest() { + _clause = new SelectClause( new TestSqlBuilder() ); + } + + /// + /// 获取Sql语句 + /// + private string GetSql( ISelectClause clause = null ) { + clause ??= _clause; + var builder = new StringBuilder(); + clause.AppendTo( builder ); + return builder.ToString(); + } + + #endregion + + #region 默认输出 + + /// + /// 默认输出 + /// + [Fact] + public void TestDefault() { + Assert.Empty( GetSql() ); + } + + #endregion + + #region Select + + /// + /// 测试设置列名为* + /// + [Fact] + public void TestSelect_1() { + _clause.Select(); + Assert.Equal( "Select *", GetSql() ); + } + + /// + /// 测试设置列名为* + /// + [Fact] + public void TestSelect_2() { + _clause.Select( "*" ); + Assert.Equal( "Select *", GetSql() ); + } + + /// + /// 测试设置1个简单列 + /// + [Fact] + public void TestSelect_3() { + _clause.Select( "a" ); + Assert.Equal( "Select [a]", GetSql() ); + } + + /// + /// 测试设置2个简单列 + /// + [Fact] + public void TestSelect_4() { + _clause.Select( "a,b" ); + Assert.Equal( "Select [a],[b]", GetSql() ); + } + + /// + /// 测试设置1个带表别名的列 + /// + [Fact] + public void TestSelect_5() { + _clause.Select( "a.b" ); + Assert.Equal( "Select [a].[b]", GetSql() ); + } + + /// + /// 测试设置1个带表别名和列别名的列 + /// + [Fact] + public void TestSelect_6() { + _clause.Select( "a.b as c" ); + Assert.Equal( "Select [a].[b] As [c]", GetSql() ); + } + + /// + /// 测试设置2个带表别名和列别名的列 + /// + [Fact] + public void TestSelect_7() { + _clause.Select( "a.b as c,[d].[e] [F]" ); + Assert.Equal( "Select [a].[b] As [c],[d].[e] As [F]", GetSql() ); + } + + /// + /// 测试设置多个select + /// + [Fact] + public void TestSelect_8() { + _clause.Select( "a.b as c" ); + _clause.Select( "[d].[e] [F]" ); + Assert.Equal( "Select [a].[b] As [c],[d].[e] As [F]", GetSql() ); + } + + /// + /// 测试设置子查询列 + /// + [Fact] + public void TestSelect_9() { + var result = new StringBuilder(); + result.Append( "Select [a].[b]," ); + result.AppendLine( "(Select [a] " ); + result.Append( "From [b]) As [c]" ); + + var builder = new TestSqlBuilder().Select( "a" ).From( "b" ); + _clause.Select( "a.b" ); + _clause.Select( builder,"c" ); + Assert.Equal( result.ToString(), GetSql() ); + } + + /// + /// 测试设置子查询列 - 内嵌表达式 + /// + [Fact] + public void TestSelect_10() { + var result = new StringBuilder(); + result.Append( "Select [a].[b]," ); + result.AppendLine( "(Select [a] " ); + result.Append( "From [b]) As [c]" ); + + _clause.Select( "a.b" ); + _clause.Select( t => t.Select( "a" ).From( "b" ), "c" ); + Assert.Equal( result.ToString(), GetSql() ); + } + + /// + /// 测试设置列 - 验证空值 + /// + [Fact] + public void TestSelect_11() { + _clause.Select( "a" ); + _clause.Select( "" ); + Assert.Equal( "Select [a]", GetSql() ); + } + + #endregion + + #region AppendSql + + /// + /// 添加到select子句 - 替换[]为特定转义字符 + /// + [Fact] + public void TestAppendSql_1() { + var clause = new SelectClause( new TestSqlBuilder( new TestDialect2(), new TestColumnCache( new TestDialect2() ) ) ); + clause.AppendSql( "[a].[b], c.[D]", false ); + Assert.Equal( "Select $a&.$b&, c.$D&", GetSql( clause ) ); + } + + /// + /// 添加到select子句 - 原样添加 + /// + [Fact] + public void TestAppendSql_2() { + var clause = new SelectClause( new TestSqlBuilder( new TestDialect2(), new TestColumnCache( new TestDialect2() ) ) ); + clause.AppendSql( "[a].[b], c.[D]", true ); + Assert.Equal( "Select [a].[b], c.[D]", GetSql( clause ) ); + } + + /// + /// 添加到select子句 - 多次调用 + /// + [Fact] + public void TestAppendSql_3() { + var clause = new SelectClause( new TestSqlBuilder( new TestDialect2(), new TestColumnCache( new TestDialect2() ) ) ); + clause.AppendSql( "[a].[b],", true ); + clause.AppendSql( "c.[D]", true ); + Assert.Equal( "Select [a].[b],c.[D]", GetSql( clause ) ); + } + + /// + /// 测试添加到select子句 - 子查询 + /// + [Fact] + public void TestAppendSql_4() { + var result = new StringBuilder(); + result.Append( "Select [a].[b]," ); + result.AppendLine( "(Select [a] " ); + result.Append( "From [b]) As [c]" ); + + var builder = new TestSqlBuilder().Select( "a" ).From( "b" ); + _clause.AppendSql( "[a].[b],",true ); + _clause.AppendSql( "(", true ); + _clause.AppendSql( builder ); + _clause.AppendSql( ") As [c]", true ); + Assert.Equal( result.ToString(), GetSql() ); + } + + /// + /// 测试添加到select子句 - 子查询 - 内嵌表达式 + /// + [Fact] + public void TestAppendSql_5() { + var result = new StringBuilder(); + result.Append( "Select [a].[b]," ); + result.AppendLine( "(Select [a] " ); + result.Append( "From [b]) As [c]" ); + + _clause.AppendSql( "[a].[b],", true ); + _clause.AppendSql( "(", true ); + _clause.AppendSql( t => t.Select( "a" ).From( "b" ) ); + _clause.AppendSql( ") As [c]", true ); + Assert.Equal( result.ToString(), GetSql() ); + } + + /// + /// 测试添加到select子句 - AppendSql末尾添加逗号,后跟Select + /// + [Fact] + public void TestAppendSql_6() { + var result = new StringBuilder(); + result.Append( "Select [a].[b],c,[d]" ); + + _clause.Select( "a.b" ); + _clause.AppendSql( ",c,", true ); + _clause.Select( "d" ); + Assert.Equal( result.ToString(), GetSql() ); + } + + /// + /// 添加到select子句 - 对[]转义 + /// + [Fact] + public void TestAppendSql_7() { + var clause = new SelectClause( new TestSqlBuilder( new TestDialect2(), new TestColumnCache( new TestDialect2() ) ) ); + clause.AppendSql( "[[a]].[b], c.[D]", false ); + Assert.Equal( "Select [a].$b&, c.$D&", GetSql( clause ) ); + } + + #endregion + + #region Clear + + /// + /// 测试清理 + /// + [Fact] + public void TestClear() { + _clause.Select( "a" ); + _clause.Clear(); + Assert.Empty( GetSql() ); + } + + #endregion + + #region Clone + + /// + /// 测试复制Select子句 + /// + [Fact] + public void TestClone() { + //设置列 + _clause.Select( "a" ); + + //复制并验证 + var clone = _clause.Clone( new TestSqlBuilder() ); + Assert.Equal( "Select [a]", GetSql( clone ) ); + + //修改原始子句,复制子句不应受影响 + _clause.Select( "b" ); + Assert.Equal( "Select [a]", GetSql( clone ) ); + } + + #endregion + } +} diff --git a/test/Util.Data.Sql.Tests/Builders/Clauses/StartClauseTest.cs b/test/Util.Data.Sql.Tests/Builders/Clauses/StartClauseTest.cs new file mode 100644 index 00000000..5eff4c50 --- /dev/null +++ b/test/Util.Data.Sql.Tests/Builders/Clauses/StartClauseTest.cs @@ -0,0 +1,187 @@ +using System.Text; +using Util.Data.Sql.Builders.Clauses; +using Util.Data.Sql.Tests.Samples; +using Xunit; + +namespace Util.Data.Sql.Tests.Builders.Clauses { + /// + /// 起始子句测试 + /// + public class StartClauseTest { + + #region 测试初始化 + + /// + /// 排序子句 + /// + private readonly StartClause _clause; + + /// + /// 测试初始化 + /// + public StartClauseTest() { + _clause = new StartClause( new TestSqlBuilder() ); + } + + /// + /// 获取Sql语句 + /// + private string GetSql( IStartClause clause = null ) { + clause ??= _clause; + var builder = new StringBuilder(); + clause.AppendTo( builder ); + return builder.ToString(); + } + + #endregion + + #region Cte(公用表表达式) + + /// + /// 测试公用表表达式CTE + /// + [Fact] + public void TestCte_1() { + var result = new StringBuilder(); + result.AppendLine( "With [Test] " ); + result.AppendLine( "As (Select [a] " ); + result.Append( "From [b])" ); + + var builder = new TestSqlBuilder().Select( "a" ).From( "b" ); + _clause.Cte( "Test", builder ); + Assert.Equal( result.ToString(), GetSql() ); + } + + /// + /// 测试公用表表达式CTE - 两个表达式 + /// + [Fact] + public void TestCte_2() { + var result = new StringBuilder(); + result.AppendLine( "With [Test1] " ); + result.AppendLine( "As (Select [a] " ); + result.AppendLine( "From [b])," ); + result.AppendLine( "[Test2] " ); + result.AppendLine( "As (Select [a] " ); + result.Append( "From [b])" ); + + var builder1 = new TestSqlBuilder().Select( "a" ).From( "b" ); + var builder2 = new TestSqlBuilder().Select( "a" ).From( "b" ); + _clause.Cte( "Test1", builder1 ); + _clause.Cte( "Test2", builder2 ); + Assert.Equal( result.ToString(), GetSql() ); + } + + #endregion + + #region Append + + /// + /// 测试添加到起始位置 - 替换[]为特定转义字符 + /// + [Fact] + public void TestAppend_1() { + var clause = new StartClause( new TestSqlBuilder( new TestDialect2() ) ); + clause.Append( "[a].[b]", false ); + Assert.Equal( "$a&.$b&", GetSql( clause ) ); + } + + /// + /// 测试添加到起始位置 - 原样添加 + /// + [Fact] + public void TestAppend_2() { + var clause = new StartClause( new TestSqlBuilder( new TestDialect2() ) ); + clause.Append( "[a].[b]", true ); + Assert.Equal( "[a].[b]", GetSql( clause ) ); + } + + /// + /// 测试添加到起始位置 - 多次调用 + /// + [Fact] + public void TestAppend_3() { + var clause = new StartClause( new TestSqlBuilder( new TestDialect2() ) ); + clause.Append( "[a].", true ); + clause.Append( "[b]", true ); + Assert.Equal( "[a].[b]", GetSql( clause ) ); + } + + #endregion + + #region ClearCte + + /// + /// 测试清理公用表表达式CTE + /// + [Fact] + public void TestClearCte() { + var builder = new TestSqlBuilder().Select( "a" ).From( "b" ); + _clause.Cte( "Test", builder ); + _clause.ClearCte(); + Assert.Empty( GetSql() ); + } + + #endregion + + #region Clear + + /// + /// 测试清理 + /// + [Fact] + public void TestClear() { + var builder = new TestSqlBuilder().Select( "a" ).From( "b" ); + _clause.Cte( "Test", builder ); + _clause.Append( "[a].[b]", false ); + _clause.Clear(); + Assert.Empty( GetSql() ); + } + + #endregion + + #region Clone + + /// + /// 测试起始子句 - 复制子句结果 + /// + [Fact] + public void TestClone_Result() { + _clause.Append( "a", true ); + + //复制并验证 + var clone = _clause.Clone( new TestSqlBuilder() ); + Assert.Equal( "a", GetSql( clone ) ); + + //修改原始子句,复制子句不应受影响 + _clause.Append( "b", true ); + Assert.Equal( "a", GetSql( clone ) ); + } + + /// + /// 测试起始子句 - 复制CTE + /// + [Fact] + public void TestClone_Cte() { + //Cte结果 + var result = new StringBuilder(); + result.AppendLine( "With [Test] " ); + result.AppendLine( "As (Select [a] " ); + result.Append( "From [b])" ); + + //设置Cte + var builder = new TestSqlBuilder().Select( "a" ).From( "b" ); + _clause.Cte( "Test", builder ); + + //复制并验证 + var clone = _clause.Clone( new TestSqlBuilder() ); + Assert.Equal( result.ToString(), GetSql( clone ) ); + + //修改原Sql生成器,复制子句不应受影响 + builder.Where( "c", 1 ); + Assert.Equal( result.ToString(), GetSql( clone ) ); + } + + #endregion + } +} diff --git a/test/Util.Data.Sql.Tests/Builders/Clauses/WhereClauseTest.cs b/test/Util.Data.Sql.Tests/Builders/Clauses/WhereClauseTest.cs new file mode 100644 index 00000000..f3cb907f --- /dev/null +++ b/test/Util.Data.Sql.Tests/Builders/Clauses/WhereClauseTest.cs @@ -0,0 +1,595 @@ +using System; +using System.Text; +using Util.Data.Queries; +using Util.Data.Sql.Builders.Clauses; +using Util.Data.Sql.Builders.Params; +using Util.Data.Sql.Tests.Samples; +using Xunit; + +namespace Util.Data.Sql.Tests.Builders.Clauses { + /// + /// Where子句测试 + /// + public class WhereClauseTest { + + #region 测试初始化 + + /// + /// 参数管理器 + /// + private readonly IParameterManager _parameterManager; + /// + /// Where子句 + /// + private readonly WhereClause _clause; + + /// + /// 测试初始化 + /// + public WhereClauseTest() { + _parameterManager = new ParameterManager( TestDialect.Instance ); + _clause = new WhereClause( new TestSqlBuilder( parameterManager: _parameterManager ) ); + } + + /// + /// 获取Sql语句 + /// + private string GetSql( IWhereClause clause = null ) { + clause ??= _clause; + var builder = new StringBuilder(); + clause.AppendTo( builder ); + return builder.ToString(); + } + + #endregion + + #region 默认输出 + + /// + /// 默认输出 + /// + [Fact] + public void TestDefault() { + Assert.Empty( GetSql() ); + } + + #endregion + + #region Where(设置条件) + + /// + /// 设置相等条件 - 1个条件 + /// + [Fact] + public void TestWhere_1() { + _clause.Where( "Name", "a", Operator.Equal ); + Assert.Equal( "Where [Name]=@_p_0", GetSql() ); + Assert.Equal( "a", _parameterManager.GetValue( "@_p_0" ) ); + } + + /// + /// 设置相等条件 - 带表别名 + /// + [Fact] + public void TestWhere_2() { + _clause.Where( "f.Name", "a", Operator.Equal ); + Assert.Equal( "Where [f].[Name]=@_p_0", GetSql() ); + Assert.Equal( "a", _parameterManager.GetValue( "@_p_0" ) ); + } + + /// + /// 设置相等条件 - 2个条件 + /// + [Fact] + public void TestWhere_3() { + _clause.Where( "f.Name", "a", Operator.Equal ); + _clause.Where( "s.Age", "b", Operator.Equal ); + Assert.Equal( "Where [f].[Name]=@_p_0 And [s].[Age]=@_p_1", GetSql() ); + Assert.Equal( "a", _parameterManager.GetValue( "@_p_0" ) ); + Assert.Equal( "b", _parameterManager.GetValue( "@_p_1" ) ); + } + + /// + /// 测试设置子查询条件 + /// + [Fact] + public void TestWhere_4() { + var result = new StringBuilder(); + result.Append( "Where [a].[b]=" ); + result.AppendLine( "(Select [a] " ); + result.Append( "From [b])" ); + + var builder = new TestSqlBuilder().Select( "a" ).From( "b" ); + _clause.Where( "a.b", builder,Operator.Equal ); + Assert.Equal( result.ToString(), GetSql() ); + } + + /// + /// 测试设置子查询条件 - 内嵌表达式 + /// + [Fact] + public void TestWhere_5() { + var result = new StringBuilder(); + result.Append( "Where [a].[b]=" ); + result.AppendLine( "(Select [a] " ); + result.Append( "From [b])" ); + + _clause.Where( "a.b", t => t.Select( "a" ).From( "b" ), Operator.Equal ); + Assert.Equal( result.ToString(), GetSql() ); + } + + #endregion + + #region IsNull + + /// + /// 设置Is Null条件 + /// + [Fact] + public void TestIsNull() { + _clause.IsNull( "f.Name" ); + Assert.Equal( "Where [f].[Name] Is Null", GetSql() ); + Assert.Equal( 0, _parameterManager.GetParams().Count ); + } + + #endregion + + #region IsNotNull + + /// + /// 设置Is Not Null条件 + /// + [Fact] + public void TestIsNotNull_1() { + _clause.IsNotNull( "f.Name" ); + Assert.Equal( "Where [f].[Name] Is Not Null", GetSql() ); + Assert.Equal( 0, _parameterManager.GetParams().Count ); + } + + #endregion + + #region IsEmpty + + /// + /// 设置空条件 + /// + [Fact] + public void TestIsEmpty_1() { + _clause.IsEmpty( "f.Name" ); + Assert.Equal( "Where ([f].[Name] Is Null Or [f].[Name]='')", GetSql() ); + Assert.Equal( 0, _parameterManager.GetParams().Count ); + } + + #endregion + + #region IsNotEmpty + + /// + /// 设置空条件 + /// + [Fact] + public void TestIsNotEmpty_1() { + _clause.IsNotEmpty( "f.Name" ); + Assert.Equal( "Where [f].[Name] Is Not Null And [f].[Name]<>''", GetSql() ); + Assert.Equal( 0, _parameterManager.GetParams().Count ); + } + + #endregion + + #region Between(范围查询) + + /// + /// 测试范围查询 - 整型 + /// + [Fact] + public void TestBetween_1() { + //结果 + var result = new StringBuilder(); + result.Append( "Where [a].[B]>=@_p_0 And [a].[B]<=@_p_1" ); + + //执行 + _clause.Between( "a.B", 1, 2, Boundary.Both ); + + //验证 + Assert.Equal( 1, _parameterManager.GetValue( "@_p_0" ) ); + Assert.Equal( 2, _parameterManager.GetValue( "@_p_1" ) ); + Assert.Equal( result.ToString(), GetSql() ); + } + + /// + /// 测试范围查询 - 整型 - 不包含边界 + /// + [Fact] + public void TestBetween_2() { + //结果 + var result = new StringBuilder(); + result.Append( "Where [a].[B]>@_p_0 And [a].[B]<@_p_1" ); + + //执行 + _clause.Between( "a.B", 1, 2, Boundary.Neither ); + + //验证 + Assert.Equal( 1, _parameterManager.GetValue( "@_p_0" ) ); + Assert.Equal( 2, _parameterManager.GetValue( "@_p_1" ) ); + Assert.Equal( result.ToString(), GetSql() ); + } + + /// + /// 测试范围查询 - 整型 - 最小值大于最大值,则交换大小值的位置 + /// + [Fact] + public void TestBetween_3() { + //结果 + var result = new StringBuilder(); + result.Append( "Where [a].[B]>@_p_0 And [a].[B]<@_p_1" ); + + //执行 + _clause.Between( "a.B", 2, 1, Boundary.Neither ); + + //验证 + Assert.Equal( 1, _parameterManager.GetValue( "@_p_0" ) ); + Assert.Equal( 2, _parameterManager.GetValue( "@_p_1" ) ); + Assert.Equal( result.ToString(), GetSql() ); + } + + /// + /// 测试范围查询 - 整型 - 最小值为空,忽略最小值条件 + /// + [Fact] + public void TestBetween_4() { + //结果 + var result = new StringBuilder(); + result.Append( "Where [a].[B]<=@_p_0" ); + + //执行 + _clause.Between( "a.B", null, 2, Boundary.Both ); + + //验证 + Assert.Equal( 2, _parameterManager.GetValue( "@_p_0" ) ); + Assert.Equal( result.ToString(), GetSql() ); + } + + /// + /// 测试范围查询 - 整型 - 最大值为空,忽略最大值条件 + /// + [Fact] + public void TestBetween_5() { + //结果 + var result = new StringBuilder(); + result.Append( "Where [a].[B]>=@_p_0" ); + + //执行 + _clause.Between( "a.B", 1, null, Boundary.Both ); + + //验证 + Assert.Equal( 1, _parameterManager.GetValue( "@_p_0" ) ); + Assert.Equal( result.ToString(), GetSql() ); + } + + /// + /// 测试范围查询 - 整型 - 最大值和最小值均为null,忽略所有条件 + /// + [Fact] + public void TestBetween_6() { + //执行 + _clause.Between( "a.B", null, null, Boundary.Both ); + + //验证 + Assert.Empty( _parameterManager.GetParams() ); + Assert.Empty( GetSql() ); + } + + /// + /// 测试范围查询 - double + /// + [Fact] + public void TestBetween_7() { + //结果 + var result = new StringBuilder(); + result.Append( "Where [a].[B]>=@_p_0 And [a].[B]<=@_p_1" ); + + //执行 + _clause.Between( "a.B", 1.2, 3.4, Boundary.Both ); + + //验证 + Assert.Equal( 1.2, _parameterManager.GetValue( "@_p_0" ) ); + Assert.Equal( 3.4, _parameterManager.GetValue( "@_p_1" ) ); + Assert.Equal( result.ToString(), GetSql() ); + } + + /// + /// 测试范围查询 - decimal + /// + [Fact] + public void TestBetween_8() { + //结果 + var result = new StringBuilder(); + result.Append( "Where [a].[B]>=@_p_0 And [a].[B]<=@_p_1" ); + + //执行 + _clause.Between( "a.B", 1.2M, 3.4M, Boundary.Both ); + + //验证 + Assert.Equal( 1.2M, _parameterManager.GetValue( "@_p_0" ) ); + Assert.Equal( 3.4M, _parameterManager.GetValue( "@_p_1" ) ); + Assert.Equal( result.ToString(), GetSql() ); + } + + /// + /// 测试范围查询 - 日期 - 包含时间 + /// + [Fact] + public void TestBetween_9() { + //结果 + var result = new StringBuilder(); + result.Append( "Where [a].[B]>=@_p_0 And [a].[B]<=@_p_1" ); + + //执行 + var min = DateTime.Parse( "2000-1-1 10:10:10" ); + var max = DateTime.Parse( "2000-1-2 10:10:10" ); + _clause.Between( "a.B", min, max, true, null ); + + //验证 + Assert.Equal( min, _parameterManager.GetValue( "@_p_0" ) ); + Assert.Equal( max, _parameterManager.GetValue( "@_p_1" ) ); + Assert.Equal( result.ToString(), GetSql() ); + } + + /// + /// 测试范围查询 - 日期 - 不包含时间 + /// + [Fact] + public void TestBetween_10() { + //结果 + var result = new StringBuilder(); + result.Append( "Where [a].[B]>=@_p_0 And [a].[B]<@_p_1" ); + + //执行 + var min = DateTime.Parse( "2000-1-1 10:10:10" ); + var max = DateTime.Parse( "2000-1-2 10:10:10" ); + _clause.Between( "a.B", min, max, false, null ); + + //验证 + Assert.Equal( DateTime.Parse( "2000-1-1" ), _parameterManager.GetValue( "@_p_0" ) ); + Assert.Equal( DateTime.Parse( "2000-1-3" ), _parameterManager.GetValue( "@_p_1" ) ); + Assert.Equal( result.ToString(), GetSql() ); + } + + /// + /// 测试范围查询 - 日期 - 设置边界 + /// + [Fact] + public void TestBetween_11() { + //结果 + var result = new StringBuilder(); + result.Append( "Where [a].[B]>@_p_0 And [a].[B]<@_p_1" ); + + //执行 + var min = DateTime.Parse( "2000-1-1 10:10:10" ); + var max = DateTime.Parse( "2000-1-2 10:10:10" ); + _clause.Between( "a.B", min, max, true, Boundary.Neither ); + + //验证 + Assert.Equal( min, _parameterManager.GetValue( "@_p_0" ) ); + Assert.Equal( max, _parameterManager.GetValue( "@_p_1" ) ); + Assert.Equal( result.ToString(), GetSql() ); + } + + /// + /// 测试范围查询 - 日期 - 不包含时间 - 最大值为空 + /// + [Fact] + public void TestBetween_12() { + //结果 + var result = new StringBuilder(); + result.Append( "Where [a].[B]>=@_p_0" ); + + //执行 + var min = DateTime.Parse( "2000-1-1 10:10:10" ); + _clause.Between( "a.B", min, null, false, null ); + + //验证 + Assert.Equal( DateTime.Parse( "2000-1-1" ), _parameterManager.GetValue( "@_p_0" ) ); + Assert.Equal( result.ToString(), GetSql() ); + } + + /// + /// 测试范围查询 - 日期 - 包含时间 - 最大值为空 + /// + [Fact] + public void TestBetween_13() { + //结果 + var result = new StringBuilder(); + result.Append( "Where [a].[B]>=@_p_0" ); + + //执行 + var min = DateTime.Parse( "2000-1-1 10:10:10" ); + _clause.Between( "a.B", min, null, true, null ); + + //验证 + Assert.Equal( min, _parameterManager.GetValue( "@_p_0" ) ); + Assert.Equal( result.ToString(), GetSql() ); + } + + /// + /// 测试范围查询 - 日期 - 不包含时间 - 最小值为空 + /// + [Fact] + public void TestBetween_14() { + //结果 + var result = new StringBuilder(); + result.Append( "Where [a].[B]<@_p_0" ); + + //执行 + var max = DateTime.Parse( "2000-1-2 10:10:10" ); + _clause.Between( "a.B", null, max, false, null ); + + //验证 + Assert.Equal( DateTime.Parse( "2000-1-3" ), _parameterManager.GetValue( "@_p_0" ) ); + Assert.Equal( result.ToString(), GetSql() ); + } + + /// + /// 测试范围查询 - 日期 - 包含时间 - 最小值为空 + /// + [Fact] + public void TestBetween_15() { + //结果 + var result = new StringBuilder(); + result.Append( "Where [a].[B]<=@_p_0" ); + + //执行 + var max = DateTime.Parse( "2000-1-2 10:10:10" ); + _clause.Between( "a.B", null, max, true, null ); + + //验证 + Assert.Equal( max, _parameterManager.GetValue( "@_p_0" ) ); + Assert.Equal( result.ToString(), GetSql() ); + } + + #endregion + + #region Exists + + /// + /// 设置Exists条件 - 子查询Sql生成器 + /// + [Fact] + public void TestExists_1() { + //结果 + var result = new StringBuilder(); + result.Append( "Where Exists (" ); + result.AppendLine( "Select [Name] " ); + result.Append( "From [t]" ); + result.Append( ")" ); + + //子查询 + var subBuilder = new TestSqlBuilder(); + subBuilder.Select( "Name" ).From( "t" ); + + //执行 + _clause.Exists( subBuilder ); + + //验证 + Assert.Equal( result.ToString(), GetSql() ); + } + + /// + /// 设置Exists条件 - 子查询操作 + /// + [Fact] + public void TestExists_2() { + //结果 + var result = new StringBuilder(); + result.Append( "Where Exists (" ); + result.AppendLine( "Select [Name] " ); + result.Append( "From [t]" ); + result.Append( ")" ); + + //执行 + _clause.Exists( t => t.Select( "Name" ).From( "t" ) ); + + //验证 + Assert.Equal( result.ToString(), GetSql() ); + } + + #endregion + + #region NotExists + + /// + /// 设置Not Exists条件 - 子查询Sql生成器 + /// + [Fact] + public void TestNotExists_1() { + //结果 + var result = new StringBuilder(); + result.Append( "Where Not Exists (" ); + result.AppendLine( "Select [Name] " ); + result.Append( "From [t]" ); + result.Append( ")" ); + + //子查询 + var subBuilder = new TestSqlBuilder(); + subBuilder.Select( "Name" ).From( "t" ); + + //执行 + _clause.NotExists( subBuilder ); + + //验证 + Assert.Equal( result.ToString(), GetSql() ); + } + + /// + /// 设置Not Exists条件 - 子查询操作 + /// + [Fact] + public void TestNotExists_2() { + //结果 + var result = new StringBuilder(); + result.Append( "Where Not Exists (" ); + result.AppendLine( "Select [Name] " ); + result.Append( "From [t]" ); + result.Append( ")" ); + + //执行 + _clause.NotExists( t => t.Select( "Name" ).From( "t" ) ); + + //验证 + Assert.Equal( result.ToString(), GetSql() ); + } + + #endregion + + #region AppendSql(添加到Where子句) + + /// + /// 添加到Where子句 + /// + [Fact] + public void TestAppendSql() { + var clause = new WhereClause( new TestSqlBuilder( new TestDialect2(), new TestColumnCache( new TestDialect2() ) ) ); + clause.AppendSql( "[a]", false ); + clause.AppendSql( "[b]", true ); + Assert.Equal( "Where $a& And [b]", GetSql( clause ) ); + } + + #endregion + + #region Clear + + /// + /// 测试清理 + /// + [Fact] + public void TestClear() { + _clause.Where( "Name", "a", Operator.Equal ); + _clause.Clear(); + Assert.Empty( GetSql() ); + } + + #endregion + + #region Clone + + /// + /// 测试复制Where子句 + /// + [Fact] + public void TestClone() { + //设置条件 + _clause.Where( "Name", "a", Operator.Equal ); + + //复制并验证 + var sqlBuilder = new TestSqlBuilder(); + var clone = _clause.Clone( sqlBuilder ); + Assert.Equal( "Where [Name]=@_p_0", GetSql( clone ) ); + + //修改原始子句,复制子句不应受影响 + _clause.Where( "Code", "b", Operator.Equal ); + Assert.Equal( "Where [Name]=@_p_0", GetSql( clone ) ); + } + + #endregion + } +} diff --git a/test/Util.Data.Sql.Tests/Builders/Conditions/AndConditionTest.cs b/test/Util.Data.Sql.Tests/Builders/Conditions/AndConditionTest.cs new file mode 100644 index 00000000..e6586be7 --- /dev/null +++ b/test/Util.Data.Sql.Tests/Builders/Conditions/AndConditionTest.cs @@ -0,0 +1,103 @@ +using System.Text; +using Util.Data.Sql.Builders.Conditions; +using Util.Data.Sql.Builders.Params; +using Util.Data.Sql.Tests.Samples; +using Xunit; + +namespace Util.Data.Sql.Tests.Builders.Conditions { + /// + /// And连接条件测试 + /// + public class AndConditionTest { + /// + /// 参数管理器 + /// + private readonly IParameterManager _parameterManager; + + /// + /// 测试初始化 + /// + public AndConditionTest() { + _parameterManager = new ParameterManager( TestDialect.Instance ); + } + + /// + /// 测试与连接条件 + /// + [Fact] + public void Test_1() { + var result = new StringBuilder(); + var condition1 = new EqualCondition( _parameterManager, "Name", "@Name", false ); + condition1.AppendTo( result ); + var condition2 = new GreaterCondition( _parameterManager, "Age", "@Age", false ); + var andCondition = new AndCondition( condition2 ); + andCondition.AppendTo( result ); + Assert.Equal( "Name=@Name And Age>@Age", result.ToString() ); + } + + /// + /// 测试或连接条件 - 构造器传入2个条件 + /// + [Fact] + public void Test_2() { + var result = new StringBuilder(); + var condition1 = new EqualCondition( _parameterManager, "Name", "@Name", false ); + condition1.AppendTo( result ); + var condition2 = new EqualCondition( _parameterManager, "Code", "@Code", false ); + var condition3 = new GreaterCondition( _parameterManager, "Age", "@Age", false ); + var orCondition = new AndCondition( condition2, condition3 ); + orCondition.AppendTo( result ); + Assert.Equal( "Name=@Name And Code=@Code And Age>@Age", result.ToString() ); + } + + /// + /// 测试或连接条件 - 第2个条件为空条件 + /// + [Fact] + public void Test_3() { + var result = new StringBuilder(); + var condition1 = new EqualCondition( _parameterManager, "Name", "@Name", false ); + condition1.AppendTo( result ); + var condition2 = new EqualCondition( _parameterManager, "Code", "@Code", false ); + var orCondition = new AndCondition( condition2, NullCondition.Instance ); + orCondition.AppendTo( result ); + Assert.Equal( "Name=@Name And Code=@Code", result.ToString() ); + } + + /// + /// 测试条件1为空 + /// + [Fact] + public void Test_4() { + var result = new StringBuilder(); + var condition2 = new GreaterCondition( _parameterManager, "Age", "@Age", false ); + var andCondition = new AndCondition( condition2 ); + andCondition.AppendTo( result ); + Assert.Equal( "Age>@Age", result.ToString() ); + } + + /// + /// 测试条件2为空 + /// + [Fact] + public void Test_5() { + var result = new StringBuilder(); + var condition1 = new EqualCondition( _parameterManager, "Name", "@Name", false ); + condition1.AppendTo( result ); + var andCondition = new AndCondition( null ); + andCondition.AppendTo( result ); + Assert.Equal( "Name=@Name", result.ToString() ); + } + + /// + /// 测试条件都为空 + /// + [Fact] + public void Test_6() { + var result = new StringBuilder(); + var andCondition = new AndCondition( null ); + andCondition.AppendTo( result ); + Assert.Empty( result.ToString() ); + } + } +} diff --git a/test/Util.Data.Sql.Tests/Builders/Conditions/ContainsConditionTest.cs b/test/Util.Data.Sql.Tests/Builders/Conditions/ContainsConditionTest.cs new file mode 100644 index 00000000..f57687d3 --- /dev/null +++ b/test/Util.Data.Sql.Tests/Builders/Conditions/ContainsConditionTest.cs @@ -0,0 +1,64 @@ +using System; +using System.Text; +using Util.Data.Sql.Builders.Conditions; +using Util.Data.Sql.Builders.Params; +using Util.Data.Sql.Tests.Samples; +using Xunit; + +namespace Util.Data.Sql.Tests.Builders.Conditions { + /// + /// Sql模糊匹配查询条件测试 + /// + public class ContainsConditionTest { + /// + /// 参数管理器 + /// + private readonly IParameterManager _parameterManager; + + /// + /// 测试初始化 + /// + public ContainsConditionTest() { + _parameterManager = new ParameterManager( TestDialect.Instance ); + } + + /// + /// 获取结果 + /// + private string GetResult( ISqlCondition condition ) { + var result = new StringBuilder(); + condition.AppendTo( result ); + return result.ToString(); + } + + /// + /// 测试创建条件 - 验证列名为空 + /// + [Fact] + public void TestCreate_Validate() { + Assert.Throws( () => { + var condition = new ContainsCondition( _parameterManager, "", 1, true ); + } ); + } + + /// + /// 测试获取条件 - 参数化 + /// + [Fact] + public void TestGetCondition_1() { + var condition = new ContainsCondition( _parameterManager, "a", "b", true ); + Assert.Equal( "a Like @_p_0", GetResult( condition ) ); + Assert.Equal( "%b%", _parameterManager.GetValue( "@_p_0" ) ); + } + + /// + /// 测试获取条件 - 非参数化 + /// + [Fact] + public void TestGetCondition_2() { + var condition = new ContainsCondition( _parameterManager, "a", "b", false ); + Assert.Equal( "a Like '%b%'", GetResult( condition ) ); + Assert.Equal( 0, _parameterManager.GetParams().Count ); + } + } +} diff --git a/test/Util.Data.Sql.Tests/Builders/Conditions/EndsConditionTest.cs b/test/Util.Data.Sql.Tests/Builders/Conditions/EndsConditionTest.cs new file mode 100644 index 00000000..0b5af970 --- /dev/null +++ b/test/Util.Data.Sql.Tests/Builders/Conditions/EndsConditionTest.cs @@ -0,0 +1,64 @@ +using System; +using System.Text; +using Util.Data.Sql.Builders.Conditions; +using Util.Data.Sql.Builders.Params; +using Util.Data.Sql.Tests.Samples; +using Xunit; + +namespace Util.Data.Sql.Tests.Builders.Conditions { + /// + /// Sql尾匹配查询条件测试 + /// + public class EndsConditionTest { + /// + /// 参数管理器 + /// + private readonly IParameterManager _parameterManager; + + /// + /// 测试初始化 + /// + public EndsConditionTest() { + _parameterManager = new ParameterManager( TestDialect.Instance ); + } + + /// + /// 获取结果 + /// + private string GetResult( ISqlCondition condition ) { + var result = new StringBuilder(); + condition.AppendTo( result ); + return result.ToString(); + } + + /// + /// 测试创建条件 - 验证列名为空 + /// + [Fact] + public void TestCreate_Validate() { + Assert.Throws( () => { + var condition = new EndsCondition( _parameterManager, "", 1, true ); + } ); + } + + /// + /// 测试获取条件 - 参数化 + /// + [Fact] + public void TestGetCondition_1() { + var condition = new EndsCondition( _parameterManager, "a", "b", true ); + Assert.Equal( "a Like @_p_0", GetResult( condition ) ); + Assert.Equal( "%b", _parameterManager.GetValue( "@_p_0" ) ); + } + + /// + /// 测试获取条件 - 非参数化 + /// + [Fact] + public void TestGetCondition_2() { + var condition = new EndsCondition( _parameterManager, "a", "b", false ); + Assert.Equal( "a Like '%b'", GetResult( condition ) ); + Assert.Equal( 0, _parameterManager.GetParams().Count ); + } + } +} diff --git a/test/Util.Data.Sql.Tests/Builders/Conditions/EqualConditionTest.cs b/test/Util.Data.Sql.Tests/Builders/Conditions/EqualConditionTest.cs new file mode 100644 index 00000000..879fccd1 --- /dev/null +++ b/test/Util.Data.Sql.Tests/Builders/Conditions/EqualConditionTest.cs @@ -0,0 +1,90 @@ +using System; +using System.Text; +using Util.Data.Sql.Builders; +using Util.Data.Sql.Builders.Conditions; +using Util.Data.Sql.Builders.Params; +using Util.Data.Sql.Tests.Samples; +using Xunit; + +namespace Util.Data.Sql.Tests.Builders.Conditions { + /// + /// Sql相等查询条件测试 + /// + public class EqualConditionTest { + /// + /// 参数管理器 + /// + private readonly IParameterManager _parameterManager; + + /// + /// 测试初始化 + /// + public EqualConditionTest() { + _parameterManager = new ParameterManager( TestDialect.Instance ); + } + + /// + /// 获取结果 + /// + private string GetResult( ISqlCondition condition ) { + var result = new StringBuilder(); + condition.AppendTo( result ); + return result.ToString(); + } + + /// + /// 测试创建条件 - 验证列名为空 + /// + [Fact] + public void TestCreate_Validate() { + Assert.Throws( () => { + var condition = new EqualCondition( _parameterManager, "", 1, true ); + } ); + } + + /// + /// 测试获取条件 - 参数化 + /// + [Fact] + public void TestGetCondition_1() { + var condition = new EqualCondition( _parameterManager, "a", 1, true ); + Assert.Equal( "a=@_p_0", GetResult( condition ) ); + Assert.Equal( 1, _parameterManager.GetValue( "@_p_0" ) ); + } + + /// + /// 测试获取条件 - 非参数化 + /// + [Fact] + public void TestGetCondition_2() { + var condition = new EqualCondition( _parameterManager, "a", "b", false ); + Assert.Equal( "a=b", GetResult( condition ) ); + Assert.Equal( 0, _parameterManager.GetParams().Count ); + } + + /// + /// 测试获取条件 - 参数值为null,则输出 is null + /// + [Fact] + public void TestGetCondition_3() { + var condition = new EqualCondition( _parameterManager, "a", null, true ); + Assert.Equal( "a Is Null", GetResult( condition ) ); + Assert.Equal( 0, _parameterManager.GetParams().Count ); + } + + /// + /// 测试获取条件 - 值为ISqlBuilder + /// + [Fact] + public void TestGetCondition_4() { + var result = new StringBuilder(); + result.Append( "a=" ); + result.AppendLine( "(Select [a] " ); + result.Append( "From [b])" ); + + var builder = new TestSqlBuilder().Select( "a" ).From( "b" ); + var condition = new EqualCondition( _parameterManager, "a", builder, true ); + Assert.Equal( result.ToString(), GetResult( condition ) ); + } + } +} diff --git a/test/Util.Data.Sql.Tests/Builders/Conditions/ExistsConditionTest.cs b/test/Util.Data.Sql.Tests/Builders/Conditions/ExistsConditionTest.cs new file mode 100644 index 00000000..755c2687 --- /dev/null +++ b/test/Util.Data.Sql.Tests/Builders/Conditions/ExistsConditionTest.cs @@ -0,0 +1,43 @@ +using System.Text; +using Util.Data.Sql.Builders.Conditions; +using Util.Data.Sql.Tests.Samples; +using Xunit; + +namespace Util.Data.Sql.Tests.Builders.Conditions { + /// + /// Exists查询条件测试 + /// + public class ExistsConditionTest { + /// + /// 获取结果 + /// + private string GetResult( ISqlCondition condition ) { + var result = new StringBuilder(); + condition.AppendTo( result ); + return result.ToString(); + } + + /// + /// 测试Exists查询条件 + /// + [Fact] + public void Test() { + //结果 + var result = new StringBuilder(); + result.Append( "Exists (" ); + result.AppendLine( "Select [Name] " ); + result.Append( "From [t]" ); + result.Append( ")" ); + + //子查询 + var subBuilder = new TestSqlBuilder(); + subBuilder.Select( "Name" ).From( "t" ); + + //创建条件 + var condition = new ExistsCondition( subBuilder ); + + //验证 + Assert.Equal( result.ToString(), GetResult( condition ) ); + } + } +} diff --git a/test/Util.Data.Sql.Tests/Builders/Conditions/GreaterConditionTest.cs b/test/Util.Data.Sql.Tests/Builders/Conditions/GreaterConditionTest.cs new file mode 100644 index 00000000..80d2a5d4 --- /dev/null +++ b/test/Util.Data.Sql.Tests/Builders/Conditions/GreaterConditionTest.cs @@ -0,0 +1,79 @@ +using System; +using System.Text; +using Util.Data.Sql.Builders.Conditions; +using Util.Data.Sql.Builders.Params; +using Util.Data.Sql.Tests.Samples; +using Xunit; + +namespace Util.Data.Sql.Tests.Builders.Conditions { + /// + /// Sql大于查询条件测试 + /// + public class GreaterConditionTest { + /// + /// 参数管理器 + /// + private readonly IParameterManager _parameterManager; + + /// + /// 测试初始化 + /// + public GreaterConditionTest() { + _parameterManager = new ParameterManager( TestDialect.Instance ); + } + + /// + /// 获取结果 + /// + private string GetResult( ISqlCondition condition ) { + var result = new StringBuilder(); + condition.AppendTo( result ); + return result.ToString(); + } + + /// + /// 测试创建条件 - 验证列名为空 + /// + [Fact] + public void TestCreate_Validate() { + Assert.Throws( () => { + var condition = new GreaterCondition( _parameterManager, "", 1, true ); + } ); + } + + /// + /// 测试获取条件 - 参数化 + /// + [Fact] + public void TestGetCondition_1() { + var condition = new GreaterCondition( _parameterManager, "a", 1, true ); + Assert.Equal( "a>@_p_0", GetResult( condition ) ); + Assert.Equal( 1, _parameterManager.GetValue( "@_p_0" ) ); + } + + /// + /// 测试获取条件 - 非参数化 + /// + [Fact] + public void TestGetCondition_2() { + var condition = new GreaterCondition( _parameterManager, "a", "b", false ); + Assert.Equal( "a>b", GetResult( condition ) ); + Assert.Equal( 0, _parameterManager.GetParams().Count ); + } + + /// + /// 测试获取条件 - 值为ISqlBuilder + /// + [Fact] + public void TestGetCondition_3() { + var result = new StringBuilder(); + result.Append( "a>" ); + result.AppendLine( "(Select [a] " ); + result.Append( "From [b])" ); + + var builder = new TestSqlBuilder().Select( "a" ).From( "b" ); + var condition = new GreaterCondition( _parameterManager, "a", builder, true ); + Assert.Equal( result.ToString(), GetResult( condition ) ); + } + } +} \ No newline at end of file diff --git a/test/Util.Data.Sql.Tests/Builders/Conditions/GreaterEqualConditionTest.cs b/test/Util.Data.Sql.Tests/Builders/Conditions/GreaterEqualConditionTest.cs new file mode 100644 index 00000000..b80b0066 --- /dev/null +++ b/test/Util.Data.Sql.Tests/Builders/Conditions/GreaterEqualConditionTest.cs @@ -0,0 +1,79 @@ +using System; +using System.Text; +using Util.Data.Sql.Builders.Conditions; +using Util.Data.Sql.Builders.Params; +using Util.Data.Sql.Tests.Samples; +using Xunit; + +namespace Util.Data.Sql.Tests.Builders.Conditions { + /// + /// Sql大于等于查询条件测试 + /// + public class GreaterEqualConditionTest { + /// + /// 参数管理器 + /// + private readonly IParameterManager _parameterManager; + + /// + /// 测试初始化 + /// + public GreaterEqualConditionTest() { + _parameterManager = new ParameterManager( TestDialect.Instance ); + } + + /// + /// 获取结果 + /// + private string GetResult( ISqlCondition condition ) { + var result = new StringBuilder(); + condition.AppendTo( result ); + return result.ToString(); + } + + /// + /// 测试创建条件 - 验证列名为空 + /// + [Fact] + public void TestCreate_Validate() { + Assert.Throws( () => { + var condition = new GreaterEqualCondition( _parameterManager, "", 1, true ); + } ); + } + + /// + /// 测试获取条件 - 参数化 + /// + [Fact] + public void TestGetCondition_1() { + var condition = new GreaterEqualCondition( _parameterManager, "a", 1, true ); + Assert.Equal( "a>=@_p_0", GetResult( condition ) ); + Assert.Equal( 1, _parameterManager.GetValue( "@_p_0" ) ); + } + + /// + /// 测试获取条件 - 非参数化 + /// + [Fact] + public void TestGetCondition_2() { + var condition = new GreaterEqualCondition( _parameterManager, "a", "b", false ); + Assert.Equal( "a>=b", GetResult( condition ) ); + Assert.Equal( 0, _parameterManager.GetParams().Count ); + } + + /// + /// 测试获取条件 - 值为ISqlBuilder + /// + [Fact] + public void TestGetCondition_3() { + var result = new StringBuilder(); + result.Append( "a>=" ); + result.AppendLine( "(Select [a] " ); + result.Append( "From [b])" ); + + var builder = new TestSqlBuilder().Select( "a" ).From( "b" ); + var condition = new GreaterEqualCondition( _parameterManager, "a", builder, true ); + Assert.Equal( result.ToString(), GetResult( condition ) ); + } + } +} \ No newline at end of file diff --git a/test/Util.Data.Sql.Tests/Builders/Conditions/InConditionTest.cs b/test/Util.Data.Sql.Tests/Builders/Conditions/InConditionTest.cs new file mode 100644 index 00000000..a61b4591 --- /dev/null +++ b/test/Util.Data.Sql.Tests/Builders/Conditions/InConditionTest.cs @@ -0,0 +1,139 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Util.Data.Sql.Builders.Conditions; +using Util.Data.Sql.Builders.Params; +using Util.Data.Sql.Tests.Samples; +using Xunit; + +namespace Util.Data.Sql.Tests.Builders.Conditions { + /// + /// In查询条件测试 + /// + public class InConditionTest { + /// + /// 参数管理器 + /// + private readonly IParameterManager _parameterManager; + + /// + /// 测试初始化 + /// + public InConditionTest() { + _parameterManager = new ParameterManager( TestDialect.Instance ); + } + + /// + /// 获取结果 + /// + private string GetResult( ISqlCondition condition ) { + var result = new StringBuilder(); + condition.AppendTo( result ); + return result.ToString(); + } + + /// + /// 测试创建条件 - 验证列名为空 + /// + [Fact] + public void TestCreate_Validate() { + var parameters = new List { "b" }; + Assert.Throws( () => { + var condition = new InCondition( _parameterManager, "", parameters, true ); + } ); + } + + /// + /// 测试获取条件 - 参数化 - 1个字符串型参数 + /// + [Fact] + public void TestGetCondition_1() { + var parameters = new List { "b" }; + var condition = new InCondition( _parameterManager, "a", parameters, true ); + Assert.Equal( "a In (@_p_0)", GetResult( condition ) ); + Assert.Equal( "b", _parameterManager.GetValue( "@_p_0" ) ); + } + + /// + /// 测试获取条件 - 参数化 - 1个数值型参数 + /// + [Fact] + public void TestGetCondition_2() { + var parameters = new List { 1 }; + var condition = new InCondition( _parameterManager, "a", parameters, true ); + Assert.Equal( "a In (@_p_0)", GetResult( condition ) ); + Assert.Equal( 1, _parameterManager.GetValue( "@_p_0" ) ); + } + + /// + /// 测试获取条件 - 参数化 - 2个参数 + /// + [Fact] + public void TestGetCondition_3() { + var parameters = new List { "b", "c" }; + var condition = new InCondition( _parameterManager, "a", parameters, true ); + Assert.Equal( "a In (@_p_0,@_p_1)", GetResult( condition ) ); + Assert.Equal( "b", _parameterManager.GetValue( "@_p_0" ) ); + Assert.Equal( "c", _parameterManager.GetValue( "@_p_1" ) ); + } + + /// + /// 测试获取条件 - 参数化 - 0个参数 + /// + [Fact] + public void TestGetCondition_4() { + var parameters = new List(); + var condition = new InCondition( _parameterManager, "a", parameters, true ); + Assert.Empty( GetResult( condition ) ); + Assert.Equal( 0, _parameterManager.GetParams().Count ); + } + + /// + /// 测试获取条件 - 非参数化 - 1个字符串型参数 + /// + [Fact] + public void TestGetCondition_5() { + var parameters = new List { "b" }; + var condition = new InCondition( _parameterManager, "a", parameters, false ); + Assert.Equal( "a In ('b')", GetResult( condition ) ); + Assert.Equal( 0, _parameterManager.GetParams().Count ); + } + + /// + /// 测试获取条件 - 非参数化 - 1个数值型参数 + /// + [Fact] + public void TestGetCondition_6() { + var parameters = new List { 1 }; + var condition = new InCondition( _parameterManager, "a", parameters, false ); + Assert.Equal( "a In (1)", GetResult( condition ) ); + Assert.Equal( 0, _parameterManager.GetParams().Count ); + } + + /// + /// 测试获取条件 - 非参数化 - 2个参数 + /// + [Fact] + public void TestGetCondition_7() { + var parameters = new List { "b", "c" }; + var condition = new InCondition( _parameterManager, "a", parameters, false ); + Assert.Equal( "a In ('b','c')", GetResult( condition ) ); + Assert.Equal( 0, _parameterManager.GetParams().Count ); + } + + /// + /// 测试获取条件 - 值为ISqlBuilder + /// + [Fact] + public void TestGetCondition_8() { + var result = new StringBuilder(); + result.Append( "a In " ); + result.AppendLine( "(Select [a] " ); + result.Append( "From [b])" ); + + var builder = new TestSqlBuilder().Select( "a" ).From( "b" ); + var condition = new InCondition( _parameterManager, "a", builder, true ); + Assert.Equal( result.ToString(), GetResult( condition ) ); + } + } +} diff --git a/test/Util.Data.Sql.Tests/Builders/Conditions/IsNotNullConditionTest.cs b/test/Util.Data.Sql.Tests/Builders/Conditions/IsNotNullConditionTest.cs new file mode 100644 index 00000000..eca082fa --- /dev/null +++ b/test/Util.Data.Sql.Tests/Builders/Conditions/IsNotNullConditionTest.cs @@ -0,0 +1,37 @@ +using System.Text; +using Util.Data.Sql.Builders.Conditions; +using Xunit; + +namespace Util.Data.Sql.Tests.Builders.Conditions { + /// + /// Is Not Null查询条件测试 + /// + public class IsNotNullConditionTest { + /// + /// 获取结果 + /// + private string GetResult( ISqlCondition condition ) { + var result = new StringBuilder(); + condition.AppendTo( result ); + return result.ToString(); + } + + /// + /// 获取条件 + /// + [Fact] + public void Test_1() { + var condition = new IsNotNullCondition( "Email" ); + Assert.Equal( "Email Is Not Null", GetResult( condition ) ); + } + + /// + /// 获取条件 - 验证列为空 + /// + [Fact] + public void Test_2() { + var condition = new IsNotNullCondition( "" ); + Assert.Empty( GetResult( condition ) ); + } + } +} diff --git a/test/Util.Data.Sql.Tests/Builders/Conditions/IsNullConditionTest.cs b/test/Util.Data.Sql.Tests/Builders/Conditions/IsNullConditionTest.cs new file mode 100644 index 00000000..8b4b617e --- /dev/null +++ b/test/Util.Data.Sql.Tests/Builders/Conditions/IsNullConditionTest.cs @@ -0,0 +1,37 @@ +using System.Text; +using Util.Data.Sql.Builders.Conditions; +using Xunit; + +namespace Util.Data.Sql.Tests.Builders.Conditions { + /// + /// Is Null查询条件测试 + /// + public class IsNullConditionTest { + /// + /// 获取结果 + /// + private string GetResult( ISqlCondition condition ) { + var result = new StringBuilder(); + condition.AppendTo( result ); + return result.ToString(); + } + + /// + /// 获取条件 + /// + [Fact] + public void Test_1() { + var condition = new IsNullCondition( "Email" ); + Assert.Equal( "Email Is Null", GetResult( condition ) ); + } + + /// + /// 获取条件 - 验证列为空 + /// + [Fact] + public void Test_2() { + var condition = new IsNullCondition( "" ); + Assert.Empty( GetResult( condition ) ); + } + } +} diff --git a/test/Util.Data.Sql.Tests/Builders/Conditions/LessConditionTest.cs b/test/Util.Data.Sql.Tests/Builders/Conditions/LessConditionTest.cs new file mode 100644 index 00000000..9f1c51cc --- /dev/null +++ b/test/Util.Data.Sql.Tests/Builders/Conditions/LessConditionTest.cs @@ -0,0 +1,79 @@ +using System; +using System.Text; +using Util.Data.Sql.Builders.Conditions; +using Util.Data.Sql.Builders.Params; +using Util.Data.Sql.Tests.Samples; +using Xunit; + +namespace Util.Data.Sql.Tests.Builders.Conditions { + /// + /// Sql小于查询条件测试 + /// + public class LessConditionTest { + /// + /// 参数管理器 + /// + private readonly IParameterManager _parameterManager; + + /// + /// 测试初始化 + /// + public LessConditionTest() { + _parameterManager = new ParameterManager( TestDialect.Instance ); + } + + /// + /// 获取结果 + /// + private string GetResult( ISqlCondition condition ) { + var result = new StringBuilder(); + condition.AppendTo( result ); + return result.ToString(); + } + + /// + /// 测试创建条件 - 验证列名为空 + /// + [Fact] + public void TestCreate_Validate() { + Assert.Throws( () => { + var condition = new LessCondition( _parameterManager, "", 1, true ); + } ); + } + + /// + /// 测试获取条件 - 参数化 + /// + [Fact] + public void TestGetCondition_1() { + var condition = new LessCondition( _parameterManager, "a", 1, true ); + Assert.Equal( "a<@_p_0", GetResult( condition ) ); + Assert.Equal( 1, _parameterManager.GetValue( "@_p_0" ) ); + } + + /// + /// 测试获取条件 - 非参数化 + /// + [Fact] + public void TestGetCondition_2() { + var condition = new LessCondition( _parameterManager, "a", "b", false ); + Assert.Equal( "a + /// 测试获取条件 - 值为ISqlBuilder + /// + [Fact] + public void TestGetCondition_3() { + var result = new StringBuilder(); + result.Append( "a<" ); + result.AppendLine( "(Select [a] " ); + result.Append( "From [b])" ); + + var builder = new TestSqlBuilder().Select( "a" ).From( "b" ); + var condition = new LessCondition( _parameterManager, "a", builder, true ); + Assert.Equal( result.ToString(), GetResult( condition ) ); + } + } +} \ No newline at end of file diff --git a/test/Util.Data.Sql.Tests/Builders/Conditions/LessEqualConditionTest.cs b/test/Util.Data.Sql.Tests/Builders/Conditions/LessEqualConditionTest.cs new file mode 100644 index 00000000..b0181291 --- /dev/null +++ b/test/Util.Data.Sql.Tests/Builders/Conditions/LessEqualConditionTest.cs @@ -0,0 +1,79 @@ +using System; +using System.Text; +using Util.Data.Sql.Builders.Conditions; +using Util.Data.Sql.Builders.Params; +using Util.Data.Sql.Tests.Samples; +using Xunit; + +namespace Util.Data.Sql.Tests.Builders.Conditions { + /// + /// Sql小于等于查询条件测试 + /// + public class LessEqualConditionTest { + /// + /// 参数管理器 + /// + private readonly IParameterManager _parameterManager; + + /// + /// 测试初始化 + /// + public LessEqualConditionTest() { + _parameterManager = new ParameterManager( TestDialect.Instance ); + } + + /// + /// 获取结果 + /// + private string GetResult( ISqlCondition condition ) { + var result = new StringBuilder(); + condition.AppendTo( result ); + return result.ToString(); + } + + /// + /// 测试创建条件 - 验证列名为空 + /// + [Fact] + public void TestCreate_Validate() { + Assert.Throws( () => { + var condition = new LessEqualCondition( _parameterManager, "", 1, true ); + } ); + } + + /// + /// 测试获取条件 - 参数化 + /// + [Fact] + public void TestGetCondition_1() { + var condition = new LessEqualCondition( _parameterManager, "a", 1, true ); + Assert.Equal( "a<=@_p_0", GetResult( condition ) ); + Assert.Equal( 1, _parameterManager.GetValue( "@_p_0" ) ); + } + + /// + /// 测试获取条件 - 非参数化 + /// + [Fact] + public void TestGetCondition_2() { + var condition = new LessEqualCondition( _parameterManager, "a", "b", false ); + Assert.Equal( "a<=b", GetResult( condition ) ); + Assert.Equal( 0, _parameterManager.GetParams().Count ); + } + + /// + /// 测试获取条件 - 值为ISqlBuilder + /// + [Fact] + public void TestGetCondition_3() { + var result = new StringBuilder(); + result.Append( "a<=" ); + result.AppendLine( "(Select [a] " ); + result.Append( "From [b])" ); + + var builder = new TestSqlBuilder().Select( "a" ).From( "b" ); + var condition = new LessEqualCondition( _parameterManager, "a", builder, true ); + Assert.Equal( result.ToString(), GetResult( condition ) ); + } + } +} \ No newline at end of file diff --git a/test/Util.Data.Sql.Tests/Builders/Conditions/NotEqualConditionTest.cs b/test/Util.Data.Sql.Tests/Builders/Conditions/NotEqualConditionTest.cs new file mode 100644 index 00000000..975ed82d --- /dev/null +++ b/test/Util.Data.Sql.Tests/Builders/Conditions/NotEqualConditionTest.cs @@ -0,0 +1,89 @@ +using System; +using System.Text; +using Util.Data.Sql.Builders.Conditions; +using Util.Data.Sql.Builders.Params; +using Util.Data.Sql.Tests.Samples; +using Xunit; + +namespace Util.Data.Sql.Tests.Builders.Conditions { + /// + /// Sql不相等查询条件测试 + /// + public class NotEqualConditionTest { + /// + /// 参数管理器 + /// + private readonly IParameterManager _parameterManager; + + /// + /// 测试初始化 + /// + public NotEqualConditionTest() { + _parameterManager = new ParameterManager( TestDialect.Instance ); + } + + /// + /// 获取结果 + /// + private string GetResult( ISqlCondition condition ) { + var result = new StringBuilder(); + condition.AppendTo( result ); + return result.ToString(); + } + + /// + /// 测试创建条件 - 验证列名为空 + /// + [Fact] + public void TestCreate_Validate() { + Assert.Throws( () => { + var condition = new NotEqualCondition( _parameterManager, "", 1, true ); + } ); + } + + /// + /// 测试获取条件 - 参数化 + /// + [Fact] + public void TestGetCondition_1() { + var condition = new NotEqualCondition( _parameterManager, "a", 1, true ); + Assert.Equal( "a<>@_p_0", GetResult( condition ) ); + Assert.Equal( 1, _parameterManager.GetValue( "@_p_0" ) ); + } + + /// + /// 测试获取条件 - 非参数化 + /// + [Fact] + public void TestGetCondition_2() { + var condition = new NotEqualCondition( _parameterManager, "a", "b", false ); + Assert.Equal( "a<>b", GetResult( condition ) ); + Assert.Equal( 0, _parameterManager.GetParams().Count ); + } + + /// + /// 测试获取条件 - 参数值为null,则输出 is null + /// + [Fact] + public void TestGetCondition_3() { + var condition = new NotEqualCondition( _parameterManager, "a", null, true ); + Assert.Equal( "a Is Not Null", GetResult( condition ) ); + Assert.Equal( 0, _parameterManager.GetParams().Count ); + } + + /// + /// 测试获取条件 - 值为ISqlBuilder + /// + [Fact] + public void TestGetCondition_4() { + var result = new StringBuilder(); + result.Append( "a<>" ); + result.AppendLine( "(Select [a] " ); + result.Append( "From [b])" ); + + var builder = new TestSqlBuilder().Select( "a" ).From( "b" ); + var condition = new NotEqualCondition( _parameterManager, "a", builder, true ); + Assert.Equal( result.ToString(), GetResult( condition ) ); + } + } +} \ No newline at end of file diff --git a/test/Util.Data.Sql.Tests/Builders/Conditions/NotExistsConditionTest.cs b/test/Util.Data.Sql.Tests/Builders/Conditions/NotExistsConditionTest.cs new file mode 100644 index 00000000..dde9dfdb --- /dev/null +++ b/test/Util.Data.Sql.Tests/Builders/Conditions/NotExistsConditionTest.cs @@ -0,0 +1,43 @@ +using System.Text; +using Util.Data.Sql.Builders.Conditions; +using Util.Data.Sql.Tests.Samples; +using Xunit; + +namespace Util.Data.Sql.Tests.Builders.Conditions { + /// + /// Not Exists查询条件测试 + /// + public class NotExistsConditionTest { + /// + /// 获取结果 + /// + private string GetResult( ISqlCondition condition ) { + var result = new StringBuilder(); + condition.AppendTo( result ); + return result.ToString(); + } + + /// + /// 测试Not Exists查询条件 + /// + [Fact] + public void Test() { + //结果 + var result = new StringBuilder(); + result.Append( "Not Exists (" ); + result.AppendLine( "Select [Name] " ); + result.Append( "From [t]" ); + result.Append( ")" ); + + //子查询 + var subBuilder = new TestSqlBuilder(); + subBuilder.Select( "Name" ).From( "t" ); + + //创建条件 + var condition = new NotExistsCondition( subBuilder ); + + //验证 + Assert.Equal( result.ToString(), GetResult( condition ) ); + } + } +} diff --git a/test/Util.Data.Sql.Tests/Builders/Conditions/NotInConditionTest.cs b/test/Util.Data.Sql.Tests/Builders/Conditions/NotInConditionTest.cs new file mode 100644 index 00000000..3ce765f4 --- /dev/null +++ b/test/Util.Data.Sql.Tests/Builders/Conditions/NotInConditionTest.cs @@ -0,0 +1,139 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Util.Data.Sql.Builders.Conditions; +using Util.Data.Sql.Builders.Params; +using Util.Data.Sql.Tests.Samples; +using Xunit; + +namespace Util.Data.Sql.Tests.Builders.Conditions { + /// + /// Not In查询条件测试 + /// + public class NotInConditionTest { + /// + /// 参数管理器 + /// + private readonly IParameterManager _parameterManager; + + /// + /// 测试初始化 + /// + public NotInConditionTest() { + _parameterManager = new ParameterManager( TestDialect.Instance ); + } + + /// + /// 获取结果 + /// + private string GetResult( ISqlCondition condition ) { + var result = new StringBuilder(); + condition.AppendTo( result ); + return result.ToString(); + } + + /// + /// 测试创建条件 - 验证列名为空 + /// + [Fact] + public void TestCreate_Validate() { + var parameters = new List { "b" }; + Assert.Throws( () => { + var condition = new NotInCondition( _parameterManager, "", parameters, true ); + } ); + } + + /// + /// 测试获取条件 - 参数化 - 1个字符串型参数 + /// + [Fact] + public void TestGetCondition_1() { + var parameters = new List { "b" }; + var condition = new NotInCondition( _parameterManager, "a", parameters, true ); + Assert.Equal( "a Not In (@_p_0)", GetResult( condition ) ); + Assert.Equal( "b", _parameterManager.GetValue( "@_p_0" ) ); + } + + /// + /// 测试获取条件 - 参数化 - 1个数值型参数 + /// + [Fact] + public void TestGetCondition_2() { + var parameters = new List { 1 }; + var condition = new NotInCondition( _parameterManager, "a", parameters, true ); + Assert.Equal( "a Not In (@_p_0)", GetResult( condition ) ); + Assert.Equal( 1, _parameterManager.GetValue( "@_p_0" ) ); + } + + /// + /// 测试获取条件 - 参数化 - 2个参数 + /// + [Fact] + public void TestGetCondition_3() { + var parameters = new List { "b", "c" }; + var condition = new NotInCondition( _parameterManager, "a", parameters, true ); + Assert.Equal( "a Not In (@_p_0,@_p_1)", GetResult( condition ) ); + Assert.Equal( "b", _parameterManager.GetValue( "@_p_0" ) ); + Assert.Equal( "c", _parameterManager.GetValue( "@_p_1" ) ); + } + + /// + /// 测试获取条件 - 参数化 - 0个参数 + /// + [Fact] + public void TestGetCondition_4() { + var parameters = new List(); + var condition = new NotInCondition( _parameterManager, "a", parameters, true ); + Assert.Empty( GetResult( condition ) ); + Assert.Equal( 0, _parameterManager.GetParams().Count ); + } + + /// + /// 测试获取条件 - 非参数化 - 1个字符串型参数 + /// + [Fact] + public void TestGetCondition_5() { + var parameters = new List { "b" }; + var condition = new NotInCondition( _parameterManager, "a", parameters, false ); + Assert.Equal( "a Not In ('b')", GetResult( condition ) ); + Assert.Equal( 0, _parameterManager.GetParams().Count ); + } + + /// + /// 测试获取条件 - 非参数化 - 1个数值型参数 + /// + [Fact] + public void TestGetCondition_6() { + var parameters = new List { 1 }; + var condition = new NotInCondition( _parameterManager, "a", parameters, false ); + Assert.Equal( "a Not In (1)", GetResult( condition ) ); + Assert.Equal( 0, _parameterManager.GetParams().Count ); + } + + /// + /// 测试获取条件 - 非参数化 - 2个参数 + /// + [Fact] + public void TestGetCondition_7() { + var parameters = new List { "b", "c" }; + var condition = new NotInCondition( _parameterManager, "a", parameters, false ); + Assert.Equal( "a Not In ('b','c')", GetResult( condition ) ); + Assert.Equal( 0, _parameterManager.GetParams().Count ); + } + + /// + /// 测试获取条件 - 值为ISqlBuilder + /// + [Fact] + public void TestGetCondition_8() { + var result = new StringBuilder(); + result.Append( "a Not In " ); + result.AppendLine( "(Select [a] " ); + result.Append( "From [b])" ); + + var builder = new TestSqlBuilder().Select( "a" ).From( "b" ); + var condition = new NotInCondition( _parameterManager, "a", builder, true ); + Assert.Equal( result.ToString(), GetResult( condition ) ); + } + } +} diff --git a/test/Util.Data.Sql.Tests/Builders/Conditions/OrConditionTest.cs b/test/Util.Data.Sql.Tests/Builders/Conditions/OrConditionTest.cs new file mode 100644 index 00000000..bc6dad44 --- /dev/null +++ b/test/Util.Data.Sql.Tests/Builders/Conditions/OrConditionTest.cs @@ -0,0 +1,103 @@ +using System.Text; +using Util.Data.Sql.Builders.Conditions; +using Util.Data.Sql.Builders.Params; +using Util.Data.Sql.Tests.Samples; +using Xunit; + +namespace Util.Data.Sql.Tests.Builders.Conditions { + /// + /// Or连接条件测试 + /// + public class OrConditionTest { + /// + /// 参数管理器 + /// + private readonly IParameterManager _parameterManager; + + /// + /// 测试初始化 + /// + public OrConditionTest() { + _parameterManager = new ParameterManager( TestDialect.Instance ); + } + + /// + /// 测试或连接条件 - 构造器传入1个条件 + /// + [Fact] + public void Test_1() { + var result = new StringBuilder(); + var condition1 = new EqualCondition( _parameterManager, "Name", "@Name", false ); + condition1.AppendTo( result ); + var condition2 = new GreaterCondition( _parameterManager, "Age", "@Age", false ); + var orCondition = new OrCondition( condition2 ); + orCondition.AppendTo( result ); + Assert.Equal( "(Name=@Name Or Age>@Age)", result.ToString() ); + } + + /// + /// 测试或连接条件 - 构造器传入2个条件 + /// + [Fact] + public void Test_2() { + var result = new StringBuilder(); + var condition1 = new EqualCondition( _parameterManager, "Name", "@Name", false ); + condition1.AppendTo( result ); + var condition2 = new EqualCondition( _parameterManager, "Code", "@Code", false ); + var condition3 = new GreaterCondition( _parameterManager, "Age", "@Age", false ); + var orCondition = new OrCondition( condition2, condition3 ); + orCondition.AppendTo( result ); + Assert.Equal( "Name=@Name And (Code=@Code Or Age>@Age)", result.ToString() ); + } + + /// + /// 测试或连接条件 - 第2个条件为空条件 + /// + [Fact] + public void Test_3() { + var result = new StringBuilder(); + var condition1 = new EqualCondition( _parameterManager, "Name", "@Name", false ); + condition1.AppendTo( result ); + var condition2 = new EqualCondition( _parameterManager, "Code", "@Code", false ); + var orCondition = new OrCondition( condition2, NullCondition.Instance ); + orCondition.AppendTo( result ); + Assert.Equal( "(Name=@Name Or Code=@Code)", result.ToString() ); + } + + /// + /// 测试条件1为空 + /// + [Fact] + public void Test_4() { + var result = new StringBuilder(); + var condition2 = new GreaterCondition( _parameterManager, "Age", "@Age", false ); + var orCondition = new OrCondition( condition2 ); + orCondition.AppendTo( result ); + Assert.Equal( "Age>@Age", result.ToString() ); + } + + /// + /// 测试条件2为空 + /// + [Fact] + public void Test_5() { + var result = new StringBuilder(); + var condition1 = new EqualCondition( _parameterManager, "Name", "@Name", false ); + condition1.AppendTo( result ); + var orCondition = new OrCondition( null ); + orCondition.AppendTo( result ); + Assert.Equal( "Name=@Name", result.ToString() ); + } + + /// + /// 测试条件都为空 + /// + [Fact] + public void Test_6() { + var result = new StringBuilder(); + var orCondition = new OrCondition( null ); + orCondition.AppendTo( result ); + Assert.Empty( result.ToString() ); + } + } +} \ No newline at end of file diff --git a/test/Util.Data.Sql.Tests/Builders/Conditions/SegmentConditionTest.cs b/test/Util.Data.Sql.Tests/Builders/Conditions/SegmentConditionTest.cs new file mode 100644 index 00000000..f50b557f --- /dev/null +++ b/test/Util.Data.Sql.Tests/Builders/Conditions/SegmentConditionTest.cs @@ -0,0 +1,119 @@ +using System; +using System.Text; +using Util.Data.Queries; +using Util.Data.Sql.Builders.Conditions; +using Util.Data.Sql.Builders.Params; +using Util.Data.Sql.Tests.Samples; +using Xunit; + +namespace Util.Data.Sql.Tests.Builders.Conditions { + /// + /// 范围过滤条件测试 + /// + public class SegmentConditionTest { + /// + /// 参数管理器 + /// + private readonly IParameterManager _parameterManager; + + /// + /// 测试初始化 + /// + public SegmentConditionTest() { + _parameterManager = new ParameterManager( TestDialect.Instance ); + } + + /// + /// 获取结果 + /// + private string GetResult( ISqlCondition condition ) { + var result = new StringBuilder(); + condition.AppendTo( result ); + return result.ToString(); + } + + /// + /// 测试创建条件 - 验证列名为空 + /// + [Fact] + public void TestCreate_Validate() { + Assert.Throws( () => { + var condition = new SegmentCondition( _parameterManager, "", 1,2,Boundary.Left, true ); + } ); + } + + /// + /// 测试获取条件 - 参数化 - 包含两边边界 + /// + [Fact] + public void TestGetCondition_1() { + var condition = new SegmentCondition( _parameterManager, "a", 1, 2, Boundary.Both, true ); + Assert.Equal( "a>=@_p_0 And a<=@_p_1", GetResult( condition ) ); + Assert.Equal( 1, _parameterManager.GetValue( "@_p_0" ) ); + Assert.Equal( 2, _parameterManager.GetValue( "@_p_1" ) ); + } + + /// + /// 测试获取条件 - 参数化 - 包含左边边界 + /// + [Fact] + public void TestGetCondition_2() { + var condition = new SegmentCondition( _parameterManager, "a", 1, 2, Boundary.Left, true ); + Assert.Equal( "a>=@_p_0 And a<@_p_1", GetResult( condition ) ); + Assert.Equal( 1, _parameterManager.GetValue( "@_p_0" ) ); + Assert.Equal( 2, _parameterManager.GetValue( "@_p_1" ) ); + } + + /// + /// 测试获取条件 - 参数化 - 包含右边边界 + /// + [Fact] + public void TestGetCondition_3() { + var condition = new SegmentCondition( _parameterManager, "a", 1, 2, Boundary.Right, true ); + Assert.Equal( "a>@_p_0 And a<=@_p_1", GetResult( condition ) ); + Assert.Equal( 1, _parameterManager.GetValue( "@_p_0" ) ); + Assert.Equal( 2, _parameterManager.GetValue( "@_p_1" ) ); + } + + /// + /// 测试获取条件 - 参数化 - 不包含边界 + /// + [Fact] + public void TestGetCondition_4() { + var condition = new SegmentCondition( _parameterManager, "a", 1, 2, Boundary.Neither, true ); + Assert.Equal( "a>@_p_0 And a<@_p_1", GetResult( condition ) ); + Assert.Equal( 1, _parameterManager.GetValue( "@_p_0" ) ); + Assert.Equal( 2, _parameterManager.GetValue( "@_p_1" ) ); + } + + /// + /// 测试获取条件 - 参数化 - 没有最大值 + /// + [Fact] + public void TestGetCondition_5() { + var condition = new SegmentCondition( _parameterManager, "a", 1, null, Boundary.Both, true ); + Assert.Equal( "a>=@_p_0", GetResult( condition ) ); + Assert.Equal( 1, _parameterManager.GetValue( "@_p_0" ) ); + } + + /// + /// 测试获取条件 - 参数化 - 没有最小值 + /// + [Fact] + public void TestGetCondition_6() { + var condition = new SegmentCondition( _parameterManager, "a", null, 1, Boundary.Both, true ); + Assert.Equal( "a<=@_p_0", GetResult( condition ) ); + Assert.Equal( 1, _parameterManager.GetValue( "@_p_0" ) ); + } + + /// + /// 测试获取条件 - 非参数化 + /// + [Fact] + public void TestGetCondition_7() { + var condition = new SegmentCondition( _parameterManager, "a", 1, 2, Boundary.Both, false ); + Assert.Equal( "a>=1 And a<=2", GetResult( condition ) ); + Assert.Equal( 0, _parameterManager.GetParams().Count ); + } + } +} diff --git a/test/Util.Data.Sql.Tests/Builders/Conditions/StartsConditionTest.cs b/test/Util.Data.Sql.Tests/Builders/Conditions/StartsConditionTest.cs new file mode 100644 index 00000000..58f504c8 --- /dev/null +++ b/test/Util.Data.Sql.Tests/Builders/Conditions/StartsConditionTest.cs @@ -0,0 +1,64 @@ +using System; +using System.Text; +using Util.Data.Sql.Builders.Conditions; +using Util.Data.Sql.Builders.Params; +using Util.Data.Sql.Tests.Samples; +using Xunit; + +namespace Util.Data.Sql.Tests.Builders.Conditions { + /// + /// Sql头匹配查询条件测试 + /// + public class StartsConditionTest { + /// + /// 参数管理器 + /// + private readonly IParameterManager _parameterManager; + + /// + /// 测试初始化 + /// + public StartsConditionTest() { + _parameterManager = new ParameterManager( TestDialect.Instance ); + } + + /// + /// 获取结果 + /// + private string GetResult( ISqlCondition condition ) { + var result = new StringBuilder(); + condition.AppendTo( result ); + return result.ToString(); + } + + /// + /// 测试创建条件 - 验证列名为空 + /// + [Fact] + public void TestCreate_Validate() { + Assert.Throws( () => { + var condition = new StartsCondition( _parameterManager, "", 1, true ); + } ); + } + + /// + /// 测试获取条件 - 参数化 + /// + [Fact] + public void TestGetCondition_1() { + var condition = new StartsCondition( _parameterManager, "a", "b", true ); + Assert.Equal( "a Like @_p_0", GetResult( condition ) ); + Assert.Equal( "b%", _parameterManager.GetValue( "@_p_0" ) ); + } + + /// + /// 测试获取条件 - 非参数化 + /// + [Fact] + public void TestGetCondition_2() { + var condition = new StartsCondition( _parameterManager, "a", "b", false ); + Assert.Equal( "a Like 'b%'", GetResult( condition ) ); + Assert.Equal( 0, _parameterManager.GetParams().Count ); + } + } +} diff --git a/test/Util.Data.Sql.Tests/Builders/Core/ColumnItemTest.cs b/test/Util.Data.Sql.Tests/Builders/Core/ColumnItemTest.cs new file mode 100644 index 00000000..27ea9314 --- /dev/null +++ b/test/Util.Data.Sql.Tests/Builders/Core/ColumnItemTest.cs @@ -0,0 +1,164 @@ +using Util.Data.Sql.Builders; +using Util.Data.Sql.Builders.Core; +using Util.Data.Sql.Tests.Samples; +using Xunit; + +namespace Util.Data.Sql.Tests.Builders.Core { + /// + /// 列测试 + /// + public class ColumnItemTest { + /// + /// Sql方言 + /// + private readonly IDialect _dialect; + + /// + /// 测试初始化 + /// + public ColumnItemTest() { + _dialect = TestDialect.Instance; + } + + /// + /// 测试解析简单列名 + /// + [Fact] + public void Test_1() { + var item = new ColumnItem( _dialect,"a" ); + Assert.Null( item.TableAlias ); + Assert.Equal( "a", item.Name ); + } + + /// + /// 测试解析带表别名的列 + /// + [Fact] + public void Test_2() { + var item = new ColumnItem( _dialect, "a.b" ); + Assert.Equal( "a", item.TableAlias ); + Assert.Equal( "b", item.Name ); + } + + /// + /// 测试解析带表别名和列别名的列 - 使用as关键字 + /// + [Fact] + public void Test_3() { + var item = new ColumnItem( _dialect, "a.b as c" ); + Assert.Equal( "a", item.TableAlias ); + Assert.Equal( "b", item.Name ); + Assert.Equal( "c", item.ColumnAlias ); + } + + /// + /// 测试解析带表别名和列别名的列 - 使用As关键字 + /// + [Fact] + public void Test_4() { + var item = new ColumnItem( _dialect, "a.b As c" ); + Assert.Equal( "a", item.TableAlias ); + Assert.Equal( "b", item.Name ); + Assert.Equal( "c", item.ColumnAlias ); + } + + /// + /// 测试解析带表别名和列别名的列 - 使用空格 + /// + [Fact] + public void Test_5() { + var item = new ColumnItem( _dialect, "a.b c" ); + Assert.Equal( "a", item.TableAlias ); + Assert.Equal( "b", item.Name ); + Assert.Equal( "c", item.ColumnAlias ); + } + + /// + /// 测试.前有空格 + /// + [Fact] + public void Test_6() { + var item = new ColumnItem( _dialect, "a .b" ); + Assert.Equal( "a", item.TableAlias ); + Assert.Equal( "b", item.Name ); + } + + /// + /// 测试.后有空格 + /// + [Fact] + public void Test_7() { + var item = new ColumnItem( _dialect, "a. b" ); + Assert.Equal( "a", item.TableAlias ); + Assert.Equal( "b", item.Name ); + } + + /// + /// 测试.后有空格 + /// + [Fact] + public void Test_8() { + var item = new ColumnItem( _dialect, "a . b" ); + Assert.Equal( "a", item.TableAlias ); + Assert.Equal( "b", item.Name ); + } + + /// + /// 测试多个空格 + /// + [Fact] + public void Test_9() { + var item = new ColumnItem( _dialect, " a . b As c " ); + Assert.Equal( "a", item.TableAlias ); + Assert.Equal( "b", item.Name ); + Assert.Equal( "c", item.ColumnAlias ); + } + + /// + /// 测试添加了转义符 + /// + [Fact] + public void Test_10() { + var item = new ColumnItem( _dialect, "[a].[b] as [c]" ); + Assert.Equal( "[a]", item.TableAlias ); + Assert.Equal( "[b]", item.Name ); + Assert.Equal( "[c]", item.ColumnAlias ); + } + + /// + /// 测试获取Sql结果 - 简单列名 + /// + [Fact] + public void TestToSql_1() { + var item = new ColumnItem( _dialect, "a" ); + Assert.Equal( "[a]", item.ToResult() ); + } + + /// + /// 测试获取Sql结果 - 带表别名的列 + /// + [Fact] + public void TestToSql_2() { + var item = new ColumnItem( _dialect, "a.b" ); + Assert.Equal( "[a].[b]", item.ToResult() ); + } + + /// + /// 测试获取Sql结果 - 带表别名和列别名的列 + /// + [Fact] + public void TestToSql_3() { + var item = new ColumnItem( _dialect, "a.b as c" ); + Assert.Equal( "[a].[b] As [c]", item.ToResult() ); + } + + /// + /// 测试获取Sql结果 - 添加了转义符和多余的空格 + /// + [Fact] + public void TestToSql_4() { + var item = new ColumnItem( _dialect, " [a] . [b] as [c] " ); + Assert.Equal( "[a].[b] As [c]", item.ToResult() ); + } + } +} diff --git a/test/Util.Data.Sql.Tests/Builders/Core/OrderByItemTest.cs b/test/Util.Data.Sql.Tests/Builders/Core/OrderByItemTest.cs new file mode 100644 index 00000000..3c113cf8 --- /dev/null +++ b/test/Util.Data.Sql.Tests/Builders/Core/OrderByItemTest.cs @@ -0,0 +1,105 @@ +using Util.Data.Sql.Builders.Core; +using Xunit; + +namespace Util.Data.Sql.Tests.Builders.Core { + /// + /// 排序项测试 + /// + public class OrderByItemTest { + /// + /// 测试初始化 + /// + public OrderByItemTest() { + } + + /// + /// 测试解析排序列 + /// + [Fact] + public void Test_1() { + var item = new OrderByItem( "a.B" ); + Assert.Equal( "a.B", item.Column ); + Assert.False( item.Desc ); + } + + /// + /// 测试解析排序列 - 前后有空格 + /// + [Fact] + public void Test_2() { + var item = new OrderByItem( " a.B " ); + Assert.Equal( "a.B", item.Column ); + Assert.False( item.Desc ); + } + + /// + /// 测试解析排序列 - 带ASC + /// + [Fact] + public void Test_3() { + var item = new OrderByItem( "a.B Asc" ); + Assert.Equal( "a.B", item.Column ); + Assert.False( item.Desc ); + } + + /// + /// 测试解析排序列 - 列名为ASC + /// + [Fact] + public void Test_4() { + var item = new OrderByItem( "Asc" ); + Assert.Equal( "Asc", item.Column ); + Assert.False( item.Desc ); + } + + /// + /// 测试解析排序列 - 列名为ASC,前后有空格 + /// + [Fact] + public void Test_5() { + var item = new OrderByItem( " Asc " ); + Assert.Equal( "Asc", item.Column ); + Assert.False( item.Desc ); + } + + /// + /// 测试解析排序列 - 降序 + /// + [Fact] + public void Test_6() { + var item = new OrderByItem( "a.B Desc" ); + Assert.Equal( "a.B", item.Column ); + Assert.True( item.Desc ); + } + + /// + /// 测试解析排序列 - 降序,前后添加空格 + /// + [Fact] + public void Test_7() { + var item = new OrderByItem( " a.B desc " ); + Assert.Equal( "a.B", item.Column ); + Assert.True( item.Desc ); + } + + /// + /// 测试解析排序列 - 列名为Desc + /// + [Fact] + public void Test_8() { + var item = new OrderByItem( "Desc" ); + Assert.Equal( "Desc", item.Column ); + Assert.False( item.Desc ); + } + + /// + /// 测试解析排序列 - 列名为Desc,前后有空格 + /// + [Fact] + public void Test_9() { + var item = new OrderByItem( " Desc " ); + Assert.Equal( "Desc", item.Column ); + Assert.False( item.Desc ); + } + } +} diff --git a/test/Util.Data.Sql.Tests/Builders/Core/SplitItemTest.cs b/test/Util.Data.Sql.Tests/Builders/Core/SplitItemTest.cs new file mode 100644 index 00000000..0c7d6934 --- /dev/null +++ b/test/Util.Data.Sql.Tests/Builders/Core/SplitItemTest.cs @@ -0,0 +1,69 @@ +using Util.Data.Sql.Builders.Core; +using Xunit; + +namespace Util.Data.Sql.Tests.Builders.Core { + /// + /// 拆分项测试 + /// + public class SplitItemTest { + /// + /// 测试设置单个字符 + /// + [Fact] + public void Test_1() { + var item = new SplitItem( "a" ); + Assert.Equal( "a", item.Left ); + Assert.Null( item.Right ); + } + + /// + /// 测试设置空字符 + /// + [Fact] + public void Test_2() { + var item = new SplitItem( "" ); + Assert.Null( item.Left ); + Assert.Null( item.Right ); + } + + /// + /// 测试设置null + /// + [Fact] + public void Test_3() { + var item = new SplitItem( null ); + Assert.Null( item.Left ); + Assert.Null( item.Right ); + } + + /// + /// 测试默认使用空格拆分 + /// + [Fact] + public void Test_4() { + var item = new SplitItem( "a b" ); + Assert.Equal( "a", item.Left ); + Assert.Equal( "b", item.Right ); + } + + /// + /// 测试设置.进行拆分 + /// + [Fact] + public void Test_5() { + var item = new SplitItem( "a.b","." ); + Assert.Equal( "a", item.Left ); + Assert.Equal( "b", item.Right ); + } + + /// + /// 测试去掉两端空格 + /// + [Fact] + public void Test_6() { + var item = new SplitItem( " a.b ", "." ); + Assert.Equal( "a", item.Left ); + Assert.Equal( "b", item.Right ); + } + } +} diff --git a/test/Util.Data.Sql.Tests/Builders/Core/SqlBuilderItemTest.cs b/test/Util.Data.Sql.Tests/Builders/Core/SqlBuilderItemTest.cs new file mode 100644 index 00000000..5d4d1114 --- /dev/null +++ b/test/Util.Data.Sql.Tests/Builders/Core/SqlBuilderItemTest.cs @@ -0,0 +1,43 @@ +using System.Text; +using Util.Data.Sql.Builders.Core; +using Util.Data.Sql.Tests.Samples; +using Xunit; + +namespace Util.Data.Sql.Tests.Builders.Core { + /// + /// Sql生成器项测试 + /// + public class SqlBuilderItemTest { + /// + /// 测试带别名 + /// + [Fact] + public void Test_1() { + var result = new StringBuilder(); + result.AppendLine( "(Select [a] " ); + result.Append( "From [b]) As [c]" ); + + var builder = new TestSqlBuilder().Select( "a" ).From( "b" ); + var item = new SqlBuilderItem( TestDialect.Instance, builder, "c" ); + var sql = new StringBuilder(); + item.AppendTo( sql ); + Assert.Equal( result.ToString(), sql.ToString() ); + } + + /// + /// 测试不带别名 + /// + [Fact] + public void Test_2() { + var result = new StringBuilder(); + result.AppendLine( "(Select [a] " ); + result.Append( "From [b])" ); + + var builder = new TestSqlBuilder().Select( "a" ).From( "b" ); + var item = new SqlBuilderItem( TestDialect.Instance, builder ); + var sql = new StringBuilder(); + item.AppendTo( sql ); + Assert.Equal( result.ToString(), sql.ToString() ); + } + } +} diff --git a/test/Util.Data.Sql.Tests/Builders/Core/SqlConditionFactoryTest.cs b/test/Util.Data.Sql.Tests/Builders/Core/SqlConditionFactoryTest.cs new file mode 100644 index 00000000..2189a8b5 --- /dev/null +++ b/test/Util.Data.Sql.Tests/Builders/Core/SqlConditionFactoryTest.cs @@ -0,0 +1,186 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Util.Data.Sql.Builders; +using Util.Data.Sql.Builders.Params; +using Util.Data.Sql.Tests.Samples; +using Xunit; + +namespace Util.Data.Sql.Tests.Builders.Core { + /// + /// Sql条件工厂测试 + /// + public class SqlConditionFactoryTest { + /// + /// 参数管理器 + /// + private readonly IParameterManager _parameterManager; + /// + /// Sql条件工厂 + /// + private readonly SqlConditionFactory _conditionFactory; + + /// + /// 测试初始化 + /// + public SqlConditionFactoryTest() { + _parameterManager = new ParameterManager( TestDialect.Instance ); + _conditionFactory = new SqlConditionFactory( _parameterManager ); + } + + /// + /// 获取结果 + /// + private string GetResult( ISqlCondition condition ) { + var result = new StringBuilder(); + condition.AppendTo( result ); + return result.ToString(); + } + + /// + /// 测试创建条件 - 验证列名为空 + /// + [Fact] + public void TestCreate_Validate() { + Assert.Throws( () => { + _conditionFactory.Create( "", 1, Operator.Equal ); + } ); + } + + /// + /// 测试创建条件 - 相等 + /// + [Fact] + public void TestCreate_1() { + var condition = _conditionFactory.Create( "a", 1, Operator.Equal ); + Assert.Equal( "a=@_p_0", GetResult( condition ) ); + Assert.Equal( 1, _parameterManager.GetValue( "@_p_0" ) ); + } + + /// + /// 测试创建条件 - 不相等 + /// + [Fact] + public void TestCreate_2() { + var condition = _conditionFactory.Create( "a", 1, Operator.NotEqual ); + Assert.Equal( "a<>@_p_0", GetResult( condition ) ); + Assert.Equal( 1, _parameterManager.GetValue( "@_p_0" ) ); + } + + /// + /// 测试创建条件 - is null + /// + [Fact] + public void TestCreate_3() { + var condition = _conditionFactory.Create( "a", null, Operator.Equal ); + Assert.Equal( "a Is Null", GetResult( condition ) ); + Assert.Equal( 0, _parameterManager.GetParams().Count ); + } + + /// + /// 测试创建条件 - is not null + /// + [Fact] + public void TestCreate_4() { + var condition = _conditionFactory.Create( "a", null, Operator.NotEqual ); + Assert.Equal( "a Is Not Null", GetResult( condition ) ); + Assert.Equal( 0, _parameterManager.GetParams().Count ); + } + + /// + /// 测试创建条件 - 大于 + /// + [Fact] + public void TestCreate_5() { + var condition = _conditionFactory.Create( "a", 1, Operator.Greater ); + Assert.Equal( "a>@_p_0", GetResult( condition ) ); + Assert.Equal( 1, _parameterManager.GetValue( "@_p_0" ) ); + } + + /// + /// 测试创建条件 - 大于等于 + /// + [Fact] + public void TestCreate_6() { + var condition = _conditionFactory.Create( "a", 1, Operator.GreaterEqual ); + Assert.Equal( "a>=@_p_0", GetResult( condition ) ); + Assert.Equal( 1, _parameterManager.GetValue( "@_p_0" ) ); + } + + /// + /// 测试创建条件 - 小于 + /// + [Fact] + public void TestCreate_7() { + var condition = _conditionFactory.Create( "a", 1, Operator.Less ); + Assert.Equal( "a<@_p_0", GetResult( condition ) ); + Assert.Equal( 1, _parameterManager.GetValue( "@_p_0" ) ); + } + + /// + /// 测试创建条件 - 小于等于 + /// + [Fact] + public void TestCreate_8() { + var condition = _conditionFactory.Create( "a", 1, Operator.LessEqual ); + Assert.Equal( "a<=@_p_0", GetResult( condition ) ); + Assert.Equal( 1, _parameterManager.GetValue( "@_p_0" ) ); + } + + /// + /// 测试创建条件 - 模糊匹配 + /// + [Fact] + public void TestCreate_9() { + var condition = _conditionFactory.Create( "a", "abc", Operator.Contains ); + Assert.Equal( "a Like @_p_0", GetResult( condition ) ); + Assert.Equal( "%abc%", _parameterManager.GetValue( "@_p_0" ) ); + } + + /// + /// 测试创建条件 - 头匹配 + /// + [Fact] + public void TestCreate_10() { + var condition = _conditionFactory.Create( "a", "abc", Operator.Starts ); + Assert.Equal( "a Like @_p_0", GetResult( condition ) ); + Assert.Equal( "abc%", _parameterManager.GetValue( "@_p_0" ) ); + } + + /// + /// 测试创建条件 - 尾匹配 + /// + [Fact] + public void TestCreate_11() { + var condition = _conditionFactory.Create( "a", "abc", Operator.Ends ); + Assert.Equal( "a Like @_p_0", GetResult( condition ) ); + Assert.Equal( "%abc", _parameterManager.GetValue( "@_p_0" ) ); + } + + /// + /// 测试创建条件 - in + /// + [Fact] + public void TestCreate_12() { + var list = new List { "1", "2" }; + var condition = _conditionFactory.Create( "a", list, Operator.In ); + Assert.Equal( "a In (@_p_0,@_p_1)", GetResult( condition ) ); + Assert.Equal( 2, _parameterManager.GetParams().Count ); + Assert.Equal( "1", _parameterManager.GetValue( "@_p_0" ) ); + Assert.Equal( "2", _parameterManager.GetValue( "@_p_1" ) ); + } + + /// + /// 测试创建条件 - not in + /// + [Fact] + public void TestCreate_13() { + var list = new List { "1", "2" }; + var condition = _conditionFactory.Create( "a", list, Operator.NotIn ); + Assert.Equal( "a Not In (@_p_0,@_p_1)", GetResult( condition ) ); + Assert.Equal( 2, _parameterManager.GetParams().Count ); + Assert.Equal( "1", _parameterManager.GetValue( "@_p_0" ) ); + Assert.Equal( "2", _parameterManager.GetValue( "@_p_1" ) ); + } + } +} diff --git a/test/Util.Data.Sql.Tests/Builders/Core/TableItemTest.cs b/test/Util.Data.Sql.Tests/Builders/Core/TableItemTest.cs new file mode 100644 index 00000000..02519ada --- /dev/null +++ b/test/Util.Data.Sql.Tests/Builders/Core/TableItemTest.cs @@ -0,0 +1,135 @@ +using Util.Data.Sql.Builders; +using Util.Data.Sql.Builders.Core; +using Util.Data.Sql.Tests.Samples; +using Xunit; + +namespace Util.Data.Sql.Tests.Builders.Core { + /// + /// 表测试 + /// + public class TableItemTest { + /// + /// Sql方言 + /// + private readonly IDialect _dialect; + + /// + /// 测试初始化 + /// + public TableItemTest() { + _dialect = TestDialect.Instance; + } + + /// + /// 测试解析简单表名 + /// + [Fact] + public void Test_1() { + var item = new TableItem( _dialect,"a" ); + Assert.Null( item.Schema ); + Assert.Equal( "a", item.Name ); + Assert.Null( item.TableAlias ); + } + + /// + /// 测试解析带架构的表 + /// + [Fact] + public void Test_2() { + var item = new TableItem( _dialect, "a.b" ); + Assert.Equal( "a", item.Schema ); + Assert.Equal( "b", item.Name ); + Assert.Null( item.TableAlias ); + } + + /// + /// 测试解析带架构和表别名的表 - 使用as关键字 + /// + [Fact] + public void Test_3() { + var item = new TableItem( _dialect, "a.b as c" ); + Assert.Equal( "a", item.Schema ); + Assert.Equal( "b", item.Name ); + Assert.Equal( "c", item.TableAlias ); + } + + /// + /// 测试解析带架构和表别名的表 - 使用空格 + /// + [Fact] + public void Test_4() { + var item = new TableItem( _dialect, "a.b c" ); + Assert.Equal( "a", item.Schema ); + Assert.Equal( "b", item.Name ); + Assert.Equal( "c", item.TableAlias ); + } + + /// + /// 测试.前后有空格 + /// + [Fact] + public void Test_5() { + var item = new TableItem( _dialect, "a . b" ); + Assert.Equal( "a", item.Schema ); + Assert.Equal( "b", item.Name ); + } + + /// + /// 测试多个空格 + /// + [Fact] + public void Test_6() { + var item = new TableItem( _dialect, " a . b As c " ); + Assert.Equal( "a", item.Schema ); + Assert.Equal( "b", item.Name ); + Assert.Equal( "c", item.TableAlias ); + } + + /// + /// 测试添加了转义符 + /// + [Fact] + public void Test_7() { + var item = new TableItem( _dialect, "[a].[b] as [c]" ); + Assert.Equal( "[a]", item.Schema ); + Assert.Equal( "[b]", item.Name ); + Assert.Equal( "[c]", item.TableAlias ); + } + + /// + /// 测试获取Sql结果 - 简单表名 + /// + [Fact] + public void TestToResult_1() { + var item = new TableItem( _dialect, "a" ); + Assert.Equal( "[a]", item.ToResult() ); + } + + /// + /// 测试获取Sql结果 - 带架构的表 + /// + [Fact] + public void TestToResult_2() { + var item = new TableItem( _dialect, "a.b" ); + Assert.Equal( "[a].[b]", item.ToResult() ); + } + + /// + /// 测试获取Sql结果 - 带架构和表别名的表 + /// + [Fact] + public void TestToResult_3() { + var item = new TableItem( _dialect, "a.b as c" ); + Assert.Equal( "[a].[b] As [c]", item.ToResult() ); + } + + /// + /// 测试获取Sql结果 - 添加了转义符和多余的空格 + /// + [Fact] + public void TestToResult_4() { + var item = new TableItem( _dialect, " [a] . [b] as [c] " ); + Assert.Equal( "[a].[b] As [c]", item.ToResult() ); + } + } +} diff --git a/test/Util.Data.Sql.Tests/Builders/Params/ParameterManagerTest.cs b/test/Util.Data.Sql.Tests/Builders/Params/ParameterManagerTest.cs new file mode 100644 index 00000000..80cc2371 --- /dev/null +++ b/test/Util.Data.Sql.Tests/Builders/Params/ParameterManagerTest.cs @@ -0,0 +1,187 @@ +using Util.Data.Sql.Builders.Params; +using Util.Data.Sql.Tests.Samples; +using Xunit; + +namespace Util.Data.Sql.Tests.Builders.Params { + /// + /// Sql参数管理器测试 + /// + public class ParameterManagerTest { + + #region 测试初始化 + + /// + /// Sql参数管理器 + /// + private readonly ParameterManager _manager; + + /// + /// 测试初始化 + /// + public ParameterManagerTest() { + _manager = new ParameterManager( TestDialect.Instance ); + } + + #endregion + + #region GenerateName + + /// + /// 测试创建参数名 + /// + [Fact] + public void TestGenerateName() { + Assert.Equal( "@_p_0", _manager.GenerateName() ); + Assert.Equal( "@_p_1", _manager.GenerateName() ); + } + + #endregion + + #region Contains + + /// + /// 测试是否包含参数 + /// + [Fact] + public void TestContains_1() { + _manager.Add( "a", 1 ); + Assert.True( _manager.Contains("a") ); + Assert.True( _manager.Contains( "@a" ) ); + Assert.False( _manager.Contains( "b" ) ); + } + + /// + /// 测试是否包含参数 + /// + [Fact] + public void TestContains_2() { + _manager.Add( "@a", 1 ); + Assert.True( _manager.Contains( "a" ) ); + Assert.True( _manager.Contains( "@a" ) ); + Assert.False( _manager.Contains( "b" ) ); + } + + #endregion + + #region GetParams + + /// + /// 测试获取参数列表 + /// + [Fact] + public void TestGetParams() { + var parameters = _manager.GetParams(); + Assert.Equal( 0, parameters.Count ); + } + + #endregion + + #region Add + + /// + /// 测试添加1个参数 + /// + [Fact] + public void TestAdd_1() { + _manager.Add( "a", 1 ); + var parameters = _manager.GetParams(); + Assert.Equal( 1, parameters.Count ); + Assert.Equal( 1, _manager.GetValue( "a" ) ); + } + + /// + /// 测试添加2个参数 + /// + [Fact] + public void TestAdd_2() { + _manager.Add( "a", 1 ); + _manager.Add( "b", 2 ); + var parameters = _manager.GetParams(); + Assert.Equal( 2, parameters.Count ); + Assert.Equal( 1, _manager.GetValue( "a" ) ); + Assert.Equal( 2, _manager.GetValue( "b" ) ); + } + + /// + /// 测试覆盖参数 + /// + [Fact] + public void TestAdd_3() { + _manager.Add( "a", 1 ); + _manager.Add( "a", 2 ); + var parameters = _manager.GetParams(); + Assert.Equal( 1, parameters.Count ); + Assert.Equal( 2, _manager.GetValue( "a" ) ); + } + + /// + /// 测试添加参数 - 参数名为空 + /// + [Fact] + public void TestAdd_4() { + _manager.Add( "", 1 ); + var parameters = _manager.GetParams(); + Assert.Equal( 0, parameters.Count ); + } + + #endregion + + #region AddDynamicParams + + /// + /// 测试添加1个动态参数 + /// + [Fact] + public void TestAddDynamicParams() { + _manager.AddDynamicParams( new { A = 2 } ); + var parameters = _manager.GetDynamicParams(); + Assert.Equal( 1, parameters.Count ); + Assert.Equal( 2, ( (dynamic)parameters[0] ).A ); + } + + #endregion + + #region Clear + + /// + /// 测试清空参数 + /// + [Fact] + public void TestClear() { + var paramName = _manager.GenerateName(); + _manager.Add( paramName, 1 ); + _manager.Clear(); + var parameters = _manager.GetParams(); + Assert.Equal( 0, parameters.Count ); + Assert.Equal( "@_p_0", _manager.GenerateName() ); + } + + #endregion + + #region Clone + + /// + /// 测试复制Sql参数管理器副本 - 参数 + /// + [Fact] + public void TestClone_Param() { + _manager.Add( "name", "a" ); + var clone = _manager.Clone(); + Assert.Equal( "a", clone.GetValue( "name" ) ); + } + + /// + /// 测试复制Sql参数管理器副本 - 动态参数 + /// + [Fact] + public void TestClone_DynamicParam() { + var parameter = new TestParameter { Code = "1" }; + _manager.AddDynamicParams( parameter ); + var clone = _manager.Clone(); + var result = (TestParameter)clone.GetDynamicParams()[0]; + Assert.Equal( "1", result.Code ); + } + + #endregion + } +} diff --git a/test/Util.Data.Sql.Tests/Builders/Sets/SqlBuilderSetTest.cs b/test/Util.Data.Sql.Tests/Builders/Sets/SqlBuilderSetTest.cs new file mode 100644 index 00000000..23953bb9 --- /dev/null +++ b/test/Util.Data.Sql.Tests/Builders/Sets/SqlBuilderSetTest.cs @@ -0,0 +1,361 @@ +using System.Text; +using Util.Data.Sql.Builders.Sets; +using Util.Data.Sql.Tests.Samples; +using Xunit; + +namespace Util.Data.Sql.Tests.Builders.Sets { + /// + /// Sql生成器集合测试 + /// + public class SqlBuilderSetTest { + + #region 测试初始化 + + /// + /// Sql生成器集合 + /// + private readonly SqlBuilderSet _set; + + /// + /// 测试初始化 + /// + public SqlBuilderSetTest() { + var builder = CreateMasterSqlBuilder(); + _set = new SqlBuilderSet( builder ); + } + + /// + /// 创建主Sql生成器 + /// + private TestSqlBuilder CreateMasterSqlBuilder() { + return new TestSqlBuilder() + .Select( "a" ) + .From( "b" ) + .Join( "c" ).On( "b.id","c.id" ) + .AppendWhere( "[d]=1" ) + .GroupBy( "e" ).AppendHaving( "Count(f)>1" ) + .OrderBy( "g" ) + .Take( 10 ); + } + + /// + /// 创建测试Sql生成器 + /// + private ISqlBuilder CreateSqlBuilder2() { + return new TestSqlBuilder() + .Select( "a1" ) + .From( "b1" ) + .Join( "c1" ).On( "b1.id", "c1.id" ) + .AppendWhere( "[d1]=1" ) + .GroupBy( "e1" ).AppendHaving( "Count(f1)>1" ) + .OrderBy( "g1" ) + .Take( 20 ); + } + + /// + /// 创建测试Sql生成器 + /// + private ISqlBuilder CreateSqlBuilder3() { + return new TestSqlBuilder() + .Select( "a2" ) + .From( "b2" ) + .Join( "c2" ).On( "b2.id", "c2.id" ) + .AppendWhere( "[d2]=1" ) + .GroupBy( "e2" ).AppendHaving( "Count(f2)>1" ) + .OrderBy( "g2" ) + .Take( 30 ); + } + + #endregion + + #region ToResult + + /// + /// 测试获取Sql - 只有主Sql生成器 + /// + [Fact] + public void TestToResult() { + var result = new StringBuilder(); + result.AppendLine( "Select [a] " ); + result.AppendLine( "From [b] " ); + result.AppendLine( "Join [c] On [b].[id]=[c].[id] " ); + result.AppendLine( "Where [d]=1 " ); + result.AppendLine( "Group By [e] Having Count(f)>1 " ); + result.AppendLine( "Order By [g] " ); + result.Append( "Limit @_p_0 OFFSET @_p_1" ); + Assert.Equal( result.ToString(), _set.ToResult() ); + } + + #endregion + + #region Union + + /// + /// 测试联合操作 - 合并1个查询 + /// + [Fact] + public void TestUnion_1() { + var result = new StringBuilder(); + result.AppendLine( "(" ); + result.AppendLine( "Select [a] " ); + result.AppendLine( "From [b] " ); + result.AppendLine( "Join [c] On [b].[id]=[c].[id] " ); + result.AppendLine( "Where [d]=1 " ); + result.AppendLine( "Group By [e] Having Count(f)>1 " ); + result.AppendLine( ")" ); + result.AppendLine( "Union " ); + result.AppendLine( "(" ); + result.AppendLine( "Select [a1] " ); + result.AppendLine( "From [b1] " ); + result.AppendLine( "Join [c1] On [b1].[id]=[c1].[id] " ); + result.AppendLine( "Where [d1]=1 " ); + result.AppendLine( "Group By [e1] Having Count(f1)>1 " ); + result.AppendLine( ")" ); + result.AppendLine( "Order By [g] " ); + result.Append( "Limit @_p_0 OFFSET @_p_1" ); + + var builder2 = CreateSqlBuilder2(); + _set.Union( builder2 ); + + Assert.Equal( result.ToString(), _set.ToResult() ); + } + + /// + /// 测试联合操作 - 合并2个查询 + /// + [Fact] + public void TestUnion_2() { + var result = new StringBuilder(); + result.AppendLine( "(" ); + result.AppendLine( "Select [a] " ); + result.AppendLine( "From [b] " ); + result.AppendLine( "Join [c] On [b].[id]=[c].[id] " ); + result.AppendLine( "Where [d]=1 " ); + result.AppendLine( "Group By [e] Having Count(f)>1 " ); + result.AppendLine( ")" ); + result.AppendLine( "Union " ); + result.AppendLine( "(" ); + result.AppendLine( "Select [a1] " ); + result.AppendLine( "From [b1] " ); + result.AppendLine( "Join [c1] On [b1].[id]=[c1].[id] " ); + result.AppendLine( "Where [d1]=1 " ); + result.AppendLine( "Group By [e1] Having Count(f1)>1 " ); + result.AppendLine( ")" ); + result.AppendLine( "Union " ); + result.AppendLine( "(" ); + result.AppendLine( "Select [a2] " ); + result.AppendLine( "From [b2] " ); + result.AppendLine( "Join [c2] On [b2].[id]=[c2].[id] " ); + result.AppendLine( "Where [d2]=1 " ); + result.AppendLine( "Group By [e2] Having Count(f2)>1 " ); + result.AppendLine( ")" ); + result.AppendLine( "Order By [g] " ); + result.Append( "Limit @_p_0 OFFSET @_p_1" ); + + var builder2 = CreateSqlBuilder2(); + var builder3 = CreateSqlBuilder3(); + _set.Union( builder2, builder3 ); + + Assert.Equal( result.ToString(), _set.ToResult() ); + } + + #endregion + + #region UnionAll + + /// + /// 测试联合操作 + /// + [Fact] + public void TestUnionAll() { + var result = new StringBuilder(); + result.AppendLine( "(" ); + result.AppendLine( "Select [a] " ); + result.AppendLine( "From [b] " ); + result.AppendLine( "Join [c] On [b].[id]=[c].[id] " ); + result.AppendLine( "Where [d]=1 " ); + result.AppendLine( "Group By [e] Having Count(f)>1 " ); + result.AppendLine( ")" ); + result.AppendLine( "Union All " ); + result.AppendLine( "(" ); + result.AppendLine( "Select [a1] " ); + result.AppendLine( "From [b1] " ); + result.AppendLine( "Join [c1] On [b1].[id]=[c1].[id] " ); + result.AppendLine( "Where [d1]=1 " ); + result.AppendLine( "Group By [e1] Having Count(f1)>1 " ); + result.AppendLine( ")" ); + result.AppendLine( "Union All " ); + result.AppendLine( "(" ); + result.AppendLine( "Select [a2] " ); + result.AppendLine( "From [b2] " ); + result.AppendLine( "Join [c2] On [b2].[id]=[c2].[id] " ); + result.AppendLine( "Where [d2]=1 " ); + result.AppendLine( "Group By [e2] Having Count(f2)>1 " ); + result.AppendLine( ")" ); + result.AppendLine( "Order By [g] " ); + result.Append( "Limit @_p_0 OFFSET @_p_1" ); + + var builder2 = CreateSqlBuilder2(); + var builder3 = CreateSqlBuilder3(); + _set.UnionAll( builder2, builder3 ); + + Assert.Equal( result.ToString(), _set.ToResult() ); + } + + #endregion + + #region Intersect + + /// + /// 测试交集 + /// + [Fact] + public void TestIntersect() { + var result = new StringBuilder(); + result.AppendLine( "(" ); + result.AppendLine( "Select [a] " ); + result.AppendLine( "From [b] " ); + result.AppendLine( "Join [c] On [b].[id]=[c].[id] " ); + result.AppendLine( "Where [d]=1 " ); + result.AppendLine( "Group By [e] Having Count(f)>1 " ); + result.AppendLine( ")" ); + result.AppendLine( "Intersect " ); + result.AppendLine( "(" ); + result.AppendLine( "Select [a1] " ); + result.AppendLine( "From [b1] " ); + result.AppendLine( "Join [c1] On [b1].[id]=[c1].[id] " ); + result.AppendLine( "Where [d1]=1 " ); + result.AppendLine( "Group By [e1] Having Count(f1)>1 " ); + result.AppendLine( ")" ); + result.AppendLine( "Intersect " ); + result.AppendLine( "(" ); + result.AppendLine( "Select [a2] " ); + result.AppendLine( "From [b2] " ); + result.AppendLine( "Join [c2] On [b2].[id]=[c2].[id] " ); + result.AppendLine( "Where [d2]=1 " ); + result.AppendLine( "Group By [e2] Having Count(f2)>1 " ); + result.AppendLine( ")" ); + result.AppendLine( "Order By [g] " ); + result.Append( "Limit @_p_0 OFFSET @_p_1" ); + + var builder2 = CreateSqlBuilder2(); + var builder3 = CreateSqlBuilder3(); + _set.Intersect( builder2, builder3 ); + + Assert.Equal( result.ToString(), _set.ToResult() ); + } + + #endregion + + #region Except + + /// + /// 测试差集 + /// + [Fact] + public void TestExcept() { + var result = new StringBuilder(); + result.AppendLine( "(" ); + result.AppendLine( "Select [a] " ); + result.AppendLine( "From [b] " ); + result.AppendLine( "Join [c] On [b].[id]=[c].[id] " ); + result.AppendLine( "Where [d]=1 " ); + result.AppendLine( "Group By [e] Having Count(f)>1 " ); + result.AppendLine( ")" ); + result.AppendLine( "Except " ); + result.AppendLine( "(" ); + result.AppendLine( "Select [a1] " ); + result.AppendLine( "From [b1] " ); + result.AppendLine( "Join [c1] On [b1].[id]=[c1].[id] " ); + result.AppendLine( "Where [d1]=1 " ); + result.AppendLine( "Group By [e1] Having Count(f1)>1 " ); + result.AppendLine( ")" ); + result.AppendLine( "Except " ); + result.AppendLine( "(" ); + result.AppendLine( "Select [a2] " ); + result.AppendLine( "From [b2] " ); + result.AppendLine( "Join [c2] On [b2].[id]=[c2].[id] " ); + result.AppendLine( "Where [d2]=1 " ); + result.AppendLine( "Group By [e2] Having Count(f2)>1 " ); + result.AppendLine( ")" ); + result.AppendLine( "Order By [g] " ); + result.Append( "Limit @_p_0 OFFSET @_p_1" ); + + var builder2 = CreateSqlBuilder2(); + var builder3 = CreateSqlBuilder3(); + _set.Except( builder2, builder3 ); + + Assert.Equal( result.ToString(), _set.ToResult() ); + } + + #endregion + + #region Clear + + /// + /// 测试清理 + /// + [Fact] + public void TestClear() { + var result = new StringBuilder(); + result.AppendLine( "Select [a] " ); + result.AppendLine( "From [b] " ); + result.AppendLine( "Join [c] On [b].[id]=[c].[id] " ); + result.AppendLine( "Where [d]=1 " ); + result.AppendLine( "Group By [e] Having Count(f)>1 " ); + result.AppendLine( "Order By [g] " ); + result.Append( "Limit @_p_0 OFFSET @_p_1" ); + + var builder2 = CreateSqlBuilder2(); + _set.Union( builder2 ); + _set.Clear(); + + Assert.Equal( result.ToString(), _set.ToResult() ); + } + + #endregion + + #region Clone + + /// + /// 测试复制Sql生成器集合 + /// + [Fact] + public void TestClone() { + //结果 + var result = new StringBuilder(); + result.AppendLine( "(" ); + result.AppendLine( "Select [a] " ); + result.AppendLine( "From [b] " ); + result.AppendLine( "Join [c] On [b].[id]=[c].[id] " ); + result.AppendLine( "Where [d]=1 " ); + result.AppendLine( "Group By [e] Having Count(f)>1 " ); + result.AppendLine( ")" ); + result.AppendLine( "Union " ); + result.AppendLine( "(" ); + result.AppendLine( "Select [a1] " ); + result.AppendLine( "From [b1] " ); + result.AppendLine( "Join [c1] On [b1].[id]=[c1].[id] " ); + result.AppendLine( "Where [d1]=1 " ); + result.AppendLine( "Group By [e1] Having Count(f1)>1 " ); + result.AppendLine( ")" ); + result.AppendLine( "Order By [g] " ); + result.Append( "Limit @_p_0 OFFSET @_p_1" ); + + //合并一个Sql集合 + var builder2 = CreateSqlBuilder2(); + _set.Union( builder2 ); + + //复制并验证 + var clone = _set.Clone( CreateMasterSqlBuilder() ); + Assert.Equal( result.ToString(), clone.ToResult() ); + + //修改原始集合,复制集合不应受影响 + var builder3 = CreateSqlBuilder3(); + _set.Union( builder3 ); + Assert.Equal( result.ToString(), clone.ToResult() ); + } + + #endregion + } +} diff --git a/test/Util.Data.Sql.Tests/Builders/SqlBuilderTest.End.cs b/test/Util.Data.Sql.Tests/Builders/SqlBuilderTest.End.cs new file mode 100644 index 00000000..a3f1e0c1 --- /dev/null +++ b/test/Util.Data.Sql.Tests/Builders/SqlBuilderTest.End.cs @@ -0,0 +1,172 @@ +using System.Text; +using Util.Data.Queries; +using Xunit; + +namespace Util.Data.Sql.Tests.Builders { + /// + /// Sql生成器测试 - 结束子句 + /// + public partial class SqlBuilderTest { + + #region Take + + /// + /// 测试设置获取行数 + /// + [Fact] + public void TestTake() { + //结果 + var result = new StringBuilder(); + result.AppendLine( "Select [c].[D] As [e] " ); + result.AppendLine( "From [a].[B] As [c] " ); + result.Append( "Limit @_p_0 OFFSET @_p_1" ); + + //执行 + _builder + .Select( "c.D as e" ) + .From( "a.B as c" ) + .Take( 20 ); + + //验证 + Assert.Equal( result.ToString(), _builder.GetSql() ); + Assert.Equal( 20, _builder.GetParam( "@_p_0" ) ); + Assert.Equal( 0, _builder.GetParam( "@_p_1" ) ); + } + + #endregion + + #region Skip + + /// + /// 测试设置跳过行数 + /// + [Fact] + public void TestSkip() { + //结果 + var result = new StringBuilder(); + result.AppendLine( "Select [c].[D] As [e] " ); + result.AppendLine( "From [a].[B] As [c] " ); + result.Append( "Limit @_p_1 OFFSET @_p_0" ); + + //执行 + _builder + .Select( "c.D as e" ) + .From( "a.B as c" ) + .Skip( 80 ) + .Take( 40 ); + + //验证 + Assert.Equal( result.ToString(), _builder.GetSql() ); + Assert.Equal( 80, _builder.GetParam("@_p_0") ); + Assert.Equal( 40, _builder.GetParam( "@_p_1" ) ); + } + + #endregion + + #region Page + + /// + /// 测试设置分页 + /// + [Fact] + public void TestPage() { + //结果 + var result = new StringBuilder(); + result.AppendLine( "Select [c].[D] As [e] " ); + result.AppendLine( "From [a].[B] As [c] " ); + result.Append( "Limit @_p_1 OFFSET @_p_0" ); + + //执行 + var page = new Pager( 3, 40 ); + _builder + .Select( "c.D as e" ) + .From( "a.B as c" ) + .Page( page ); + + //验证 + Assert.Equal( result.ToString(), _builder.GetSql() ); + Assert.Equal( 80, _builder.GetParam( "@_p_0" ) ); + Assert.Equal( 40, _builder.GetParam( "@_p_1" ) ); + } + + #endregion + + #region AppendEnd + + /// + /// 添加到结束位置 + /// + [Fact] + public void TestAppendEnd_1() { + //结果 + var result = new StringBuilder(); + result.AppendLine( "Select [c].[D] As [e] " ); + result.AppendLine( "From [a].[B] As [c] " ); + result.Append( "Order By abc" ); + + //执行 + _builder + .Select( "c.D as e" ) + .From( "a.B as c" ) + .AppendEnd( "Order By abc" ); + + //验证 + Assert.Equal( result.ToString(), _builder.GetSql() ); + } + + #endregion + + #region ClearPage + + /// + /// 测试清理分页 + /// + [Fact] + public void TestClearPage() { + //结果 + var result = new StringBuilder(); + result.AppendLine( "Select [c].[D] As [e] " ); + result.Append( "From [a].[B] As [c]" ); + + //执行 + var page = new Pager( 3, 40 ); + _builder + .Select( "c.D as e" ) + .From( "a.B as c" ) + .Page( page ) + .ClearPage(); + + //验证 + Assert.Equal( result.ToString(), _builder.GetSql() ); + } + + #endregion + + #region ClearEnd + + /// + /// 测试清理结束子句 + /// + [Fact] + public void TestClearEnd() { + //结果 + var result = new StringBuilder(); + result.AppendLine( "Select [c].[D] As [e] " ); + result.Append( "From [a].[B] As [c]" ); + + //执行 + var page = new Pager( 3, 40 ); + _builder + .Select( "c.D as e" ) + .From( "a.B as c" ) + .Page( page ) + .AppendEnd( "Order By abc" ) + .ClearEnd(); + + //验证 + Assert.Equal( result.ToString(), _builder.GetSql() ); + } + + #endregion + } +} diff --git a/test/Util.Data.Sql.Tests/Builders/SqlBuilderTest.From.cs b/test/Util.Data.Sql.Tests/Builders/SqlBuilderTest.From.cs new file mode 100644 index 00000000..c15e1444 --- /dev/null +++ b/test/Util.Data.Sql.Tests/Builders/SqlBuilderTest.From.cs @@ -0,0 +1,118 @@ +using System.Text; +using Util.Data.Sql.Tests.Samples; +using Xunit; + +namespace Util.Data.Sql.Tests.Builders { + /// + /// Sql生成器测试 - From子句 + /// + public partial class SqlBuilderTest { + + #region From + + /// + /// 设置表 + /// + [Fact] + public void TestFrom_1() { + //结果 + var result = new StringBuilder(); + result.AppendLine( "Select [c].[D] As [e] " ); + result.Append( "From [a].[B] As [c]" ); + + //执行 + _builder.Select( "c.D as e" ) + .From( "a.B as c" ); + + //验证 + Assert.Equal( result.ToString(), _builder.GetSql() ); + } + + /// + /// 设置子查询表 + /// + [Fact] + public void TestFrom_2() { + //结果 + var result = new StringBuilder(); + result.AppendLine( "Select [a].[b] " ); + result.AppendLine( "From (Select [a] " ); + result.Append( "From [b]) As [c]" ); + + //执行 + var builder = new TestSqlBuilder().Select( "a" ).From( "b" ); + _builder.Select( "a.b" ) + .From( builder, "c" ); + + //验证 + Assert.Equal( result.ToString(), _builder.GetSql() ); + } + + /// + /// 设置子查询表 - 内嵌表达式 + /// + [Fact] + public void TestFrom_3() { + //结果 + var result = new StringBuilder(); + result.AppendLine( "Select [a].[b] " ); + result.AppendLine( "From (Select [a] " ); + result.Append( "From [b]) As [c]" ); + + //执行 + _builder.Select( "a.b" ) + .From( t => t.Select( "a" ).From( "b" ), "c" ); + + //验证 + Assert.Equal( result.ToString(), _builder.GetSql() ); + } + + #endregion + + #region AppendFrom + + /// + /// 添加到from子句 + /// + [Fact] + public void TestAppendFrom_1() { + //结果 + var result = new StringBuilder(); + result.AppendLine( "Select [c].[D] As [e] " ); + result.Append( "From [a].[B] As [c]" ); + + //执行 + _builder.Select( "c.D as e" ) + .AppendFrom( "[a].[B] As [c]" ); + + //验证 + Assert.Equal( result.ToString(), _builder.GetSql() ); + } + + #endregion + + #region ClearFrom + + /// + /// 测试清空From子句 + /// + [Fact] + public void TestClearFrom() { + //结果 + var result = new StringBuilder(); + result.AppendLine( "Select [c].[D] As [e] " ); + result.Append( "From [d]" ); + + //执行 + _builder.Select( "c.D as e" ) + .From( "a.B as c" ) + .ClearFrom() + .From( "d" ); + + //验证 + Assert.Equal( result.ToString(), _builder.GetSql() ); + } + + #endregion + } +} diff --git a/test/Util.Data.Sql.Tests/Builders/SqlBuilderTest.GroupBy.cs b/test/Util.Data.Sql.Tests/Builders/SqlBuilderTest.GroupBy.cs new file mode 100644 index 00000000..187b794a --- /dev/null +++ b/test/Util.Data.Sql.Tests/Builders/SqlBuilderTest.GroupBy.cs @@ -0,0 +1,87 @@ +using System.Text; +using Xunit; + +namespace Util.Data.Sql.Tests.Builders { + /// + /// Sql生成器测试 - GroupBy子句 + /// + public partial class SqlBuilderTest { + + #region GroupBy + + /// + /// 测试分组 + /// + [Fact] + public void TestGroupBy_1() { + //结果 + var result = new StringBuilder(); + result.AppendLine( "Select [a].[b] As [c] " ); + result.AppendLine( "From [t] " ); + result.Append( "Group By [t].[x] " ); + result.Append( "Having Count([a].[x])=10" ); + + //执行 + _builder.Select( "a.b as c" ) + .From( "t" ) + .GroupBy( "t.x" ) + .Having( "Count([a].[x])", 10, Operator.Equal, false ); + + //验证 + Assert.Equal( result.ToString(), _builder.GetSql() ); + } + + #endregion + + #region AppendGroupBy + + /// + /// 测试添加到Group By子句 + /// + [Fact] + public void TestAppendGroupBy() { + //结果 + var result = new StringBuilder(); + result.AppendLine( "Select [a].[b] As [c] " ); + result.AppendLine( "From [t] " ); + result.Append( "Group By [t].[x] " ); + result.Append( "Having Count([a].[x])=10" ); + + //执行 + _builder.Select( "a.b as c" ) + .From( "t" ) + .AppendGroupBy( "[t].[x]" ) + .AppendHaving( "Count([a].[x])=10" ); + + //验证 + Assert.Equal( result.ToString(), _builder.GetSql() ); + } + + #endregion + + #region ClearGroupBy + + /// + /// 测试清空GroupBy子句 + /// + [Fact] + public void TestClearGroupBy() { + //结果 + var result = new StringBuilder(); + result.AppendLine( "Select [a].[b] As [c] " ); + result.Append( "From [t]" ); + + //执行 + _builder.Select( "a.b as c" ) + .From( "t" ) + .GroupBy( "t.x" ) + .Having( "Count([a].[x])", 10, Operator.Equal, false ) + .ClearGroupBy(); + + //验证 + Assert.Equal( result.ToString(), _builder.GetSql() ); + } + + #endregion + } +} diff --git a/test/Util.Data.Sql.Tests/Builders/SqlBuilderTest.Insert.cs b/test/Util.Data.Sql.Tests/Builders/SqlBuilderTest.Insert.cs new file mode 100644 index 00000000..fd60b633 --- /dev/null +++ b/test/Util.Data.Sql.Tests/Builders/SqlBuilderTest.Insert.cs @@ -0,0 +1,123 @@ +using System.Text; +using Xunit; + +namespace Util.Data.Sql.Tests.Builders { + /// + /// Sql生成器测试 - Insert子句 + /// + public partial class SqlBuilderTest { + + #region Insert + + /// + /// 测试插入一行 + /// + [Fact] + public void TestInsert_1() { + //结果 + var result = new StringBuilder(); + result.AppendLine( "Insert Into [t]([a],[b]) " ); + result.Append( "Values(@_p_0,@_p_1)" ); + + //执行 + _builder.Insert( "a,b","t" ) + .Values( 1,"a" ); + + //验证 + Assert.Equal( result.ToString(), _builder.GetSql() ); + Assert.Equal( 1, _builder.GetParam( "@_p_0" ) ); + Assert.Equal( "a", _builder.GetParam( "@_p_1" ) ); + } + + /// + /// 测试插入2行 + /// + [Fact] + public void TestInsert_2() { + //结果 + var result = new StringBuilder(); + result.AppendLine( "Insert Into [t]([a],[b]) " ); + result.Append( "Values(@_p_0,@_p_1),(@_p_2,@_p_3)" ); + + //执行 + _builder.Insert( "a,b", "t" ) + .Values( 1, "a" ) + .Values( 2, "b" ); + + //验证 + Assert.Equal( result.ToString(), _builder.GetSql() ); + Assert.Equal( 1, _builder.GetParam( "@_p_0" ) ); + Assert.Equal( "a", _builder.GetParam( "@_p_1" ) ); + Assert.Equal( 2, _builder.GetParam( "@_p_2" ) ); + Assert.Equal( "b", _builder.GetParam( "@_p_3" ) ); + } + + #endregion + + #region AppendInsert + + /// + /// 添加到Insert子句 + /// + [Fact] + public void TestAppendInsert() { + //结果 + var result = new StringBuilder(); + result.AppendLine( "Insert Into [t]([a],[b]) " ); + result.Append( "Values(@_p_0,@_p_1)" ); + + //执行 + _builder.AppendInsert( "[t]([a],[b])" ) + .Values( 1, "a" ); + + //验证 + Assert.Equal( result.ToString(), _builder.GetSql() ); + Assert.Equal( 1, _builder.GetParam( "@_p_0" ) ); + Assert.Equal( "a", _builder.GetParam( "@_p_1" ) ); + } + + #endregion + + #region AppendValues + + /// + /// 添加到Values子句 + /// + [Fact] + public void TestAppendValues() { + //结果 + var result = new StringBuilder(); + result.AppendLine( "Insert Into [t]([a],[b]) " ); + result.Append( "Values(@_p_0,@_p_1)" ); + + //执行 + _builder.Insert( "a,b", "t" ) + .AppendValues( "(@_p_0,@_p_1)" ); + + //验证 + Assert.Equal( result.ToString(), _builder.GetSql() ); + } + + #endregion + + #region ClearInsert + + /// + /// 测试清空Insert子句 + /// + [Fact] + public void TestClearInsert() { + //执行 + _builder.Insert( "a,b", "t" ) + .Values( 1, "a" ) + .AppendInsert( "[t]([a],[b])" ) + .AppendValues( "(@_p_0,@_p_1)" ) + .ClearInsert(); + + //验证 + Assert.Empty( _builder.GetSql() ); + } + + #endregion + } +} diff --git a/test/Util.Data.Sql.Tests/Builders/SqlBuilderTest.Join.cs b/test/Util.Data.Sql.Tests/Builders/SqlBuilderTest.Join.cs new file mode 100644 index 00000000..572b9025 --- /dev/null +++ b/test/Util.Data.Sql.Tests/Builders/SqlBuilderTest.Join.cs @@ -0,0 +1,357 @@ +using System.Text; +using Util.Data.Sql.Tests.Samples; +using Xunit; + +namespace Util.Data.Sql.Tests.Builders { + /// + /// Sql生成器测试 - Join子句 + /// + public partial class SqlBuilderTest { + + #region Join + + /// + /// 内连接 + /// + [Fact] + public void TestJoin_1() { + //结果 + var result = new StringBuilder(); + result.AppendLine( "Select [a] " ); + result.AppendLine( "From [b] " ); + result.Append( "Join [c] As [d]" ); + + //执行 + _builder.Select( "a" ) + .From( "b" ) + .Join( "c as d" ); + + //验证 + Assert.Equal( result.ToString(), _builder.GetSql() ); + } + + /// + /// 内连接 - 子查询 + /// + [Fact] + public void TestJoin_2() { + //结果 + var result = new StringBuilder(); + result.AppendLine( "Select [a] " ); + result.AppendLine( "From [b] " ); + result.AppendLine( "Join (Select [a] " ); + result.Append( "From [b]) As [c]" ); + + //执行 + var builder = new TestSqlBuilder().Select( "a" ).From( "b" ); + _builder.Select( "a" ) + .From( "b" ) + .Join( builder, "c" ); + + //验证 + Assert.Equal( result.ToString(), _builder.GetSql() ); + } + + /// + /// 内连接 - 子查询 - 内嵌表达式 + /// + [Fact] + public void TestJoin_3() { + //结果 + var result = new StringBuilder(); + result.AppendLine( "Select [a] " ); + result.AppendLine( "From [b] " ); + result.AppendLine( "Join (Select [a] " ); + result.Append( "From [b]) As [c]" ); + + //执行 + _builder.Select( "a" ) + .From( "b" ) + .Join( t => t.Select( "a" ).From( "b" ), "c" ); + + //验证 + Assert.Equal( result.ToString(), _builder.GetSql() ); + } + + #endregion + + #region LeftJoin + + /// + /// 左外连接 + /// + [Fact] + public void TestLeftJoin_1() { + //结果 + var result = new StringBuilder(); + result.AppendLine( "Select [a] " ); + result.AppendLine( "From [b] " ); + result.Append( "Left Join [c] As [d]" ); + + //执行 + _builder.Select( "a" ) + .From( "b" ) + .LeftJoin( "c as d" ); + + //验证 + Assert.Equal( result.ToString(), _builder.GetSql() ); + } + + /// + /// 左外连接 - 子查询 + /// + [Fact] + public void TestLeftJoin_2() { + //结果 + var result = new StringBuilder(); + result.AppendLine( "Select [a] " ); + result.AppendLine( "From [b] " ); + result.AppendLine( "Left Join (Select [a] " ); + result.Append( "From [b]) As [c]" ); + + //执行 + var builder = new TestSqlBuilder().Select( "a" ).From( "b" ); + _builder.Select( "a" ) + .From( "b" ) + .LeftJoin( builder, "c" ); + + //验证 + Assert.Equal( result.ToString(), _builder.GetSql() ); + } + + /// + /// 左外连接 - 子查询 - 内嵌表达式 + /// + [Fact] + public void TestLeftJoin_3() { + //结果 + var result = new StringBuilder(); + result.AppendLine( "Select [a] " ); + result.AppendLine( "From [b] " ); + result.AppendLine( "Left Join (Select [a] " ); + result.Append( "From [b]) As [c]" ); + + //执行 + _builder.Select( "a" ) + .From( "b" ) + .LeftJoin( t => t.Select( "a" ).From( "b" ), "c" ); + + //验证 + Assert.Equal( result.ToString(), _builder.GetSql() ); + } + + #endregion + + #region RightJoin + + /// + /// 右外连接 + /// + [Fact] + public void TestRightJoin_1() { + //结果 + var result = new StringBuilder(); + result.AppendLine( "Select [a] " ); + result.AppendLine( "From [b] " ); + result.Append( "Right Join [c] As [d]" ); + + //执行 + _builder.Select( "a" ) + .From( "b" ) + .RightJoin( "c as d" ); + + //验证 + Assert.Equal( result.ToString(), _builder.GetSql() ); + } + + /// + /// 右外连接 - 子查询 + /// + [Fact] + public void TestRightJoin_2() { + //结果 + var result = new StringBuilder(); + result.AppendLine( "Select [a] " ); + result.AppendLine( "From [b] " ); + result.AppendLine( "Right Join (Select [a] " ); + result.Append( "From [b]) As [c]" ); + + //执行 + var builder = new TestSqlBuilder().Select( "a" ).From( "b" ); + _builder.Select( "a" ) + .From( "b" ) + .RightJoin( builder, "c" ); + + //验证 + Assert.Equal( result.ToString(), _builder.GetSql() ); + } + + /// + /// 右外连接 - 子查询 - 内嵌表达式 + /// + [Fact] + public void TestRightJoin_3() { + //结果 + var result = new StringBuilder(); + result.AppendLine( "Select [a] " ); + result.AppendLine( "From [b] " ); + result.AppendLine( "Right Join (Select [a] " ); + result.Append( "From [b]) As [c]" ); + + //执行 + _builder.Select( "a" ) + .From( "b" ) + .RightJoin( t => t.Select( "a" ).From( "b" ), "c" ); + + //验证 + Assert.Equal( result.ToString(), _builder.GetSql() ); + } + + #endregion + + #region On + + /// + /// 连接条件 + /// + [Fact] + public void TestOn_1() { + //结果 + var result = new StringBuilder(); + result.AppendLine( "Select [a] " ); + result.AppendLine( "From [b] " ); + result.Append( "Join [c] As [d] On [b].[Id]<>[d].[Id]" ); + + //执行 + _builder.Select( "a" ) + .From( "b" ) + .Join( "c as d" ).On( "b.Id", "d.Id", Operator.NotEqual ); + + //验证 + Assert.Equal( result.ToString(), _builder.GetSql() ); + } + + #endregion + + #region AppendJoin + + /// + /// 测试添加到内连接 + /// + [Fact] + public void TestAppendJoin() { + //结果 + var result = new StringBuilder(); + result.AppendLine( "Select [a] " ); + result.AppendLine( "From [b] " ); + result.Append( "Join c" ); + + //执行 + _builder.Select( "a" ) + .From( "b" ) + .AppendJoin( "c" ); + + //验证 + Assert.Equal( result.ToString(), _builder.GetSql() ); + } + + #endregion + + #region AppendLeftJoin + + /// + /// 测试添加到左外连接子句 + /// + [Fact] + public void TestAppendLeftJoin() { + //结果 + var result = new StringBuilder(); + result.AppendLine( "Select [a] " ); + result.AppendLine( "From [b] " ); + result.Append( "Left Join c" ); + + //执行 + _builder.Select( "a" ) + .From( "b" ) + .AppendLeftJoin( "c" ); + + //验证 + Assert.Equal( result.ToString(), _builder.GetSql() ); + } + + #endregion + + #region AppendRightJoin + + /// + /// 测试添加到右外连接子句 + /// + [Fact] + public void TestAppendRightJoin() { + //结果 + var result = new StringBuilder(); + result.AppendLine( "Select [a] " ); + result.AppendLine( "From [b] " ); + result.Append( "Right Join c" ); + + //执行 + _builder.Select( "a" ) + .From( "b" ) + .AppendRightJoin( "c" ); + + //验证 + Assert.Equal( result.ToString(), _builder.GetSql() ); + } + + #endregion + + #region AppendOn + + /// + /// 测试添加到On子句 + /// + [Fact] + public void TestAppendOn() { + //结果 + var result = new StringBuilder(); + result.AppendLine( "Select [a] " ); + result.AppendLine( "From [b] " ); + result.Append( "Join c On d" ); + + //执行 + _builder.Select( "a" ) + .From( "b" ) + .AppendJoin( "c" ) + .AppendOn( "d" ); + + //验证 + Assert.Equal( result.ToString(), _builder.GetSql() ); + } + + #endregion + + #region ClearJoin + + /// + /// 测试清空Join子句 + /// + [Fact] + public void TestClearJoin() { + //结果 + var result = new StringBuilder(); + result.AppendLine( "Select [a] " ); + result.Append( "From [b]" ); + + //执行 + _builder.Select( "a" ) + .From( "b" ) + .Join( "c as d" ).On( "b.Id", "d.Id", Operator.NotEqual ) + .ClearJoin(); + + //验证 + Assert.Equal( result.ToString(), _builder.GetSql() ); + } + + #endregion + } +} \ No newline at end of file diff --git a/test/Util.Data.Sql.Tests/Builders/SqlBuilderTest.OrderBy.cs b/test/Util.Data.Sql.Tests/Builders/SqlBuilderTest.OrderBy.cs new file mode 100644 index 00000000..839e471d --- /dev/null +++ b/test/Util.Data.Sql.Tests/Builders/SqlBuilderTest.OrderBy.cs @@ -0,0 +1,82 @@ +using System.Text; +using Xunit; + +namespace Util.Data.Sql.Tests.Builders { + /// + /// Sql生成器测试 - OrderBy子句 + /// + public partial class SqlBuilderTest { + + #region OrderBy + + /// + /// 测试排序 + /// + [Fact] + public void TestOrderBy_1() { + //结果 + var result = new StringBuilder(); + result.AppendLine( "Select [c].[D] As [e] " ); + result.AppendLine( "From [a].[B] As [c] " ); + result.Append( "Order By [c].[b] Desc" ); + + //执行 + _builder.Select( "c.D as e" ) + .From( "a.B as c" ) + .OrderBy( "c.b desc" ); + + //验证 + Assert.Equal( result.ToString(), _builder.GetSql() ); + } + + #endregion + + #region AppendOrderBy + + /// + /// 测试添加到Order By子句 + /// + [Fact] + public void TestAppendOrderBy_1() { + //结果 + var result = new StringBuilder(); + result.AppendLine( "Select [c].[D] As [e] " ); + result.AppendLine( "From [a].[B] As [c] " ); + result.Append( "Order By [c].[b] Desc" ); + + //执行 + _builder.Select( "c.D as e" ) + .From( "a.B as c" ) + .AppendOrderBy( "[c].[b] Desc" ); + + //验证 + Assert.Equal( result.ToString(), _builder.GetSql() ); + } + + #endregion + + #region ClearOrderBy + + /// + /// 测试清空Order By子句 + /// + [Fact] + public void TestClearOrderBy() { + //结果 + var result = new StringBuilder(); + result.AppendLine( "Select [c].[D] As [e] " ); + result.Append( "From [a].[B] As [c]" ); + + //执行 + _builder.Select( "c.D as e" ) + .From( "a.B as c" ) + .OrderBy( "c.b desc" ) + .ClearOrderBy(); + + //验证 + Assert.Equal( result.ToString(), _builder.GetSql() ); + } + + #endregion + } +} diff --git a/test/Util.Data.Sql.Tests/Builders/SqlBuilderTest.Parameter.cs b/test/Util.Data.Sql.Tests/Builders/SqlBuilderTest.Parameter.cs new file mode 100644 index 00000000..ce665e6a --- /dev/null +++ b/test/Util.Data.Sql.Tests/Builders/SqlBuilderTest.Parameter.cs @@ -0,0 +1,62 @@ +using System.Text; +using Xunit; + +namespace Util.Data.Sql.Tests.Builders { + /// + /// Sql生成器测试 - 参数 + /// + public partial class SqlBuilderTest { + + #region AddParam + + /// + /// 测试添加Sql参数 + /// + [Fact] + public void TestAddParam() { + //结果 + var result = new StringBuilder(); + result.AppendLine( "Select [a] " ); + result.AppendLine( "From [b] " ); + result.Append( "Where [b].[Name]<>@Test" ); + + //执行 + _builder.Select( "a" ) + .From( "b" ) + .AppendWhere( "[b].[Name]<>@Test" ) + .AddParam("@Test", "abc" ); + + //验证 + Assert.Equal( result.ToString(), _builder.GetSql() ); + Assert.Single( _builder.GetParams() ); + Assert.Equal( "abc", _builder.GetParam( "@Test" ) ); + } + + #endregion + + #region ClearParams + + /// + /// 测试清空Sql参数 + /// + [Fact] + public void TestClearParams() { + //添加参数 + _builder.Select( "a" ) + .From( "b" ) + .Where( "b.Name", "abc", Operator.NotEqual ); + + //验证 + Assert.Single( _builder.GetParams() ); + Assert.Equal( "abc", _builder.GetParam( "@_p_0" ) ); + + //清空参数 + _builder.ClearParams(); + + //验证 + Assert.Empty( _builder.GetParams() ); + } + + #endregion + } +} diff --git a/test/Util.Data.Sql.Tests/Builders/SqlBuilderTest.Select.cs b/test/Util.Data.Sql.Tests/Builders/SqlBuilderTest.Select.cs new file mode 100644 index 00000000..0c84da26 --- /dev/null +++ b/test/Util.Data.Sql.Tests/Builders/SqlBuilderTest.Select.cs @@ -0,0 +1,180 @@ +using System.Text; +using Util.Data.Sql.Tests.Samples; +using Xunit; + +namespace Util.Data.Sql.Tests.Builders { + /// + /// Sql生成器测试 - Select子句 + /// + public partial class SqlBuilderTest { + + #region Select + + /// + /// 设置*列 + /// + [Fact] + public void TestSelect_1() { + //结果 + var result = new StringBuilder(); + result.AppendLine( "Select * " ); + result.Append( "From [t]" ); + + //执行 + _builder.Select().From( "t" ); + + //验证 + Assert.Equal( result.ToString(), _builder.GetSql() ); + } + + /// + /// 设置列 + /// + [Fact] + public void TestSelect_2() { + //结果 + var result = new StringBuilder(); + result.AppendLine( "Select [a].[b] As [c] " ); + result.Append( "From [t]" ); + + //执行 + _builder.Select( "a.b as c" ) + .From( "t" ); + + //验证 + Assert.Equal( result.ToString(), _builder.GetSql() ); + } + + /// + /// 设置子查询列 + /// + [Fact] + public void TestSelect_3() { + //结果 + var result = new StringBuilder(); + result.Append( "Select [a].[b]," ); + result.AppendLine( "(Select [a] " ); + result.AppendLine( "From [b]) As [c] " ); + result.Append( "From [t]" ); + + //执行 + var builder = new TestSqlBuilder().Select( "a" ).From( "b" ); + _builder.Select( "a.b" ) + .Select( builder,"c" ) + .From( "t" ); + + //验证 + Assert.Equal( result.ToString(), _builder.GetSql() ); + } + + /// + /// 设置子查询列 - 内嵌表达式 + /// + [Fact] + public void TestSelect_4() { + //结果 + var result = new StringBuilder(); + result.Append( "Select [a].[b]," ); + result.AppendLine( "(Select [a] " ); + result.AppendLine( "From [b]) As [c] " ); + result.Append( "From [t]" ); + + //执行 + _builder.Select( "a.b" ) + .Select( t => t.Select( "a" ).From( "b" ), "c" ) + .From( "t" ); + + //验证 + Assert.Equal( result.ToString(), _builder.GetSql() ); + } + + #endregion + + #region AppendSelect + + /// + /// 添加到select子句 + /// + [Fact] + public void TestAppendSelect_1() { + //结果 + var result = new StringBuilder(); + result.AppendLine( "Select [a].[b] as [c] " ); + result.Append( "From [t]" ); + + //执行 + _builder.AppendSelect( "[a].[b] " ) + .AppendSelect( "as [c]" ) + .From( "t" ); + + //验证 + Assert.Equal( result.ToString(), _builder.GetSql() ); + } + + /// + /// 添加到select子句 - 子查询 + /// + [Fact] + public void TestAppendSelect_2() { + //结果 + var result = new StringBuilder(); + result.Append( "Select [a].[b]," ); + result.AppendLine( "(Select [a] " ); + result.AppendLine( "From [b]) As [c] " ); + result.Append( "From [t]" ); + + //执行 + var builder = new TestSqlBuilder().Select( "a" ).From( "b" ); + _builder.AppendSelect( "[a].[b]," ) + .AppendSelect( "(" ) + .AppendSelect( builder ) + .AppendSelect( ") As [c]" ) + .From( "t" ); + + //验证 + Assert.Equal( result.ToString(), _builder.GetSql() ); + } + + /// + /// 添加到select子句 - 子查询 - 内嵌表达式 + /// + [Fact] + public void TestAppendSelect_3() { + //结果 + var result = new StringBuilder(); + result.Append( "Select [a].[b]," ); + result.AppendLine( "(Select [a] " ); + result.AppendLine( "From [b]) As [c] " ); + result.Append( "From [t]" ); + + //执行 + _builder.AppendSelect( "[a].[b]," ) + .AppendSelect( "(" ) + .AppendSelect( t => t.Select( "a" ).From( "b" ) ) + .AppendSelect( ") As [c]" ) + .From( "t" ); + + //验证 + Assert.Equal( result.ToString(), _builder.GetSql() ); + } + + #endregion + + #region ClearSelect + + /// + /// 测试清空Select子句 + /// + [Fact] + public void TestClearSelect() { + //执行 + _builder.Select( "a.b as c" ) + .ClearSelect(); + + //验证 + Assert.Empty( _builder.GetSql() ); + } + + #endregion + } +} \ No newline at end of file diff --git a/test/Util.Data.Sql.Tests/Builders/SqlBuilderTest.Set.cs b/test/Util.Data.Sql.Tests/Builders/SqlBuilderTest.Set.cs new file mode 100644 index 00000000..c5de5b61 --- /dev/null +++ b/test/Util.Data.Sql.Tests/Builders/SqlBuilderTest.Set.cs @@ -0,0 +1,275 @@ +using System.Text; +using Util.Data.Sql.Tests.Samples; +using Xunit; + +namespace Util.Data.Sql.Tests.Builders { + /// + /// Sql生成器测试 - 集合操作 + /// + public partial class SqlBuilderTest { + + #region 辅助方法 + + /// + /// 创建主Sql生成器 + /// + private ISqlBuilder CreateMasterSqlBuilder() { + return new TestSqlBuilder() + .Select( "a" ) + .From( "b" ) + .Join( "c" ).On( "b.id", "c.id" ) + .AppendWhere( "[d]=1" ) + .GroupBy( "e" ).AppendHaving( "Count(f)>1" ) + .OrderBy( "g" ) + .Take( 10 ); + } + + /// + /// 创建测试Sql生成器 + /// + private ISqlBuilder CreateSqlBuilder2() { + return new TestSqlBuilder() + .Select( "a1" ) + .From( "b1" ) + .Join( "c1" ).On( "b1.id", "c1.id" ) + .AppendWhere( "[d1]=1" ) + .GroupBy( "e1" ).AppendHaving( "Count(f1)>1" ) + .OrderBy( "g1" ) + .Take( 20 ); + } + + /// + /// 创建测试Sql生成器 + /// + private ISqlBuilder CreateSqlBuilder3() { + return new TestSqlBuilder() + .Select( "a2" ) + .From( "b2" ) + .Join( "c2" ).On( "b2.id", "c2.id" ) + .AppendWhere( "[d2]=1" ) + .GroupBy( "e2" ).AppendHaving( "Count(f2)>1" ) + .OrderBy( "g2" ) + .Take( 30 ); + } + + #endregion + + #region Union + + /// + /// 测试合并结果集 + /// + [Fact] + public void TestUnion() { + //结果 + var result = new StringBuilder(); + result.AppendLine( "(" ); + result.AppendLine( "Select [a] " ); + result.AppendLine( "From [b] " ); + result.AppendLine( "Join [c] On [b].[id]=[c].[id] " ); + result.AppendLine( "Where [d]=1 " ); + result.AppendLine( "Group By [e] Having Count(f)>1 " ); + result.AppendLine( ")" ); + result.AppendLine( "Union " ); + result.AppendLine( "(" ); + result.AppendLine( "Select [a1] " ); + result.AppendLine( "From [b1] " ); + result.AppendLine( "Join [c1] On [b1].[id]=[c1].[id] " ); + result.AppendLine( "Where [d1]=1 " ); + result.AppendLine( "Group By [e1] Having Count(f1)>1 " ); + result.AppendLine( ")" ); + result.AppendLine( "Union " ); + result.AppendLine( "(" ); + result.AppendLine( "Select [a2] " ); + result.AppendLine( "From [b2] " ); + result.AppendLine( "Join [c2] On [b2].[id]=[c2].[id] " ); + result.AppendLine( "Where [d2]=1 " ); + result.AppendLine( "Group By [e2] Having Count(f2)>1 " ); + result.AppendLine( ")" ); + result.AppendLine( "Order By [g] " ); + result.Append( "Limit @_p_0 OFFSET @_p_1" ); + + //执行 + var builder = CreateMasterSqlBuilder(); + var builder2 = CreateSqlBuilder2(); + var builder3 = CreateSqlBuilder3(); + builder.Union( builder2, builder3 ); + + //验证 + Assert.Equal( result.ToString(), builder.GetSql() ); + } + + #endregion + + #region UnionAll + + /// + /// 测试合并结果集 + /// + [Fact] + public void TestUnionAll() { + //结果 + var result = new StringBuilder(); + result.AppendLine( "(" ); + result.AppendLine( "Select [a] " ); + result.AppendLine( "From [b] " ); + result.AppendLine( "Join [c] On [b].[id]=[c].[id] " ); + result.AppendLine( "Where [d]=1 " ); + result.AppendLine( "Group By [e] Having Count(f)>1 " ); + result.AppendLine( ")" ); + result.AppendLine( "Union All " ); + result.AppendLine( "(" ); + result.AppendLine( "Select [a1] " ); + result.AppendLine( "From [b1] " ); + result.AppendLine( "Join [c1] On [b1].[id]=[c1].[id] " ); + result.AppendLine( "Where [d1]=1 " ); + result.AppendLine( "Group By [e1] Having Count(f1)>1 " ); + result.AppendLine( ")" ); + result.AppendLine( "Union All " ); + result.AppendLine( "(" ); + result.AppendLine( "Select [a2] " ); + result.AppendLine( "From [b2] " ); + result.AppendLine( "Join [c2] On [b2].[id]=[c2].[id] " ); + result.AppendLine( "Where [d2]=1 " ); + result.AppendLine( "Group By [e2] Having Count(f2)>1 " ); + result.AppendLine( ")" ); + result.AppendLine( "Order By [g] " ); + result.Append( "Limit @_p_0 OFFSET @_p_1" ); + + //执行 + var builder = CreateMasterSqlBuilder(); + var builder2 = CreateSqlBuilder2(); + var builder3 = CreateSqlBuilder3(); + builder.UnionAll( builder2, builder3 ); + + //验证 + Assert.Equal( result.ToString(), builder.GetSql() ); + } + + #endregion + + #region Intersect + + /// + /// 测试交集 + /// + [Fact] + public void TestIntersect() { + //结果 + var result = new StringBuilder(); + result.AppendLine( "(" ); + result.AppendLine( "Select [a] " ); + result.AppendLine( "From [b] " ); + result.AppendLine( "Join [c] On [b].[id]=[c].[id] " ); + result.AppendLine( "Where [d]=1 " ); + result.AppendLine( "Group By [e] Having Count(f)>1 " ); + result.AppendLine( ")" ); + result.AppendLine( "Intersect " ); + result.AppendLine( "(" ); + result.AppendLine( "Select [a1] " ); + result.AppendLine( "From [b1] " ); + result.AppendLine( "Join [c1] On [b1].[id]=[c1].[id] " ); + result.AppendLine( "Where [d1]=1 " ); + result.AppendLine( "Group By [e1] Having Count(f1)>1 " ); + result.AppendLine( ")" ); + result.AppendLine( "Intersect " ); + result.AppendLine( "(" ); + result.AppendLine( "Select [a2] " ); + result.AppendLine( "From [b2] " ); + result.AppendLine( "Join [c2] On [b2].[id]=[c2].[id] " ); + result.AppendLine( "Where [d2]=1 " ); + result.AppendLine( "Group By [e2] Having Count(f2)>1 " ); + result.AppendLine( ")" ); + result.AppendLine( "Order By [g] " ); + result.Append( "Limit @_p_0 OFFSET @_p_1" ); + + //执行 + var builder = CreateMasterSqlBuilder(); + var builder2 = CreateSqlBuilder2(); + var builder3 = CreateSqlBuilder3(); + builder.Intersect( builder2, builder3 ); + + //验证 + Assert.Equal( result.ToString(), builder.GetSql() ); + } + + #endregion + + #region Except + + /// + /// 测试差集 + /// + [Fact] + public void TestExcept() { + //结果 + var result = new StringBuilder(); + result.AppendLine( "(" ); + result.AppendLine( "Select [a] " ); + result.AppendLine( "From [b] " ); + result.AppendLine( "Join [c] On [b].[id]=[c].[id] " ); + result.AppendLine( "Where [d]=1 " ); + result.AppendLine( "Group By [e] Having Count(f)>1 " ); + result.AppendLine( ")" ); + result.AppendLine( "Except " ); + result.AppendLine( "(" ); + result.AppendLine( "Select [a1] " ); + result.AppendLine( "From [b1] " ); + result.AppendLine( "Join [c1] On [b1].[id]=[c1].[id] " ); + result.AppendLine( "Where [d1]=1 " ); + result.AppendLine( "Group By [e1] Having Count(f1)>1 " ); + result.AppendLine( ")" ); + result.AppendLine( "Except " ); + result.AppendLine( "(" ); + result.AppendLine( "Select [a2] " ); + result.AppendLine( "From [b2] " ); + result.AppendLine( "Join [c2] On [b2].[id]=[c2].[id] " ); + result.AppendLine( "Where [d2]=1 " ); + result.AppendLine( "Group By [e2] Having Count(f2)>1 " ); + result.AppendLine( ")" ); + result.AppendLine( "Order By [g] " ); + result.Append( "Limit @_p_0 OFFSET @_p_1" ); + + //执行 + var builder = CreateMasterSqlBuilder(); + var builder2 = CreateSqlBuilder2(); + var builder3 = CreateSqlBuilder3(); + builder.Except( builder2, builder3 ); + + //验证 + Assert.Equal( result.ToString(), builder.GetSql() ); + } + + #endregion + + #region ClearSets + + /// + /// 测试清理集合 + /// + [Fact] + public void TestClearSets() { + //结果 + var result = new StringBuilder(); + result.AppendLine( "Select [a] " ); + result.AppendLine( "From [b] " ); + result.AppendLine( "Join [c] On [b].[id]=[c].[id] " ); + result.AppendLine( "Where [d]=1 " ); + result.AppendLine( "Group By [e] Having Count(f)>1 " ); + result.AppendLine( "Order By [g] " ); + result.Append( "Limit @_p_0 OFFSET @_p_1" ); + + //执行 + var builder = CreateMasterSqlBuilder(); + var builder2 = CreateSqlBuilder2(); + var builder3 = CreateSqlBuilder3(); + builder.Union( builder2, builder3 ); + builder.ClearSets(); + + //验证 + Assert.Equal( result.ToString(), builder.GetSql() ); + } + + #endregion + } +} diff --git a/test/Util.Data.Sql.Tests/Builders/SqlBuilderTest.Start.cs b/test/Util.Data.Sql.Tests/Builders/SqlBuilderTest.Start.cs new file mode 100644 index 00000000..44cfbb93 --- /dev/null +++ b/test/Util.Data.Sql.Tests/Builders/SqlBuilderTest.Start.cs @@ -0,0 +1,152 @@ +using System.Text; +using Xunit; + +namespace Util.Data.Sql.Tests.Builders { + /// + /// Sql生成器测试 - 起始子句 + /// + public partial class SqlBuilderTest { + + #region Cte + + /// + /// 测试公用表表达式CTE + /// + [Fact] + public void TestCte() { + //结果 + var result = new StringBuilder(); + result.AppendLine( "With [Test] " ); + result.AppendLine( "As (Select [a],[b] " ); + result.AppendLine( "From [Test2])," ); + result.AppendLine( "[Test3] " ); + result.AppendLine( "As (Select [a],[b] " ); + result.AppendLine( "From [Test3]) " ); + result.AppendLine( "Select [a],[b] " ); + result.Append( "From [Test]" ); + + //执行 + var builder2 = _builder.New().Select( "a,b" ).From( "Test2" ); + var builder3 = _builder.New().Select( "a,b" ).From( "Test3" ); + _builder.Cte( "Test", builder2 ).Cte( "Test3", builder3 ).Select( "a,b" ).From( "Test" ); + + //验证 + Assert.Equal( result.ToString(), _builder.GetSql() ); + } + + #endregion + + #region Append + + /// + /// 添加到起始位置 + /// + [Fact] + public void TestAppend() { + //结果 + var result = new StringBuilder(); + result.Append( "Select a From b" ); + + //执行 + _builder.Append( "Select a " ); + _builder.Append( "From b" ); + + //验证 + Assert.Equal( result.ToString(), _builder.GetSql() ); + } + + #endregion + + #region AppendLine + + /// + /// 添加到起始位置并换行 + /// + [Fact] + public void TestAppendLine() { + //结果 + var result = new StringBuilder(); + result.AppendLine( "Select a " ); + result.Append( "From b" ); + + //执行 + _builder.AppendLine( "Select a " ); + _builder.Append( "From b" ); + + //验证 + Assert.Equal( result.ToString(), _builder.GetSql() ); + } + + #endregion + + #region AppendStart + + /// + /// 添加到起始位置 + /// + [Fact] + public void TestAppendStart_1() { + //结果 + var result = new StringBuilder(); + result.AppendLine( "with(a) " ); + result.AppendLine( "Select [c].[D] As [e] " ); + result.Append( "From [a].[B] As [c]" ); + + //执行 + _builder.AppendStart( "with(a)" ) + .Select( "c.D as e" ) + .From( "a.B as c" ); + + //验证 + Assert.Equal( result.ToString(), _builder.GetSql() ); + } + + #endregion + + #region ClearCte + + /// + /// 测试清理公用表表达式CTE + /// + [Fact] + public void TestClearCte() { + //结果 + var result = new StringBuilder(); + result.AppendLine( "Select [a],[b] " ); + result.Append( "From [Test]" ); + + //执行 + var builder2 = _builder.New().Select( "a,b" ).From( "Test2" ); + var builder3 = _builder.New().Select( "a,b" ).From( "Test3" ); + _builder.Cte( "Test", builder2 ).Cte( "Test3", builder3 ).Select( "a,b" ).From( "Test" ).ClearCte(); + + //验证 + Assert.Equal( result.ToString(), _builder.GetSql() ); + } + + #endregion + + #region ClearStart + + /// + /// 测试清理起始子句 + /// + [Fact] + public void TestClearStart() { + //结果 + var result = new StringBuilder(); + result.AppendLine( "Select [a],[b] " ); + result.Append( "From [Test]" ); + + //执行 + var builder2 = _builder.New().Select( "a,b" ).From( "Test2" ); + var builder3 = _builder.New().Select( "a,b" ).From( "Test3" ); + _builder.AppendStart( "with(a)" ).Cte( "Test", builder2 ).Cte( "Test3", builder3 ).Select( "a,b" ).From( "Test" ).ClearStart(); + + //验证 + Assert.Equal( result.ToString(), _builder.GetSql() ); + } + + #endregion + } +} diff --git a/test/Util.Data.Sql.Tests/Builders/SqlBuilderTest.Where.cs b/test/Util.Data.Sql.Tests/Builders/SqlBuilderTest.Where.cs new file mode 100644 index 00000000..468d405f --- /dev/null +++ b/test/Util.Data.Sql.Tests/Builders/SqlBuilderTest.Where.cs @@ -0,0 +1,663 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Util.Data.Queries; +using Util.Data.Sql.Tests.Samples; +using Xunit; + +namespace Util.Data.Sql.Tests.Builders { + /// + /// Sql生成器测试 - Where子句 + /// + public partial class SqlBuilderTest { + + #region Where + + /// + /// 设置条件 + /// + [Fact] + public void TestWhere_1() { + //结果 + var result = new StringBuilder(); + result.AppendLine( "Select [a] " ); + result.AppendLine( "From [b] " ); + result.Append( "Where [b].[Name]<>@_p_0" ); + + //执行 + _builder.Select( "a" ) + .From( "b" ) + .Where( "b.Name", "abc", Operator.NotEqual ); + + //验证 + Assert.Equal( result.ToString(), _builder.GetSql() ); + Assert.Single( _builder.GetParams() ); + Assert.Equal( "abc", _builder.GetParam( "@_p_0" ) ); + } + + /// + /// 添加Where子查询 + /// + [Fact] + public void TestWhere_2() { + //结果 + var result = new StringBuilder(); + result.AppendLine( "Select * " ); + result.AppendLine( "From [abc].[Test] " ); + result.Append( "Where [b2]<>" ); + result.AppendLine( "(Select [a] " ); + result.AppendLine( "From [Test2] " ); + result.Append( "Where [Name]=@_p_0) " ); + result.Append( "And [Age]=@_p_1" ); + + //执行 + var builder2 = _builder.New().Select("a").From( "Test2" ).Where( "Name", "a" ); + _builder.Select().From( "abc.Test" ).Where( "b2", builder2, Operator.NotEqual ).Where( "Age", 1 ); + _output.WriteLine( _builder.GetSql() ); + + //验证 + Assert.Equal( result.ToString(), _builder.GetSql() ); + Assert.Equal( 2, _builder.GetParams().Count ); + Assert.Equal( "a", _builder.GetParam( "@_p_0" ) ); + Assert.Equal( 1, _builder.GetParam( "@_p_1" ) ); + } + + /// + /// 添加Where子查询 - 内嵌表达式 + /// + [Fact] + public void TestWhere_3() { + //结果 + var result = new StringBuilder(); + result.AppendLine( "Select * " ); + result.AppendLine( "From [abc].[Test] " ); + result.Append( "Where [b2]<>" ); + result.AppendLine( "(Select [a] " ); + result.AppendLine( "From [Test2] " ); + result.Append( "Where [Name]=@_p_0) " ); + result.Append( "And [Age]=@_p_1" ); + + //执行 + _builder.Select().From( "abc.Test" ).Where( "b2", t => t.Select( "a" ).From( "Test2" ).Where( "Name", "a" ), Operator.NotEqual ).Where( "Age", 1 ); + _output.WriteLine( _builder.GetSql() ); + + //验证 + Assert.Equal( result.ToString(), _builder.GetSql() ); + Assert.Equal( 2, _builder.GetParams().Count ); + Assert.Equal( "a", _builder.GetParam( "@_p_0" ) ); + Assert.Equal( 1, _builder.GetParam( "@_p_1" ) ); + } + + #endregion + + #region In + + /// + /// 设置In条件 + /// + [Fact] + public void TestIn_1() { + //结果 + var result = new StringBuilder(); + result.AppendLine( "Select [a].[Email] " ); + result.AppendLine( "From [Sample] As [a] " ); + result.Append( "Where [a].[Email] In (@_p_0,@_p_1)" ); + + //执行 + var list = new List { "a", "b" }; + _builder.Select( "a.Email" ) + .From( "Sample as a" ) + .In( "a.Email", list ); + + //验证 + Assert.Equal( result.ToString(), _builder.GetSql() ); + Assert.Equal( 2, _builder.GetParams().Count ); + Assert.Equal( "a", _builder.GetParam( "@_p_0" ) ); + Assert.Equal( "b", _builder.GetParam( "@_p_1" ) ); + } + + /// + /// 设置In条件 - 数组 + /// + [Fact] + public void TestIn_2() { + //结果 + var result = new StringBuilder(); + result.AppendLine( "Select [a].[Email] " ); + result.AppendLine( "From [Sample] As [a] " ); + result.Append( "Where [a].[Email] In (@_p_0,@_p_1)" ); + + //执行 + var list = new[] { "a", "b" }; + _builder.Select( "a.Email" ) + .From( "Sample as a" ) + .In( "a.Email", list ); + + //验证 + Assert.Equal( result.ToString(), _builder.GetSql() ); + Assert.Equal( 2, _builder.GetParams().Count ); + Assert.Equal( "a", _builder.GetParam( "@_p_0" ) ); + Assert.Equal( "b", _builder.GetParam( "@_p_1" ) ); + } + + /// + /// 设置In条件 - 子查询 + /// + [Fact] + public void TestIn_3() { + //结果 + var result = new StringBuilder(); + result.AppendLine( "Select [a].[Email] " ); + result.AppendLine( "From [Sample] As [a] " ); + result.Append( "Where [a].[Name]=@_p_1 And " ); + result.Append( "[a].[Email] In (" ); + result.AppendLine( "Select [a] " ); + result.AppendLine( "From [b] " ); + result.Append( "Where [b].[Url]=@_p_0" ); + result.Append( ")" ); + + //执行 + var builder = _builder.New().Select( "a" ).From( "b" ).Where( "b.Url", "u" ); + _builder.Select( "a.Email" ) + .From( "Sample as a" ) + .Where( "a.Name", "n" ) + .In( "a.Email", builder ); + + //验证 + Assert.Equal( result.ToString(), _builder.GetSql() ); + Assert.Equal( 2, _builder.GetParams().Count ); + Assert.Equal( "u", _builder.GetParam( "@_p_0" ) ); + Assert.Equal( "n", _builder.GetParam( "@_p_1" ) ); + } + + /// + /// 设置In条件 - 子查询 - 内嵌表达式 + /// + [Fact] + public void TestIn_4() { + //结果 + var result = new StringBuilder(); + result.AppendLine( "Select [a].[Email] " ); + result.AppendLine( "From [Sample] As [a] " ); + result.Append( "Where [a].[Name]=@_p_0 And " ); + result.Append( "[a].[Email] In (" ); + result.AppendLine( "Select [a] " ); + result.AppendLine( "From [b] " ); + result.Append( "Where [b].[Url]=@_p_1" ); + result.Append( ")" ); + + //执行 + _builder.Select( "a.Email" ) + .From( "Sample as a" ) + .Where( "a.Name", "n" ) + .In( "a.Email", builder => builder.Select( "a" ).From( "b" ).Where( "b.Url", "u" ) ); + + //验证 + Assert.Equal( result.ToString(), _builder.GetSql() ); + Assert.Equal( 2, _builder.GetParams().Count ); + Assert.Equal( "n", _builder.GetParam( "@_p_0" ) ); + Assert.Equal( "u", _builder.GetParam( "@_p_1" ) ); + } + + #endregion + + #region NotIn + + /// + /// 设置NotIn条件 + /// + [Fact] + public void TestNotIn_1() { + //结果 + var result = new StringBuilder(); + result.AppendLine( "Select [a].[Email] " ); + result.AppendLine( "From [Sample] As [a] " ); + result.Append( "Where [a].[Email] Not In (@_p_0,@_p_1)" ); + + //执行 + var list = new List { "a", "b" }; + _builder.Select( "a.Email" ) + .From( "Sample as a" ) + .NotIn( "a.Email", list ); + + //验证 + Assert.Equal( result.ToString(), _builder.GetSql() ); + Assert.Equal( 2, _builder.GetParams().Count ); + Assert.Equal( "a", _builder.GetParam( "@_p_0" ) ); + Assert.Equal( "b", _builder.GetParam( "@_p_1" ) ); + } + + /// + /// 设置NotIn条件 - 数组 + /// + [Fact] + public void TestNotIn_2() { + //结果 + var result = new StringBuilder(); + result.AppendLine( "Select [a].[Email] " ); + result.AppendLine( "From [Sample] As [a] " ); + result.Append( "Where [a].[Email] Not In (@_p_0,@_p_1)" ); + + //执行 + var list = new[] { "a", "b" }; + _builder.Select( "a.Email" ) + .From( "Sample as a" ) + .NotIn( "a.Email", list ); + + //验证 + Assert.Equal( result.ToString(), _builder.GetSql() ); + Assert.Equal( 2, _builder.GetParams().Count ); + Assert.Equal( "a", _builder.GetParam( "@_p_0" ) ); + Assert.Equal( "b", _builder.GetParam( "@_p_1" ) ); + } + + /// + /// 设置NotIn条件 - 子查询 + /// + [Fact] + public void TestNotIn_3() { + //结果 + var result = new StringBuilder(); + result.AppendLine( "Select [a].[Email] " ); + result.AppendLine( "From [Sample] As [a] " ); + result.Append( "Where [a].[Name]=@_p_1 And " ); + result.Append( "[a].[Email] Not In (" ); + result.AppendLine( "Select [a] " ); + result.AppendLine( "From [b] " ); + result.Append( "Where [b].[Url]=@_p_0" ); + result.Append( ")" ); + + //执行 + var builder = _builder.New().Select( "a" ).From( "b" ).Where( "b.Url", "u" ); + _builder.Select( "a.Email" ) + .From( "Sample as a" ) + .Where( "a.Name", "n" ) + .NotIn( "a.Email", builder ); + + //验证 + Assert.Equal( result.ToString(), _builder.GetSql() ); + Assert.Equal( 2, _builder.GetParams().Count ); + Assert.Equal( "u", _builder.GetParam( "@_p_0" ) ); + Assert.Equal( "n", _builder.GetParam( "@_p_1" ) ); + } + + /// + /// 设置NotIn条件 - 子查询 - 内嵌表达式 + /// + [Fact] + public void TestNotIn_4() { + //结果 + var result = new StringBuilder(); + result.AppendLine( "Select [a].[Email] " ); + result.AppendLine( "From [Sample] As [a] " ); + result.Append( "Where [a].[Name]=@_p_0 And " ); + result.Append( "[a].[Email] Not In (" ); + result.AppendLine( "Select [a] " ); + result.AppendLine( "From [b] " ); + result.Append( "Where [b].[Url]=@_p_1" ); + result.Append( ")" ); + + //执行 + _builder.Select( "a.Email" ) + .From( "Sample as a" ) + .Where( "a.Name", "n" ) + .NotIn( "a.Email", builder => builder.Select( "a" ).From( "b" ).Where( "b.Url", "u" ) ); + + //验证 + Assert.Equal( result.ToString(), _builder.GetSql() ); + Assert.Equal( 2, _builder.GetParams().Count ); + Assert.Equal( "n", _builder.GetParam( "@_p_0" ) ); + Assert.Equal( "u", _builder.GetParam( "@_p_1" ) ); + } + + #endregion + + #region IsNull + + /// + /// 设置Is Null条件 + /// + [Fact] + public void TestIsNull() { + //结果 + var result = new StringBuilder(); + result.AppendLine( "Select [a].[Email] " ); + result.AppendLine( "From [Sample] As [a] " ); + result.Append( "Where [a].[Email] Is Null" ); + + //执行 + _builder.Select( "a.Email" ) + .From( "Sample a" ) + .IsNull( "a.Email" ); + + //验证 + Assert.Equal( result.ToString(), _builder.GetSql() ); + } + + #endregion + + #region IsNotNull + + /// + /// 设置条件 - Is Not Null + /// + [Fact] + public void TestIsNotNull() { + //结果 + var result = new StringBuilder(); + result.AppendLine( "Select [a].[Email] " ); + result.AppendLine( "From [Sample] As [a] " ); + result.Append( "Where [a].[Email] Is Not Null" ); + + //执行 + _builder.Select( "a.Email" ) + .From( "Sample a" ) + .IsNotNull( "a.Email" ); + + //验证 + Assert.Equal( result.ToString(), _builder.GetSql() ); + } + + #endregion + + #region IsEmpty + + /// + /// 测试设置空条件 + /// + [Fact] + public void TestIsEmpty() { + //结果 + var result = new StringBuilder(); + result.AppendLine( "Select [a].[Email] " ); + result.AppendLine( "From [Sample] As [a] " ); + result.Append( "Where ([a].[Email] Is Null Or [a].[Email]='')" ); + + //执行 + _builder.Select( "a.Email" ) + .From( "Sample a" ) + .IsEmpty( "a.Email" ); + + //验证 + Assert.Equal( result.ToString(), _builder.GetSql() ); + } + + #endregion + + #region IsNotEmpty + + /// + /// 设置非空条件 + /// + [Fact] + public void TestIsNotEmpty() { + //结果 + var result = new StringBuilder(); + result.AppendLine( "Select [a].[Email] " ); + result.AppendLine( "From [Sample] As [a] " ); + result.Append( "Where [a].[Email] Is Not Null And [a].[Email]<>''" ); + + //执行 + _builder.Select( "a.Email" ) + .From( "Sample a" ) + .IsNotEmpty( "a.Email" ); + + //验证 + Assert.Equal( result.ToString(), _builder.GetSql() ); + } + + #endregion + + #region Between + + /// + /// 测试范围查询 - int类型 + /// + [Fact] + public void TestBetween_1() { + //结果 + var result = new StringBuilder(); + result.AppendLine( "Select [a].[Email] " ); + result.AppendLine( "From [Sample] As [a] " ); + result.Append( "Where [a].[B]>=@_p_0 And [a].[B]<@_p_1" ); + + //执行 + _builder.Select( "a.Email" ) + .From( "Sample a" ) + .Between( "a.B", 1, 2,Boundary.Left ); + + //验证 + Assert.Equal( 1, _builder.GetParam( "@_p_0" ) ); + Assert.Equal( 2, _builder.GetParam( "@_p_1" ) ); + Assert.Equal( result.ToString(), _builder.GetSql() ); + } + + /// + /// 测试范围查询 - double类型 + /// + [Fact] + public void TestBetween_2() { + //结果 + var result = new StringBuilder(); + result.AppendLine( "Select [a].[Email] " ); + result.AppendLine( "From [Sample] As [a] " ); + result.Append( "Where [a].[B]>=@_p_0 And [a].[B]<@_p_1" ); + + //执行 + _builder.Select( "a.Email" ) + .From( "Sample a" ) + .Between( "a.B", 1.1, 2.2, Boundary.Left ); + + //验证 + Assert.Equal( 1.1, _builder.GetParam( "@_p_0" ) ); + Assert.Equal( 2.2, _builder.GetParam( "@_p_1" ) ); + Assert.Equal( result.ToString(), _builder.GetSql() ); + } + + /// + /// 测试范围查询 - decimal类型 + /// + [Fact] + public void TestBetween_3() { + //结果 + var result = new StringBuilder(); + result.AppendLine( "Select [a].[Email] " ); + result.AppendLine( "From [Sample] As [a] " ); + result.Append( "Where [a].[B]>=@_p_0 And [a].[B]<@_p_1" ); + + //执行 + _builder.Select( "a.Email" ) + .From( "Sample a" ) + .Between( "a.B", 1.1M, 2.2M, Boundary.Left ); + + //验证 + Assert.Equal( 1.1M, _builder.GetParam( "@_p_0" ) ); + Assert.Equal( 2.2M, _builder.GetParam( "@_p_1" ) ); + Assert.Equal( result.ToString(), _builder.GetSql() ); + } + + /// + /// 测试范围查询 - DateTime类型 + /// + [Fact] + public void TestBetween_4() { + //结果 + var result = new StringBuilder(); + result.AppendLine( "Select [a].[Email] " ); + result.AppendLine( "From [Sample] As [a] " ); + result.Append( "Where [a].[B]>=@_p_0 And [a].[B]<@_p_1" ); + + //日期 + var min = "2012-12-12 12:12:12".ToDateTime(); + var max = "2012-12-16 12:12:12".ToDateTime(); + + //执行 + _builder.Select( "a.Email" ) + .From( "Sample a" ) + .Between( "a.B", min, max,true, Boundary.Left ); + + //验证 + Assert.Equal( min, _builder.GetParam( "@_p_0" ) ); + Assert.Equal( max, _builder.GetParam( "@_p_1" ) ); + Assert.Equal( result.ToString(), _builder.GetSql() ); + } + + #endregion + + #region Exists + + /// + /// 设置Exists条件 - 子查询Sql生成器 + /// + [Fact] + public void TestExists_1() { + //结果 + var result = new StringBuilder(); + result.AppendLine( "Select [a] " ); + result.AppendLine( "From [b] " ); + result.Append( "Where Exists (" ); + result.AppendLine( "Select [Name] " ); + result.Append( "From [t]" ); + result.Append( ")" ); + + //子查询 + var subBuilder = new TestSqlBuilder(); + subBuilder.Select( "Name" ).From( "t" ); + + //执行 + _builder.Select( "a" ) + .From( "b" ) + .Exists( subBuilder ); + + //验证 + Assert.Equal( result.ToString(), _builder.GetSql() ); + } + + /// + /// 设置Exists条件 - 子查询操作 + /// + [Fact] + public void TestExists_2() { + //结果 + var result = new StringBuilder(); + result.AppendLine( "Select [a] " ); + result.AppendLine( "From [b] " ); + result.Append( "Where Exists (" ); + result.AppendLine( "Select [Name] " ); + result.Append( "From [t]" ); + result.Append( ")" ); + + //执行 + _builder.Select( "a" ) + .From( "b" ) + .Exists( t => t.Select( "Name" ).From( "t" ) ); + + //验证 + Assert.Equal( result.ToString(), _builder.GetSql() ); + } + + #endregion + + #region NotExists + + /// + /// 设置Not Exists条件 - 子查询Sql生成器 + /// + [Fact] + public void TestNotExists_1() { + //结果 + var result = new StringBuilder(); + result.AppendLine( "Select [a] " ); + result.AppendLine( "From [b] " ); + result.Append( "Where Not Exists (" ); + result.AppendLine( "Select [Name] " ); + result.Append( "From [t]" ); + result.Append( ")" ); + + //子查询 + var subBuilder = new TestSqlBuilder(); + subBuilder.Select( "Name" ).From( "t" ); + + //执行 + _builder.Select( "a" ) + .From( "b" ) + .NotExists( subBuilder ); + + //验证 + Assert.Equal( result.ToString(), _builder.GetSql() ); + } + + /// + /// 设置Not Exists条件 - 子查询操作 + /// + [Fact] + public void TestNotExists_2() { + //结果 + var result = new StringBuilder(); + result.AppendLine( "Select [a] " ); + result.AppendLine( "From [b] " ); + result.Append( "Where Not Exists (" ); + result.AppendLine( "Select [Name] " ); + result.Append( "From [t]" ); + result.Append( ")" ); + + //执行 + _builder.Select( "a" ) + .From( "b" ) + .NotExists( t => t.Select( "Name" ).From( "t" ) ); + + //验证 + Assert.Equal( result.ToString(), _builder.GetSql() ); + } + + #endregion + + #region AppendWhere + + /// + /// 测试添加到Where子句 + /// + [Fact] + public void TestAppendWhere_1() { + //结果 + var result = new StringBuilder(); + result.AppendLine( "Select [a] " ); + result.AppendLine( "From [b] " ); + result.Append( "Where [b].[Name]<>'abc'" ); + + //执行 + _builder.Select( "a" ) + .From( "b" ) + .AppendWhere( "[b].[Name]<>'abc'" ); + + //验证 + Assert.Equal( result.ToString(), _builder.GetSql() ); + } + + #endregion + + #region ClearWhere + + /// + /// 测试清空Where子句 + /// + [Fact] + public void TestClearWhere() { + //结果 + var result = new StringBuilder(); + result.AppendLine( "Select [a] " ); + result.Append( "From [b]" ); + + //执行 + _builder.Select( "a" ) + .From( "b" ) + .Where( "b.Name", "abc", Operator.NotEqual ) + .ClearWhere(); + + //验证 + Assert.Equal( result.ToString(), _builder.GetSql() ); + } + + #endregion + } +} \ No newline at end of file diff --git a/test/Util.Data.Sql.Tests/Builders/SqlBuilderTest.cs b/test/Util.Data.Sql.Tests/Builders/SqlBuilderTest.cs new file mode 100644 index 00000000..67b32803 --- /dev/null +++ b/test/Util.Data.Sql.Tests/Builders/SqlBuilderTest.cs @@ -0,0 +1,27 @@ +using Util.Data.Sql.Tests.Samples; +using Xunit; +using Xunit.Abstractions; + +namespace Util.Data.Sql.Tests.Builders { + /// + /// Sql生成器测试 + /// + public partial class SqlBuilderTest { + /// + /// 输出工具 + /// + private readonly ITestOutputHelper _output; + /// + /// 测试Sql生成器 + /// + private readonly TestSqlBuilder _builder; + + /// + /// 测试初始化 + /// + public SqlBuilderTest( ITestOutputHelper output ) { + _output = output; + _builder = new TestSqlBuilder(); + } + } +} diff --git a/test/Util.Data.Sql.Tests/Samples/TestColumnCache.cs b/test/Util.Data.Sql.Tests/Samples/TestColumnCache.cs new file mode 100644 index 00000000..42000526 --- /dev/null +++ b/test/Util.Data.Sql.Tests/Samples/TestColumnCache.cs @@ -0,0 +1,49 @@ +using System.Collections.Concurrent; +using Util.Data.Sql.Builders; +using Util.Data.Sql.Builders.Caches; + +namespace Util.Data.Sql.Tests.Samples { + /// + /// 测试列缓存 + /// + public class TestColumnCache : ColumnCacheBase { + /// + /// 列名缓存 + /// + private readonly ConcurrentDictionary _cache; + + /// + /// 初始化测试列缓存 + /// + public TestColumnCache() : this( TestDialect.Instance ) { + } + + /// + /// 初始化测试列缓存 + /// + public TestColumnCache( IDialect dialect ) : base( dialect ) { + _cache = new ConcurrentDictionary(); + } + + /// + /// 测试列缓存实例 + /// + public static readonly IColumnCache Instance = new TestColumnCache(); + + /// + /// 从缓存中获取处理后的列集合 + /// + /// 列集合 + public override string GetSafeColumns( string columns ) { + return _cache.GetOrAdd( columns.GetHashCode(), key => NormalizeColumns( columns ) ); + } + + /// + /// 从缓存中获取处理后的列 + /// + /// 列 + public override string GetSafeColumn( string column ) { + return _cache.GetOrAdd( column.GetHashCode(), key => NormalizeColumn( column ) ); + } + } +} diff --git a/test/Util.Data.Sql.Tests/Samples/TestDialect.cs b/test/Util.Data.Sql.Tests/Samples/TestDialect.cs new file mode 100644 index 00000000..00416d07 --- /dev/null +++ b/test/Util.Data.Sql.Tests/Samples/TestDialect.cs @@ -0,0 +1,41 @@ +using Util.Data.Sql.Builders; +using Util.Data.Sql.Builders.Core; + +namespace Util.Data.Sql.Tests.Samples { + /// + /// 测试方言 + /// + public class TestDialect : DialectBase { + /// + /// 封闭构造方法 + /// + private TestDialect() { + } + + /// + /// 测试方言实例 + /// + public static readonly IDialect Instance = new TestDialect(); + + /// + /// 获取起始转义标识符 + /// + public override string GetOpeningIdentifier() { + return "["; + } + + /// + /// 获取结束转义标识符 + /// + public override string GetClosingIdentifier() { + return "]"; + } + + /// + /// 获取参数前缀 + /// + public override string GetPrefix() { + return "@"; + } + } +} diff --git a/test/Util.Data.Sql.Tests/Samples/TestDialect2.cs b/test/Util.Data.Sql.Tests/Samples/TestDialect2.cs new file mode 100644 index 00000000..b6e2de52 --- /dev/null +++ b/test/Util.Data.Sql.Tests/Samples/TestDialect2.cs @@ -0,0 +1,29 @@ +using Util.Data.Sql.Builders.Core; + +namespace Util.Data.Sql.Tests.Samples { + /// + /// 测试方言2 + /// + public class TestDialect2 : DialectBase { + /// + /// 获取起始转义标识符 + /// + public override string GetOpeningIdentifier() { + return "$"; + } + + /// + /// 获取结束转义标识符 + /// + public override string GetClosingIdentifier() { + return "&"; + } + + /// + /// 获取参数前缀 + /// + public override string GetPrefix() { + return "*"; + } + } +} diff --git a/test/Util.Data.Sql.Tests/Samples/TestParameter.cs b/test/Util.Data.Sql.Tests/Samples/TestParameter.cs new file mode 100644 index 00000000..3d6737c8 --- /dev/null +++ b/test/Util.Data.Sql.Tests/Samples/TestParameter.cs @@ -0,0 +1,11 @@ +namespace Util.Data.Sql.Tests.Samples { + /// + /// 测试参数 + /// + public class TestParameter { + /// + /// 编码 + /// + public string Code { get; set; } + } +} diff --git a/test/Util.Data.Sql.Tests/Samples/TestSqlBuilder.cs b/test/Util.Data.Sql.Tests/Samples/TestSqlBuilder.cs new file mode 100644 index 00000000..fa6445de --- /dev/null +++ b/test/Util.Data.Sql.Tests/Samples/TestSqlBuilder.cs @@ -0,0 +1,62 @@ +using Util.Data.Sql.Builders; +using Util.Data.Sql.Builders.Caches; +using Util.Data.Sql.Builders.Params; + +namespace Util.Data.Sql.Tests.Samples { + /// + /// 测试Sql生成器 + /// + public class TestSqlBuilder : SqlBuilderBase { + /// + /// Sql方言 + /// + private readonly IDialect _dialect; + /// + /// 列缓存 + /// + private readonly IColumnCache _columnCache; + + /// + /// 初始化Sql生成器 + /// + public TestSqlBuilder( IDialect dialect = null, IColumnCache columnCache = null, IParameterManager parameterManager = null ) + : base( parameterManager ) { + _dialect = dialect; + _columnCache = columnCache; + } + + /// + /// 获取Sql方言 + /// + protected override IDialect CreateDialect() { + if ( _dialect != null ) + return _dialect; + return TestDialect.Instance; + } + + /// + /// 获取列缓存 + /// + protected override IColumnCache CreateColumnCache() { + if ( _columnCache != null ) + return _columnCache; + return TestColumnCache.Instance; + } + + /// + /// 创建Sql生成器 + /// + public override ISqlBuilder New() { + return new TestSqlBuilder( Dialect,ColumnCache, ParameterManager ); + } + + /// + /// 复制Sql生成器 + /// + public override ISqlBuilder Clone() { + var result = new TestSqlBuilder(); + result.Clone( this ); + return result; + } + } +} diff --git a/test/Util.Data.Sql.Tests/Util.Data.Sql.Tests.csproj b/test/Util.Data.Sql.Tests/Util.Data.Sql.Tests.csproj new file mode 100644 index 00000000..f08f6b26 --- /dev/null +++ b/test/Util.Data.Sql.Tests/Util.Data.Sql.Tests.csproj @@ -0,0 +1,25 @@ + + + + $(NetTargetFramework) + false + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + diff --git a/test/Util.Data.Tests/Queries/Conditions/DateSegmentConditionTest.cs b/test/Util.Data.Tests/Queries/Conditions/DateSegmentConditionTest.cs index 1116277e..e258a8c4 100644 --- a/test/Util.Data.Tests/Queries/Conditions/DateSegmentConditionTest.cs +++ b/test/Util.Data.Tests/Queries/Conditions/DateSegmentConditionTest.cs @@ -1,5 +1,7 @@ using System; +using System.Globalization; using System.Text; +using System.Threading; using Util.Data.Queries; using Util.Data.Queries.Conditions; using Util.Data.Tests.Samples; @@ -20,6 +22,11 @@ namespace Util.Data.Tests.Queries.Conditions { /// 测试初始化 /// public DateSegmentConditionTest( ITestOutputHelper output) { + Thread.CurrentThread.CurrentCulture = new CultureInfo( "zh-CN" ) { + DateTimeFormat = new DateTimeFormatInfo { + ShortDatePattern = "yyyy/M/d" + } + }; _output = output; _min = "2000-1-1 10:10:10".ToDateTime(); _max = "2000-1-3 10:10:10".ToDateTime(); @@ -40,8 +47,8 @@ namespace Util.Data.Tests.Queries.Conditions { [Fact] public void TestGetCondition_Neither() { var result = new StringBuilder(); - result.Append( "t => ((t.DateValue >= Convert(Parse(\"2000/1/2 0:00:00\"), DateTime))" ); - result.Append( " AndAlso (t.DateValue < Convert(Parse(\"2000/1/3 0:00:00\"), DateTime)))" ); + result.Append( "t => ((t.DateValue >= Convert(Parse(\"2000/1/2 00:00:00\"), DateTime))" ); + result.Append( " AndAlso (t.DateValue < Convert(Parse(\"2000/1/3 00:00:00\"), DateTime)))" ); var condition = new DateSegmentCondition( t => t.DateValue, _min, _max, Boundary.Neither ); Assert.Equal( result.ToString(), condition.GetCondition().ToString() ); } @@ -52,8 +59,8 @@ namespace Util.Data.Tests.Queries.Conditions { [Fact] public void TestGetCondition_Left() { var result = new StringBuilder(); - result.Append( "t => ((t.DateValue >= Convert(Parse(\"2000/1/1 0:00:00\"), DateTime))" ); - result.Append( " AndAlso (t.DateValue < Convert(Parse(\"2000/1/3 0:00:00\"), DateTime)))" ); + result.Append( "t => ((t.DateValue >= Convert(Parse(\"2000/1/1 00:00:00\"), DateTime))" ); + result.Append( " AndAlso (t.DateValue < Convert(Parse(\"2000/1/3 00:00:00\"), DateTime)))" ); var condition = new DateSegmentCondition( t => t.DateValue, _min, _max, Boundary.Left ); Assert.Equal( result.ToString(), condition.GetCondition().ToString() ); } @@ -64,8 +71,8 @@ namespace Util.Data.Tests.Queries.Conditions { [Fact] public void TestGetCondition_Right() { var result = new StringBuilder(); - result.Append( "t => ((t.NullableDateValue >= Convert(Parse(\"2000/1/2 0:00:00\"), Nullable`1))" ); - result.Append( " AndAlso (t.NullableDateValue < Convert(Parse(\"2000/1/4 0:00:00\"), Nullable`1)))" ); + result.Append( "t => ((t.NullableDateValue >= Convert(Parse(\"2000/1/2 00:00:00\"), Nullable`1))" ); + result.Append( " AndAlso (t.NullableDateValue < Convert(Parse(\"2000/1/4 00:00:00\"), Nullable`1)))" ); var condition = new DateSegmentCondition( t => t.NullableDateValue, _min, _max, Boundary.Right ); Assert.Equal( result.ToString(), condition.GetCondition().ToString() ); } @@ -76,8 +83,8 @@ namespace Util.Data.Tests.Queries.Conditions { [Fact] public void TestGetCondition_Both() { var result = new StringBuilder(); - result.Append( "t => ((t.NullableDateValue >= Convert(Parse(\"2000/1/1 0:00:00\"), Nullable`1))" ); - result.Append( " AndAlso (t.NullableDateValue < Convert(Parse(\"2000/1/4 0:00:00\"), Nullable`1)))" ); + result.Append( "t => ((t.NullableDateValue >= Convert(Parse(\"2000/1/1 00:00:00\"), Nullable`1))" ); + result.Append( " AndAlso (t.NullableDateValue < Convert(Parse(\"2000/1/4 00:00:00\"), Nullable`1)))" ); var condition = new DateSegmentCondition( t => t.NullableDateValue, _min, _max, Boundary.Both ); Assert.Equal( result.ToString(), condition.GetCondition().ToString() ); } diff --git a/test/Util.Data.Tests/Queries/Conditions/DateTimeSegmentConditionTest.cs b/test/Util.Data.Tests/Queries/Conditions/DateTimeSegmentConditionTest.cs index 3ca8b334..47001941 100644 --- a/test/Util.Data.Tests/Queries/Conditions/DateTimeSegmentConditionTest.cs +++ b/test/Util.Data.Tests/Queries/Conditions/DateTimeSegmentConditionTest.cs @@ -1,5 +1,7 @@ using System; +using System.Globalization; using System.Text; +using System.Threading; using Util.Data.Queries; using Util.Data.Queries.Conditions; using Util.Data.Tests.Samples; @@ -14,6 +16,11 @@ namespace Util.Data.Tests.Queries.Conditions { /// 测试初始化 /// public DateTimeSegmentConditionTest() { + Thread.CurrentThread.CurrentCulture = new CultureInfo( "zh-CN" ) { + DateTimeFormat = new DateTimeFormatInfo { + ShortDatePattern = "yyyy/M/d" + } + }; _min = DateTime.Parse( "2000-1-1 10:10:10" ); _max = DateTime.Parse( "2000-1-2 10:10:10" ); } diff --git a/test/Util.Data.Tests/Queries/Conditions/DoubleSegmentConditionTest.cs b/test/Util.Data.Tests/Queries/Conditions/DoubleSegmentConditionTest.cs index 8a0e66e3..c98977f7 100644 --- a/test/Util.Data.Tests/Queries/Conditions/DoubleSegmentConditionTest.cs +++ b/test/Util.Data.Tests/Queries/Conditions/DoubleSegmentConditionTest.cs @@ -8,7 +8,7 @@ namespace Util.Data.Tests.Queries.Conditions { /// /// 测试double范围过滤条件 /// - public class DoubleSegmentConditionTest { + public class DoubleSegmentConditionTest { /// /// 测试获取查询条件 /// diff --git a/test/Util.Data.Tests/Queries/Conditions/IntSegmentConditionTest.cs b/test/Util.Data.Tests/Queries/Conditions/IntSegmentConditionTest.cs index ff310701..fa552085 100644 --- a/test/Util.Data.Tests/Queries/Conditions/IntSegmentConditionTest.cs +++ b/test/Util.Data.Tests/Queries/Conditions/IntSegmentConditionTest.cs @@ -7,7 +7,7 @@ namespace Util.Data.Tests.Queries.Conditions { /// /// 测试整数范围过滤条件 /// - public class IntSegmentConditionTest { + public class IntSegmentConditionTest { /// /// 测试获取查询条件 /// diff --git a/test/Util.Data.Tests/Util.Data.Tests.csproj b/test/Util.Data.Tests/Util.Data.Tests.csproj index f1687e4f..4d288214 100644 --- a/test/Util.Data.Tests/Util.Data.Tests.csproj +++ b/test/Util.Data.Tests/Util.Data.Tests.csproj @@ -6,13 +6,13 @@ - + - + runtime; build; native; contentfiles; analyzers; buildtransitive all - + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/test/Util.Domain.Tests/Util.Domain.Tests.csproj b/test/Util.Domain.Tests/Util.Domain.Tests.csproj index 8b79d5c1..495a2df4 100644 --- a/test/Util.Domain.Tests/Util.Domain.Tests.csproj +++ b/test/Util.Domain.Tests/Util.Domain.Tests.csproj @@ -6,13 +6,13 @@ - + - + runtime; build; native; contentfiles; analyzers; buildtransitive all - + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/test/Util.Events.Tests/Startup.cs b/test/Util.Events.Tests/Startup.cs index 871b3baa..7088db3c 100644 --- a/test/Util.Events.Tests/Startup.cs +++ b/test/Util.Events.Tests/Startup.cs @@ -1,4 +1,4 @@ -using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using Xunit.DependencyInjection; using Xunit.DependencyInjection.Logging; @@ -9,10 +9,10 @@ namespace Util.Events.Tests { /// public class Startup { /// - /// ÅäÖ÷þÎñ + /// ÅäÖÃÖ÷»ú /// - public void ConfigureServices( IServiceCollection services ) { - services.AddUtil(); + public void ConfigureHost( IHostBuilder hostBuilder ) { + hostBuilder.AddUtil(); } /// diff --git a/test/Util.Events.Tests/Util.Events.Tests.csproj b/test/Util.Events.Tests/Util.Events.Tests.csproj index 89c8c319..330e773b 100644 --- a/test/Util.Events.Tests/Util.Events.Tests.csproj +++ b/test/Util.Events.Tests/Util.Events.Tests.csproj @@ -6,16 +6,16 @@ - - - - + + + + - + runtime; build; native; contentfiles; analyzers; buildtransitive all - + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/test/Util.Localization.Resources/Properties/AssemblyInfo.cs b/test/Util.Localization.Resources/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..0201aafa --- /dev/null +++ b/test/Util.Localization.Resources/Properties/AssemblyInfo.cs @@ -0,0 +1,2 @@ +using Microsoft.Extensions.Localization; +[assembly: ResourceLocation( "Resources2" )] \ No newline at end of file diff --git a/test/Util.Localization.Resources/ResourceTypes/Resource101.cs b/test/Util.Localization.Resources/ResourceTypes/Resource101.cs new file mode 100644 index 00000000..df3dac9d --- /dev/null +++ b/test/Util.Localization.Resources/ResourceTypes/Resource101.cs @@ -0,0 +1,7 @@ +namespace Util.Localization.Resources.ResourceTypes { + /// + /// 资源类型101 + /// + public class Resource101 { + } +} diff --git a/test/Util.Localization.Resources/ResourceTypes/Resource102.cs b/test/Util.Localization.Resources/ResourceTypes/Resource102.cs new file mode 100644 index 00000000..a4084c42 --- /dev/null +++ b/test/Util.Localization.Resources/ResourceTypes/Resource102.cs @@ -0,0 +1,7 @@ +namespace Util.Localization.Resources.ResourceTypes { + /// + /// 资源类型102 + /// + public class Resource102 { + } +} diff --git a/test/Util.Localization.Resources/Resources2/ResourceTypes.Resource101.en-US.json b/test/Util.Localization.Resources/Resources2/ResourceTypes.Resource101.en-US.json new file mode 100644 index 00000000..d406b828 --- /dev/null +++ b/test/Util.Localization.Resources/Resources2/ResourceTypes.Resource101.en-US.json @@ -0,0 +1,3 @@ +{ + "Hello": "hi" +} diff --git a/test/Util.Localization.Resources/Resources2/ResourceTypes.Resource101.zh-CN.json b/test/Util.Localization.Resources/Resources2/ResourceTypes.Resource101.zh-CN.json new file mode 100644 index 00000000..cc364708 --- /dev/null +++ b/test/Util.Localization.Resources/Resources2/ResourceTypes.Resource101.zh-CN.json @@ -0,0 +1,3 @@ +{ + "Hello": "哈楼" +} diff --git a/test/Util.Localization.Resources/Resources2/ResourceTypes/Resource102.zh-CN.json b/test/Util.Localization.Resources/Resources2/ResourceTypes/Resource102.zh-CN.json new file mode 100644 index 00000000..56ef3dd3 --- /dev/null +++ b/test/Util.Localization.Resources/Resources2/ResourceTypes/Resource102.zh-CN.json @@ -0,0 +1,3 @@ +{ + "Hello": "哈罗" +} diff --git a/test/Util.Localization.Resources/Util.Localization.Resources.csproj b/test/Util.Localization.Resources/Util.Localization.Resources.csproj new file mode 100644 index 00000000..38c5ff67 --- /dev/null +++ b/test/Util.Localization.Resources/Util.Localization.Resources.csproj @@ -0,0 +1,36 @@ + + + + $(NetTargetFramework) + enable + + + + + + + + + + + PreserveNewest + true + PreserveNewest + + + PreserveNewest + true + PreserveNewest + + + PreserveNewest + true + PreserveNewest + + + + + + + + diff --git a/test/Util.Localization.Tests.Integration/Properties/AssemblyInfo.cs b/test/Util.Localization.Tests.Integration/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..4b3d7a56 --- /dev/null +++ b/test/Util.Localization.Tests.Integration/Properties/AssemblyInfo.cs @@ -0,0 +1,2 @@ +using Microsoft.Extensions.Localization; +[assembly: RootNamespace( "Util.Localization" )] \ No newline at end of file diff --git a/test/Util.Localization.Tests.Integration/Properties/launchSettings.json b/test/Util.Localization.Tests.Integration/Properties/launchSettings.json new file mode 100644 index 00000000..2cf1a03a --- /dev/null +++ b/test/Util.Localization.Tests.Integration/Properties/launchSettings.json @@ -0,0 +1,12 @@ +{ + "profiles": { + "Util.Localization.Tests.Integration": { + "commandName": "Project", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "applicationUrl": "https://localhost:54279;http://localhost:54280" + } + } +} \ No newline at end of file diff --git a/test/Util.Localization.Tests.Integration/ResourceTypes/Resource1.cs b/test/Util.Localization.Tests.Integration/ResourceTypes/Resource1.cs new file mode 100644 index 00000000..079d7773 --- /dev/null +++ b/test/Util.Localization.Tests.Integration/ResourceTypes/Resource1.cs @@ -0,0 +1,7 @@ +namespace Util.Localization.ResourceTypes { + /// + /// 资源类型1 + /// + public class Resource1 { + } +} diff --git a/test/Util.Localization.Tests.Integration/ResourceTypes/Resource2.cs b/test/Util.Localization.Tests.Integration/ResourceTypes/Resource2.cs new file mode 100644 index 00000000..50afd09e --- /dev/null +++ b/test/Util.Localization.Tests.Integration/ResourceTypes/Resource2.cs @@ -0,0 +1,7 @@ +namespace Util.Localization.ResourceTypes { + /// + /// 资源类型2 + /// + public class Resource2 { + } +} diff --git a/test/Util.Localization.Tests.Integration/ResourceTypes/Resource3.cs b/test/Util.Localization.Tests.Integration/ResourceTypes/Resource3.cs new file mode 100644 index 00000000..afdad2b6 --- /dev/null +++ b/test/Util.Localization.Tests.Integration/ResourceTypes/Resource3.cs @@ -0,0 +1,7 @@ +namespace Util.Localization.ResourceTypes { + /// + /// 资源类型3 + /// + public class Resource3 { + } +} diff --git a/test/Util.Localization.Tests.Integration/ResourceTypes/Resource4.cs b/test/Util.Localization.Tests.Integration/ResourceTypes/Resource4.cs new file mode 100644 index 00000000..a81d3698 --- /dev/null +++ b/test/Util.Localization.Tests.Integration/ResourceTypes/Resource4.cs @@ -0,0 +1,14 @@ +namespace Util.Localization.ResourceTypes { + /// + /// 资源类型4 + /// + public class Resource4 { + + /// + /// 资源类型41 - 测试内部类 + /// + public class Resource41 { + } + + } +} diff --git a/test/Util.Localization.Tests.Integration/ResourceTypes/Resource5.cs b/test/Util.Localization.Tests.Integration/ResourceTypes/Resource5.cs new file mode 100644 index 00000000..19071b89 --- /dev/null +++ b/test/Util.Localization.Tests.Integration/ResourceTypes/Resource5.cs @@ -0,0 +1,7 @@ +namespace Util.Localization.ResourceTypes { + /// + /// 资源类型5 + /// + public class Resource5 { + } +} diff --git a/test/Util.Localization.Tests.Integration/ResourceTypes/Resource6.cs b/test/Util.Localization.Tests.Integration/ResourceTypes/Resource6.cs new file mode 100644 index 00000000..cfa940f4 --- /dev/null +++ b/test/Util.Localization.Tests.Integration/ResourceTypes/Resource6.cs @@ -0,0 +1,7 @@ +namespace Util.Localization.ResourceTypes { + /// + /// 资源类型6 + /// + public class Resource6 { + } +} diff --git a/test/Util.Localization.Tests.Integration/Resources/ResourceTypes.Resource1.en-US.json b/test/Util.Localization.Tests.Integration/Resources/ResourceTypes.Resource1.en-US.json new file mode 100644 index 00000000..d406b828 --- /dev/null +++ b/test/Util.Localization.Tests.Integration/Resources/ResourceTypes.Resource1.en-US.json @@ -0,0 +1,3 @@ +{ + "Hello": "hi" +} diff --git a/test/Util.Localization.Tests.Integration/Resources/ResourceTypes.Resource1.zh-CN.json b/test/Util.Localization.Tests.Integration/Resources/ResourceTypes.Resource1.zh-CN.json new file mode 100644 index 00000000..cc364708 --- /dev/null +++ b/test/Util.Localization.Tests.Integration/Resources/ResourceTypes.Resource1.zh-CN.json @@ -0,0 +1,3 @@ +{ + "Hello": "哈楼" +} diff --git a/test/Util.Localization.Tests.Integration/Resources/ResourceTypes/Resource2.en-US.json b/test/Util.Localization.Tests.Integration/Resources/ResourceTypes/Resource2.en-US.json new file mode 100644 index 00000000..d406b828 --- /dev/null +++ b/test/Util.Localization.Tests.Integration/Resources/ResourceTypes/Resource2.en-US.json @@ -0,0 +1,3 @@ +{ + "Hello": "hi" +} diff --git a/test/Util.Localization.Tests.Integration/Resources/ResourceTypes/Resource2.zh-CN.json b/test/Util.Localization.Tests.Integration/Resources/ResourceTypes/Resource2.zh-CN.json new file mode 100644 index 00000000..260dd0fd --- /dev/null +++ b/test/Util.Localization.Tests.Integration/Resources/ResourceTypes/Resource2.zh-CN.json @@ -0,0 +1,5 @@ +{ + "Hello": "哈楼", + "World": "世界", + "Hello,{0},{1},World": "哈楼,{0},{1},世界" +} diff --git a/test/Util.Localization.Tests.Integration/Resources/ResourceTypes/Resource2.zh-Hans.json b/test/Util.Localization.Tests.Integration/Resources/ResourceTypes/Resource2.zh-Hans.json new file mode 100644 index 00000000..8588bbee --- /dev/null +++ b/test/Util.Localization.Tests.Integration/Resources/ResourceTypes/Resource2.zh-Hans.json @@ -0,0 +1,4 @@ +{ + "Hello": "哈哈", + "World": "世界" +} diff --git a/test/Util.Localization.Tests.Integration/Resources/ResourceTypes/Resource2.zh.json b/test/Util.Localization.Tests.Integration/Resources/ResourceTypes/Resource2.zh.json new file mode 100644 index 00000000..adfe1e36 --- /dev/null +++ b/test/Util.Localization.Tests.Integration/Resources/ResourceTypes/Resource2.zh.json @@ -0,0 +1,4 @@ +{ + "Hello": "嘿嘿", + "World": "世界" +} diff --git a/test/Util.Localization.Tests.Integration/Resources/ResourceTypes/Resource3.zh-Hans.json b/test/Util.Localization.Tests.Integration/Resources/ResourceTypes/Resource3.zh-Hans.json new file mode 100644 index 00000000..8588bbee --- /dev/null +++ b/test/Util.Localization.Tests.Integration/Resources/ResourceTypes/Resource3.zh-Hans.json @@ -0,0 +1,4 @@ +{ + "Hello": "哈哈", + "World": "世界" +} diff --git a/test/Util.Localization.Tests.Integration/Resources/ResourceTypes/Resource4.Resource41.zh-CN.json b/test/Util.Localization.Tests.Integration/Resources/ResourceTypes/Resource4.Resource41.zh-CN.json new file mode 100644 index 00000000..b2deb534 --- /dev/null +++ b/test/Util.Localization.Tests.Integration/Resources/ResourceTypes/Resource4.Resource41.zh-CN.json @@ -0,0 +1,4 @@ +{ + "Hello": "嘻嘻", + "World": "世界" +} diff --git a/test/Util.Localization.Tests.Integration/Resources/ResourceTypes/Resource4.zh.json b/test/Util.Localization.Tests.Integration/Resources/ResourceTypes/Resource4.zh.json new file mode 100644 index 00000000..adfe1e36 --- /dev/null +++ b/test/Util.Localization.Tests.Integration/Resources/ResourceTypes/Resource4.zh.json @@ -0,0 +1,4 @@ +{ + "Hello": "嘿嘿", + "World": "世界" +} diff --git a/test/Util.Localization.Tests.Integration/Resources/ResourceTypes/Resource5.zh-CN.json b/test/Util.Localization.Tests.Integration/Resources/ResourceTypes/Resource5.zh-CN.json new file mode 100644 index 00000000..a6765098 --- /dev/null +++ b/test/Util.Localization.Tests.Integration/Resources/ResourceTypes/Resource5.zh-CN.json @@ -0,0 +1,4 @@ +{ + "Hello": "哈楼", + "World": "世界" +} diff --git a/test/Util.Localization.Tests.Integration/Resources/ResourceTypes/Resource5.zh-Hans.json b/test/Util.Localization.Tests.Integration/Resources/ResourceTypes/Resource5.zh-Hans.json new file mode 100644 index 00000000..d82d6980 --- /dev/null +++ b/test/Util.Localization.Tests.Integration/Resources/ResourceTypes/Resource5.zh-Hans.json @@ -0,0 +1,4 @@ +{ + "Hello2": "哈楼2", + "World2": "世界2" +} \ No newline at end of file diff --git a/test/Util.Localization.Tests.Integration/Resources/ResourceTypes/Resource5.zh.json b/test/Util.Localization.Tests.Integration/Resources/ResourceTypes/Resource5.zh.json new file mode 100644 index 00000000..97eb2e00 --- /dev/null +++ b/test/Util.Localization.Tests.Integration/Resources/ResourceTypes/Resource5.zh.json @@ -0,0 +1,4 @@ +{ + "Hello3": "哈楼3", + "World3": "世界3" +} \ No newline at end of file diff --git a/test/Util.Localization.Tests.Integration/Resources/zh.json b/test/Util.Localization.Tests.Integration/Resources/zh.json new file mode 100644 index 00000000..58a5d017 --- /dev/null +++ b/test/Util.Localization.Tests.Integration/Resources/zh.json @@ -0,0 +1,4 @@ +{ + "Hello": "呜呜", + "World": "世界" +} diff --git a/test/Util.Localization.Tests.Integration/Startup.cs b/test/Util.Localization.Tests.Integration/Startup.cs new file mode 100644 index 00000000..15e9fc22 --- /dev/null +++ b/test/Util.Localization.Tests.Integration/Startup.cs @@ -0,0 +1,54 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.TestHost; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using Util.Http; +using Xunit.DependencyInjection; +using Xunit.DependencyInjection.Logging; + +namespace Util.Localization { + /// + /// Æô¶¯ÅäÖà + /// + public class Startup { + /// + /// ÅäÖÃÖ÷»ú + /// + public void ConfigureHost( IHostBuilder hostBuilder ) { + hostBuilder.ConfigureDefaults( null ) + .ConfigureWebHostDefaults( webHostBuilder => { + webHostBuilder.UseTestServer() + .Configure( t => { + t.UseRouting(); + t.UseEndpoints( endpoints => { + endpoints.MapControllers(); + } ); + } ); + } ) + .AddUtil( options => { + options.UseJsonLocalization(); + } ); + } + + /// + /// ÅäÖ÷þÎñ + /// + public void ConfigureServices( IServiceCollection services ) { + services.AddControllers(); + services.AddTransient( t => { + var client = new HttpClientService(); + client.SetHttpClient( t.GetService().GetTestClient() ); + return client; + } ); + } + + /// + /// ÅäÖÃÈÕ־Ìṩ³ÌÐò + /// + public void Configure( ILoggerFactory loggerFactory, ITestOutputHelperAccessor accessor ) { + loggerFactory.AddProvider( new XunitTestOutputLoggerProvider( accessor ) ); + } + } +} diff --git a/test/Util.Localization.Tests.Integration/Tests/JsonStringLocalizerFactoryTest.cs b/test/Util.Localization.Tests.Integration/Tests/JsonStringLocalizerFactoryTest.cs new file mode 100644 index 00000000..bc52a1fb --- /dev/null +++ b/test/Util.Localization.Tests.Integration/Tests/JsonStringLocalizerFactoryTest.cs @@ -0,0 +1,110 @@ +using System.Globalization; +using System.Reflection; +using Microsoft.Extensions.Localization; +using Util.Localization.Resources.ResourceTypes; +using Util.Localization.ResourceTypes; +using Xunit; + +namespace Util.Localization.Tests { + /// + /// Json字符串定位器工厂测试 + /// + public class JsonStringLocalizerFactoryTest { + /// + /// Json字符串定位器工厂 + /// + private readonly IStringLocalizerFactory _factory; + + /// + /// 测试初始化 + /// + /// Json字符串定位器工厂 + public JsonStringLocalizerFactoryTest( IStringLocalizerFactory factory ) { + _factory = factory; + } + + /// + /// 测试获取本地化字符串值 - 读取 Resources\ResourceTypes.Resource1.en-US.json + /// + [Fact] + public void Test_1() { + CultureInfo.CurrentUICulture = new CultureInfo( "en-US" ); + var assemblyName = new AssemblyName( GetType().Assembly.FullName ); + var localizer = _factory.Create( "ResourceTypes.Resource1", assemblyName.Name ); + var value = localizer["Hello"]; + Assert.Equal( "hi", value ); + } + + /// + /// 测试获取本地化字符串值 - 读取 Resources\ResourceTypes.Resource1.zh-CN.json + /// + [Fact] + public void Test_2() { + CultureInfo.CurrentUICulture = new CultureInfo( "zh-CN" ); + var assemblyName = new AssemblyName( GetType().Assembly.FullName ); + var localizer = _factory.Create( "ResourceTypes.Resource1", assemblyName.Name ); + var value = localizer["Hello"]; + Assert.Equal( "哈楼", value ); + } + + /// + /// 测试获取本地化字符串值 - 读取 Resources2\ResourceTypes.Resource101.en-US.json + /// + [Fact] + public void Test_3() { + CultureInfo.CurrentUICulture = new CultureInfo( "en-US" ); + var assemblyName = new AssemblyName( typeof( Resource101 ).Assembly.FullName ); + var localizer = _factory.Create( "ResourceTypes.Resource101", assemblyName.Name ); + var value = localizer["Hello"]; + Assert.Equal( "hi", value ); + } + + /// + /// 测试获取本地化字符串值 - 读取 Resources2\ResourceTypes.Resource101.zh-CN.json + /// + [Fact] + public void Test_4() { + CultureInfo.CurrentUICulture = new CultureInfo( "zh-CN" ); + var assemblyName = new AssemblyName( typeof( Resource101 ).Assembly.FullName ); + var localizer = _factory.Create( "ResourceTypes.Resource101", assemblyName.Name ); + var value = localizer["Hello"]; + Assert.Equal( "哈楼", value ); + } + + /// + /// 测试获取本地化字符串值 - 读取 Resources\ResourceTypes\Resource2.en-US.json + /// + [Fact] + public void Test_5() { + CultureInfo.CurrentUICulture = new CultureInfo( "en-US" ); + var assemblyName = new AssemblyName( typeof( Resource2 ).Assembly.FullName ); + var localizer = _factory.Create( "ResourceTypes.Resource2", assemblyName.Name ); + var value = localizer["Hello"]; + Assert.Equal( "hi", value ); + } + + /// + /// 测试获取本地化字符串值 - 读取 Resources\ResourceTypes\Resource2.zh-CN.json + /// + [Fact] + public void Test_6() { + CultureInfo.CurrentUICulture = new CultureInfo( "zh-CN" ); + var assemblyName = new AssemblyName( typeof( Resource2 ).Assembly.FullName ); + var localizer = _factory.Create( "ResourceTypes.Resource2", assemblyName.Name ); + var value = localizer["Hello"]; + Assert.Equal( "哈楼", value ); + } + + /// + /// 测试获取本地化字符串值 - 读取 Resources\zh.json + /// + [Fact] + public void Test_7() { + CultureInfo.CurrentUICulture = new CultureInfo( "zh-CN" ); + var assemblyName = new AssemblyName( GetType().Assembly.FullName ); + var localizer = _factory.Create( null, assemblyName.Name ); + var value = localizer["Hello"]; + Assert.Equal( "呜呜", value ); + } + } +} diff --git a/test/Util.Localization.Tests.Integration/Tests/PathResolverTest.cs b/test/Util.Localization.Tests.Integration/Tests/PathResolverTest.cs new file mode 100644 index 00000000..6537c97c --- /dev/null +++ b/test/Util.Localization.Tests.Integration/Tests/PathResolverTest.cs @@ -0,0 +1,118 @@ +using System.Globalization; +using System.IO; +using Util.Helpers; +using Util.Localization.Json; +using Util.Localization.Resources.ResourceTypes; +using Xunit; +using Xunit.Abstractions; + +namespace Util.Localization.Tests { + /// + /// 路径解析器测试 + /// + public class PathResolverTest { + /// + /// 路径解析器 + /// + private readonly PathResolver _resolver; + /// + /// 输出消息 + /// + private readonly ITestOutputHelper _output; + + /// + /// 初始化路径解析器 + /// + public PathResolverTest( ITestOutputHelper output ) { + _output = output; + _resolver = new PathResolver(); + } + + /// + /// 测试获取根命名空间 - 未设置RootNamespace特性,返回程序集名称 + /// + [Fact] + public void TestGetRootNamespace_AssemblyName() { + var type = typeof(Resource101); + Assert.Equal( "Util.Localization.Resources", _resolver.GetRootNamespace( type.Assembly )); + } + + /// + /// 测试获取根命名空间 - 设置RootNamespace特性,返回特性值 + /// + [Fact] + public void TestGetRootNamespace_RootNamespace() { + var type = typeof( PathResolverTest ); + Assert.Equal( "Util.Localization", _resolver.GetRootNamespace( type.Assembly ) ); + } + + /// + /// 测试获取资源根目录路径 - 未设置ResourceLocation特性,返回传入的资源根路径 + /// + [Fact] + public void TestGetResourcesRootPath_ResourcesPath() { + var type = typeof( PathResolverTest ); + Assert.Equal( "Resources", _resolver.GetResourcesRootPath( type.Assembly, "Resources" ) ); + } + + /// + /// 测试获取资源根目录路径 - 设置ResourceLocation特性,返回特性值 + /// + [Fact] + public void TestGetResourcesRootPath_ResourceLocation() { + var type = typeof( Resource101 ); + Assert.Equal( "Resources2", _resolver.GetResourcesRootPath( type.Assembly, "Resources" ) ); + } + + /// + /// 测试获取资源基名称 - 未设置RootNamespace特性 + /// + [Fact] + public void TestGetResourcesBaseName_1() { + var type = typeof( Resource101 ); + Assert.Equal( "ResourceTypes.Resource101", _resolver.GetResourcesBaseName( type.Assembly, type.FullName ) ); + } + + /// + /// 测试获取资源基名称 - 设置RootNamespace特性 + /// + [Fact] + public void TestGetResourcesBaseName_2() { + var type = typeof( PathResolverTest ); + Assert.Equal( "Tests.PathResolverTest", _resolver.GetResourcesBaseName( type.Assembly, type.FullName ) ); + } + + /// + /// 测试获取Json资源文件绝对路径 + /// + [Fact] + public void TestGetJsonResourcePath() { + var result = Path.Combine( Platform.ApplicationBaseDirectory, "Resources", "Tests.PathResolverTest.zh-CN.json" ); + var path = _resolver.GetJsonResourcePath( "Resources", "Tests.PathResolverTest", new CultureInfo( "zh-CN" ) ); + _output.WriteLine( path ); + Assert.Equal( result,path ); + } + + /// + /// 测试获取Json资源文件绝对路径 - 内部类带+ + /// + [Fact] + public void TestGetJsonResourcePath_InnerClass() { + var result = Path.Combine( Platform.ApplicationBaseDirectory, "Resources", "ResourceTypes.Resource4.Resource41.zh-CN.json" ); + var path = _resolver.GetJsonResourcePath( "Resources", "ResourceTypes.Resource4+Resource41", new CultureInfo( "zh-CN" ) ); + _output.WriteLine( path ); + Assert.Equal( result, path ); + } + + /// + /// 测试获取Json资源文件绝对路径 - 基名称为空 + /// + [Fact] + public void TestGetJsonResourcePath_NullBaseName() { + var result = Path.Combine( Platform.ApplicationBaseDirectory, "Resources", "zh-CN.json" ); + var path = _resolver.GetJsonResourcePath( "Resources", null, new CultureInfo( "zh-CN" ) ); + _output.WriteLine( path ); + Assert.Equal( result, path ); + } + } +} diff --git a/test/Util.Localization.Tests.Integration/Tests/StringLocalizerTest.cs b/test/Util.Localization.Tests.Integration/Tests/StringLocalizerTest.cs new file mode 100644 index 00000000..84900832 --- /dev/null +++ b/test/Util.Localization.Tests.Integration/Tests/StringLocalizerTest.cs @@ -0,0 +1,232 @@ +using System.Globalization; +using System.Linq; +using Microsoft.Extensions.Localization; +using Util.Localization.Resources.ResourceTypes; +using Util.Localization.ResourceTypes; +using Xunit; + +namespace Util.Localization.Tests { + /// + /// Json字符串定位器测试 + /// + public class StringLocalizerTest { + /// + /// Json资源文件字符串定位器1 + /// + private readonly IStringLocalizer _resource1Localizer; + /// + /// Json资源文件字符串定位器101 + /// + private readonly IStringLocalizer _resource101Localizer; + /// + /// Json资源文件字符串定位器2 + /// + private readonly IStringLocalizer _resource2Localizer; + /// + /// Json资源文件字符串定位器102 + /// + private readonly IStringLocalizer _resource102Localizer; + /// + /// Json资源文件字符串定位器3 + /// + private readonly IStringLocalizer _resource3Localizer; + /// + /// Json资源文件字符串定位器4 + /// + private readonly IStringLocalizer _resource4Localizer; + /// + /// Json资源文件字符串定位器41 + /// + private readonly IStringLocalizer _resource41Localizer; + /// + /// Json资源文件字符串定位器5 + /// + private readonly IStringLocalizer _resource5Localizer; + /// + /// Json资源文件字符串定位器 - 非泛型 + /// + private readonly IStringLocalizer _localizer; + /// + /// Json资源文件字符串定位器6 + /// + private readonly IStringLocalizer _resource6Localizer; + + /// + /// 测试初始化 + /// + public StringLocalizerTest( IStringLocalizer resource1Localizer, IStringLocalizer resource101Localizer, + IStringLocalizer resource2Localizer, IStringLocalizer resource102Localizer, + IStringLocalizer resource3Localizer, IStringLocalizer resource4Localizer, + IStringLocalizer resource41Localizer, IStringLocalizer resource5Localizer, + IStringLocalizer localizer, IStringLocalizer resource6Localizer ) { + _resource1Localizer = resource1Localizer; + _resource101Localizer = resource101Localizer; + _resource2Localizer = resource2Localizer; + _resource102Localizer = resource102Localizer; + _resource3Localizer = resource3Localizer; + _resource4Localizer = resource4Localizer; + _resource41Localizer = resource41Localizer; + _resource5Localizer = resource5Localizer; + _localizer = localizer; + _resource6Localizer = resource6Localizer; + } + + /// + /// 测试获取本地化字符串值 - 读取 Resources\ResourceTypes.Resource1.en-US.json + /// + [Fact] + public void Test_1() { + CultureInfo.CurrentUICulture = new CultureInfo( "en-US" ); + var value = _resource1Localizer["Hello"]; + Assert.Equal( "hi", value ); + } + + /// + /// 测试获取本地化字符串值 - 读取 Resources\ResourceTypes.Resource1.zh-CN.json + /// + [Fact] + public void Test_2() { + CultureInfo.CurrentUICulture = new CultureInfo( "zh-CN" ); + var value = _resource1Localizer["Hello"]; + Assert.Equal( "哈楼", value ); + } + + /// + /// 测试获取本地化字符串值 - 读取 Resources2\ResourceTypes.Resource101.en-US.json + /// + [Fact] + public void Test_3() { + CultureInfo.CurrentUICulture = new CultureInfo( "en-US" ); + var value = _resource101Localizer["Hello"]; + Assert.Equal( "hi", value ); + } + + /// + /// 测试获取本地化字符串值 - 读取 Resources2\ResourceTypes.Resource101.zh-CN.json + /// + [Fact] + public void Test_4() { + CultureInfo.CurrentUICulture = new CultureInfo( "zh-CN" ); + var value = _resource101Localizer["Hello"]; + Assert.Equal( "哈楼", value ); + } + + /// + /// 测试获取本地化字符串值 - 读取 Resources\ResourceTypes\Resource2.en-US.json + /// + [Fact] + public void Test_5() { + CultureInfo.CurrentUICulture = new CultureInfo( "en-US" ); + var value = _resource2Localizer["Hello"]; + Assert.Equal( "hi", value ); + } + + /// + /// 测试获取本地化字符串值 - 读取 Resources\ResourceTypes\Resource2.zh-CN.json + /// + [Fact] + public void Test_6() { + CultureInfo.CurrentUICulture = new CultureInfo( "zh-CN" ); + var value = _resource2Localizer["Hello"]; + Assert.Equal( "哈楼", value ); + } + + /// + /// 测试获取本地化字符串值 - 读取 Resources2\ResourceTypes\Resource102.zh-CN.json + /// + [Fact] + public void Test_7() { + CultureInfo.CurrentUICulture = new CultureInfo( "zh-CN" ); + var value = _resource102Localizer["Hello"]; + Assert.Equal( "哈罗", value ); + } + + /// + /// 测试获取本地化字符串值 - 读取 Resources\ResourceTypes\Resource3.zh-Hans.json + /// + [Fact] + public void Test_8() { + CultureInfo.CurrentUICulture = new CultureInfo( "zh-CN" ); + var value = _resource3Localizer["Hello"]; + Assert.Equal( "哈哈", value ); + } + + /// + /// 测试获取本地化字符串值 - 读取 Resources\ResourceTypes\Resource4.zh.json + /// + [Fact] + public void Test_9() { + CultureInfo.CurrentUICulture = new CultureInfo( "zh-CN" ); + var value = _resource4Localizer["Hello"]; + Assert.Equal( "嘿嘿", value ); + } + + /// + /// 测试获取本地化字符串值 - 读取 Resources\ResourceTypes\Resource4.Resource41.zh-CN.json + /// + [Fact] + public void Test_10() { + CultureInfo.CurrentUICulture = new CultureInfo( "zh-CN" ); + var value = _resource41Localizer["Hello"]; + Assert.Equal( "嘻嘻", value ); + } + + /// + /// 测试获取本地化字符串值 - 带参数 - 读取 Resources\ResourceTypes\Resource2.zh-CN.json + /// + [Fact] + public void Test_11() { + CultureInfo.CurrentUICulture = new CultureInfo( "zh-CN" ); + var value = _resource2Localizer["Hello,{0},{1},World", "你", "我"]; + Assert.Equal( "哈楼,你,我,世界", value ); + } + + /// + /// 测试获取本地化字符串值 - 读取 Resources\zh.json + /// + [Fact] + public void Test_12() { + CultureInfo.CurrentUICulture = new CultureInfo( "zh-CN" ); + var value = _localizer["Hello"]; + Assert.Equal( "呜呜", value ); + } + + /// + /// 测试获取本地化字符串值 - 资源6未设置, 读取 Resources\zh.json + /// + [Fact] + public void Test_13() { + CultureInfo.CurrentUICulture = new CultureInfo( "zh-CN" ); + var value = _resource6Localizer["Hello"]; + Assert.Equal( "呜呜", value ); + } + + /// + /// 测试获取全部本地化字符串 - 不包含父区域 + /// + [Fact] + public void TestGetAllStrings_1() { + CultureInfo.CurrentUICulture = new CultureInfo( "zh-CN" ); + var value = _resource5Localizer.GetAllStrings( false ).ToList(); + Assert.Equal( 2, value.Count ); + var resource = value.Find( t => t.Name == "Hello" ); + Assert.Equal( "哈楼", resource?.Value ); + Assert.Equal( "Resources.ResourceTypes.Resource5", resource?.SearchedLocation ); + Assert.False( resource?.ResourceNotFound ); + } + + /// + /// 测试获取全部本地化字符串 - 包含父区域 + /// + [Fact] + public void TestGetAllStrings_2() { + CultureInfo.CurrentUICulture = new CultureInfo( "zh-CN" ); + var value = _resource5Localizer.GetAllStrings( true ).ToList(); + Assert.Equal( 6, value.Count ); + var resource = value.Find( t => t.Name == "Hello3" ); + Assert.Equal( "哈楼3", resource?.Value ); + Assert.Equal( "Resources.ResourceTypes.Resource5", resource?.SearchedLocation ); + Assert.False( resource?.ResourceNotFound ); + } + } +} diff --git a/test/Util.Localization.Tests.Integration/Util.Localization.Tests.Integration.csproj b/test/Util.Localization.Tests.Integration/Util.Localization.Tests.Integration.csproj new file mode 100644 index 00000000..d39de31e --- /dev/null +++ b/test/Util.Localization.Tests.Integration/Util.Localization.Tests.Integration.csproj @@ -0,0 +1,34 @@ + + + + $(NetTargetFramework) + false + Util.Localization + Util.Localization.Startup + + + + + + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + + + \ No newline at end of file diff --git a/test/Util.Logging.Serilog.Tests/LogContextAccessor.cs b/test/Util.Logging.Serilog.Exceptionless.Tests.Integration/LogContextAccessor.cs similarity index 100% rename from test/Util.Logging.Serilog.Tests/LogContextAccessor.cs rename to test/Util.Logging.Serilog.Exceptionless.Tests.Integration/LogContextAccessor.cs diff --git a/test/Util.Logging.Serilog.Exceptionless.Tests/LogTest.cs b/test/Util.Logging.Serilog.Exceptionless.Tests.Integration/LogTest.cs similarity index 97% rename from test/Util.Logging.Serilog.Exceptionless.Tests/LogTest.cs rename to test/Util.Logging.Serilog.Exceptionless.Tests.Integration/LogTest.cs index a692f1cb..050ee2c2 100644 --- a/test/Util.Logging.Serilog.Exceptionless.Tests/LogTest.cs +++ b/test/Util.Logging.Serilog.Exceptionless.Tests.Integration/LogTest.cs @@ -2,10 +2,10 @@ using System; using System.Collections.Generic; using System.Diagnostics; using Util.Helpers; -using Util.Logging.Exceptionless.Tests.Samples; +using Util.Logging.Tests.Samples; using Xunit; -namespace Util.Logging.Serilog.Exceptionless.Tests { +namespace Util.Logging.Tests { /// /// ExceptionLessÈÕ־²Ù×÷²âÊÔ /// diff --git a/test/Util.Logging.Serilog.Tests/Samples/Product.cs b/test/Util.Logging.Serilog.Exceptionless.Tests.Integration/Samples/Product.cs similarity index 100% rename from test/Util.Logging.Serilog.Tests/Samples/Product.cs rename to test/Util.Logging.Serilog.Exceptionless.Tests.Integration/Samples/Product.cs diff --git a/test/Util.Logging.Serilog.Exceptionless.Tests/Startup.cs b/test/Util.Logging.Serilog.Exceptionless.Tests.Integration/Startup.cs similarity index 68% rename from test/Util.Logging.Serilog.Exceptionless.Tests/Startup.cs rename to test/Util.Logging.Serilog.Exceptionless.Tests.Integration/Startup.cs index bfdf9bd5..6299ce04 100644 --- a/test/Util.Logging.Serilog.Exceptionless.Tests/Startup.cs +++ b/test/Util.Logging.Serilog.Exceptionless.Tests.Integration/Startup.cs @@ -1,10 +1,12 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; +using Util.Helpers; +using Util.Logging.Serilog; using Xunit.DependencyInjection; using Xunit.DependencyInjection.Logging; -namespace Util.Logging.Serilog.Exceptionless.Tests { +namespace Util.Logging.Tests { /// /// Æô¶¯ÅäÖà /// @@ -13,7 +15,11 @@ namespace Util.Logging.Serilog.Exceptionless.Tests { /// ÅäÖÃÖ÷»ú /// public void ConfigureHost( IHostBuilder hostBuilder ) { - hostBuilder.ConfigureDefaults( null ); + hostBuilder.ConfigureDefaults( null ) + .ConfigureHostConfiguration( builder => { + Environment.SetDevelopment(); + } ) + .AddUtil( options => options.UseSerilog( t => t.AddExceptionless() ) ); } /// @@ -21,14 +27,13 @@ namespace Util.Logging.Serilog.Exceptionless.Tests { /// public void ConfigureServices( IServiceCollection services ) { services.AddSingleton(); - services.AddUtil( options => options.UseSerilog( t => t.AddExceptionless() ) ); } /// /// ÅäÖÃÈÕ־Ìṩ³ÌÐò /// public void Configure( ILoggerFactory loggerFactory, ITestOutputHelperAccessor accessor ) { - loggerFactory.AddProvider( new XunitTestOutputLoggerProvider( accessor,(s,logLevel) => logLevel >= LogLevel.Trace ) ); + loggerFactory.AddProvider( new XunitTestOutputLoggerProvider( accessor, ( s, logLevel ) => logLevel >= LogLevel.Trace ) ); } } } diff --git a/test/Util.Logging.Serilog.Exceptionless.Tests/Util.Logging.Serilog.Exceptionless.Tests.csproj b/test/Util.Logging.Serilog.Exceptionless.Tests.Integration/Util.Logging.Serilog.Exceptionless.Tests.Integration.csproj similarity index 79% rename from test/Util.Logging.Serilog.Exceptionless.Tests/Util.Logging.Serilog.Exceptionless.Tests.csproj rename to test/Util.Logging.Serilog.Exceptionless.Tests.Integration/Util.Logging.Serilog.Exceptionless.Tests.Integration.csproj index 02c9f2d2..61cb38df 100644 --- a/test/Util.Logging.Serilog.Exceptionless.Tests/Util.Logging.Serilog.Exceptionless.Tests.csproj +++ b/test/Util.Logging.Serilog.Exceptionless.Tests.Integration/Util.Logging.Serilog.Exceptionless.Tests.Integration.csproj @@ -3,19 +3,21 @@ $(NetTargetFramework) false + Util.Logging.Tests + Util.Logging.Tests.Startup - - - - + + + + - + runtime; build; native; contentfiles; analyzers; buildtransitive all - + runtime; build; native; contentfiles; analyzers; buildtransitive all @@ -26,6 +28,9 @@ + + Always + Always diff --git a/test/Util.Logging.Serilog.Exceptionless.Tests.Integration/appsettings.Production.json b/test/Util.Logging.Serilog.Exceptionless.Tests.Integration/appsettings.Production.json new file mode 100644 index 00000000..6977d660 --- /dev/null +++ b/test/Util.Logging.Serilog.Exceptionless.Tests.Integration/appsettings.Production.json @@ -0,0 +1,13 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Trace", + "Microsoft": "Warning" + } + }, + "Exceptionless": { + "ApiKey": "0yYDCrbsgdGZX7PImygwk06KMTf5dNI5opsrKA6x", + "ServerUrl": "http://exceptionless.common/", + "QueueMaxAttempts": 1 + } +} \ No newline at end of file diff --git a/test/Util.Logging.Serilog.Exceptionless.Tests/appsettings.json b/test/Util.Logging.Serilog.Exceptionless.Tests.Integration/appsettings.json similarity index 59% rename from test/Util.Logging.Serilog.Exceptionless.Tests/appsettings.json rename to test/Util.Logging.Serilog.Exceptionless.Tests.Integration/appsettings.json index 5bba1fd9..394ac90a 100644 --- a/test/Util.Logging.Serilog.Exceptionless.Tests/appsettings.json +++ b/test/Util.Logging.Serilog.Exceptionless.Tests.Integration/appsettings.json @@ -6,8 +6,8 @@ } }, "Exceptionless": { - "ApiKey": "I59SQ2gLSMWQNWdhrWReOG5yO5yP0pc7aE7liuta", - "ServerUrl": "http://192.168.31.77/", + "ApiKey": "0yYDCrbsgdGZX7PImygwk06KMTf5dNI5opsrKA6x", + "ServerUrl": "http://exceptionless.a.com/", "QueueMaxAttempts": 1 } } \ No newline at end of file diff --git a/test/Util.Logging.Serilog.Exceptionless.Tests/LogContextAccessor.cs b/test/Util.Logging.Serilog.Tests.Integration/LogContextAccessor.cs similarity index 93% rename from test/Util.Logging.Serilog.Exceptionless.Tests/LogContextAccessor.cs rename to test/Util.Logging.Serilog.Tests.Integration/LogContextAccessor.cs index 49ec6a4a..8862d586 100644 --- a/test/Util.Logging.Serilog.Exceptionless.Tests/LogContextAccessor.cs +++ b/test/Util.Logging.Serilog.Tests.Integration/LogContextAccessor.cs @@ -1,4 +1,4 @@ -namespace Util.Logging.Serilog.Exceptionless.Tests { +namespace Util.Logging.Tests { /// /// 日志上下文访问器 /// diff --git a/test/Util.Logging.Serilog.Tests/LogTest.cs b/test/Util.Logging.Serilog.Tests.Integration/LogTest.cs similarity index 100% rename from test/Util.Logging.Serilog.Tests/LogTest.cs rename to test/Util.Logging.Serilog.Tests.Integration/LogTest.cs diff --git a/test/Util.Logging.Serilog.Exceptionless.Tests/Samples/Product.cs b/test/Util.Logging.Serilog.Tests.Integration/Samples/Product.cs similarity index 88% rename from test/Util.Logging.Serilog.Exceptionless.Tests/Samples/Product.cs rename to test/Util.Logging.Serilog.Tests.Integration/Samples/Product.cs index 613bb37e..f1103458 100644 --- a/test/Util.Logging.Serilog.Exceptionless.Tests/Samples/Product.cs +++ b/test/Util.Logging.Serilog.Tests.Integration/Samples/Product.cs @@ -1,4 +1,4 @@ -namespace Util.Logging.Exceptionless.Tests.Samples { +namespace Util.Logging.Tests.Samples { /// /// 产品 /// diff --git a/test/Util.Logging.Serilog.Tests/Startup.cs b/test/Util.Logging.Serilog.Tests.Integration/Startup.cs similarity index 87% rename from test/Util.Logging.Serilog.Tests/Startup.cs rename to test/Util.Logging.Serilog.Tests.Integration/Startup.cs index 997cdaf5..0bab0911 100644 --- a/test/Util.Logging.Serilog.Tests/Startup.cs +++ b/test/Util.Logging.Serilog.Tests.Integration/Startup.cs @@ -17,13 +17,14 @@ namespace Util.Logging.Tests { /// public void ConfigureHost( IHostBuilder hostBuilder ) { AppDomain.CurrentDomain.ProcessExit += CurrentDomain_ProcessExit; - hostBuilder.ConfigureDefaults( null ); + hostBuilder.ConfigureDefaults( null ) + .AddUtil( options => options.UseSerilog() ); } /// /// ½ø³ÌÍ˳öʱÊͷÅÈÕ־ʵÀý,ÓÃÓڽâ¾öSeqÎ޷¨дÈëµÄÎÊÌâ /// - private void CurrentDomain_ProcessExit( object? sender, EventArgs e ) { + private void CurrentDomain_ProcessExit( object sender, EventArgs e ) { var log = (serilog.Core.Logger)serilog.Log.Logger; log.Dispose(); } @@ -33,7 +34,6 @@ namespace Util.Logging.Tests { /// public void ConfigureServices( IServiceCollection services ) { services.AddSingleton(); - services.AddUtil( options => options.UseSerilog() ); } /// diff --git a/test/Util.Logging.Serilog.Tests/Util.Logging.Serilog.Tests.csproj b/test/Util.Logging.Serilog.Tests.Integration/Util.Logging.Serilog.Tests.Integration.csproj similarity index 86% rename from test/Util.Logging.Serilog.Tests/Util.Logging.Serilog.Tests.csproj rename to test/Util.Logging.Serilog.Tests.Integration/Util.Logging.Serilog.Tests.Integration.csproj index 1d7cbb89..f11ff492 100644 --- a/test/Util.Logging.Serilog.Tests/Util.Logging.Serilog.Tests.csproj +++ b/test/Util.Logging.Serilog.Tests.Integration/Util.Logging.Serilog.Tests.Integration.csproj @@ -8,16 +8,16 @@ - - - - + + + + - + runtime; build; native; contentfiles; analyzers; buildtransitive all - + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/test/Util.Logging.Serilog.Tests/appsettings.json b/test/Util.Logging.Serilog.Tests.Integration/appsettings.json similarity index 100% rename from test/Util.Logging.Serilog.Tests/appsettings.json rename to test/Util.Logging.Serilog.Tests.Integration/appsettings.json diff --git a/test/Util.Logging.Tests/LogTest.Trace .cs b/test/Util.Logging.Tests/LogTest.Trace .cs index 7ef1c87f..6dfc6462 100644 --- a/test/Util.Logging.Tests/LogTest.Trace .cs +++ b/test/Util.Logging.Tests/LogTest.Trace .cs @@ -16,8 +16,7 @@ namespace Util.Logging.Tests { [Fact] public void TestLogTrace_Message_Validate_Empty() { _log.Message( "" ).LogTrace(); - _mockLogger.Verify( t => t.LogTrace( It.IsAny(), It.IsAny(), It.IsAny() ),Times.Never ); - + _mockLogger.Verify( t => t.LogTrace( It.IsAny(), It.IsAny(), It.IsAny() ), Times.Never ); } /// diff --git a/test/Util.Logging.Tests/Util.Logging.Tests.csproj b/test/Util.Logging.Tests/Util.Logging.Tests.csproj index 12c85903..ac75aca2 100644 --- a/test/Util.Logging.Tests/Util.Logging.Tests.csproj +++ b/test/Util.Logging.Tests/Util.Logging.Tests.csproj @@ -6,14 +6,14 @@ - - + + - + runtime; build; native; contentfiles; analyzers; buildtransitive all - + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/test/Util.ObjectMapping.AutoMapper.Tests/Startup.cs b/test/Util.ObjectMapping.AutoMapper.Tests/Startup.cs index d430e3df..277cd382 100644 --- a/test/Util.ObjectMapping.AutoMapper.Tests/Startup.cs +++ b/test/Util.ObjectMapping.AutoMapper.Tests/Startup.cs @@ -1,4 +1,4 @@ -using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using Xunit.DependencyInjection; using Xunit.DependencyInjection.Logging; @@ -9,10 +9,10 @@ namespace Util.ObjectMapping.AutoMapper.Tests { /// public class Startup { /// - /// ÅäÖ÷þÎñ + /// ÅäÖÃÖ÷»ú /// - public void ConfigureServices( IServiceCollection services ) { - services.AddUtil(); + public void ConfigureHost( IHostBuilder hostBuilder ) { + hostBuilder.AddUtil(); } /// diff --git a/test/Util.ObjectMapping.AutoMapper.Tests/Util.ObjectMapping.AutoMapper.Tests.csproj b/test/Util.ObjectMapping.AutoMapper.Tests/Util.ObjectMapping.AutoMapper.Tests.csproj index 1f899a2d..63fdaf81 100644 --- a/test/Util.ObjectMapping.AutoMapper.Tests/Util.ObjectMapping.AutoMapper.Tests.csproj +++ b/test/Util.ObjectMapping.AutoMapper.Tests/Util.ObjectMapping.AutoMapper.Tests.csproj @@ -6,16 +6,16 @@ - - - - + + + + - + runtime; build; native; contentfiles; analyzers; buildtransitive all - + runtime; build; native; contentfiles; analyzers; buildtransitive all @@ -24,7 +24,7 @@ - + diff --git a/test/Util.Templates.Handlebars.Tests/Startup.cs b/test/Util.Templates.Handlebars.Tests/Startup.cs index db2f1701..e4594df8 100644 --- a/test/Util.Templates.Handlebars.Tests/Startup.cs +++ b/test/Util.Templates.Handlebars.Tests/Startup.cs @@ -1,4 +1,4 @@ -using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using Xunit.DependencyInjection; using Xunit.DependencyInjection.Logging; @@ -9,10 +9,10 @@ namespace Util.Templates.Handlebars.Tests { /// public class Startup { /// - /// ÅäÖ÷þÎñ + /// ÅäÖÃÖ÷»ú /// - public void ConfigureServices( IServiceCollection services ) { - services.AddUtil(); + public void ConfigureHost( IHostBuilder hostBuilder ) { + hostBuilder.AddUtil(); } /// diff --git a/test/Util.Templates.Handlebars.Tests/Util.Templates.Handlebars.Tests.csproj b/test/Util.Templates.Handlebars.Tests/Util.Templates.Handlebars.Tests.csproj index 5a8b9905..c8e6e814 100644 --- a/test/Util.Templates.Handlebars.Tests/Util.Templates.Handlebars.Tests.csproj +++ b/test/Util.Templates.Handlebars.Tests/Util.Templates.Handlebars.Tests.csproj @@ -6,16 +6,16 @@ - - - - + + + + - + runtime; build; native; contentfiles; analyzers; buildtransitive all - + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/test/Util.Templates.Razor.Tests/Startup.cs b/test/Util.Templates.Razor.Tests/Startup.cs index 4e439c19..4c859416 100644 --- a/test/Util.Templates.Razor.Tests/Startup.cs +++ b/test/Util.Templates.Razor.Tests/Startup.cs @@ -1,4 +1,4 @@ -using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using Xunit.DependencyInjection; using Xunit.DependencyInjection.Logging; @@ -9,10 +9,10 @@ namespace Util.Templates.Razor.Tests { /// public class Startup { /// - /// ÅäÖ÷þÎñ + /// ÅäÖÃÖ÷»ú /// - public void ConfigureServices( IServiceCollection services ) { - services.AddUtil(); + public void ConfigureHost( IHostBuilder hostBuilder ) { + hostBuilder.AddUtil(); } /// diff --git a/test/Util.Templates.Razor.Tests/Util.Templates.Razor.Tests.csproj b/test/Util.Templates.Razor.Tests/Util.Templates.Razor.Tests.csproj index 0242a92f..5bc30ecd 100644 --- a/test/Util.Templates.Razor.Tests/Util.Templates.Razor.Tests.csproj +++ b/test/Util.Templates.Razor.Tests/Util.Templates.Razor.Tests.csproj @@ -6,16 +6,16 @@ - - - - + + + + - + runtime; build; native; contentfiles; analyzers; buildtransitive all - + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/EntityTypeConfigurations/CustomerConfiguration.cs b/test/Util.TestShare.MySql/EntityTypeConfigurations/CustomerConfiguration.cs similarity index 81% rename from test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/EntityTypeConfigurations/CustomerConfiguration.cs rename to test/Util.TestShare.MySql/EntityTypeConfigurations/CustomerConfiguration.cs index 3b7697d1..15debfab 100644 --- a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/EntityTypeConfigurations/CustomerConfiguration.cs +++ b/test/Util.TestShare.MySql/EntityTypeConfigurations/CustomerConfiguration.cs @@ -1,8 +1,9 @@ using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; -using Util.Data.EntityFrameworkCore.Models; +using Util.Tests.Configs; +using Util.Tests.Models; -namespace Util.Data.EntityFrameworkCore.EntityTypeConfigurations { +namespace Util.Tests.EntityTypeConfigurations { /// /// 客户类型配置 /// @@ -15,13 +16,14 @@ namespace Util.Data.EntityFrameworkCore.EntityTypeConfigurations { ConfigTable( builder ); ConfigId( builder ); ConfigProperties( builder ); + InitData( builder ); } /// /// 配置表 /// private void ConfigTable( EntityTypeBuilder builder ) { - builder.ToTable( "Customer", "Customers" ).HasComment( "客户" ); + builder.ToTable( "Customer" ).HasComment( "客户" ); } /// @@ -52,7 +54,6 @@ namespace Util.Data.EntityFrameworkCore.EntityTypeConfigurations { .HasComment( "性别" ); builder.Property( t => t.Birthday ) .HasColumnName( "Birthday" ) - .HasColumnType( "timestamp" ) .HasComment( "出生日期" ); builder.Property( t => t.Nation ) .HasColumnName( "Nation" ) @@ -65,18 +66,29 @@ namespace Util.Data.EntityFrameworkCore.EntityTypeConfigurations { .HasComment( "电子邮件" ); builder.Property( t => t.CreationTime ) .HasColumnName( "CreationTime" ) - .HasColumnType( "timestamp" ) .HasComment( "创建时间" ); builder.Property( t => t.CreatorId ) .HasColumnName( "CreatorId" ) .HasComment( "创建人" ); builder.Property( t => t.LastModificationTime ) .HasColumnName( "LastModificationTime" ) - .HasColumnType( "timestamp" ) .HasComment( "最后修改时间" ); builder.Property( t => t.LastModifierId ) .HasColumnName( "LastModifierId" ) .HasComment( "最后修改人" ); + builder.Property( t => t.IsDeleted ) + .HasDefaultValue( false ); + } + + /// + /// 初始化数据 + /// + private void InitData( EntityTypeBuilder builder ) { + var customer = new Customer( 1 ) { + Code = TestConfig.Value, + Birthday = TestConfig.DateTimeValue + }; + builder.HasData( customer ); } } } \ No newline at end of file diff --git a/test/Util.TestShare.MySql/EntityTypeConfigurations/OperationLogConfiguration.cs b/test/Util.TestShare.MySql/EntityTypeConfigurations/OperationLogConfiguration.cs new file mode 100644 index 00000000..cd5bbb55 --- /dev/null +++ b/test/Util.TestShare.MySql/EntityTypeConfigurations/OperationLogConfiguration.cs @@ -0,0 +1,55 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; +using Util.Tests.Models; + +namespace Util.Tests.EntityTypeConfigurations { + /// + /// 操作日志类型配置 + /// + public class OperationLogConfiguration : IEntityTypeConfiguration { + /// + /// 配置 + /// + /// 实体类型生成器 + public void Configure( EntityTypeBuilder builder ) { + ConfigTable( builder ); + ConfigId( builder ); + ConfigProperties( builder ); + } + + /// + /// 配置表 + /// + private void ConfigTable( EntityTypeBuilder builder ) { + builder.ToTable( "OperationLog" ).HasComment( "操作日志" ); + } + + /// + /// 配置标识 + /// + private void ConfigId( EntityTypeBuilder builder ) { + builder.Property( t => t.Id ) + .HasColumnName( "LogId" ) + .HasComment( "操作标识" ) + .ValueGeneratedOnAdd(); + } + + /// + /// 配置属性 + /// + private void ConfigProperties( EntityTypeBuilder builder ) { + builder.Property( t => t.LogName ) + .HasColumnName( "LogName" ) + .HasComment( "日志名称" ); + builder.Property( t => t.OperationTime ) + .HasColumnName( "OperationTime" ) + .HasComment( "操作时间" ); + builder.Property( t => t.Caption ) + .HasColumnName( "Caption" ) + .HasComment( "标题" ); + builder.Property( t => t.Content ) + .HasColumnName( "Content" ) + .HasComment( "内容" ); + } + } +} \ No newline at end of file diff --git a/test/Util.TestShare.MySql/EntityTypeConfigurations/OrderConfiguration.cs b/test/Util.TestShare.MySql/EntityTypeConfigurations/OrderConfiguration.cs new file mode 100644 index 00000000..20f9a804 --- /dev/null +++ b/test/Util.TestShare.MySql/EntityTypeConfigurations/OrderConfiguration.cs @@ -0,0 +1,65 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; +using Util.Tests.Configs; +using Util.Tests.Models; + +namespace Util.Tests.EntityTypeConfigurations { + /// + /// 订单类型配置 + /// + public class OrderConfiguration : IEntityTypeConfiguration { + /// + /// 配置 + /// + /// 实体类型生成器 + public void Configure( EntityTypeBuilder builder ) { + ConfigTable( builder ); + ConfigId( builder ); + ConfigProperties( builder ); + } + + /// + /// 配置表 + /// + private void ConfigTable( EntityTypeBuilder builder ) { + builder.ToTable( "Order" ).HasComment( "订单" ); + } + + /// + /// 配置标识 + /// + private void ConfigId( EntityTypeBuilder builder ) { + builder.Property( t => t.Id ) + .HasMaxLength( 50 ) + .HasColumnName( "OrderId" ) + .HasComment( "订单标识" ); + } + + /// + /// 配置属性 + /// + private void ConfigProperties( EntityTypeBuilder builder ) { + builder.Property( t => t.CustomerId ) + .HasColumnName( "CustomerId" ) + .HasComment( "客户标识" ); + builder.Property( t => t.CustomerName ) + .HasColumnName( "CustomerName" ) + .HasComment( "客户名称" ); + builder.Property( t => t.Amount ) + .HasColumnName( "Amount" ) + .HasComment( "金额" ) + .HasPrecision(15,2) + .HasDefaultValue(0); + builder.Property( t => t.PlaceOrderTime ) + .HasColumnName( "PlaceOrderTime" ) + .HasComment( "下单时间" ) + .HasDefaultValue( TestConfig.DateTimeValue ); + builder.Property( t => t.State ) + .HasColumnName( "State" ) + .HasComment( "订单状态" ) + .HasDefaultValue( 0 ); + builder.Property( t => t.IsDeleted ) + .HasDefaultValue( false ); + } + } +} \ No newline at end of file diff --git a/test/Util.TestShare.MySql/EntityTypeConfigurations/OrderItemConfiguration.cs b/test/Util.TestShare.MySql/EntityTypeConfigurations/OrderItemConfiguration.cs new file mode 100644 index 00000000..478138a2 --- /dev/null +++ b/test/Util.TestShare.MySql/EntityTypeConfigurations/OrderItemConfiguration.cs @@ -0,0 +1,70 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; +using Util.Tests.Models; + +namespace Util.Tests.EntityTypeConfigurations { + /// + /// 订单明细类型配置 + /// + public class OrderItemConfiguration : IEntityTypeConfiguration { + /// + /// 配置 + /// + /// 实体类型生成器 + public void Configure( EntityTypeBuilder builder ) { + ConfigTable( builder ); + ConfigId( builder ); + ConfigProperties( builder ); + ConfigAssociations( builder ); + } + + /// + /// 配置表 + /// + private void ConfigTable( EntityTypeBuilder builder ) { + builder.ToTable( "OrderItem" ).HasComment( "订单明细" ); + } + + /// + /// 配置标识 + /// + private void ConfigId( EntityTypeBuilder builder ) { + builder.Property( t => t.Id ) + .HasColumnName( "OrderItemId" ) + .HasComment( "订单明细标识" ); + } + + /// + /// 配置属性 + /// + private void ConfigProperties( EntityTypeBuilder builder ) { + builder.Property( t => t.OrderId ) + .HasColumnName( "OrderId" ) + .HasMaxLength( 50 ) + .HasComment( "订单标识" ); + builder.Property( t => t.ProductId ) + .HasColumnName( "ProductId" ) + .HasComment( "产品标识" ); + builder.Property( t => t.ProductName ) + .HasColumnName( "ProductName" ) + .HasComment( "产品名称" ); + builder.Property( t => t.Price ) + .HasColumnName( "Price" ) + .HasComment( "单价" ) + .HasPrecision(12,2); + builder.Property( t => t.Quantity ) + .HasColumnName( "Quantity" ) + .HasComment( "数量" ) + .HasDefaultValue( 1 ); + } + + /// + /// 映射导航属性 + /// + private void ConfigAssociations( EntityTypeBuilder builder ) { + builder.HasOne( t => t.Order ) + .WithMany( t => t.OrderItems ) + .HasForeignKey( t => t.OrderId ); + } + } +} \ No newline at end of file diff --git a/test/Util.TestShare.MySql/EntityTypeConfigurations/PostConfiguration.cs b/test/Util.TestShare.MySql/EntityTypeConfigurations/PostConfiguration.cs new file mode 100644 index 00000000..2fa46dd8 --- /dev/null +++ b/test/Util.TestShare.MySql/EntityTypeConfigurations/PostConfiguration.cs @@ -0,0 +1,63 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; +using Util.Tests.Models; + +namespace Util.Tests.EntityTypeConfigurations { + /// + /// 贴子类型配置 + /// + public class PostConfiguration : IEntityTypeConfiguration { + /// + /// 配置 + /// + /// 实体类型生成器 + public void Configure( EntityTypeBuilder builder ) { + ConfigTable( builder ); + ConfigId( builder ); + ConfigProperties( builder ); + } + + /// + /// 配置表 + /// + private void ConfigTable( EntityTypeBuilder builder ) { + builder.ToTable( "Post" ).HasComment( "贴子" ); + } + + /// + /// 配置标识 + /// + private void ConfigId( EntityTypeBuilder builder ) { + builder.Property( t => t.Id ) + .HasColumnName( "PostId" ) + .HasComment( "贴子标识" ); + } + + /// + /// 配置属性 + /// + private void ConfigProperties( EntityTypeBuilder builder ) { + builder.Property( t => t.Title ) + .HasColumnName( "Title" ) + .HasComment( "标题" ); + builder.Property( t => t.Content ) + .HasColumnName( "Content" ) + .HasComment( "内容" ); + builder.Property( t => t.CreationTime ) + .HasColumnName( "CreationTime" ) + .HasComment( "创建时间" ); + builder.Property( t => t.CreatorId ) + .HasColumnName( "CreatorId" ) + .HasComment( "创建人" ); + builder.Property( t => t.LastModificationTime ) + .HasColumnName( "LastModificationTime" ) + .HasComment( "最后修改时间" ); + builder.Property( t => t.LastModifierId ) + .HasColumnName( "LastModifierId" ) + .HasComment( "最后修改人" ); + builder.HasMany( t => t.Tags ) + .WithMany( t => t.Posts ) + .UsingEntity( t => t.ToTable( "PostTag2" ) ); + } + } +} \ No newline at end of file diff --git a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/EntityTypeConfigurations/ProductConfiguration.cs b/test/Util.TestShare.MySql/EntityTypeConfigurations/ProductConfiguration.cs similarity index 62% rename from test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/EntityTypeConfigurations/ProductConfiguration.cs rename to test/Util.TestShare.MySql/EntityTypeConfigurations/ProductConfiguration.cs index 711b0a32..a062b792 100644 --- a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/EntityTypeConfigurations/ProductConfiguration.cs +++ b/test/Util.TestShare.MySql/EntityTypeConfigurations/ProductConfiguration.cs @@ -1,8 +1,9 @@ using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; -using Util.Data.EntityFrameworkCore.Models; +using Util.Tests.Configs; +using Util.Tests.Models; -namespace Util.Data.EntityFrameworkCore.EntityTypeConfigurations { +namespace Util.Tests.EntityTypeConfigurations { /// /// 产品类型配置 /// @@ -15,13 +16,14 @@ namespace Util.Data.EntityFrameworkCore.EntityTypeConfigurations { ConfigTable( builder ); ConfigId( builder ); ConfigProperties( builder ); + InitData( builder ); } /// /// 配置表 /// private void ConfigTable( EntityTypeBuilder builder ) { - builder.ToTable( "Product", "Products" ).HasComment( "产品" ); + builder.ToTable( "Product" ).HasComment( "产品" ); } /// @@ -46,27 +48,55 @@ namespace Util.Data.EntityFrameworkCore.EntityTypeConfigurations { builder.Property( t => t.Price ) .HasColumnName( "Price" ) .HasComment( "价格" ) - .HasPrecision( 12, 2 ); ; + .HasDefaultValue( 0 ) + .HasPrecision( 12, 2 ); + builder.Property( t => t.IntPrice ) + .HasColumnName( "IntPrice" ) + .HasComment( "价格" ) + .HasDefaultValue( 0 ); + builder.Property( t => t.LongPrice ) + .HasColumnName( "LongPrice" ) + .HasComment( "价格" ) + .HasDefaultValue( 0 ); + builder.Property( t => t.FloatPrice ) + .HasColumnName( "FloatPrice" ) + .HasComment( "价格" ) + .HasDefaultValue( 0 ); builder.Property( t => t.Description ) .HasColumnName( "Description" ) .HasComment( "描述" ); builder.Property( t => t.Enabled ) .HasColumnName( "Enabled" ) + .HasDefaultValue( TestConfig.BoolValue ) .HasComment( "启用" ); builder.Property( t => t.CreationTime ) .HasColumnName( "CreationTime" ) - .HasColumnType( "timestamp" ) .HasComment( "创建时间" ); builder.Property( t => t.CreatorId ) .HasColumnName( "CreatorId" ) .HasComment( "创建人" ); builder.Property( t => t.LastModificationTime ) .HasColumnName( "LastModificationTime" ) - .HasColumnType( "timestamp" ) .HasComment( "最后修改时间" ); builder.Property( t => t.LastModifierId ) .HasColumnName( "LastModifierId" ) .HasComment( "最后修改人" ); + builder.Property( t => t.IsDeleted ) + .HasDefaultValue( false ); + } + + /// + /// 初始化数据 + /// + private void InitData( EntityTypeBuilder builder ) { + var product = new Product( TestConfig.Id ) { + Code = TestConfig.Value, + Price = TestConfig.DecimalValue, + IntPrice = TestConfig.IntValue, + LongPrice = TestConfig.LongValue, + FloatPrice = TestConfig.FloatValue + }; + builder.HasData( product ); } } } \ No newline at end of file diff --git a/test/Util.TestShare.MySql/EntityTypeConfigurations/TagConfiguration.cs b/test/Util.TestShare.MySql/EntityTypeConfigurations/TagConfiguration.cs new file mode 100644 index 00000000..12956262 --- /dev/null +++ b/test/Util.TestShare.MySql/EntityTypeConfigurations/TagConfiguration.cs @@ -0,0 +1,57 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; +using Util.Tests.Models; + +namespace Util.Tests.EntityTypeConfigurations { + /// + /// 标签类型配置 + /// + public class TagConfiguration : IEntityTypeConfiguration { + /// + /// 配置 + /// + /// 实体类型生成器 + public void Configure( EntityTypeBuilder builder ) { + ConfigTable( builder ); + ConfigId( builder ); + ConfigProperties( builder ); + } + + /// + /// 配置表 + /// + private void ConfigTable( EntityTypeBuilder builder ) { + builder.ToTable( "Tag" ).HasComment( "标签" ); + } + + /// + /// 配置标识 + /// + private void ConfigId( EntityTypeBuilder builder ) { + builder.Property( t => t.Id ) + .HasColumnName( "TagId" ) + .HasComment( "标签标识" ); + } + + /// + /// 配置属性 + /// + private void ConfigProperties( EntityTypeBuilder builder ) { + builder.Property( t => t.Name ) + .HasColumnName( "Name" ) + .HasComment( "标签名称" ); + builder.Property( t => t.CreationTime ) + .HasColumnName( "CreationTime" ) + .HasComment( "创建时间" ); + builder.Property( t => t.CreatorId ) + .HasColumnName( "CreatorId" ) + .HasComment( "创建人" ); + builder.Property( t => t.LastModificationTime ) + .HasColumnName( "LastModificationTime" ) + .HasComment( "最后修改时间" ); + builder.Property( t => t.LastModifierId ) + .HasColumnName( "LastModifierId" ) + .HasComment( "最后修改人" ); + } + } +} \ No newline at end of file diff --git a/test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/Repositories/CustomerRepository.cs b/test/Util.TestShare.MySql/Repositories/CustomerRepository.cs similarity index 62% rename from test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/Repositories/CustomerRepository.cs rename to test/Util.TestShare.MySql/Repositories/CustomerRepository.cs index b7a39749..780d3b12 100644 --- a/test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/Repositories/CustomerRepository.cs +++ b/test/Util.TestShare.MySql/Repositories/CustomerRepository.cs @@ -1,8 +1,8 @@ -using Util.Applications.Models; -using Util.Applications.UnitOfWorks; using Util.Data.EntityFrameworkCore; +using Util.Tests.Models; +using Util.Tests.UnitOfWorks; -namespace Util.Applications.Repositories { +namespace Util.Tests.Repositories { /// /// 客户仓储 /// @@ -11,7 +11,7 @@ namespace Util.Applications.Repositories { /// 初始化客户仓储 /// /// 工作单元 - public CustomerRepository( ISqlServerUnitOfWork unitOfWork ) : base( unitOfWork ) { + public CustomerRepository( ITestUnitOfWork unitOfWork ) : base( unitOfWork ) { } } } \ No newline at end of file diff --git a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Repositories/OperationLogRepository.cs b/test/Util.TestShare.MySql/Repositories/OperationLogRepository.cs similarity index 57% rename from test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Repositories/OperationLogRepository.cs rename to test/Util.TestShare.MySql/Repositories/OperationLogRepository.cs index a3a8ec15..75c9ab91 100644 --- a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Repositories/OperationLogRepository.cs +++ b/test/Util.TestShare.MySql/Repositories/OperationLogRepository.cs @@ -1,7 +1,8 @@ -using Util.Data.EntityFrameworkCore.Models; -using Util.Data.EntityFrameworkCore.UnitOfWorks; +using Util.Data.EntityFrameworkCore; +using Util.Tests.Models; +using Util.Tests.UnitOfWorks; -namespace Util.Data.EntityFrameworkCore.Repositories { +namespace Util.Tests.Repositories { /// /// 操作日志仓储 /// @@ -10,7 +11,7 @@ namespace Util.Data.EntityFrameworkCore.Repositories { /// 初始化操作日志仓储 /// /// 工作单元 - public OperationLogRepository( IPgSqlUnitOfWork unitOfWork ) : base( unitOfWork ) { + public OperationLogRepository( ITestUnitOfWork unitOfWork ) : base( unitOfWork ) { } } } \ No newline at end of file diff --git a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Repositories/OrderRepository.cs b/test/Util.TestShare.MySql/Repositories/OrderRepository.cs similarity index 55% rename from test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Repositories/OrderRepository.cs rename to test/Util.TestShare.MySql/Repositories/OrderRepository.cs index d9eb942a..0ba4d0c4 100644 --- a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Repositories/OrderRepository.cs +++ b/test/Util.TestShare.MySql/Repositories/OrderRepository.cs @@ -1,7 +1,8 @@ -using Util.Data.EntityFrameworkCore.Models; -using Util.Data.EntityFrameworkCore.UnitOfWorks; +using Util.Data.EntityFrameworkCore; +using Util.Tests.Models; +using Util.Tests.UnitOfWorks; -namespace Util.Data.EntityFrameworkCore.Repositories { +namespace Util.Tests.Repositories { /// /// 订单仓储 /// @@ -10,7 +11,7 @@ namespace Util.Data.EntityFrameworkCore.Repositories { /// 初始化订单仓储 /// /// 工作单元 - public OrderRepository( IPgSqlUnitOfWork unitOfWork ) : base( unitOfWork ) { + public OrderRepository( ITestUnitOfWork unitOfWork ) : base( unitOfWork ) { } } } \ No newline at end of file diff --git a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Repositories/PostRepository.cs b/test/Util.TestShare.MySql/Repositories/PostRepository.cs similarity index 55% rename from test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Repositories/PostRepository.cs rename to test/Util.TestShare.MySql/Repositories/PostRepository.cs index 8304ab67..a57bbb67 100644 --- a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Repositories/PostRepository.cs +++ b/test/Util.TestShare.MySql/Repositories/PostRepository.cs @@ -1,7 +1,8 @@ -using Util.Data.EntityFrameworkCore.Models; -using Util.Data.EntityFrameworkCore.UnitOfWorks; +using Util.Data.EntityFrameworkCore; +using Util.Tests.Models; +using Util.Tests.UnitOfWorks; -namespace Util.Data.EntityFrameworkCore.Repositories { +namespace Util.Tests.Repositories { /// /// 贴子仓储 /// @@ -10,7 +11,7 @@ namespace Util.Data.EntityFrameworkCore.Repositories { /// 初始化贴子仓储 /// /// 工作单元 - public PostRepository( IPgSqlUnitOfWork unitOfWork ) : base( unitOfWork ) { + public PostRepository( ITestUnitOfWork unitOfWork ) : base( unitOfWork ) { } } } \ No newline at end of file diff --git a/test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/Repositories/ProductRepository.cs b/test/Util.TestShare.MySql/Repositories/ProductRepository.cs similarity index 73% rename from test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/Repositories/ProductRepository.cs rename to test/Util.TestShare.MySql/Repositories/ProductRepository.cs index 2a10557e..bdcb3988 100644 --- a/test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/Repositories/ProductRepository.cs +++ b/test/Util.TestShare.MySql/Repositories/ProductRepository.cs @@ -1,8 +1,8 @@ -using Util.Applications.Models; -using Util.Applications.UnitOfWorks; using Util.Data.EntityFrameworkCore; +using Util.Tests.Models; +using Util.Tests.UnitOfWorks; -namespace Util.Applications.Repositories { +namespace Util.Tests.Repositories { /// /// 产品仓储 /// @@ -11,7 +11,7 @@ namespace Util.Applications.Repositories { /// 初始化产品仓储 /// /// 工作单元 - public ProductRepository( ISqlServerUnitOfWork unitOfWork ) : base( unitOfWork ) { + public ProductRepository( ITestUnitOfWork unitOfWork ) : base( unitOfWork ) { } /// diff --git a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Repositories/TagRepository.cs b/test/Util.TestShare.MySql/Repositories/TagRepository.cs similarity index 55% rename from test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Repositories/TagRepository.cs rename to test/Util.TestShare.MySql/Repositories/TagRepository.cs index 20c35cbd..25d00508 100644 --- a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Repositories/TagRepository.cs +++ b/test/Util.TestShare.MySql/Repositories/TagRepository.cs @@ -1,7 +1,8 @@ -using Util.Data.EntityFrameworkCore.Models; -using Util.Data.EntityFrameworkCore.UnitOfWorks; +using Util.Data.EntityFrameworkCore; +using Util.Tests.Models; +using Util.Tests.UnitOfWorks; -namespace Util.Data.EntityFrameworkCore.Repositories { +namespace Util.Tests.Repositories { /// /// 标签仓储 /// @@ -10,7 +11,7 @@ namespace Util.Data.EntityFrameworkCore.Repositories { /// 初始化标签仓储 /// /// 工作单元 - public TagRepository( IPgSqlUnitOfWork unitOfWork ) : base( unitOfWork ) { + public TagRepository( ITestUnitOfWork unitOfWork ) : base( unitOfWork ) { } } } \ No newline at end of file diff --git a/test/Util.TestShare.MySql/UnitOfWorks/MySqlUnitOfWork.cs b/test/Util.TestShare.MySql/UnitOfWorks/MySqlUnitOfWork.cs new file mode 100644 index 00000000..1c38e924 --- /dev/null +++ b/test/Util.TestShare.MySql/UnitOfWorks/MySqlUnitOfWork.cs @@ -0,0 +1,26 @@ +using System; +using Microsoft.EntityFrameworkCore; +using Util.Data.EntityFrameworkCore; +using Util.Sessions; + +namespace Util.Tests.UnitOfWorks { + /// + /// MySql工作单元 + /// + public class MySqlUnitOfWork : MySqlUnitOfWorkBase, ITestUnitOfWork { + /// + /// 初始化工作单元 + /// + /// 服务提供器 + /// 配置项 + public MySqlUnitOfWork( IServiceProvider serviceProvider ,DbContextOptions options) : base( serviceProvider, options ) { + } + + /// + /// 设置用户会话 + /// + public void SetSession( ISession session ) { + Session = session; + } + } +} \ No newline at end of file diff --git a/test/Util.TestShare.MySql/Util.TestShare.MySql.csproj b/test/Util.TestShare.MySql/Util.TestShare.MySql.csproj new file mode 100644 index 00000000..6782a3a7 --- /dev/null +++ b/test/Util.TestShare.MySql/Util.TestShare.MySql.csproj @@ -0,0 +1,13 @@ + + + + $(NetTargetFramework) + false + Util.Tests + + + + + + + \ No newline at end of file diff --git a/test/Util.TestShare.Oracle/EntityTypeConfigurations/CustomerConfiguration.cs b/test/Util.TestShare.Oracle/EntityTypeConfigurations/CustomerConfiguration.cs new file mode 100644 index 00000000..5b1135c4 --- /dev/null +++ b/test/Util.TestShare.Oracle/EntityTypeConfigurations/CustomerConfiguration.cs @@ -0,0 +1,94 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; +using Util.Tests.Configs; +using Util.Tests.Models; + +namespace Util.Tests.EntityTypeConfigurations { + /// + /// 客户类型配置 + /// + public class CustomerConfiguration : IEntityTypeConfiguration { + /// + /// 配置 + /// + /// 实体类型生成器 + public void Configure( EntityTypeBuilder builder ) { + ConfigTable( builder ); + ConfigId( builder ); + ConfigProperties( builder ); + //InitData( builder ); + } + + /// + /// 配置表 + /// + private void ConfigTable( EntityTypeBuilder builder ) { + builder.ToTable( "Customer" ).HasComment( "客户" ); + } + + /// + /// 配置标识 + /// + private void ConfigId( EntityTypeBuilder builder ) { + builder.Property( t => t.Id ) + .HasColumnName( "CustomerId" ) + .HasComment( "客户标识" ) + .ValueGeneratedOnAdd(); + } + + /// + /// 配置属性 + /// + private void ConfigProperties( EntityTypeBuilder builder ) { + builder.Property( t => t.Code ) + .HasColumnName( "Code" ) + .HasComment( "编码" ); + builder.Property( t => t.Name ) + .HasColumnName( "Name" ) + .HasComment( "姓名" ); + builder.Property( t => t.Nickname ) + .HasColumnName( "Nickname" ) + .HasComment( "昵称" ); + builder.Property( t => t.Gender ) + .HasColumnName( "Gender" ) + .HasComment( "性别" ); + builder.Property( t => t.Birthday ) + .HasColumnName( "Birthday" ) + .HasComment( "出生日期" ); + builder.Property( t => t.Nation ) + .HasColumnName( "Nation" ) + .HasComment( "民族" ); + builder.Property( t => t.Phone ) + .HasColumnName( "Phone" ) + .HasComment( "手机号" ); + builder.Property( t => t.Email ) + .HasColumnName( "Email" ) + .HasComment( "电子邮件" ); + builder.Property( t => t.CreationTime ) + .HasColumnName( "CreationTime" ) + .HasComment( "创建时间" ); + builder.Property( t => t.CreatorId ) + .HasColumnName( "CreatorId" ) + .HasComment( "创建人" ); + builder.Property( t => t.LastModificationTime ) + .HasColumnName( "LastModificationTime" ) + .HasComment( "最后修改时间" ); + builder.Property( t => t.LastModifierId ) + .HasColumnName( "LastModifierId" ) + .HasComment( "最后修改人" ); + builder.Property( t => t.IsDeleted ) + .HasDefaultValue( false ); + } + + /// + /// 初始化数据 + /// + private void InitData( EntityTypeBuilder builder ) { + var customer = new Customer( 1 ) { + Code = TestConfig.Value, + Birthday = TestConfig.DateTimeValue + }; + builder.HasData( customer ); + } + } +} \ No newline at end of file diff --git a/test/Util.TestShare.Oracle/EntityTypeConfigurations/OperationLogConfiguration.cs b/test/Util.TestShare.Oracle/EntityTypeConfigurations/OperationLogConfiguration.cs new file mode 100644 index 00000000..cd5bbb55 --- /dev/null +++ b/test/Util.TestShare.Oracle/EntityTypeConfigurations/OperationLogConfiguration.cs @@ -0,0 +1,55 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; +using Util.Tests.Models; + +namespace Util.Tests.EntityTypeConfigurations { + /// + /// 操作日志类型配置 + /// + public class OperationLogConfiguration : IEntityTypeConfiguration { + /// + /// 配置 + /// + /// 实体类型生成器 + public void Configure( EntityTypeBuilder builder ) { + ConfigTable( builder ); + ConfigId( builder ); + ConfigProperties( builder ); + } + + /// + /// 配置表 + /// + private void ConfigTable( EntityTypeBuilder builder ) { + builder.ToTable( "OperationLog" ).HasComment( "操作日志" ); + } + + /// + /// 配置标识 + /// + private void ConfigId( EntityTypeBuilder builder ) { + builder.Property( t => t.Id ) + .HasColumnName( "LogId" ) + .HasComment( "操作标识" ) + .ValueGeneratedOnAdd(); + } + + /// + /// 配置属性 + /// + private void ConfigProperties( EntityTypeBuilder builder ) { + builder.Property( t => t.LogName ) + .HasColumnName( "LogName" ) + .HasComment( "日志名称" ); + builder.Property( t => t.OperationTime ) + .HasColumnName( "OperationTime" ) + .HasComment( "操作时间" ); + builder.Property( t => t.Caption ) + .HasColumnName( "Caption" ) + .HasComment( "标题" ); + builder.Property( t => t.Content ) + .HasColumnName( "Content" ) + .HasComment( "内容" ); + } + } +} \ No newline at end of file diff --git a/test/Util.TestShare.Oracle/EntityTypeConfigurations/OrderConfiguration.cs b/test/Util.TestShare.Oracle/EntityTypeConfigurations/OrderConfiguration.cs new file mode 100644 index 00000000..20f9a804 --- /dev/null +++ b/test/Util.TestShare.Oracle/EntityTypeConfigurations/OrderConfiguration.cs @@ -0,0 +1,65 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; +using Util.Tests.Configs; +using Util.Tests.Models; + +namespace Util.Tests.EntityTypeConfigurations { + /// + /// 订单类型配置 + /// + public class OrderConfiguration : IEntityTypeConfiguration { + /// + /// 配置 + /// + /// 实体类型生成器 + public void Configure( EntityTypeBuilder builder ) { + ConfigTable( builder ); + ConfigId( builder ); + ConfigProperties( builder ); + } + + /// + /// 配置表 + /// + private void ConfigTable( EntityTypeBuilder builder ) { + builder.ToTable( "Order" ).HasComment( "订单" ); + } + + /// + /// 配置标识 + /// + private void ConfigId( EntityTypeBuilder builder ) { + builder.Property( t => t.Id ) + .HasMaxLength( 50 ) + .HasColumnName( "OrderId" ) + .HasComment( "订单标识" ); + } + + /// + /// 配置属性 + /// + private void ConfigProperties( EntityTypeBuilder builder ) { + builder.Property( t => t.CustomerId ) + .HasColumnName( "CustomerId" ) + .HasComment( "客户标识" ); + builder.Property( t => t.CustomerName ) + .HasColumnName( "CustomerName" ) + .HasComment( "客户名称" ); + builder.Property( t => t.Amount ) + .HasColumnName( "Amount" ) + .HasComment( "金额" ) + .HasPrecision(15,2) + .HasDefaultValue(0); + builder.Property( t => t.PlaceOrderTime ) + .HasColumnName( "PlaceOrderTime" ) + .HasComment( "下单时间" ) + .HasDefaultValue( TestConfig.DateTimeValue ); + builder.Property( t => t.State ) + .HasColumnName( "State" ) + .HasComment( "订单状态" ) + .HasDefaultValue( 0 ); + builder.Property( t => t.IsDeleted ) + .HasDefaultValue( false ); + } + } +} \ No newline at end of file diff --git a/test/Util.TestShare.Oracle/EntityTypeConfigurations/OrderItemConfiguration.cs b/test/Util.TestShare.Oracle/EntityTypeConfigurations/OrderItemConfiguration.cs new file mode 100644 index 00000000..478138a2 --- /dev/null +++ b/test/Util.TestShare.Oracle/EntityTypeConfigurations/OrderItemConfiguration.cs @@ -0,0 +1,70 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; +using Util.Tests.Models; + +namespace Util.Tests.EntityTypeConfigurations { + /// + /// 订单明细类型配置 + /// + public class OrderItemConfiguration : IEntityTypeConfiguration { + /// + /// 配置 + /// + /// 实体类型生成器 + public void Configure( EntityTypeBuilder builder ) { + ConfigTable( builder ); + ConfigId( builder ); + ConfigProperties( builder ); + ConfigAssociations( builder ); + } + + /// + /// 配置表 + /// + private void ConfigTable( EntityTypeBuilder builder ) { + builder.ToTable( "OrderItem" ).HasComment( "订单明细" ); + } + + /// + /// 配置标识 + /// + private void ConfigId( EntityTypeBuilder builder ) { + builder.Property( t => t.Id ) + .HasColumnName( "OrderItemId" ) + .HasComment( "订单明细标识" ); + } + + /// + /// 配置属性 + /// + private void ConfigProperties( EntityTypeBuilder builder ) { + builder.Property( t => t.OrderId ) + .HasColumnName( "OrderId" ) + .HasMaxLength( 50 ) + .HasComment( "订单标识" ); + builder.Property( t => t.ProductId ) + .HasColumnName( "ProductId" ) + .HasComment( "产品标识" ); + builder.Property( t => t.ProductName ) + .HasColumnName( "ProductName" ) + .HasComment( "产品名称" ); + builder.Property( t => t.Price ) + .HasColumnName( "Price" ) + .HasComment( "单价" ) + .HasPrecision(12,2); + builder.Property( t => t.Quantity ) + .HasColumnName( "Quantity" ) + .HasComment( "数量" ) + .HasDefaultValue( 1 ); + } + + /// + /// 映射导航属性 + /// + private void ConfigAssociations( EntityTypeBuilder builder ) { + builder.HasOne( t => t.Order ) + .WithMany( t => t.OrderItems ) + .HasForeignKey( t => t.OrderId ); + } + } +} \ No newline at end of file diff --git a/test/Util.TestShare.Oracle/EntityTypeConfigurations/PostConfiguration.cs b/test/Util.TestShare.Oracle/EntityTypeConfigurations/PostConfiguration.cs new file mode 100644 index 00000000..2fa46dd8 --- /dev/null +++ b/test/Util.TestShare.Oracle/EntityTypeConfigurations/PostConfiguration.cs @@ -0,0 +1,63 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; +using Util.Tests.Models; + +namespace Util.Tests.EntityTypeConfigurations { + /// + /// 贴子类型配置 + /// + public class PostConfiguration : IEntityTypeConfiguration { + /// + /// 配置 + /// + /// 实体类型生成器 + public void Configure( EntityTypeBuilder builder ) { + ConfigTable( builder ); + ConfigId( builder ); + ConfigProperties( builder ); + } + + /// + /// 配置表 + /// + private void ConfigTable( EntityTypeBuilder builder ) { + builder.ToTable( "Post" ).HasComment( "贴子" ); + } + + /// + /// 配置标识 + /// + private void ConfigId( EntityTypeBuilder builder ) { + builder.Property( t => t.Id ) + .HasColumnName( "PostId" ) + .HasComment( "贴子标识" ); + } + + /// + /// 配置属性 + /// + private void ConfigProperties( EntityTypeBuilder builder ) { + builder.Property( t => t.Title ) + .HasColumnName( "Title" ) + .HasComment( "标题" ); + builder.Property( t => t.Content ) + .HasColumnName( "Content" ) + .HasComment( "内容" ); + builder.Property( t => t.CreationTime ) + .HasColumnName( "CreationTime" ) + .HasComment( "创建时间" ); + builder.Property( t => t.CreatorId ) + .HasColumnName( "CreatorId" ) + .HasComment( "创建人" ); + builder.Property( t => t.LastModificationTime ) + .HasColumnName( "LastModificationTime" ) + .HasComment( "最后修改时间" ); + builder.Property( t => t.LastModifierId ) + .HasColumnName( "LastModifierId" ) + .HasComment( "最后修改人" ); + builder.HasMany( t => t.Tags ) + .WithMany( t => t.Posts ) + .UsingEntity( t => t.ToTable( "PostTag2" ) ); + } + } +} \ No newline at end of file diff --git a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/EntityTypeConfigurations/ProductConfiguration.cs b/test/Util.TestShare.Oracle/EntityTypeConfigurations/ProductConfiguration.cs similarity index 62% rename from test/Util.Data.EntityFrameworkCore.SqlServer.Tests/EntityTypeConfigurations/ProductConfiguration.cs rename to test/Util.TestShare.Oracle/EntityTypeConfigurations/ProductConfiguration.cs index 565853e9..a062b792 100644 --- a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/EntityTypeConfigurations/ProductConfiguration.cs +++ b/test/Util.TestShare.Oracle/EntityTypeConfigurations/ProductConfiguration.cs @@ -1,8 +1,9 @@ using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; -using Util.Data.EntityFrameworkCore.Models; +using Util.Tests.Configs; +using Util.Tests.Models; -namespace Util.Data.EntityFrameworkCore.EntityTypeConfigurations { +namespace Util.Tests.EntityTypeConfigurations { /// /// 产品类型配置 /// @@ -15,13 +16,14 @@ namespace Util.Data.EntityFrameworkCore.EntityTypeConfigurations { ConfigTable( builder ); ConfigId( builder ); ConfigProperties( builder ); + InitData( builder ); } /// /// 配置表 /// private void ConfigTable( EntityTypeBuilder builder ) { - builder.ToTable( "Product", "Products" ).HasComment( "产品" ); + builder.ToTable( "Product" ).HasComment( "产品" ); } /// @@ -46,12 +48,26 @@ namespace Util.Data.EntityFrameworkCore.EntityTypeConfigurations { builder.Property( t => t.Price ) .HasColumnName( "Price" ) .HasComment( "价格" ) - .HasPrecision( 12, 2 ); ; + .HasDefaultValue( 0 ) + .HasPrecision( 12, 2 ); + builder.Property( t => t.IntPrice ) + .HasColumnName( "IntPrice" ) + .HasComment( "价格" ) + .HasDefaultValue( 0 ); + builder.Property( t => t.LongPrice ) + .HasColumnName( "LongPrice" ) + .HasComment( "价格" ) + .HasDefaultValue( 0 ); + builder.Property( t => t.FloatPrice ) + .HasColumnName( "FloatPrice" ) + .HasComment( "价格" ) + .HasDefaultValue( 0 ); builder.Property( t => t.Description ) .HasColumnName( "Description" ) .HasComment( "描述" ); builder.Property( t => t.Enabled ) .HasColumnName( "Enabled" ) + .HasDefaultValue( TestConfig.BoolValue ) .HasComment( "启用" ); builder.Property( t => t.CreationTime ) .HasColumnName( "CreationTime" ) @@ -65,6 +81,22 @@ namespace Util.Data.EntityFrameworkCore.EntityTypeConfigurations { builder.Property( t => t.LastModifierId ) .HasColumnName( "LastModifierId" ) .HasComment( "最后修改人" ); + builder.Property( t => t.IsDeleted ) + .HasDefaultValue( false ); + } + + /// + /// 初始化数据 + /// + private void InitData( EntityTypeBuilder builder ) { + var product = new Product( TestConfig.Id ) { + Code = TestConfig.Value, + Price = TestConfig.DecimalValue, + IntPrice = TestConfig.IntValue, + LongPrice = TestConfig.LongValue, + FloatPrice = TestConfig.FloatValue + }; + builder.HasData( product ); } } } \ No newline at end of file diff --git a/test/Util.TestShare.Oracle/EntityTypeConfigurations/TagConfiguration.cs b/test/Util.TestShare.Oracle/EntityTypeConfigurations/TagConfiguration.cs new file mode 100644 index 00000000..12956262 --- /dev/null +++ b/test/Util.TestShare.Oracle/EntityTypeConfigurations/TagConfiguration.cs @@ -0,0 +1,57 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; +using Util.Tests.Models; + +namespace Util.Tests.EntityTypeConfigurations { + /// + /// 标签类型配置 + /// + public class TagConfiguration : IEntityTypeConfiguration { + /// + /// 配置 + /// + /// 实体类型生成器 + public void Configure( EntityTypeBuilder builder ) { + ConfigTable( builder ); + ConfigId( builder ); + ConfigProperties( builder ); + } + + /// + /// 配置表 + /// + private void ConfigTable( EntityTypeBuilder builder ) { + builder.ToTable( "Tag" ).HasComment( "标签" ); + } + + /// + /// 配置标识 + /// + private void ConfigId( EntityTypeBuilder builder ) { + builder.Property( t => t.Id ) + .HasColumnName( "TagId" ) + .HasComment( "标签标识" ); + } + + /// + /// 配置属性 + /// + private void ConfigProperties( EntityTypeBuilder builder ) { + builder.Property( t => t.Name ) + .HasColumnName( "Name" ) + .HasComment( "标签名称" ); + builder.Property( t => t.CreationTime ) + .HasColumnName( "CreationTime" ) + .HasComment( "创建时间" ); + builder.Property( t => t.CreatorId ) + .HasColumnName( "CreatorId" ) + .HasComment( "创建人" ); + builder.Property( t => t.LastModificationTime ) + .HasColumnName( "LastModificationTime" ) + .HasComment( "最后修改时间" ); + builder.Property( t => t.LastModifierId ) + .HasColumnName( "LastModifierId" ) + .HasComment( "最后修改人" ); + } + } +} \ No newline at end of file diff --git a/test/Util.Application.WebApi.Tests.Integration/Repositories/CustomerRepository.cs b/test/Util.TestShare.Oracle/Repositories/CustomerRepository.cs similarity index 62% rename from test/Util.Application.WebApi.Tests.Integration/Repositories/CustomerRepository.cs rename to test/Util.TestShare.Oracle/Repositories/CustomerRepository.cs index b7a39749..780d3b12 100644 --- a/test/Util.Application.WebApi.Tests.Integration/Repositories/CustomerRepository.cs +++ b/test/Util.TestShare.Oracle/Repositories/CustomerRepository.cs @@ -1,8 +1,8 @@ -using Util.Applications.Models; -using Util.Applications.UnitOfWorks; using Util.Data.EntityFrameworkCore; +using Util.Tests.Models; +using Util.Tests.UnitOfWorks; -namespace Util.Applications.Repositories { +namespace Util.Tests.Repositories { /// /// 客户仓储 /// @@ -11,7 +11,7 @@ namespace Util.Applications.Repositories { /// 初始化客户仓储 /// /// 工作单元 - public CustomerRepository( ISqlServerUnitOfWork unitOfWork ) : base( unitOfWork ) { + public CustomerRepository( ITestUnitOfWork unitOfWork ) : base( unitOfWork ) { } } } \ No newline at end of file diff --git a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Repositories/OperationLogRepository.cs b/test/Util.TestShare.Oracle/Repositories/OperationLogRepository.cs similarity index 57% rename from test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Repositories/OperationLogRepository.cs rename to test/Util.TestShare.Oracle/Repositories/OperationLogRepository.cs index 622de9fc..75c9ab91 100644 --- a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Repositories/OperationLogRepository.cs +++ b/test/Util.TestShare.Oracle/Repositories/OperationLogRepository.cs @@ -1,7 +1,8 @@ -using Util.Data.EntityFrameworkCore.Models; -using Util.Data.EntityFrameworkCore.UnitOfWorks; +using Util.Data.EntityFrameworkCore; +using Util.Tests.Models; +using Util.Tests.UnitOfWorks; -namespace Util.Data.EntityFrameworkCore.Repositories { +namespace Util.Tests.Repositories { /// /// 操作日志仓储 /// @@ -10,7 +11,7 @@ namespace Util.Data.EntityFrameworkCore.Repositories { /// 初始化操作日志仓储 /// /// 工作单元 - public OperationLogRepository( ISqlServerUnitOfWork unitOfWork ) : base( unitOfWork ) { + public OperationLogRepository( ITestUnitOfWork unitOfWork ) : base( unitOfWork ) { } } } \ No newline at end of file diff --git a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Repositories/OrderRepository.cs b/test/Util.TestShare.Oracle/Repositories/OrderRepository.cs similarity index 55% rename from test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Repositories/OrderRepository.cs rename to test/Util.TestShare.Oracle/Repositories/OrderRepository.cs index 5466ce95..0ba4d0c4 100644 --- a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Repositories/OrderRepository.cs +++ b/test/Util.TestShare.Oracle/Repositories/OrderRepository.cs @@ -1,7 +1,8 @@ -using Util.Data.EntityFrameworkCore.Models; -using Util.Data.EntityFrameworkCore.UnitOfWorks; +using Util.Data.EntityFrameworkCore; +using Util.Tests.Models; +using Util.Tests.UnitOfWorks; -namespace Util.Data.EntityFrameworkCore.Repositories { +namespace Util.Tests.Repositories { /// /// 订单仓储 /// @@ -10,7 +11,7 @@ namespace Util.Data.EntityFrameworkCore.Repositories { /// 初始化订单仓储 /// /// 工作单元 - public OrderRepository( ISqlServerUnitOfWork unitOfWork ) : base( unitOfWork ) { + public OrderRepository( ITestUnitOfWork unitOfWork ) : base( unitOfWork ) { } } } \ No newline at end of file diff --git a/test/Util.TestShare.Oracle/Repositories/PostRepository.cs b/test/Util.TestShare.Oracle/Repositories/PostRepository.cs new file mode 100644 index 00000000..a57bbb67 --- /dev/null +++ b/test/Util.TestShare.Oracle/Repositories/PostRepository.cs @@ -0,0 +1,17 @@ +using Util.Data.EntityFrameworkCore; +using Util.Tests.Models; +using Util.Tests.UnitOfWorks; + +namespace Util.Tests.Repositories { + /// + /// 贴子仓储 + /// + public class PostRepository : RepositoryBase,IPostRepository { + /// + /// 初始化贴子仓储 + /// + /// 工作单元 + public PostRepository( ITestUnitOfWork unitOfWork ) : base( unitOfWork ) { + } + } +} \ No newline at end of file diff --git a/test/Util.Application.WebApi.Tests.Integration/Repositories/ProductRepository.cs b/test/Util.TestShare.Oracle/Repositories/ProductRepository.cs similarity index 73% rename from test/Util.Application.WebApi.Tests.Integration/Repositories/ProductRepository.cs rename to test/Util.TestShare.Oracle/Repositories/ProductRepository.cs index 2a10557e..bdcb3988 100644 --- a/test/Util.Application.WebApi.Tests.Integration/Repositories/ProductRepository.cs +++ b/test/Util.TestShare.Oracle/Repositories/ProductRepository.cs @@ -1,8 +1,8 @@ -using Util.Applications.Models; -using Util.Applications.UnitOfWorks; using Util.Data.EntityFrameworkCore; +using Util.Tests.Models; +using Util.Tests.UnitOfWorks; -namespace Util.Applications.Repositories { +namespace Util.Tests.Repositories { /// /// 产品仓储 /// @@ -11,7 +11,7 @@ namespace Util.Applications.Repositories { /// 初始化产品仓储 /// /// 工作单元 - public ProductRepository( ISqlServerUnitOfWork unitOfWork ) : base( unitOfWork ) { + public ProductRepository( ITestUnitOfWork unitOfWork ) : base( unitOfWork ) { } /// diff --git a/test/Util.TestShare.Oracle/Repositories/TagRepository.cs b/test/Util.TestShare.Oracle/Repositories/TagRepository.cs new file mode 100644 index 00000000..25d00508 --- /dev/null +++ b/test/Util.TestShare.Oracle/Repositories/TagRepository.cs @@ -0,0 +1,17 @@ +using Util.Data.EntityFrameworkCore; +using Util.Tests.Models; +using Util.Tests.UnitOfWorks; + +namespace Util.Tests.Repositories { + /// + /// 标签仓储 + /// + public class TagRepository : RepositoryBase,ITagRepository { + /// + /// 初始化标签仓储 + /// + /// 工作单元 + public TagRepository( ITestUnitOfWork unitOfWork ) : base( unitOfWork ) { + } + } +} \ No newline at end of file diff --git a/test/Util.TestShare.Oracle/UnitOfWorks/OracleUnitOfWork.cs b/test/Util.TestShare.Oracle/UnitOfWorks/OracleUnitOfWork.cs new file mode 100644 index 00000000..b04a24fc --- /dev/null +++ b/test/Util.TestShare.Oracle/UnitOfWorks/OracleUnitOfWork.cs @@ -0,0 +1,26 @@ +using System; +using Microsoft.EntityFrameworkCore; +using Util.Data.EntityFrameworkCore; +using Util.Sessions; + +namespace Util.Tests.UnitOfWorks { + /// + /// Oracle工作单元 + /// + public class OracleUnitOfWork : OracleUnitOfWorkBase, ITestUnitOfWork { + /// + /// 初始化工作单元 + /// + /// 服务提供器 + /// 配置项 + public OracleUnitOfWork( IServiceProvider serviceProvider, DbContextOptions options ) : base( serviceProvider, options ) { + } + + /// + /// 设置用户会话 + /// + public void SetSession( ISession session ) { + Session = session; + } + } +} \ No newline at end of file diff --git a/test/Util.TestShare.Oracle/Util.TestShare.Oracle.csproj b/test/Util.TestShare.Oracle/Util.TestShare.Oracle.csproj new file mode 100644 index 00000000..e58e45b9 --- /dev/null +++ b/test/Util.TestShare.Oracle/Util.TestShare.Oracle.csproj @@ -0,0 +1,13 @@ + + + + $(NetTargetFramework) + false + Util.Tests + + + + + + + \ No newline at end of file diff --git a/test/Util.Application.WebApi.Tests.Integration/EntityTypeConfigurations/CustomerConfiguration.cs b/test/Util.TestShare.PostgreSql/EntityTypeConfigurations/CustomerConfiguration.cs similarity index 86% rename from test/Util.Application.WebApi.Tests.Integration/EntityTypeConfigurations/CustomerConfiguration.cs rename to test/Util.TestShare.PostgreSql/EntityTypeConfigurations/CustomerConfiguration.cs index 1b0e28ab..363395e3 100644 --- a/test/Util.Application.WebApi.Tests.Integration/EntityTypeConfigurations/CustomerConfiguration.cs +++ b/test/Util.TestShare.PostgreSql/EntityTypeConfigurations/CustomerConfiguration.cs @@ -1,8 +1,9 @@ using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; -using Util.Applications.Models; +using Util.Tests.Configs; +using Util.Tests.Models; -namespace Util.Applications.EntityTypeConfigurations { +namespace Util.Tests.EntityTypeConfigurations { /// /// 客户类型配置 /// @@ -15,7 +16,7 @@ namespace Util.Applications.EntityTypeConfigurations { ConfigTable( builder ); ConfigId( builder ); ConfigProperties( builder ); - ConfigVersion( builder ); + InitData( builder ); } /// @@ -76,18 +77,18 @@ namespace Util.Applications.EntityTypeConfigurations { .HasColumnName( "LastModifierId" ) .HasComment( "最后修改人" ); builder.Property( t => t.IsDeleted ) - .HasColumnName( "IsDeleted" ) - .HasComment( "是否删除" ); + .HasDefaultValue( false ); } /// - /// 配置版本号 + /// 初始化数据 /// - private void ConfigVersion( EntityTypeBuilder builder ) { - builder.Property( t => t.Version ) - .HasColumnName( "Version" ) - .IsRowVersion() - .HasComment( "版本号" ); + private void InitData( EntityTypeBuilder builder ) { + var customer = new Customer( 1 ) { + Code = TestConfig.Value, + Birthday = TestConfig.DateTimeValue + }; + builder.HasData( customer ); } } } \ No newline at end of file diff --git a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/EntityTypeConfigurations/OperationLogConfiguration.cs b/test/Util.TestShare.PostgreSql/EntityTypeConfigurations/OperationLogConfiguration.cs similarity index 94% rename from test/Util.Data.EntityFrameworkCore.SqlServer.Tests/EntityTypeConfigurations/OperationLogConfiguration.cs rename to test/Util.TestShare.PostgreSql/EntityTypeConfigurations/OperationLogConfiguration.cs index 1e89991f..b00fdcd2 100644 --- a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/EntityTypeConfigurations/OperationLogConfiguration.cs +++ b/test/Util.TestShare.PostgreSql/EntityTypeConfigurations/OperationLogConfiguration.cs @@ -1,8 +1,8 @@ using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; -using Util.Data.EntityFrameworkCore.Models; +using Util.Tests.Models; -namespace Util.Data.EntityFrameworkCore.EntityTypeConfigurations { +namespace Util.Tests.EntityTypeConfigurations { /// /// 操作日志类型配置 /// diff --git a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/EntityTypeConfigurations/OrderConfiguration.cs b/test/Util.TestShare.PostgreSql/EntityTypeConfigurations/OrderConfiguration.cs similarity index 80% rename from test/Util.Data.EntityFrameworkCore.SqlServer.Tests/EntityTypeConfigurations/OrderConfiguration.cs rename to test/Util.TestShare.PostgreSql/EntityTypeConfigurations/OrderConfiguration.cs index f144da7a..8a694f96 100644 --- a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/EntityTypeConfigurations/OrderConfiguration.cs +++ b/test/Util.TestShare.PostgreSql/EntityTypeConfigurations/OrderConfiguration.cs @@ -1,8 +1,9 @@ using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; -using Util.Data.EntityFrameworkCore.Models; +using Util.Tests.Configs; +using Util.Tests.Models; -namespace Util.Data.EntityFrameworkCore.EntityTypeConfigurations { +namespace Util.Tests.EntityTypeConfigurations { /// /// 订单类型配置 /// @@ -47,13 +48,18 @@ namespace Util.Data.EntityFrameworkCore.EntityTypeConfigurations { builder.Property( t => t.Amount ) .HasColumnName( "Amount" ) .HasComment( "金额" ) - .HasPrecision(15,2); + .HasPrecision(15,2) + .HasDefaultValue( 0 ); builder.Property( t => t.PlaceOrderTime ) .HasColumnName( "PlaceOrderTime" ) - .HasComment( "下单时间" ); + .HasComment( "下单时间" ) + .HasDefaultValue( TestConfig.DateTimeValue ); builder.Property( t => t.State ) .HasColumnName( "State" ) - .HasComment( "订单状态" ); + .HasComment( "订单状态" ) + .HasDefaultValue( 0 ); + builder.Property( t => t.IsDeleted ) + .HasDefaultValue( false ); } } } \ No newline at end of file diff --git a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/EntityTypeConfigurations/OrderItemConfiguration.cs b/test/Util.TestShare.PostgreSql/EntityTypeConfigurations/OrderItemConfiguration.cs similarity index 93% rename from test/Util.Data.EntityFrameworkCore.SqlServer.Tests/EntityTypeConfigurations/OrderItemConfiguration.cs rename to test/Util.TestShare.PostgreSql/EntityTypeConfigurations/OrderItemConfiguration.cs index e538c76d..04d757f3 100644 --- a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/EntityTypeConfigurations/OrderItemConfiguration.cs +++ b/test/Util.TestShare.PostgreSql/EntityTypeConfigurations/OrderItemConfiguration.cs @@ -1,8 +1,8 @@ using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; -using Util.Data.EntityFrameworkCore.Models; +using Util.Tests.Models; -namespace Util.Data.EntityFrameworkCore.EntityTypeConfigurations { +namespace Util.Tests.EntityTypeConfigurations { /// /// 订单明细类型配置 /// @@ -54,7 +54,8 @@ namespace Util.Data.EntityFrameworkCore.EntityTypeConfigurations { .HasPrecision(12,2); builder.Property( t => t.Quantity ) .HasColumnName( "Quantity" ) - .HasComment( "数量" ); + .HasComment( "数量" ) + .HasDefaultValue( 1 ); } /// diff --git a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/EntityTypeConfigurations/PostConfiguration.cs b/test/Util.TestShare.PostgreSql/EntityTypeConfigurations/PostConfiguration.cs similarity index 91% rename from test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/EntityTypeConfigurations/PostConfiguration.cs rename to test/Util.TestShare.PostgreSql/EntityTypeConfigurations/PostConfiguration.cs index 11ecf6d3..0c412db8 100644 --- a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/EntityTypeConfigurations/PostConfiguration.cs +++ b/test/Util.TestShare.PostgreSql/EntityTypeConfigurations/PostConfiguration.cs @@ -1,8 +1,8 @@ using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; -using Util.Data.EntityFrameworkCore.Models; +using Util.Tests.Models; -namespace Util.Data.EntityFrameworkCore.EntityTypeConfigurations { +namespace Util.Tests.EntityTypeConfigurations { /// /// 贴子类型配置 /// @@ -45,14 +45,12 @@ namespace Util.Data.EntityFrameworkCore.EntityTypeConfigurations { .HasComment( "内容" ); builder.Property( t => t.CreationTime ) .HasColumnName( "CreationTime" ) - .HasColumnType( "timestamp" ) .HasComment( "创建时间" ); builder.Property( t => t.CreatorId ) .HasColumnName( "CreatorId" ) .HasComment( "创建人" ); builder.Property( t => t.LastModificationTime ) .HasColumnName( "LastModificationTime" ) - .HasColumnType( "timestamp" ) .HasComment( "最后修改时间" ); builder.Property( t => t.LastModifierId ) .HasColumnName( "LastModifierId" ) diff --git a/test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/EntityTypeConfigurations/ProductConfiguration.cs b/test/Util.TestShare.PostgreSql/EntityTypeConfigurations/ProductConfiguration.cs similarity index 67% rename from test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/EntityTypeConfigurations/ProductConfiguration.cs rename to test/Util.TestShare.PostgreSql/EntityTypeConfigurations/ProductConfiguration.cs index f2430ba7..a6a6047f 100644 --- a/test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/EntityTypeConfigurations/ProductConfiguration.cs +++ b/test/Util.TestShare.PostgreSql/EntityTypeConfigurations/ProductConfiguration.cs @@ -1,8 +1,9 @@ using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; -using Util.Applications.Models; +using Util.Tests.Configs; +using Util.Tests.Models; -namespace Util.Applications.EntityTypeConfigurations { +namespace Util.Tests.EntityTypeConfigurations { /// /// 产品类型配置 /// @@ -15,7 +16,7 @@ namespace Util.Applications.EntityTypeConfigurations { ConfigTable( builder ); ConfigId( builder ); ConfigProperties( builder ); - ConfigVersion( builder ); + InitData( builder ); } /// @@ -47,12 +48,26 @@ namespace Util.Applications.EntityTypeConfigurations { builder.Property( t => t.Price ) .HasColumnName( "Price" ) .HasComment( "价格" ) - .HasPrecision( 12, 2 ); ; + .HasDefaultValue( 0 ) + .HasPrecision( 12, 2 ); + builder.Property( t => t.IntPrice ) + .HasColumnName( "IntPrice" ) + .HasComment( "价格" ) + .HasDefaultValue( 0 ); + builder.Property( t => t.LongPrice ) + .HasColumnName( "LongPrice" ) + .HasComment( "价格" ) + .HasDefaultValue( 0 ); + builder.Property( t => t.FloatPrice ) + .HasColumnName( "FloatPrice" ) + .HasComment( "价格" ) + .HasDefaultValue( 0 ); builder.Property( t => t.Description ) .HasColumnName( "Description" ) .HasComment( "描述" ); builder.Property( t => t.Enabled ) .HasColumnName( "Enabled" ) + .HasDefaultValue( TestConfig.BoolValue ) .HasComment( "启用" ); builder.Property( t => t.CreationTime ) .HasColumnName( "CreationTime" ) @@ -67,18 +82,21 @@ namespace Util.Applications.EntityTypeConfigurations { .HasColumnName( "LastModifierId" ) .HasComment( "最后修改人" ); builder.Property( t => t.IsDeleted ) - .HasColumnName( "IsDeleted" ) - .HasComment( "是否删除" ); + .HasDefaultValue( false ); } /// - /// 配置版本号 + /// 初始化数据 /// - private void ConfigVersion( EntityTypeBuilder builder ) { - builder.Property( t => t.Version ) - .HasColumnName( "Version" ) - .IsRowVersion() - .HasComment( "版本号" ); + private void InitData( EntityTypeBuilder builder ) { + var product = new Product( TestConfig.Id ) { + Code = TestConfig.Value, + Price = TestConfig.DecimalValue, + IntPrice = TestConfig.IntValue, + LongPrice = TestConfig.LongValue, + FloatPrice = TestConfig.FloatValue + }; + builder.HasData( product ); } } } \ No newline at end of file diff --git a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/EntityTypeConfigurations/TagConfiguration.cs b/test/Util.TestShare.PostgreSql/EntityTypeConfigurations/TagConfiguration.cs similarity index 90% rename from test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/EntityTypeConfigurations/TagConfiguration.cs rename to test/Util.TestShare.PostgreSql/EntityTypeConfigurations/TagConfiguration.cs index fb78932f..1f4f6f34 100644 --- a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/EntityTypeConfigurations/TagConfiguration.cs +++ b/test/Util.TestShare.PostgreSql/EntityTypeConfigurations/TagConfiguration.cs @@ -1,8 +1,8 @@ using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; -using Util.Data.EntityFrameworkCore.Models; +using Util.Tests.Models; -namespace Util.Data.EntityFrameworkCore.EntityTypeConfigurations { +namespace Util.Tests.EntityTypeConfigurations { /// /// 标签类型配置 /// @@ -42,14 +42,12 @@ namespace Util.Data.EntityFrameworkCore.EntityTypeConfigurations { .HasComment( "标签名称" ); builder.Property( t => t.CreationTime ) .HasColumnName( "CreationTime" ) - .HasColumnType( "timestamp" ) .HasComment( "创建时间" ); builder.Property( t => t.CreatorId ) .HasColumnName( "CreatorId" ) .HasComment( "创建人" ); builder.Property( t => t.LastModificationTime ) .HasColumnName( "LastModificationTime" ) - .HasColumnType( "timestamp" ) .HasComment( "最后修改时间" ); builder.Property( t => t.LastModifierId ) .HasColumnName( "LastModifierId" ) diff --git a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Repositories/CustomerRepository.cs b/test/Util.TestShare.PostgreSql/Repositories/CustomerRepository.cs similarity index 56% rename from test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Repositories/CustomerRepository.cs rename to test/Util.TestShare.PostgreSql/Repositories/CustomerRepository.cs index 2c8bd2fb..780d3b12 100644 --- a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Repositories/CustomerRepository.cs +++ b/test/Util.TestShare.PostgreSql/Repositories/CustomerRepository.cs @@ -1,7 +1,8 @@ -using Util.Data.EntityFrameworkCore.Models; -using Util.Data.EntityFrameworkCore.UnitOfWorks; +using Util.Data.EntityFrameworkCore; +using Util.Tests.Models; +using Util.Tests.UnitOfWorks; -namespace Util.Data.EntityFrameworkCore.Repositories { +namespace Util.Tests.Repositories { /// /// 客户仓储 /// @@ -10,7 +11,7 @@ namespace Util.Data.EntityFrameworkCore.Repositories { /// 初始化客户仓储 /// /// 工作单元 - public CustomerRepository( IPgSqlUnitOfWork unitOfWork ) : base( unitOfWork ) { + public CustomerRepository( ITestUnitOfWork unitOfWork ) : base( unitOfWork ) { } } } \ No newline at end of file diff --git a/test/Util.TestShare.PostgreSql/Repositories/OperationLogRepository.cs b/test/Util.TestShare.PostgreSql/Repositories/OperationLogRepository.cs new file mode 100644 index 00000000..75c9ab91 --- /dev/null +++ b/test/Util.TestShare.PostgreSql/Repositories/OperationLogRepository.cs @@ -0,0 +1,17 @@ +using Util.Data.EntityFrameworkCore; +using Util.Tests.Models; +using Util.Tests.UnitOfWorks; + +namespace Util.Tests.Repositories { + /// + /// 操作日志仓储 + /// + public class OperationLogRepository : RepositoryBase,IOperationLogRepository { + /// + /// 初始化操作日志仓储 + /// + /// 工作单元 + public OperationLogRepository( ITestUnitOfWork unitOfWork ) : base( unitOfWork ) { + } + } +} \ No newline at end of file diff --git a/test/Util.TestShare.PostgreSql/Repositories/OrderRepository.cs b/test/Util.TestShare.PostgreSql/Repositories/OrderRepository.cs new file mode 100644 index 00000000..0ba4d0c4 --- /dev/null +++ b/test/Util.TestShare.PostgreSql/Repositories/OrderRepository.cs @@ -0,0 +1,17 @@ +using Util.Data.EntityFrameworkCore; +using Util.Tests.Models; +using Util.Tests.UnitOfWorks; + +namespace Util.Tests.Repositories { + /// + /// 订单仓储 + /// + public class OrderRepository : RepositoryBase,IOrderRepository { + /// + /// 初始化订单仓储 + /// + /// 工作单元 + public OrderRepository( ITestUnitOfWork unitOfWork ) : base( unitOfWork ) { + } + } +} \ No newline at end of file diff --git a/test/Util.TestShare.PostgreSql/Repositories/PostRepository.cs b/test/Util.TestShare.PostgreSql/Repositories/PostRepository.cs new file mode 100644 index 00000000..a57bbb67 --- /dev/null +++ b/test/Util.TestShare.PostgreSql/Repositories/PostRepository.cs @@ -0,0 +1,17 @@ +using Util.Data.EntityFrameworkCore; +using Util.Tests.Models; +using Util.Tests.UnitOfWorks; + +namespace Util.Tests.Repositories { + /// + /// 贴子仓储 + /// + public class PostRepository : RepositoryBase,IPostRepository { + /// + /// 初始化贴子仓储 + /// + /// 工作单元 + public PostRepository( ITestUnitOfWork unitOfWork ) : base( unitOfWork ) { + } + } +} \ No newline at end of file diff --git a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Repositories/ProductRepository.cs b/test/Util.TestShare.PostgreSql/Repositories/ProductRepository.cs similarity index 68% rename from test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Repositories/ProductRepository.cs rename to test/Util.TestShare.PostgreSql/Repositories/ProductRepository.cs index ee39da0d..bdcb3988 100644 --- a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Repositories/ProductRepository.cs +++ b/test/Util.TestShare.PostgreSql/Repositories/ProductRepository.cs @@ -1,7 +1,8 @@ -using Util.Data.EntityFrameworkCore.Models; -using Util.Data.EntityFrameworkCore.UnitOfWorks; +using Util.Data.EntityFrameworkCore; +using Util.Tests.Models; +using Util.Tests.UnitOfWorks; -namespace Util.Data.EntityFrameworkCore.Repositories { +namespace Util.Tests.Repositories { /// /// 产品仓储 /// @@ -10,7 +11,7 @@ namespace Util.Data.EntityFrameworkCore.Repositories { /// 初始化产品仓储 /// /// 工作单元 - public ProductRepository( IPgSqlUnitOfWork unitOfWork ) : base( unitOfWork ) { + public ProductRepository( ITestUnitOfWork unitOfWork ) : base( unitOfWork ) { } /// diff --git a/test/Util.TestShare.PostgreSql/Repositories/TagRepository.cs b/test/Util.TestShare.PostgreSql/Repositories/TagRepository.cs new file mode 100644 index 00000000..25d00508 --- /dev/null +++ b/test/Util.TestShare.PostgreSql/Repositories/TagRepository.cs @@ -0,0 +1,17 @@ +using Util.Data.EntityFrameworkCore; +using Util.Tests.Models; +using Util.Tests.UnitOfWorks; + +namespace Util.Tests.Repositories { + /// + /// 标签仓储 + /// + public class TagRepository : RepositoryBase,ITagRepository { + /// + /// 初始化标签仓储 + /// + /// 工作单元 + public TagRepository( ITestUnitOfWork unitOfWork ) : base( unitOfWork ) { + } + } +} \ No newline at end of file diff --git a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/UnitOfWorks/PgSqlUnitOfWork.cs b/test/Util.TestShare.PostgreSql/UnitOfWorks/PgSqlUnitOfWork.cs similarity index 82% rename from test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/UnitOfWorks/PgSqlUnitOfWork.cs rename to test/Util.TestShare.PostgreSql/UnitOfWorks/PgSqlUnitOfWork.cs index eab11f11..6294b3ee 100644 --- a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/UnitOfWorks/PgSqlUnitOfWork.cs +++ b/test/Util.TestShare.PostgreSql/UnitOfWorks/PgSqlUnitOfWork.cs @@ -1,12 +1,13 @@ using System; using Microsoft.EntityFrameworkCore; +using Util.Data.EntityFrameworkCore; using Util.Sessions; -namespace Util.Data.EntityFrameworkCore.UnitOfWorks { +namespace Util.Tests.UnitOfWorks { /// /// PgSql工作单元 /// - public class PgSqlUnitOfWork : PgSqlUnitOfWorkBase, IPgSqlUnitOfWork { + public class PgSqlUnitOfWork : PgSqlUnitOfWorkBase, ITestUnitOfWork { /// /// 初始化工作单元 /// diff --git a/test/Util.TestShare.PostgreSql/Util.TestShare.PostgreSql.csproj b/test/Util.TestShare.PostgreSql/Util.TestShare.PostgreSql.csproj new file mode 100644 index 00000000..e64ed18e --- /dev/null +++ b/test/Util.TestShare.PostgreSql/Util.TestShare.PostgreSql.csproj @@ -0,0 +1,13 @@ + + + + $(NetTargetFramework) + false + Util.Tests + + + + + + + diff --git a/test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/EntityTypeConfigurations/CustomerConfiguration.cs b/test/Util.TestShare.SqlServer/EntityTypeConfigurations/CustomerConfiguration.cs similarity index 86% rename from test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/EntityTypeConfigurations/CustomerConfiguration.cs rename to test/Util.TestShare.SqlServer/EntityTypeConfigurations/CustomerConfiguration.cs index 1b0e28ab..4c7dcda9 100644 --- a/test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/EntityTypeConfigurations/CustomerConfiguration.cs +++ b/test/Util.TestShare.SqlServer/EntityTypeConfigurations/CustomerConfiguration.cs @@ -1,8 +1,9 @@ using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; -using Util.Applications.Models; +using Util.Tests.Configs; +using Util.Tests.Models; -namespace Util.Applications.EntityTypeConfigurations { +namespace Util.Tests.EntityTypeConfigurations { /// /// 客户类型配置 /// @@ -15,7 +16,7 @@ namespace Util.Applications.EntityTypeConfigurations { ConfigTable( builder ); ConfigId( builder ); ConfigProperties( builder ); - ConfigVersion( builder ); + InitData( builder ); } /// @@ -76,18 +77,18 @@ namespace Util.Applications.EntityTypeConfigurations { .HasColumnName( "LastModifierId" ) .HasComment( "最后修改人" ); builder.Property( t => t.IsDeleted ) - .HasColumnName( "IsDeleted" ) - .HasComment( "是否删除" ); + .HasDefaultValue( false ); } /// - /// 配置版本号 + /// 初始化数据 /// - private void ConfigVersion( EntityTypeBuilder builder ) { - builder.Property( t => t.Version ) - .HasColumnName( "Version" ) - .IsRowVersion() - .HasComment( "版本号" ); + private void InitData( EntityTypeBuilder builder ) { + var customer = new Customer(1) { + Code = TestConfig.Value, + Birthday = TestConfig.DateTimeValue + }; + builder.HasData( customer ); } } } \ No newline at end of file diff --git a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/EntityTypeConfigurations/OperationLogConfiguration.cs b/test/Util.TestShare.SqlServer/EntityTypeConfigurations/OperationLogConfiguration.cs similarity index 92% rename from test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/EntityTypeConfigurations/OperationLogConfiguration.cs rename to test/Util.TestShare.SqlServer/EntityTypeConfigurations/OperationLogConfiguration.cs index 7796a741..b00fdcd2 100644 --- a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/EntityTypeConfigurations/OperationLogConfiguration.cs +++ b/test/Util.TestShare.SqlServer/EntityTypeConfigurations/OperationLogConfiguration.cs @@ -1,8 +1,8 @@ using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; -using Util.Data.EntityFrameworkCore.Models; +using Util.Tests.Models; -namespace Util.Data.EntityFrameworkCore.EntityTypeConfigurations { +namespace Util.Tests.EntityTypeConfigurations { /// /// 操作日志类型配置 /// @@ -43,7 +43,6 @@ namespace Util.Data.EntityFrameworkCore.EntityTypeConfigurations { .HasComment( "日志名称" ); builder.Property( t => t.OperationTime ) .HasColumnName( "OperationTime" ) - .HasColumnType( "timestamp" ) .HasComment( "操作时间" ); builder.Property( t => t.Caption ) .HasColumnName( "Caption" ) diff --git a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/EntityTypeConfigurations/OrderConfiguration.cs b/test/Util.TestShare.SqlServer/EntityTypeConfigurations/OrderConfiguration.cs similarity index 80% rename from test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/EntityTypeConfigurations/OrderConfiguration.cs rename to test/Util.TestShare.SqlServer/EntityTypeConfigurations/OrderConfiguration.cs index f7ad36db..ef6d5f5e 100644 --- a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/EntityTypeConfigurations/OrderConfiguration.cs +++ b/test/Util.TestShare.SqlServer/EntityTypeConfigurations/OrderConfiguration.cs @@ -1,8 +1,9 @@ using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; -using Util.Data.EntityFrameworkCore.Models; +using Util.Tests.Configs; +using Util.Tests.Models; -namespace Util.Data.EntityFrameworkCore.EntityTypeConfigurations { +namespace Util.Tests.EntityTypeConfigurations { /// /// 订单类型配置 /// @@ -47,14 +48,18 @@ namespace Util.Data.EntityFrameworkCore.EntityTypeConfigurations { builder.Property( t => t.Amount ) .HasColumnName( "Amount" ) .HasComment( "金额" ) - .HasPrecision(15,2); + .HasPrecision(15,2) + .HasDefaultValue( 0 ); builder.Property( t => t.PlaceOrderTime ) .HasColumnName( "PlaceOrderTime" ) - .HasColumnType( "timestamp" ) - .HasComment( "下单时间" ); + .HasComment( "下单时间" ) + .HasDefaultValue(TestConfig.DateTimeValue); builder.Property( t => t.State ) .HasColumnName( "State" ) - .HasComment( "订单状态" ); + .HasComment( "订单状态" ) + .HasDefaultValue(0); + builder.Property( t => t.IsDeleted ) + .HasDefaultValue( false ); } } } \ No newline at end of file diff --git a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/EntityTypeConfigurations/OrderItemConfiguration.cs b/test/Util.TestShare.SqlServer/EntityTypeConfigurations/OrderItemConfiguration.cs similarity index 93% rename from test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/EntityTypeConfigurations/OrderItemConfiguration.cs rename to test/Util.TestShare.SqlServer/EntityTypeConfigurations/OrderItemConfiguration.cs index e538c76d..a37d83b8 100644 --- a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/EntityTypeConfigurations/OrderItemConfiguration.cs +++ b/test/Util.TestShare.SqlServer/EntityTypeConfigurations/OrderItemConfiguration.cs @@ -1,8 +1,8 @@ using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; -using Util.Data.EntityFrameworkCore.Models; +using Util.Tests.Models; -namespace Util.Data.EntityFrameworkCore.EntityTypeConfigurations { +namespace Util.Tests.EntityTypeConfigurations { /// /// 订单明细类型配置 /// @@ -54,7 +54,8 @@ namespace Util.Data.EntityFrameworkCore.EntityTypeConfigurations { .HasPrecision(12,2); builder.Property( t => t.Quantity ) .HasColumnName( "Quantity" ) - .HasComment( "数量" ); + .HasComment( "数量" ) + .HasDefaultValue(1); } /// diff --git a/test/Util.TestShare.SqlServer/EntityTypeConfigurations/PostConfiguration.cs b/test/Util.TestShare.SqlServer/EntityTypeConfigurations/PostConfiguration.cs new file mode 100644 index 00000000..0c412db8 --- /dev/null +++ b/test/Util.TestShare.SqlServer/EntityTypeConfigurations/PostConfiguration.cs @@ -0,0 +1,63 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; +using Util.Tests.Models; + +namespace Util.Tests.EntityTypeConfigurations { + /// + /// 贴子类型配置 + /// + public class PostConfiguration : IEntityTypeConfiguration { + /// + /// 配置 + /// + /// 实体类型生成器 + public void Configure( EntityTypeBuilder builder ) { + ConfigTable( builder ); + ConfigId( builder ); + ConfigProperties( builder ); + } + + /// + /// 配置表 + /// + private void ConfigTable( EntityTypeBuilder builder ) { + builder.ToTable( "Post", "Blogs" ).HasComment( "贴子" ); + } + + /// + /// 配置标识 + /// + private void ConfigId( EntityTypeBuilder builder ) { + builder.Property( t => t.Id ) + .HasColumnName( "PostId" ) + .HasComment( "贴子标识" ); + } + + /// + /// 配置属性 + /// + private void ConfigProperties( EntityTypeBuilder builder ) { + builder.Property( t => t.Title ) + .HasColumnName( "Title" ) + .HasComment( "标题" ); + builder.Property( t => t.Content ) + .HasColumnName( "Content" ) + .HasComment( "内容" ); + builder.Property( t => t.CreationTime ) + .HasColumnName( "CreationTime" ) + .HasComment( "创建时间" ); + builder.Property( t => t.CreatorId ) + .HasColumnName( "CreatorId" ) + .HasComment( "创建人" ); + builder.Property( t => t.LastModificationTime ) + .HasColumnName( "LastModificationTime" ) + .HasComment( "最后修改时间" ); + builder.Property( t => t.LastModifierId ) + .HasColumnName( "LastModifierId" ) + .HasComment( "最后修改人" ); + builder.HasMany( t => t.Tags ) + .WithMany( t => t.Posts ) + .UsingEntity( t => t.ToTable( "PostTag2" ) ); + } + } +} \ No newline at end of file diff --git a/test/Util.Application.WebApi.Tests.Integration/EntityTypeConfigurations/ProductConfiguration.cs b/test/Util.TestShare.SqlServer/EntityTypeConfigurations/ProductConfiguration.cs similarity index 67% rename from test/Util.Application.WebApi.Tests.Integration/EntityTypeConfigurations/ProductConfiguration.cs rename to test/Util.TestShare.SqlServer/EntityTypeConfigurations/ProductConfiguration.cs index f2430ba7..a6a6047f 100644 --- a/test/Util.Application.WebApi.Tests.Integration/EntityTypeConfigurations/ProductConfiguration.cs +++ b/test/Util.TestShare.SqlServer/EntityTypeConfigurations/ProductConfiguration.cs @@ -1,8 +1,9 @@ using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; -using Util.Applications.Models; +using Util.Tests.Configs; +using Util.Tests.Models; -namespace Util.Applications.EntityTypeConfigurations { +namespace Util.Tests.EntityTypeConfigurations { /// /// 产品类型配置 /// @@ -15,7 +16,7 @@ namespace Util.Applications.EntityTypeConfigurations { ConfigTable( builder ); ConfigId( builder ); ConfigProperties( builder ); - ConfigVersion( builder ); + InitData( builder ); } /// @@ -47,12 +48,26 @@ namespace Util.Applications.EntityTypeConfigurations { builder.Property( t => t.Price ) .HasColumnName( "Price" ) .HasComment( "价格" ) - .HasPrecision( 12, 2 ); ; + .HasDefaultValue( 0 ) + .HasPrecision( 12, 2 ); + builder.Property( t => t.IntPrice ) + .HasColumnName( "IntPrice" ) + .HasComment( "价格" ) + .HasDefaultValue( 0 ); + builder.Property( t => t.LongPrice ) + .HasColumnName( "LongPrice" ) + .HasComment( "价格" ) + .HasDefaultValue( 0 ); + builder.Property( t => t.FloatPrice ) + .HasColumnName( "FloatPrice" ) + .HasComment( "价格" ) + .HasDefaultValue( 0 ); builder.Property( t => t.Description ) .HasColumnName( "Description" ) .HasComment( "描述" ); builder.Property( t => t.Enabled ) .HasColumnName( "Enabled" ) + .HasDefaultValue( TestConfig.BoolValue ) .HasComment( "启用" ); builder.Property( t => t.CreationTime ) .HasColumnName( "CreationTime" ) @@ -67,18 +82,21 @@ namespace Util.Applications.EntityTypeConfigurations { .HasColumnName( "LastModifierId" ) .HasComment( "最后修改人" ); builder.Property( t => t.IsDeleted ) - .HasColumnName( "IsDeleted" ) - .HasComment( "是否删除" ); + .HasDefaultValue( false ); } /// - /// 配置版本号 + /// 初始化数据 /// - private void ConfigVersion( EntityTypeBuilder builder ) { - builder.Property( t => t.Version ) - .HasColumnName( "Version" ) - .IsRowVersion() - .HasComment( "版本号" ); + private void InitData( EntityTypeBuilder builder ) { + var product = new Product( TestConfig.Id ) { + Code = TestConfig.Value, + Price = TestConfig.DecimalValue, + IntPrice = TestConfig.IntValue, + LongPrice = TestConfig.LongValue, + FloatPrice = TestConfig.FloatValue + }; + builder.HasData( product ); } } } \ No newline at end of file diff --git a/test/Util.TestShare.SqlServer/EntityTypeConfigurations/TagConfiguration.cs b/test/Util.TestShare.SqlServer/EntityTypeConfigurations/TagConfiguration.cs new file mode 100644 index 00000000..1f4f6f34 --- /dev/null +++ b/test/Util.TestShare.SqlServer/EntityTypeConfigurations/TagConfiguration.cs @@ -0,0 +1,57 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; +using Util.Tests.Models; + +namespace Util.Tests.EntityTypeConfigurations { + /// + /// 标签类型配置 + /// + public class TagConfiguration : IEntityTypeConfiguration { + /// + /// 配置 + /// + /// 实体类型生成器 + public void Configure( EntityTypeBuilder builder ) { + ConfigTable( builder ); + ConfigId( builder ); + ConfigProperties( builder ); + } + + /// + /// 配置表 + /// + private void ConfigTable( EntityTypeBuilder builder ) { + builder.ToTable( "Tag", "Blogs" ).HasComment( "标签" ); + } + + /// + /// 配置标识 + /// + private void ConfigId( EntityTypeBuilder builder ) { + builder.Property( t => t.Id ) + .HasColumnName( "TagId" ) + .HasComment( "标签标识" ); + } + + /// + /// 配置属性 + /// + private void ConfigProperties( EntityTypeBuilder builder ) { + builder.Property( t => t.Name ) + .HasColumnName( "Name" ) + .HasComment( "标签名称" ); + builder.Property( t => t.CreationTime ) + .HasColumnName( "CreationTime" ) + .HasComment( "创建时间" ); + builder.Property( t => t.CreatorId ) + .HasColumnName( "CreatorId" ) + .HasComment( "创建人" ); + builder.Property( t => t.LastModificationTime ) + .HasColumnName( "LastModificationTime" ) + .HasComment( "最后修改时间" ); + builder.Property( t => t.LastModifierId ) + .HasColumnName( "LastModifierId" ) + .HasComment( "最后修改人" ); + } + } +} \ No newline at end of file diff --git a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Repositories/CustomerRepository.cs b/test/Util.TestShare.SqlServer/Repositories/CustomerRepository.cs similarity index 55% rename from test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Repositories/CustomerRepository.cs rename to test/Util.TestShare.SqlServer/Repositories/CustomerRepository.cs index aa719a0c..780d3b12 100644 --- a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Repositories/CustomerRepository.cs +++ b/test/Util.TestShare.SqlServer/Repositories/CustomerRepository.cs @@ -1,7 +1,8 @@ -using Util.Data.EntityFrameworkCore.Models; -using Util.Data.EntityFrameworkCore.UnitOfWorks; +using Util.Data.EntityFrameworkCore; +using Util.Tests.Models; +using Util.Tests.UnitOfWorks; -namespace Util.Data.EntityFrameworkCore.Repositories { +namespace Util.Tests.Repositories { /// /// 客户仓储 /// @@ -10,7 +11,7 @@ namespace Util.Data.EntityFrameworkCore.Repositories { /// 初始化客户仓储 /// /// 工作单元 - public CustomerRepository( ISqlServerUnitOfWork unitOfWork ) : base( unitOfWork ) { + public CustomerRepository( ITestUnitOfWork unitOfWork ) : base( unitOfWork ) { } } } \ No newline at end of file diff --git a/test/Util.TestShare.SqlServer/Repositories/OperationLogRepository.cs b/test/Util.TestShare.SqlServer/Repositories/OperationLogRepository.cs new file mode 100644 index 00000000..75c9ab91 --- /dev/null +++ b/test/Util.TestShare.SqlServer/Repositories/OperationLogRepository.cs @@ -0,0 +1,17 @@ +using Util.Data.EntityFrameworkCore; +using Util.Tests.Models; +using Util.Tests.UnitOfWorks; + +namespace Util.Tests.Repositories { + /// + /// 操作日志仓储 + /// + public class OperationLogRepository : RepositoryBase,IOperationLogRepository { + /// + /// 初始化操作日志仓储 + /// + /// 工作单元 + public OperationLogRepository( ITestUnitOfWork unitOfWork ) : base( unitOfWork ) { + } + } +} \ No newline at end of file diff --git a/test/Util.TestShare.SqlServer/Repositories/OrderRepository.cs b/test/Util.TestShare.SqlServer/Repositories/OrderRepository.cs new file mode 100644 index 00000000..0ba4d0c4 --- /dev/null +++ b/test/Util.TestShare.SqlServer/Repositories/OrderRepository.cs @@ -0,0 +1,17 @@ +using Util.Data.EntityFrameworkCore; +using Util.Tests.Models; +using Util.Tests.UnitOfWorks; + +namespace Util.Tests.Repositories { + /// + /// 订单仓储 + /// + public class OrderRepository : RepositoryBase,IOrderRepository { + /// + /// 初始化订单仓储 + /// + /// 工作单元 + public OrderRepository( ITestUnitOfWork unitOfWork ) : base( unitOfWork ) { + } + } +} \ No newline at end of file diff --git a/test/Util.TestShare.SqlServer/Repositories/PostRepository.cs b/test/Util.TestShare.SqlServer/Repositories/PostRepository.cs new file mode 100644 index 00000000..a57bbb67 --- /dev/null +++ b/test/Util.TestShare.SqlServer/Repositories/PostRepository.cs @@ -0,0 +1,17 @@ +using Util.Data.EntityFrameworkCore; +using Util.Tests.Models; +using Util.Tests.UnitOfWorks; + +namespace Util.Tests.Repositories { + /// + /// 贴子仓储 + /// + public class PostRepository : RepositoryBase,IPostRepository { + /// + /// 初始化贴子仓储 + /// + /// 工作单元 + public PostRepository( ITestUnitOfWork unitOfWork ) : base( unitOfWork ) { + } + } +} \ No newline at end of file diff --git a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Repositories/ProductRepository.cs b/test/Util.TestShare.SqlServer/Repositories/ProductRepository.cs similarity index 68% rename from test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Repositories/ProductRepository.cs rename to test/Util.TestShare.SqlServer/Repositories/ProductRepository.cs index b20ac8f3..bdcb3988 100644 --- a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Repositories/ProductRepository.cs +++ b/test/Util.TestShare.SqlServer/Repositories/ProductRepository.cs @@ -1,7 +1,8 @@ -using Util.Data.EntityFrameworkCore.Models; -using Util.Data.EntityFrameworkCore.UnitOfWorks; +using Util.Data.EntityFrameworkCore; +using Util.Tests.Models; +using Util.Tests.UnitOfWorks; -namespace Util.Data.EntityFrameworkCore.Repositories { +namespace Util.Tests.Repositories { /// /// 产品仓储 /// @@ -10,7 +11,7 @@ namespace Util.Data.EntityFrameworkCore.Repositories { /// 初始化产品仓储 /// /// 工作单元 - public ProductRepository( ISqlServerUnitOfWork unitOfWork ) : base( unitOfWork ) { + public ProductRepository( ITestUnitOfWork unitOfWork ) : base( unitOfWork ) { } /// diff --git a/test/Util.TestShare.SqlServer/Repositories/TagRepository.cs b/test/Util.TestShare.SqlServer/Repositories/TagRepository.cs new file mode 100644 index 00000000..25d00508 --- /dev/null +++ b/test/Util.TestShare.SqlServer/Repositories/TagRepository.cs @@ -0,0 +1,17 @@ +using Util.Data.EntityFrameworkCore; +using Util.Tests.Models; +using Util.Tests.UnitOfWorks; + +namespace Util.Tests.Repositories { + /// + /// 标签仓储 + /// + public class TagRepository : RepositoryBase,ITagRepository { + /// + /// 初始化标签仓储 + /// + /// 工作单元 + public TagRepository( ITestUnitOfWork unitOfWork ) : base( unitOfWork ) { + } + } +} \ No newline at end of file diff --git a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/UnitOfWorks/SqlServerUnitOfWork.cs b/test/Util.TestShare.SqlServer/UnitOfWorks/SqlServerUnitOfWork.cs similarity index 89% rename from test/Util.Data.EntityFrameworkCore.SqlServer.Tests/UnitOfWorks/SqlServerUnitOfWork.cs rename to test/Util.TestShare.SqlServer/UnitOfWorks/SqlServerUnitOfWork.cs index 6ba5cdcd..ba717e6f 100644 --- a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/UnitOfWorks/SqlServerUnitOfWork.cs +++ b/test/Util.TestShare.SqlServer/UnitOfWorks/SqlServerUnitOfWork.cs @@ -1,12 +1,13 @@ using System; using Microsoft.EntityFrameworkCore; +using Util.Data.EntityFrameworkCore; using Util.Sessions; -namespace Util.Data.EntityFrameworkCore.UnitOfWorks { +namespace Util.Tests.UnitOfWorks { /// /// SqlServer工作单元 /// - public class SqlServerUnitOfWork : SqlServerUnitOfWorkBase, ISqlServerUnitOfWork { + public class SqlServerUnitOfWork : SqlServerUnitOfWorkBase, ITestUnitOfWork { /// /// 初始化工作单元 /// diff --git a/test/Util.TestShare.SqlServer/Util.TestShare.SqlServer.csproj b/test/Util.TestShare.SqlServer/Util.TestShare.SqlServer.csproj new file mode 100644 index 00000000..1de43866 --- /dev/null +++ b/test/Util.TestShare.SqlServer/Util.TestShare.SqlServer.csproj @@ -0,0 +1,14 @@ + + + + $(NetTargetFramework) + false + Util.Tests + + + + + + + + diff --git a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/EntityTypeConfigurations/CustomerConfiguration.cs b/test/Util.TestShare.Sqlite/EntityTypeConfigurations/CustomerConfiguration.cs similarity index 81% rename from test/Util.Data.EntityFrameworkCore.SqlServer.Tests/EntityTypeConfigurations/CustomerConfiguration.cs rename to test/Util.TestShare.Sqlite/EntityTypeConfigurations/CustomerConfiguration.cs index 268420e0..15debfab 100644 --- a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/EntityTypeConfigurations/CustomerConfiguration.cs +++ b/test/Util.TestShare.Sqlite/EntityTypeConfigurations/CustomerConfiguration.cs @@ -1,8 +1,9 @@ using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; -using Util.Data.EntityFrameworkCore.Models; +using Util.Tests.Configs; +using Util.Tests.Models; -namespace Util.Data.EntityFrameworkCore.EntityTypeConfigurations { +namespace Util.Tests.EntityTypeConfigurations { /// /// 客户类型配置 /// @@ -15,13 +16,14 @@ namespace Util.Data.EntityFrameworkCore.EntityTypeConfigurations { ConfigTable( builder ); ConfigId( builder ); ConfigProperties( builder ); + InitData( builder ); } /// /// 配置表 /// private void ConfigTable( EntityTypeBuilder builder ) { - builder.ToTable( "Customer", "Customers" ).HasComment( "客户" ); + builder.ToTable( "Customer" ).HasComment( "客户" ); } /// @@ -74,6 +76,19 @@ namespace Util.Data.EntityFrameworkCore.EntityTypeConfigurations { builder.Property( t => t.LastModifierId ) .HasColumnName( "LastModifierId" ) .HasComment( "最后修改人" ); + builder.Property( t => t.IsDeleted ) + .HasDefaultValue( false ); + } + + /// + /// 初始化数据 + /// + private void InitData( EntityTypeBuilder builder ) { + var customer = new Customer( 1 ) { + Code = TestConfig.Value, + Birthday = TestConfig.DateTimeValue + }; + builder.HasData( customer ); } } } \ No newline at end of file diff --git a/test/Util.TestShare.Sqlite/EntityTypeConfigurations/OperationLogConfiguration.cs b/test/Util.TestShare.Sqlite/EntityTypeConfigurations/OperationLogConfiguration.cs new file mode 100644 index 00000000..cd5bbb55 --- /dev/null +++ b/test/Util.TestShare.Sqlite/EntityTypeConfigurations/OperationLogConfiguration.cs @@ -0,0 +1,55 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; +using Util.Tests.Models; + +namespace Util.Tests.EntityTypeConfigurations { + /// + /// 操作日志类型配置 + /// + public class OperationLogConfiguration : IEntityTypeConfiguration { + /// + /// 配置 + /// + /// 实体类型生成器 + public void Configure( EntityTypeBuilder builder ) { + ConfigTable( builder ); + ConfigId( builder ); + ConfigProperties( builder ); + } + + /// + /// 配置表 + /// + private void ConfigTable( EntityTypeBuilder builder ) { + builder.ToTable( "OperationLog" ).HasComment( "操作日志" ); + } + + /// + /// 配置标识 + /// + private void ConfigId( EntityTypeBuilder builder ) { + builder.Property( t => t.Id ) + .HasColumnName( "LogId" ) + .HasComment( "操作标识" ) + .ValueGeneratedOnAdd(); + } + + /// + /// 配置属性 + /// + private void ConfigProperties( EntityTypeBuilder builder ) { + builder.Property( t => t.LogName ) + .HasColumnName( "LogName" ) + .HasComment( "日志名称" ); + builder.Property( t => t.OperationTime ) + .HasColumnName( "OperationTime" ) + .HasComment( "操作时间" ); + builder.Property( t => t.Caption ) + .HasColumnName( "Caption" ) + .HasComment( "标题" ); + builder.Property( t => t.Content ) + .HasColumnName( "Content" ) + .HasComment( "内容" ); + } + } +} \ No newline at end of file diff --git a/test/Util.TestShare.Sqlite/EntityTypeConfigurations/OrderConfiguration.cs b/test/Util.TestShare.Sqlite/EntityTypeConfigurations/OrderConfiguration.cs new file mode 100644 index 00000000..20f9a804 --- /dev/null +++ b/test/Util.TestShare.Sqlite/EntityTypeConfigurations/OrderConfiguration.cs @@ -0,0 +1,65 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; +using Util.Tests.Configs; +using Util.Tests.Models; + +namespace Util.Tests.EntityTypeConfigurations { + /// + /// 订单类型配置 + /// + public class OrderConfiguration : IEntityTypeConfiguration { + /// + /// 配置 + /// + /// 实体类型生成器 + public void Configure( EntityTypeBuilder builder ) { + ConfigTable( builder ); + ConfigId( builder ); + ConfigProperties( builder ); + } + + /// + /// 配置表 + /// + private void ConfigTable( EntityTypeBuilder builder ) { + builder.ToTable( "Order" ).HasComment( "订单" ); + } + + /// + /// 配置标识 + /// + private void ConfigId( EntityTypeBuilder builder ) { + builder.Property( t => t.Id ) + .HasMaxLength( 50 ) + .HasColumnName( "OrderId" ) + .HasComment( "订单标识" ); + } + + /// + /// 配置属性 + /// + private void ConfigProperties( EntityTypeBuilder builder ) { + builder.Property( t => t.CustomerId ) + .HasColumnName( "CustomerId" ) + .HasComment( "客户标识" ); + builder.Property( t => t.CustomerName ) + .HasColumnName( "CustomerName" ) + .HasComment( "客户名称" ); + builder.Property( t => t.Amount ) + .HasColumnName( "Amount" ) + .HasComment( "金额" ) + .HasPrecision(15,2) + .HasDefaultValue(0); + builder.Property( t => t.PlaceOrderTime ) + .HasColumnName( "PlaceOrderTime" ) + .HasComment( "下单时间" ) + .HasDefaultValue( TestConfig.DateTimeValue ); + builder.Property( t => t.State ) + .HasColumnName( "State" ) + .HasComment( "订单状态" ) + .HasDefaultValue( 0 ); + builder.Property( t => t.IsDeleted ) + .HasDefaultValue( false ); + } + } +} \ No newline at end of file diff --git a/test/Util.TestShare.Sqlite/EntityTypeConfigurations/OrderItemConfiguration.cs b/test/Util.TestShare.Sqlite/EntityTypeConfigurations/OrderItemConfiguration.cs new file mode 100644 index 00000000..478138a2 --- /dev/null +++ b/test/Util.TestShare.Sqlite/EntityTypeConfigurations/OrderItemConfiguration.cs @@ -0,0 +1,70 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; +using Util.Tests.Models; + +namespace Util.Tests.EntityTypeConfigurations { + /// + /// 订单明细类型配置 + /// + public class OrderItemConfiguration : IEntityTypeConfiguration { + /// + /// 配置 + /// + /// 实体类型生成器 + public void Configure( EntityTypeBuilder builder ) { + ConfigTable( builder ); + ConfigId( builder ); + ConfigProperties( builder ); + ConfigAssociations( builder ); + } + + /// + /// 配置表 + /// + private void ConfigTable( EntityTypeBuilder builder ) { + builder.ToTable( "OrderItem" ).HasComment( "订单明细" ); + } + + /// + /// 配置标识 + /// + private void ConfigId( EntityTypeBuilder builder ) { + builder.Property( t => t.Id ) + .HasColumnName( "OrderItemId" ) + .HasComment( "订单明细标识" ); + } + + /// + /// 配置属性 + /// + private void ConfigProperties( EntityTypeBuilder builder ) { + builder.Property( t => t.OrderId ) + .HasColumnName( "OrderId" ) + .HasMaxLength( 50 ) + .HasComment( "订单标识" ); + builder.Property( t => t.ProductId ) + .HasColumnName( "ProductId" ) + .HasComment( "产品标识" ); + builder.Property( t => t.ProductName ) + .HasColumnName( "ProductName" ) + .HasComment( "产品名称" ); + builder.Property( t => t.Price ) + .HasColumnName( "Price" ) + .HasComment( "单价" ) + .HasPrecision(12,2); + builder.Property( t => t.Quantity ) + .HasColumnName( "Quantity" ) + .HasComment( "数量" ) + .HasDefaultValue( 1 ); + } + + /// + /// 映射导航属性 + /// + private void ConfigAssociations( EntityTypeBuilder builder ) { + builder.HasOne( t => t.Order ) + .WithMany( t => t.OrderItems ) + .HasForeignKey( t => t.OrderId ); + } + } +} \ No newline at end of file diff --git a/test/Util.TestShare.Sqlite/EntityTypeConfigurations/PostConfiguration.cs b/test/Util.TestShare.Sqlite/EntityTypeConfigurations/PostConfiguration.cs new file mode 100644 index 00000000..2fa46dd8 --- /dev/null +++ b/test/Util.TestShare.Sqlite/EntityTypeConfigurations/PostConfiguration.cs @@ -0,0 +1,63 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; +using Util.Tests.Models; + +namespace Util.Tests.EntityTypeConfigurations { + /// + /// 贴子类型配置 + /// + public class PostConfiguration : IEntityTypeConfiguration { + /// + /// 配置 + /// + /// 实体类型生成器 + public void Configure( EntityTypeBuilder builder ) { + ConfigTable( builder ); + ConfigId( builder ); + ConfigProperties( builder ); + } + + /// + /// 配置表 + /// + private void ConfigTable( EntityTypeBuilder builder ) { + builder.ToTable( "Post" ).HasComment( "贴子" ); + } + + /// + /// 配置标识 + /// + private void ConfigId( EntityTypeBuilder builder ) { + builder.Property( t => t.Id ) + .HasColumnName( "PostId" ) + .HasComment( "贴子标识" ); + } + + /// + /// 配置属性 + /// + private void ConfigProperties( EntityTypeBuilder builder ) { + builder.Property( t => t.Title ) + .HasColumnName( "Title" ) + .HasComment( "标题" ); + builder.Property( t => t.Content ) + .HasColumnName( "Content" ) + .HasComment( "内容" ); + builder.Property( t => t.CreationTime ) + .HasColumnName( "CreationTime" ) + .HasComment( "创建时间" ); + builder.Property( t => t.CreatorId ) + .HasColumnName( "CreatorId" ) + .HasComment( "创建人" ); + builder.Property( t => t.LastModificationTime ) + .HasColumnName( "LastModificationTime" ) + .HasComment( "最后修改时间" ); + builder.Property( t => t.LastModifierId ) + .HasColumnName( "LastModifierId" ) + .HasComment( "最后修改人" ); + builder.HasMany( t => t.Tags ) + .WithMany( t => t.Posts ) + .UsingEntity( t => t.ToTable( "PostTag2" ) ); + } + } +} \ No newline at end of file diff --git a/test/Util.TestShare.Sqlite/EntityTypeConfigurations/ProductConfiguration.cs b/test/Util.TestShare.Sqlite/EntityTypeConfigurations/ProductConfiguration.cs new file mode 100644 index 00000000..a062b792 --- /dev/null +++ b/test/Util.TestShare.Sqlite/EntityTypeConfigurations/ProductConfiguration.cs @@ -0,0 +1,102 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; +using Util.Tests.Configs; +using Util.Tests.Models; + +namespace Util.Tests.EntityTypeConfigurations { + /// + /// 产品类型配置 + /// + public class ProductConfiguration : IEntityTypeConfiguration { + /// + /// 配置 + /// + /// 实体类型生成器 + public void Configure( EntityTypeBuilder builder ) { + ConfigTable( builder ); + ConfigId( builder ); + ConfigProperties( builder ); + InitData( builder ); + } + + /// + /// 配置表 + /// + private void ConfigTable( EntityTypeBuilder builder ) { + builder.ToTable( "Product" ).HasComment( "产品" ); + } + + /// + /// 配置标识 + /// + private void ConfigId( EntityTypeBuilder builder ) { + builder.Property( t => t.Id ) + .HasColumnName( "ProductId" ) + .HasComment( "产品标识" ); + } + + /// + /// 配置属性 + /// + private void ConfigProperties( EntityTypeBuilder builder ) { + builder.Property( t => t.Code ) + .HasColumnName( "Code" ) + .HasComment( "产品编码" ); + builder.Property( t => t.Name ) + .HasColumnName( "Name" ) + .HasComment( "产品名称" ); + builder.Property( t => t.Price ) + .HasColumnName( "Price" ) + .HasComment( "价格" ) + .HasDefaultValue( 0 ) + .HasPrecision( 12, 2 ); + builder.Property( t => t.IntPrice ) + .HasColumnName( "IntPrice" ) + .HasComment( "价格" ) + .HasDefaultValue( 0 ); + builder.Property( t => t.LongPrice ) + .HasColumnName( "LongPrice" ) + .HasComment( "价格" ) + .HasDefaultValue( 0 ); + builder.Property( t => t.FloatPrice ) + .HasColumnName( "FloatPrice" ) + .HasComment( "价格" ) + .HasDefaultValue( 0 ); + builder.Property( t => t.Description ) + .HasColumnName( "Description" ) + .HasComment( "描述" ); + builder.Property( t => t.Enabled ) + .HasColumnName( "Enabled" ) + .HasDefaultValue( TestConfig.BoolValue ) + .HasComment( "启用" ); + builder.Property( t => t.CreationTime ) + .HasColumnName( "CreationTime" ) + .HasComment( "创建时间" ); + builder.Property( t => t.CreatorId ) + .HasColumnName( "CreatorId" ) + .HasComment( "创建人" ); + builder.Property( t => t.LastModificationTime ) + .HasColumnName( "LastModificationTime" ) + .HasComment( "最后修改时间" ); + builder.Property( t => t.LastModifierId ) + .HasColumnName( "LastModifierId" ) + .HasComment( "最后修改人" ); + builder.Property( t => t.IsDeleted ) + .HasDefaultValue( false ); + } + + /// + /// 初始化数据 + /// + private void InitData( EntityTypeBuilder builder ) { + var product = new Product( TestConfig.Id ) { + Code = TestConfig.Value, + Price = TestConfig.DecimalValue, + IntPrice = TestConfig.IntValue, + LongPrice = TestConfig.LongValue, + FloatPrice = TestConfig.FloatValue + }; + builder.HasData( product ); + } + } +} \ No newline at end of file diff --git a/test/Util.TestShare.Sqlite/EntityTypeConfigurations/TagConfiguration.cs b/test/Util.TestShare.Sqlite/EntityTypeConfigurations/TagConfiguration.cs new file mode 100644 index 00000000..12956262 --- /dev/null +++ b/test/Util.TestShare.Sqlite/EntityTypeConfigurations/TagConfiguration.cs @@ -0,0 +1,57 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; +using Util.Tests.Models; + +namespace Util.Tests.EntityTypeConfigurations { + /// + /// 标签类型配置 + /// + public class TagConfiguration : IEntityTypeConfiguration { + /// + /// 配置 + /// + /// 实体类型生成器 + public void Configure( EntityTypeBuilder builder ) { + ConfigTable( builder ); + ConfigId( builder ); + ConfigProperties( builder ); + } + + /// + /// 配置表 + /// + private void ConfigTable( EntityTypeBuilder builder ) { + builder.ToTable( "Tag" ).HasComment( "标签" ); + } + + /// + /// 配置标识 + /// + private void ConfigId( EntityTypeBuilder builder ) { + builder.Property( t => t.Id ) + .HasColumnName( "TagId" ) + .HasComment( "标签标识" ); + } + + /// + /// 配置属性 + /// + private void ConfigProperties( EntityTypeBuilder builder ) { + builder.Property( t => t.Name ) + .HasColumnName( "Name" ) + .HasComment( "标签名称" ); + builder.Property( t => t.CreationTime ) + .HasColumnName( "CreationTime" ) + .HasComment( "创建时间" ); + builder.Property( t => t.CreatorId ) + .HasColumnName( "CreatorId" ) + .HasComment( "创建人" ); + builder.Property( t => t.LastModificationTime ) + .HasColumnName( "LastModificationTime" ) + .HasComment( "最后修改时间" ); + builder.Property( t => t.LastModifierId ) + .HasColumnName( "LastModifierId" ) + .HasComment( "最后修改人" ); + } + } +} \ No newline at end of file diff --git a/test/Util.TestShare.Sqlite/Repositories/CustomerRepository.cs b/test/Util.TestShare.Sqlite/Repositories/CustomerRepository.cs new file mode 100644 index 00000000..780d3b12 --- /dev/null +++ b/test/Util.TestShare.Sqlite/Repositories/CustomerRepository.cs @@ -0,0 +1,17 @@ +using Util.Data.EntityFrameworkCore; +using Util.Tests.Models; +using Util.Tests.UnitOfWorks; + +namespace Util.Tests.Repositories { + /// + /// 客户仓储 + /// + public class CustomerRepository : RepositoryBase,ICustomerRepository { + /// + /// 初始化客户仓储 + /// + /// 工作单元 + public CustomerRepository( ITestUnitOfWork unitOfWork ) : base( unitOfWork ) { + } + } +} \ No newline at end of file diff --git a/test/Util.TestShare.Sqlite/Repositories/OperationLogRepository.cs b/test/Util.TestShare.Sqlite/Repositories/OperationLogRepository.cs new file mode 100644 index 00000000..75c9ab91 --- /dev/null +++ b/test/Util.TestShare.Sqlite/Repositories/OperationLogRepository.cs @@ -0,0 +1,17 @@ +using Util.Data.EntityFrameworkCore; +using Util.Tests.Models; +using Util.Tests.UnitOfWorks; + +namespace Util.Tests.Repositories { + /// + /// 操作日志仓储 + /// + public class OperationLogRepository : RepositoryBase,IOperationLogRepository { + /// + /// 初始化操作日志仓储 + /// + /// 工作单元 + public OperationLogRepository( ITestUnitOfWork unitOfWork ) : base( unitOfWork ) { + } + } +} \ No newline at end of file diff --git a/test/Util.TestShare.Sqlite/Repositories/OrderRepository.cs b/test/Util.TestShare.Sqlite/Repositories/OrderRepository.cs new file mode 100644 index 00000000..0ba4d0c4 --- /dev/null +++ b/test/Util.TestShare.Sqlite/Repositories/OrderRepository.cs @@ -0,0 +1,17 @@ +using Util.Data.EntityFrameworkCore; +using Util.Tests.Models; +using Util.Tests.UnitOfWorks; + +namespace Util.Tests.Repositories { + /// + /// 订单仓储 + /// + public class OrderRepository : RepositoryBase,IOrderRepository { + /// + /// 初始化订单仓储 + /// + /// 工作单元 + public OrderRepository( ITestUnitOfWork unitOfWork ) : base( unitOfWork ) { + } + } +} \ No newline at end of file diff --git a/test/Util.TestShare.Sqlite/Repositories/PostRepository.cs b/test/Util.TestShare.Sqlite/Repositories/PostRepository.cs new file mode 100644 index 00000000..a57bbb67 --- /dev/null +++ b/test/Util.TestShare.Sqlite/Repositories/PostRepository.cs @@ -0,0 +1,17 @@ +using Util.Data.EntityFrameworkCore; +using Util.Tests.Models; +using Util.Tests.UnitOfWorks; + +namespace Util.Tests.Repositories { + /// + /// 贴子仓储 + /// + public class PostRepository : RepositoryBase,IPostRepository { + /// + /// 初始化贴子仓储 + /// + /// 工作单元 + public PostRepository( ITestUnitOfWork unitOfWork ) : base( unitOfWork ) { + } + } +} \ No newline at end of file diff --git a/test/Util.TestShare.Sqlite/Repositories/ProductRepository.cs b/test/Util.TestShare.Sqlite/Repositories/ProductRepository.cs new file mode 100644 index 00000000..bdcb3988 --- /dev/null +++ b/test/Util.TestShare.Sqlite/Repositories/ProductRepository.cs @@ -0,0 +1,25 @@ +using Util.Data.EntityFrameworkCore; +using Util.Tests.Models; +using Util.Tests.UnitOfWorks; + +namespace Util.Tests.Repositories { + /// + /// 产品仓储 + /// + public class ProductRepository : RepositoryBase,IProductRepository { + /// + /// 初始化产品仓储 + /// + /// 工作单元 + public ProductRepository( ITestUnitOfWork unitOfWork ) : base( unitOfWork ) { + } + + /// + /// 更新产品 + /// + /// 产品 + public void UpdateProduct( Product product ) { + UnitOfWork.Update( product ); + } + } +} \ No newline at end of file diff --git a/test/Util.TestShare.Sqlite/Repositories/TagRepository.cs b/test/Util.TestShare.Sqlite/Repositories/TagRepository.cs new file mode 100644 index 00000000..25d00508 --- /dev/null +++ b/test/Util.TestShare.Sqlite/Repositories/TagRepository.cs @@ -0,0 +1,17 @@ +using Util.Data.EntityFrameworkCore; +using Util.Tests.Models; +using Util.Tests.UnitOfWorks; + +namespace Util.Tests.Repositories { + /// + /// 标签仓储 + /// + public class TagRepository : RepositoryBase,ITagRepository { + /// + /// 初始化标签仓储 + /// + /// 工作单元 + public TagRepository( ITestUnitOfWork unitOfWork ) : base( unitOfWork ) { + } + } +} \ No newline at end of file diff --git a/test/Util.TestShare.Sqlite/UnitOfWorks/SqliteUnitOfWork.cs b/test/Util.TestShare.Sqlite/UnitOfWorks/SqliteUnitOfWork.cs new file mode 100644 index 00000000..90c053c7 --- /dev/null +++ b/test/Util.TestShare.Sqlite/UnitOfWorks/SqliteUnitOfWork.cs @@ -0,0 +1,26 @@ +using System; +using Microsoft.EntityFrameworkCore; +using Util.Data.EntityFrameworkCore; +using Util.Sessions; + +namespace Util.Tests.UnitOfWorks { + /// + /// Sqlite工作单元 + /// + public class SqliteUnitOfWork : SqliteUnitOfWorkBase, ITestUnitOfWork { + /// + /// 初始化工作单元 + /// + /// 服务提供器 + /// 配置项 + public SqliteUnitOfWork( IServiceProvider serviceProvider ,DbContextOptions options) : base( serviceProvider, options ) { + } + + /// + /// 设置用户会话 + /// + public void SetSession( ISession session ) { + Session = session; + } + } +} \ No newline at end of file diff --git a/test/Util.TestShare.Sqlite/Util.TestShare.Sqlite.csproj b/test/Util.TestShare.Sqlite/Util.TestShare.Sqlite.csproj new file mode 100644 index 00000000..f727a68a --- /dev/null +++ b/test/Util.TestShare.Sqlite/Util.TestShare.Sqlite.csproj @@ -0,0 +1,13 @@ + + + + $(NetTargetFramework) + false + Util.Tests + + + + + + + \ No newline at end of file diff --git a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Conditions/ProductNameCondition.cs b/test/Util.TestShare/Conditions/ProductNameCondition.cs similarity index 88% rename from test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Conditions/ProductNameCondition.cs rename to test/Util.TestShare/Conditions/ProductNameCondition.cs index a45ea6fa..3317e4a0 100644 --- a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Conditions/ProductNameCondition.cs +++ b/test/Util.TestShare/Conditions/ProductNameCondition.cs @@ -1,8 +1,9 @@ using System; using System.Linq.Expressions; -using Util.Data.EntityFrameworkCore.Models; +using Util.Data; +using Util.Tests.Models; -namespace Util.Data.EntityFrameworkCore.Conditions { +namespace Util.Tests.Conditions { /// /// 产品名称查询条件 /// diff --git a/test/Util.TestShare/Configs/TestConfig.cs b/test/Util.TestShare/Configs/TestConfig.cs new file mode 100644 index 00000000..5b1beb4c --- /dev/null +++ b/test/Util.TestShare/Configs/TestConfig.cs @@ -0,0 +1,49 @@ +using System; + +namespace Util.Tests.Configs { + /// + /// 测试配置 + /// + public class TestConfig { + /// + /// 测试标识 + /// + public static Guid Id { get; } = "08255312-DF8E-4F0C-AD4D-638B3A63D889".ToGuid(); + /// + /// 测试值 + /// + public static string Value { get; } = "abc"; + /// + /// 测试整型值 + /// + public static int IntValue { get; } = 123; + /// + /// 测试长整型值 + /// + public static long LongValue { get; } = 123456789; + /// + /// 测试Guid值 + /// + public static Guid GuidValue { get; } = "04255312-DF8E-4F0C-AD4D-638B3A63D868".ToGuid(); + /// + /// 测试布尔值 + /// + public static bool BoolValue { get; } = true; + /// + /// 测试float值 + /// + public static float FloatValue { get; } = 123.45F; + /// + /// 测试double值 + /// + public static double DoubleValue { get; } = 12345.67; + /// + /// 测试decimal值 + /// + public static decimal DecimalValue { get; } = 12345.67M; + /// + /// 测试日期值 + /// + public static DateTime DateTimeValue { get; } = "2012-12-12 12:12:12".ToDateTime(); + } +} diff --git a/test/Util.Application.WebApi.Tests.Integration/Controllers/CustomerController.cs b/test/Util.TestShare/Controllers/CustomerController.cs similarity index 92% rename from test/Util.Application.WebApi.Tests.Integration/Controllers/CustomerController.cs rename to test/Util.TestShare/Controllers/CustomerController.cs index ee4fe1f9..e1c02ae8 100644 --- a/test/Util.Application.WebApi.Tests.Integration/Controllers/CustomerController.cs +++ b/test/Util.TestShare/Controllers/CustomerController.cs @@ -1,10 +1,11 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; -using Util.Applications.Dtos; -using Util.Applications.Queries; -using Util.Applications.Services; +using Util.Applications.Controllers; +using Util.Tests.Dtos; +using Util.Tests.Queries; +using Util.Tests.Services; -namespace Util.Applications.Controllers { +namespace Util.Tests.Controllers { /// /// 客户查询控制器 /// diff --git a/test/Util.Application.WebApi.Tests.Integration/Controllers/ProductController.cs b/test/Util.TestShare/Controllers/ProductController.cs similarity index 95% rename from test/Util.Application.WebApi.Tests.Integration/Controllers/ProductController.cs rename to test/Util.TestShare/Controllers/ProductController.cs index 7418b942..cf82980b 100644 --- a/test/Util.Application.WebApi.Tests.Integration/Controllers/ProductController.cs +++ b/test/Util.TestShare/Controllers/ProductController.cs @@ -1,10 +1,11 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; -using Util.Applications.Dtos; -using Util.Applications.Queries; -using Util.Applications.Services; +using Util.Applications.Controllers; +using Util.Tests.Dtos; +using Util.Tests.Queries; +using Util.Tests.Services; -namespace Util.Applications.Controllers { +namespace Util.Tests.Controllers { /// /// 产品控制器 /// diff --git a/test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/Dtos/CustomerDto.cs b/test/Util.TestShare/Dtos/CustomerDto.cs similarity index 97% rename from test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/Dtos/CustomerDto.cs rename to test/Util.TestShare/Dtos/CustomerDto.cs index f6b56818..385003d2 100644 --- a/test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/Dtos/CustomerDto.cs +++ b/test/Util.TestShare/Dtos/CustomerDto.cs @@ -1,9 +1,10 @@ using System; using System.ComponentModel; using System.ComponentModel.DataAnnotations; +using Util.Applications.Dtos; using Util.Domain.Biz.Enums; -namespace Util.Applications.Dtos { +namespace Util.Tests.Dtos { /// /// 客户参数 /// diff --git a/test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/Dtos/ProductDto.cs b/test/Util.TestShare/Dtos/ProductDto.cs similarity index 96% rename from test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/Dtos/ProductDto.cs rename to test/Util.TestShare/Dtos/ProductDto.cs index 4ed17921..b5ff09aa 100644 --- a/test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/Dtos/ProductDto.cs +++ b/test/Util.TestShare/Dtos/ProductDto.cs @@ -2,9 +2,10 @@ using System; using System.Collections.Generic; using System.ComponentModel; using System.ComponentModel.DataAnnotations; -using Util.Applications.Models; +using Util.Applications.Dtos; +using Util.Tests.Models; -namespace Util.Applications.Dtos { +namespace Util.Tests.Dtos { /// /// 产品参数 /// diff --git a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/EventHandlers/OperationLogChangedEventHandler.cs b/test/Util.TestShare/EventHandlers/OperationLogChangedEventHandler.cs similarity index 78% rename from test/Util.Data.EntityFrameworkCore.SqlServer.Tests/EventHandlers/OperationLogChangedEventHandler.cs rename to test/Util.TestShare/EventHandlers/OperationLogChangedEventHandler.cs index adf535db..233ffa39 100644 --- a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/EventHandlers/OperationLogChangedEventHandler.cs +++ b/test/Util.TestShare/EventHandlers/OperationLogChangedEventHandler.cs @@ -1,11 +1,11 @@ using System.Threading.Tasks; -using Util.Data.EntityFrameworkCore.Models; -using Util.Data.EntityFrameworkCore.Repositories; -using Util.Data.EntityFrameworkCore.UnitOfWorks; using Util.Domain.Events; using Util.Events; +using Util.Tests.Models; +using Util.Tests.Repositories; +using Util.Tests.UnitOfWorks; -namespace Util.Data.EntityFrameworkCore.EventHandlers { +namespace Util.Tests.EventHandlers { /// /// 操作日志变更事件处理器 /// @@ -13,7 +13,7 @@ namespace Util.Data.EntityFrameworkCore.EventHandlers { /// /// 工作单元 /// - private readonly ISqlServerUnitOfWork _unitOfWork; + private readonly ITestUnitOfWork _unitOfWork; /// /// 操作日志仓储 /// @@ -24,7 +24,7 @@ namespace Util.Data.EntityFrameworkCore.EventHandlers { /// /// 工作单元 /// 操作日志仓储 - public OperationLogChangedEventHandler( ISqlServerUnitOfWork unitOfWork, IOperationLogRepository operationLogRepository ) { + public OperationLogChangedEventHandler( ITestUnitOfWork unitOfWork, IOperationLogRepository operationLogRepository ) { _unitOfWork = unitOfWork; _operationLogRepository = operationLogRepository; } diff --git a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/EventHandlers/OperationLogDeletedEventHandler.cs b/test/Util.TestShare/EventHandlers/OperationLogDeletedEventHandler.cs similarity index 78% rename from test/Util.Data.EntityFrameworkCore.SqlServer.Tests/EventHandlers/OperationLogDeletedEventHandler.cs rename to test/Util.TestShare/EventHandlers/OperationLogDeletedEventHandler.cs index 688f7ca2..14695ef0 100644 --- a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/EventHandlers/OperationLogDeletedEventHandler.cs +++ b/test/Util.TestShare/EventHandlers/OperationLogDeletedEventHandler.cs @@ -1,11 +1,11 @@ using System.Threading.Tasks; -using Util.Data.EntityFrameworkCore.Models; -using Util.Data.EntityFrameworkCore.Repositories; -using Util.Data.EntityFrameworkCore.UnitOfWorks; using Util.Domain.Events; using Util.Events; +using Util.Tests.Models; +using Util.Tests.Repositories; +using Util.Tests.UnitOfWorks; -namespace Util.Data.EntityFrameworkCore.EventHandlers { +namespace Util.Tests.EventHandlers { /// /// 操作日志删除事件处理器 /// @@ -13,7 +13,7 @@ namespace Util.Data.EntityFrameworkCore.EventHandlers { /// /// 工作单元 /// - private readonly ISqlServerUnitOfWork _unitOfWork; + private readonly ITestUnitOfWork _unitOfWork; /// /// 操作日志仓储 /// @@ -24,7 +24,7 @@ namespace Util.Data.EntityFrameworkCore.EventHandlers { /// /// 工作单元 /// 操作日志仓储 - public OperationLogDeletedEventHandler( ISqlServerUnitOfWork unitOfWork, IOperationLogRepository operationLogRepository ) { + public OperationLogDeletedEventHandler( ITestUnitOfWork unitOfWork, IOperationLogRepository operationLogRepository ) { _unitOfWork = unitOfWork; _operationLogRepository = operationLogRepository; } diff --git a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/EventHandlers/ProductChangedEventHandler.cs b/test/Util.TestShare/EventHandlers/ProductChangedEventHandler.cs similarity index 83% rename from test/Util.Data.EntityFrameworkCore.SqlServer.Tests/EventHandlers/ProductChangedEventHandler.cs rename to test/Util.TestShare/EventHandlers/ProductChangedEventHandler.cs index 3c79059a..3e6e562a 100644 --- a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/EventHandlers/ProductChangedEventHandler.cs +++ b/test/Util.TestShare/EventHandlers/ProductChangedEventHandler.cs @@ -1,12 +1,11 @@ -using System; -using System.Threading.Tasks; -using Util.Data.EntityFrameworkCore.Models; -using Util.Data.EntityFrameworkCore.Repositories; -using Util.Data.EntityFrameworkCore.UnitOfWorks; +using System.Threading.Tasks; using Util.Domain.Events; using Util.Events; +using Util.Tests.Models; +using Util.Tests.Repositories; +using Util.Tests.UnitOfWorks; -namespace Util.Data.EntityFrameworkCore.EventHandlers { +namespace Util.Tests.EventHandlers { /// /// 产品变更事件处理器 /// @@ -14,7 +13,7 @@ namespace Util.Data.EntityFrameworkCore.EventHandlers { /// /// 工作单元 /// - private readonly ISqlServerUnitOfWork _unitOfWork; + private readonly ITestUnitOfWork _unitOfWork; /// /// 操作日志仓储 /// @@ -25,7 +24,7 @@ namespace Util.Data.EntityFrameworkCore.EventHandlers { /// /// 工作单元 /// 操作日志仓储 - public ProductChangedEventHandler( ISqlServerUnitOfWork unitOfWork, IOperationLogRepository operationLogRepository ) { + public ProductChangedEventHandler( ITestUnitOfWork unitOfWork, IOperationLogRepository operationLogRepository ) { _unitOfWork = unitOfWork; _operationLogRepository = operationLogRepository; } diff --git a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/EventHandlers/ProductCreatedEventHandler.cs b/test/Util.TestShare/EventHandlers/ProductCreatedEventHandler.cs similarity index 77% rename from test/Util.Data.EntityFrameworkCore.SqlServer.Tests/EventHandlers/ProductCreatedEventHandler.cs rename to test/Util.TestShare/EventHandlers/ProductCreatedEventHandler.cs index 9cef78ae..8f50dfc2 100644 --- a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/EventHandlers/ProductCreatedEventHandler.cs +++ b/test/Util.TestShare/EventHandlers/ProductCreatedEventHandler.cs @@ -1,11 +1,11 @@ using System.Threading.Tasks; -using Util.Data.EntityFrameworkCore.Models; -using Util.Data.EntityFrameworkCore.Repositories; -using Util.Data.EntityFrameworkCore.UnitOfWorks; using Util.Domain.Events; using Util.Events; +using Util.Tests.Models; +using Util.Tests.Repositories; +using Util.Tests.UnitOfWorks; -namespace Util.Data.EntityFrameworkCore.EventHandlers { +namespace Util.Tests.EventHandlers { /// /// 产品创建事件处理器 /// @@ -13,7 +13,7 @@ namespace Util.Data.EntityFrameworkCore.EventHandlers { /// /// 工作单元 /// - private readonly ISqlServerUnitOfWork _unitOfWork; + private readonly ITestUnitOfWork _unitOfWork; /// /// 操作日志仓储 /// @@ -24,7 +24,7 @@ namespace Util.Data.EntityFrameworkCore.EventHandlers { /// /// 工作单元 /// 操作日志仓储 - public ProductCreatedEventHandler( ISqlServerUnitOfWork unitOfWork, IOperationLogRepository operationLogRepository ) { + public ProductCreatedEventHandler( ITestUnitOfWork unitOfWork, IOperationLogRepository operationLogRepository ) { _unitOfWork = unitOfWork; _operationLogRepository = operationLogRepository; } diff --git a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/EventHandlers/ProductDeletedEventHandler.cs b/test/Util.TestShare/EventHandlers/ProductDeletedEventHandler.cs similarity index 77% rename from test/Util.Data.EntityFrameworkCore.SqlServer.Tests/EventHandlers/ProductDeletedEventHandler.cs rename to test/Util.TestShare/EventHandlers/ProductDeletedEventHandler.cs index 31aed0d8..04bd6c98 100644 --- a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/EventHandlers/ProductDeletedEventHandler.cs +++ b/test/Util.TestShare/EventHandlers/ProductDeletedEventHandler.cs @@ -1,11 +1,11 @@ using System.Threading.Tasks; -using Util.Data.EntityFrameworkCore.Models; -using Util.Data.EntityFrameworkCore.Repositories; -using Util.Data.EntityFrameworkCore.UnitOfWorks; using Util.Domain.Events; using Util.Events; +using Util.Tests.Models; +using Util.Tests.Repositories; +using Util.Tests.UnitOfWorks; -namespace Util.Data.EntityFrameworkCore.EventHandlers { +namespace Util.Tests.EventHandlers { /// /// 产品删除事件处理器 /// @@ -13,7 +13,7 @@ namespace Util.Data.EntityFrameworkCore.EventHandlers { /// /// 工作单元 /// - private readonly ISqlServerUnitOfWork _unitOfWork; + private readonly ITestUnitOfWork _unitOfWork; /// /// 操作日志仓储 /// @@ -24,7 +24,7 @@ namespace Util.Data.EntityFrameworkCore.EventHandlers { /// /// 工作单元 /// 操作日志仓储 - public ProductDeletedEventHandler( ISqlServerUnitOfWork unitOfWork, IOperationLogRepository operationLogRepository ) { + public ProductDeletedEventHandler( ITestUnitOfWork unitOfWork, IOperationLogRepository operationLogRepository ) { _unitOfWork = unitOfWork; _operationLogRepository = operationLogRepository; } diff --git a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/EventHandlers/ProductUpdatedEventHandler.cs b/test/Util.TestShare/EventHandlers/ProductUpdatedEventHandler.cs similarity index 77% rename from test/Util.Data.EntityFrameworkCore.SqlServer.Tests/EventHandlers/ProductUpdatedEventHandler.cs rename to test/Util.TestShare/EventHandlers/ProductUpdatedEventHandler.cs index 8a64302e..77f56d05 100644 --- a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/EventHandlers/ProductUpdatedEventHandler.cs +++ b/test/Util.TestShare/EventHandlers/ProductUpdatedEventHandler.cs @@ -1,11 +1,11 @@ using System.Threading.Tasks; -using Util.Data.EntityFrameworkCore.Models; -using Util.Data.EntityFrameworkCore.Repositories; -using Util.Data.EntityFrameworkCore.UnitOfWorks; using Util.Domain.Events; using Util.Events; +using Util.Tests.Models; +using Util.Tests.Repositories; +using Util.Tests.UnitOfWorks; -namespace Util.Data.EntityFrameworkCore.EventHandlers { +namespace Util.Tests.EventHandlers { /// /// 产品修改事件处理器 /// @@ -13,7 +13,7 @@ namespace Util.Data.EntityFrameworkCore.EventHandlers { /// /// 工作单元 /// - private readonly ISqlServerUnitOfWork _unitOfWork; + private readonly ITestUnitOfWork _unitOfWork; /// /// 操作日志仓储 /// @@ -24,7 +24,7 @@ namespace Util.Data.EntityFrameworkCore.EventHandlers { /// /// 工作单元 /// 操作日志仓储 - public ProductUpdatedEventHandler( ISqlServerUnitOfWork unitOfWork, IOperationLogRepository operationLogRepository ) { + public ProductUpdatedEventHandler( ITestUnitOfWork unitOfWork, IOperationLogRepository operationLogRepository ) { _unitOfWork = unitOfWork; _operationLogRepository = operationLogRepository; } diff --git a/test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/Fakes/CustomerFakeService.cs b/test/Util.TestShare/Fakes/CustomerFakeService.cs similarity index 75% rename from test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/Fakes/CustomerFakeService.cs rename to test/Util.TestShare/Fakes/CustomerFakeService.cs index 523fdc8d..5a2211f5 100644 --- a/test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/Fakes/CustomerFakeService.cs +++ b/test/Util.TestShare/Fakes/CustomerFakeService.cs @@ -1,10 +1,10 @@ using System.Collections.Generic; using System.Linq; using AutoBogus; -using Util.Applications.Dtos; -using Util.Applications.Models; +using Util.Tests.Dtos; +using Util.Tests.Models; -namespace Util.Applications.Fakes { +namespace Util.Tests.Fakes { /// /// 客户模拟数据服务 /// @@ -22,6 +22,11 @@ namespace Util.Applications.Fakes { /// 行数 public static List GetCustomers( int count ) { return new AutoFaker() + .RuleFor( t => t.Code, t => t.Random.String2( 1, 100 ) ) + .RuleFor( t => t.Name, t => t.Random.String2( 1, 200 ) ) + .RuleFor( t => t.Nickname, t => t.Random.String2( 1, 50 ) ) + .RuleFor( t => t.Phone, t => t.Random.String2( 1, 50 ) ) + .RuleFor( t => t.Email, t => t.Random.String2( 1, 500 ) ) .RuleFor( t => t.IsDeleted, false ) .Generate( count ); } diff --git a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Fakes/OperationLogFakeService.cs b/test/Util.TestShare/Fakes/OperationLogFakeService.cs similarity index 84% rename from test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Fakes/OperationLogFakeService.cs rename to test/Util.TestShare/Fakes/OperationLogFakeService.cs index 150f3ba3..2839e6e7 100644 --- a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Fakes/OperationLogFakeService.cs +++ b/test/Util.TestShare/Fakes/OperationLogFakeService.cs @@ -1,9 +1,9 @@ using System.Collections.Generic; using System.Linq; using AutoBogus; -using Util.Data.EntityFrameworkCore.Models; +using Util.Tests.Models; -namespace Util.Data.EntityFrameworkCore.Fakes { +namespace Util.Tests.Fakes { /// /// 操作日志模拟数据服务 /// @@ -21,6 +21,7 @@ namespace Util.Data.EntityFrameworkCore.Fakes { /// 行数 public static List GetOperationLogs( int count ) { return new AutoFaker() + .RuleFor( t => t.LogName, t => t.Random.String2( 1, 50 ) ) .Generate( count ); } } diff --git a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Fakes/OrderFakeService.cs b/test/Util.TestShare/Fakes/OrderFakeService.cs similarity index 88% rename from test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Fakes/OrderFakeService.cs rename to test/Util.TestShare/Fakes/OrderFakeService.cs index aaefd959..36c1313f 100644 --- a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Fakes/OrderFakeService.cs +++ b/test/Util.TestShare/Fakes/OrderFakeService.cs @@ -1,9 +1,9 @@ using System.Collections.Generic; using System.Linq; using AutoBogus; -using Util.Data.EntityFrameworkCore.Models; +using Util.Tests.Models; -namespace Util.Data.EntityFrameworkCore.Fakes { +namespace Util.Tests.Fakes { /// /// 订单模拟数据服务 /// diff --git a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Fakes/OrderItemFakeService.cs b/test/Util.TestShare/Fakes/OrderItemFakeService.cs similarity index 87% rename from test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Fakes/OrderItemFakeService.cs rename to test/Util.TestShare/Fakes/OrderItemFakeService.cs index c0629669..b8cc3fcc 100644 --- a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Fakes/OrderItemFakeService.cs +++ b/test/Util.TestShare/Fakes/OrderItemFakeService.cs @@ -1,10 +1,9 @@ -using System; using System.Collections.Generic; using System.Linq; using AutoBogus; -using Util.Data.EntityFrameworkCore.Models; +using Util.Tests.Models; -namespace Util.Data.EntityFrameworkCore.Fakes { +namespace Util.Tests.Fakes { /// /// 订单明细模拟数据服务 /// diff --git a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Fakes/PostFakeService.cs b/test/Util.TestShare/Fakes/PostFakeService.cs similarity index 88% rename from test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Fakes/PostFakeService.cs rename to test/Util.TestShare/Fakes/PostFakeService.cs index 97a8079c..933aac2e 100644 --- a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Fakes/PostFakeService.cs +++ b/test/Util.TestShare/Fakes/PostFakeService.cs @@ -1,9 +1,9 @@ using System.Collections.Generic; using System.Linq; using AutoBogus; -using Util.Data.EntityFrameworkCore.Models; +using Util.Tests.Models; -namespace Util.Data.EntityFrameworkCore.Fakes { +namespace Util.Tests.Fakes { /// /// 贴子模拟数据服务 /// diff --git a/test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/Fakes/ProductFakeService.cs b/test/Util.TestShare/Fakes/ProductFakeService.cs similarity index 81% rename from test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/Fakes/ProductFakeService.cs rename to test/Util.TestShare/Fakes/ProductFakeService.cs index 31f21a1c..aeebb66a 100644 --- a/test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/Fakes/ProductFakeService.cs +++ b/test/Util.TestShare/Fakes/ProductFakeService.cs @@ -1,10 +1,10 @@ using System.Collections.Generic; using System.Linq; using AutoBogus; -using Util.Applications.Dtos; -using Util.Applications.Models; +using Util.Tests.Dtos; +using Util.Tests.Models; -namespace Util.Applications.Fakes { +namespace Util.Tests.Fakes { /// /// 产品模拟数据服务 /// @@ -22,6 +22,8 @@ namespace Util.Applications.Fakes { /// 行数 public static List GetProducts( int count ) { return new AutoFaker() + .RuleFor( t => t.Code, t => t.Random.String2( 1, 50 ) ) + .RuleFor( t => t.Name, t => t.Random.String2( 1, 500 ) ) .RuleFor( t => t.IsDeleted, false ) .Ignore( t => t.TestProperty1 ) .Generate( count ); @@ -43,10 +45,7 @@ namespace Util.Applications.Fakes { .Configure( builder => builder .WithSkip( t => t.Id ) ) - .RuleFor( t => t.IsDeleted,false ) - .Ignore( t => t.TestProperty1 ) - .Ignore( t => t.TestProperty2 ) - .Ignore( t => t.TestProperties ) + .RuleFor( t => t.IsDeleted, false ) .Generate( count ); } } diff --git a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Fakes/TagFakeService.cs b/test/Util.TestShare/Fakes/TagFakeService.cs similarity index 88% rename from test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Fakes/TagFakeService.cs rename to test/Util.TestShare/Fakes/TagFakeService.cs index b3a208e1..2af6b7c6 100644 --- a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Fakes/TagFakeService.cs +++ b/test/Util.TestShare/Fakes/TagFakeService.cs @@ -1,9 +1,9 @@ using System.Collections.Generic; using System.Linq; using AutoBogus; -using Util.Data.EntityFrameworkCore.Models; +using Util.Tests.Models; -namespace Util.Data.EntityFrameworkCore.Fakes { +namespace Util.Tests.Fakes { /// /// 标签模拟数据服务 /// diff --git a/test/Util.Application.WebApi.Tests.Integration/Infrastructure/TestBase.cs b/test/Util.TestShare/Infrastructure/ControllerTestBase.cs similarity index 94% rename from test/Util.Application.WebApi.Tests.Integration/Infrastructure/TestBase.cs rename to test/Util.TestShare/Infrastructure/ControllerTestBase.cs index ba0fd80b..f5cfdfe8 100644 --- a/test/Util.Application.WebApi.Tests.Integration/Infrastructure/TestBase.cs +++ b/test/Util.TestShare/Infrastructure/ControllerTestBase.cs @@ -1,15 +1,15 @@ using System.Threading.Tasks; using Util.Http; -namespace Util.Applications.Infrastructure { +namespace Util.Tests.Infrastructure { /// - /// 测试基类 + /// 控制器测试基类 /// - public abstract class TestBase { + public abstract class ControllerTestBase { /// /// 测试初始化 /// - protected TestBase( IHttpClient client ) { + protected ControllerTestBase( IHttpClient client ) { Client = client; } diff --git a/test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/Infrastructure/TestBase.cs b/test/Util.TestShare/Infrastructure/TestBase.cs similarity index 90% rename from test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/Infrastructure/TestBase.cs rename to test/Util.TestShare/Infrastructure/TestBase.cs index 44b02b3b..3c3bf34f 100644 --- a/test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/Infrastructure/TestBase.cs +++ b/test/Util.TestShare/Infrastructure/TestBase.cs @@ -1,6 +1,6 @@ using Util.Data; -namespace Util.Applications.Infrastructure { +namespace Util.Tests.Infrastructure { /// /// 测试基类 /// diff --git a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Infrastructure/TestSession.cs b/test/Util.TestShare/Infrastructure/TestSession.cs similarity index 91% rename from test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Infrastructure/TestSession.cs rename to test/Util.TestShare/Infrastructure/TestSession.cs index eb618205..97f6eeaf 100644 --- a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Infrastructure/TestSession.cs +++ b/test/Util.TestShare/Infrastructure/TestSession.cs @@ -1,7 +1,7 @@ using System; using Util.Sessions; -namespace Util.Data.EntityFrameworkCore.Infrastructure { +namespace Util.Tests.Infrastructure { /// /// 测试用户会话 /// diff --git a/test/Util.Application.WebApi.Tests.Integration/Infrastructure/WebApiResult.cs b/test/Util.TestShare/Infrastructure/WebApiResult.cs similarity index 80% rename from test/Util.Application.WebApi.Tests.Integration/Infrastructure/WebApiResult.cs rename to test/Util.TestShare/Infrastructure/WebApiResult.cs index 7ac3a674..87a83972 100644 --- a/test/Util.Application.WebApi.Tests.Integration/Infrastructure/WebApiResult.cs +++ b/test/Util.TestShare/Infrastructure/WebApiResult.cs @@ -1,4 +1,4 @@ -namespace Util.Applications.Infrastructure { +namespace Util.Tests.Infrastructure { /// /// Web Api操作结果 /// @@ -6,7 +6,7 @@ /// /// 状态码 /// - public StateCode Code { get; set; } + public string Code { get; set; } /// /// 消息 /// diff --git a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Models/Customer.cs b/test/Util.TestShare/Models/Customer.cs similarity index 96% rename from test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Models/Customer.cs rename to test/Util.TestShare/Models/Customer.cs index 964790ed..e89bdded 100644 --- a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Models/Customer.cs +++ b/test/Util.TestShare/Models/Customer.cs @@ -2,15 +2,16 @@ using System; using System.ComponentModel; using System.ComponentModel.DataAnnotations; using Util.Domain; +using Util.Domain.Auditing; using Util.Domain.Biz.Enums; using Util.Domain.Entities; -namespace Util.Data.EntityFrameworkCore.Models { +namespace Util.Tests.Models { /// /// 客户 /// [Description( "客户" )] - public class Customer : AggregateRoot,IDelete { + public class Customer : AggregateRoot,IDelete,IAudited { /// /// 初始化客户 /// diff --git a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Models/OperationLog.cs b/test/Util.TestShare/Models/OperationLog.cs similarity index 97% rename from test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Models/OperationLog.cs rename to test/Util.TestShare/Models/OperationLog.cs index c4acb379..148c829b 100644 --- a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Models/OperationLog.cs +++ b/test/Util.TestShare/Models/OperationLog.cs @@ -3,7 +3,7 @@ using System.ComponentModel; using System.ComponentModel.DataAnnotations; using Util.Domain.Entities; -namespace Util.Data.EntityFrameworkCore.Models { +namespace Util.Tests.Models { /// /// 操作日志 /// diff --git a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Models/Order.cs b/test/Util.TestShare/Models/Order.cs similarity index 93% rename from test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Models/Order.cs rename to test/Util.TestShare/Models/Order.cs index 725f6e9e..4f6f87fd 100644 --- a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Models/Order.cs +++ b/test/Util.TestShare/Models/Order.cs @@ -5,7 +5,7 @@ using System.ComponentModel.DataAnnotations; using Util.Domain; using Util.Domain.Entities; -namespace Util.Data.EntityFrameworkCore.Models { +namespace Util.Tests.Models { /// /// 订单 /// @@ -29,8 +29,7 @@ namespace Util.Data.EntityFrameworkCore.Models { /// 客户标识 /// [Description( "客户标识" )] - [Required( ErrorMessage = "客户标识不能为空" )] - public int CustomerId { get; set; } + public int? CustomerId { get; set; } /// /// 客户名称 /// diff --git a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Models/OrderItem.cs b/test/Util.TestShare/Models/OrderItem.cs similarity index 94% rename from test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Models/OrderItem.cs rename to test/Util.TestShare/Models/OrderItem.cs index c1f86a25..09dace79 100644 --- a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Models/OrderItem.cs +++ b/test/Util.TestShare/Models/OrderItem.cs @@ -3,7 +3,7 @@ using System.ComponentModel; using System.ComponentModel.DataAnnotations; using Util.Domain.Entities; -namespace Util.Data.EntityFrameworkCore.Models { +namespace Util.Tests.Models { /// /// 订单明细 /// @@ -38,7 +38,6 @@ namespace Util.Data.EntityFrameworkCore.Models { /// 产品名称 /// [Description( "产品名称" )] - [Required( ErrorMessage = "产品名称不能为空" )] [MaxLength( 500 )] public string ProductName { get; set; } /// diff --git a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Models/Post.cs b/test/Util.TestShare/Models/Post.cs similarity index 98% rename from test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Models/Post.cs rename to test/Util.TestShare/Models/Post.cs index 890c6b18..417be2c8 100644 --- a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Models/Post.cs +++ b/test/Util.TestShare/Models/Post.cs @@ -6,7 +6,7 @@ using Util.Domain; using Util.Domain.Auditing; using Util.Domain.Entities; -namespace Util.Data.EntityFrameworkCore.Models { +namespace Util.Tests.Models { /// /// 贴子 /// diff --git a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Models/Product.cs b/test/Util.TestShare/Models/Product.cs similarity index 91% rename from test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Models/Product.cs rename to test/Util.TestShare/Models/Product.cs index 098d95b5..21025af6 100644 --- a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Models/Product.cs +++ b/test/Util.TestShare/Models/Product.cs @@ -8,7 +8,7 @@ using Util.Domain.Auditing; using Util.Domain.Entities; using Util.Domain.Extending; -namespace Util.Data.EntityFrameworkCore.Models { +namespace Util.Tests.Models { /// /// 产品 /// @@ -48,6 +48,21 @@ namespace Util.Data.EntityFrameworkCore.Models { [Description( "价格" )] public decimal Price { get; set; } /// + /// 价格 + /// + [Description( "价格" )] + public int IntPrice { get; set; } + /// + /// 价格 + /// + [Description( "价格" )] + public long LongPrice { get; set; } + /// + /// 价格 + /// + [Description( "价格" )] + public float FloatPrice { get; set; } + /// /// 描述 /// [Description( "描述" )] diff --git a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Models/ProductEnum.cs b/test/Util.TestShare/Models/ProductEnum.cs similarity index 73% rename from test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Models/ProductEnum.cs rename to test/Util.TestShare/Models/ProductEnum.cs index 0b41f04e..1c720bec 100644 --- a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Models/ProductEnum.cs +++ b/test/Util.TestShare/Models/ProductEnum.cs @@ -1,4 +1,4 @@ -namespace Util.Data.EntityFrameworkCore.Models { +namespace Util.Tests.Models { /// /// 用于测试枚举扩展属性 /// diff --git a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Models/ProductItem.cs b/test/Util.TestShare/Models/ProductItem.cs similarity index 89% rename from test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Models/ProductItem.cs rename to test/Util.TestShare/Models/ProductItem.cs index 8e1000a2..1c4cbe5d 100644 --- a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Models/ProductItem.cs +++ b/test/Util.TestShare/Models/ProductItem.cs @@ -1,4 +1,4 @@ -namespace Util.Data.EntityFrameworkCore.Models { +namespace Util.Tests.Models { /// /// 用于测试扩展属性 /// diff --git a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Models/ProductItem2.cs b/test/Util.TestShare/Models/ProductItem2.cs similarity index 90% rename from test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Models/ProductItem2.cs rename to test/Util.TestShare/Models/ProductItem2.cs index a8d9e63b..b6d35cf8 100644 --- a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Models/ProductItem2.cs +++ b/test/Util.TestShare/Models/ProductItem2.cs @@ -1,5 +1,5 @@  -namespace Util.Data.EntityFrameworkCore.Models { +namespace Util.Tests.Models { /// /// 用于测试不可变扩展属性 /// diff --git a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Models/Tag.cs b/test/Util.TestShare/Models/Tag.cs similarity index 97% rename from test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Models/Tag.cs rename to test/Util.TestShare/Models/Tag.cs index 1e669191..54b3d59c 100644 --- a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Models/Tag.cs +++ b/test/Util.TestShare/Models/Tag.cs @@ -6,7 +6,7 @@ using Util.Domain; using Util.Domain.Auditing; using Util.Domain.Entities; -namespace Util.Data.EntityFrameworkCore.Models { +namespace Util.Tests.Models { /// /// 标签 /// diff --git a/test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/Queries/CustomerQuery.cs b/test/Util.TestShare/Queries/CustomerQuery.cs similarity index 98% rename from test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/Queries/CustomerQuery.cs rename to test/Util.TestShare/Queries/CustomerQuery.cs index eb51909a..4c8f9d89 100644 --- a/test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/Queries/CustomerQuery.cs +++ b/test/Util.TestShare/Queries/CustomerQuery.cs @@ -3,7 +3,7 @@ using System.ComponentModel; using Util.Data.Queries; using Util.Domain.Biz.Enums; -namespace Util.Applications.Queries { +namespace Util.Tests.Queries { /// /// 客户查询参数 /// diff --git a/test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/Queries/ProductQuery.cs b/test/Util.TestShare/Queries/ProductQuery.cs similarity index 98% rename from test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/Queries/ProductQuery.cs rename to test/Util.TestShare/Queries/ProductQuery.cs index 8a638819..dc8acb74 100644 --- a/test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/Queries/ProductQuery.cs +++ b/test/Util.TestShare/Queries/ProductQuery.cs @@ -2,7 +2,7 @@ using System; using System.ComponentModel; using Util.Data.Queries; -namespace Util.Applications.Queries { +namespace Util.Tests.Queries { /// /// 产品查询参数 /// diff --git a/test/Util.Application.WebApi.Tests.Integration/Repositories/ICustomerRepository.cs b/test/Util.TestShare/Repositories/ICustomerRepository.cs similarity index 69% rename from test/Util.Application.WebApi.Tests.Integration/Repositories/ICustomerRepository.cs rename to test/Util.TestShare/Repositories/ICustomerRepository.cs index 522b0901..5094842b 100644 --- a/test/Util.Application.WebApi.Tests.Integration/Repositories/ICustomerRepository.cs +++ b/test/Util.TestShare/Repositories/ICustomerRepository.cs @@ -1,7 +1,7 @@ -using Util.Applications.Models; using Util.Domain.Repositories; +using Util.Tests.Models; -namespace Util.Applications.Repositories { +namespace Util.Tests.Repositories { /// /// 客户仓储 /// diff --git a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Repositories/IOperationLogRepository.cs b/test/Util.TestShare/Repositories/IOperationLogRepository.cs similarity index 65% rename from test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Repositories/IOperationLogRepository.cs rename to test/Util.TestShare/Repositories/IOperationLogRepository.cs index 5b121efd..26f03b27 100644 --- a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Repositories/IOperationLogRepository.cs +++ b/test/Util.TestShare/Repositories/IOperationLogRepository.cs @@ -1,7 +1,7 @@ -using Util.Data.EntityFrameworkCore.Models; using Util.Domain.Repositories; +using Util.Tests.Models; -namespace Util.Data.EntityFrameworkCore.Repositories { +namespace Util.Tests.Repositories { /// /// 操作日志仓储 /// diff --git a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Repositories/IOrderRepository.cs b/test/Util.TestShare/Repositories/IOrderRepository.cs similarity index 62% rename from test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Repositories/IOrderRepository.cs rename to test/Util.TestShare/Repositories/IOrderRepository.cs index 609b1814..22aef406 100644 --- a/test/Util.Data.EntityFrameworkCore.SqlServer.Tests/Repositories/IOrderRepository.cs +++ b/test/Util.TestShare/Repositories/IOrderRepository.cs @@ -1,7 +1,7 @@ -using Util.Data.EntityFrameworkCore.Models; using Util.Domain.Repositories; +using Util.Tests.Models; -namespace Util.Data.EntityFrameworkCore.Repositories { +namespace Util.Tests.Repositories { /// /// 订单仓储 /// diff --git a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Repositories/IPostRepository.cs b/test/Util.TestShare/Repositories/IPostRepository.cs similarity index 61% rename from test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Repositories/IPostRepository.cs rename to test/Util.TestShare/Repositories/IPostRepository.cs index b2e39d8c..e6cc5d64 100644 --- a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Repositories/IPostRepository.cs +++ b/test/Util.TestShare/Repositories/IPostRepository.cs @@ -1,7 +1,7 @@ -using Util.Data.EntityFrameworkCore.Models; using Util.Domain.Repositories; +using Util.Tests.Models; -namespace Util.Data.EntityFrameworkCore.Repositories { +namespace Util.Tests.Repositories { /// /// 贴子仓储 /// diff --git a/test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/Repositories/IProductRepository.cs b/test/Util.TestShare/Repositories/IProductRepository.cs similarity index 81% rename from test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/Repositories/IProductRepository.cs rename to test/Util.TestShare/Repositories/IProductRepository.cs index 07a2dcc3..0dc7650a 100644 --- a/test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/Repositories/IProductRepository.cs +++ b/test/Util.TestShare/Repositories/IProductRepository.cs @@ -1,7 +1,7 @@ -using Util.Applications.Models; using Util.Domain.Repositories; +using Util.Tests.Models; -namespace Util.Applications.Repositories { +namespace Util.Tests.Repositories { /// /// 产品仓储 /// diff --git a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Repositories/ITagRepository.cs b/test/Util.TestShare/Repositories/ITagRepository.cs similarity index 61% rename from test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Repositories/ITagRepository.cs rename to test/Util.TestShare/Repositories/ITagRepository.cs index 81e99858..0573f53c 100644 --- a/test/Util.Data.EntityFrameworkCore.PostgreSql.Tests/Repositories/ITagRepository.cs +++ b/test/Util.TestShare/Repositories/ITagRepository.cs @@ -1,7 +1,7 @@ -using Util.Data.EntityFrameworkCore.Models; using Util.Domain.Repositories; +using Util.Tests.Models; -namespace Util.Data.EntityFrameworkCore.Repositories { +namespace Util.Tests.Repositories { /// /// 标签仓储 /// diff --git a/test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/Services/CustomerQueryService.cs b/test/Util.TestShare/Services/CustomerQueryService.cs similarity index 85% rename from test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/Services/CustomerQueryService.cs rename to test/Util.TestShare/Services/CustomerQueryService.cs index 01a333db..d40e434b 100644 --- a/test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/Services/CustomerQueryService.cs +++ b/test/Util.TestShare/Services/CustomerQueryService.cs @@ -1,12 +1,13 @@ using System; using System.Linq; -using Util.Applications.Dtos; -using Util.Applications.Models; -using Util.Applications.Queries; -using Util.Applications.Repositories; +using Util.Applications; using Util.Data; +using Util.Tests.Dtos; +using Util.Tests.Models; +using Util.Tests.Queries; +using Util.Tests.Repositories; -namespace Util.Applications.Services { +namespace Util.Tests.Services { /// /// 客户查询服务 /// diff --git a/test/Util.Application.WebApi.Tests.Integration/Services/CustomerService.cs b/test/Util.TestShare/Services/CustomerService.cs similarity index 73% rename from test/Util.Application.WebApi.Tests.Integration/Services/CustomerService.cs rename to test/Util.TestShare/Services/CustomerService.cs index 7e637a8d..f5e82c12 100644 --- a/test/Util.Application.WebApi.Tests.Integration/Services/CustomerService.cs +++ b/test/Util.TestShare/Services/CustomerService.cs @@ -1,13 +1,14 @@ using System; using System.Linq; -using Util.Applications.Dtos; -using Util.Applications.Models; -using Util.Applications.Queries; -using Util.Applications.Repositories; -using Util.Applications.UnitOfWorks; +using Util.Applications; using Util.Data; +using Util.Tests.Dtos; +using Util.Tests.Models; +using Util.Tests.Queries; +using Util.Tests.Repositories; +using Util.Tests.UnitOfWorks; -namespace Util.Applications.Services { +namespace Util.Tests.Services { /// /// 客户服务 /// @@ -18,7 +19,7 @@ namespace Util.Applications.Services { /// 服务提供器 /// 工作单元 /// 仓储 - public CustomerService( IServiceProvider serviceProvider,ISqlServerUnitOfWork unitOfWork, ICustomerRepository repository ) : base( serviceProvider,unitOfWork, repository ) { + public CustomerService( IServiceProvider serviceProvider, ITestUnitOfWork unitOfWork, ICustomerRepository repository ) : base( serviceProvider,unitOfWork, repository ) { } /// diff --git a/test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/Services/ICustomerQueryService.cs b/test/Util.TestShare/Services/ICustomerQueryService.cs similarity index 60% rename from test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/Services/ICustomerQueryService.cs rename to test/Util.TestShare/Services/ICustomerQueryService.cs index 8bd04445..542cf3fd 100644 --- a/test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/Services/ICustomerQueryService.cs +++ b/test/Util.TestShare/Services/ICustomerQueryService.cs @@ -1,7 +1,8 @@ -using Util.Applications.Dtos; -using Util.Applications.Queries; +using Util.Applications; +using Util.Tests.Dtos; +using Util.Tests.Queries; -namespace Util.Applications.Services { +namespace Util.Tests.Services { /// /// 客户查询服务 /// diff --git a/test/Util.Application.WebApi.Tests.Integration/Services/ICustomerService.cs b/test/Util.TestShare/Services/ICustomerService.cs similarity index 58% rename from test/Util.Application.WebApi.Tests.Integration/Services/ICustomerService.cs rename to test/Util.TestShare/Services/ICustomerService.cs index 58431fe0..9dd59105 100644 --- a/test/Util.Application.WebApi.Tests.Integration/Services/ICustomerService.cs +++ b/test/Util.TestShare/Services/ICustomerService.cs @@ -1,7 +1,8 @@ -using Util.Applications.Dtos; -using Util.Applications.Queries; +using Util.Applications; +using Util.Tests.Dtos; +using Util.Tests.Queries; -namespace Util.Applications.Services { +namespace Util.Tests.Services { /// /// 客户服务 /// diff --git a/test/Util.Application.WebApi.Tests.Integration/Services/IProductService.cs b/test/Util.TestShare/Services/IProductService.cs similarity index 57% rename from test/Util.Application.WebApi.Tests.Integration/Services/IProductService.cs rename to test/Util.TestShare/Services/IProductService.cs index ac9fc8e6..ea4da686 100644 --- a/test/Util.Application.WebApi.Tests.Integration/Services/IProductService.cs +++ b/test/Util.TestShare/Services/IProductService.cs @@ -1,7 +1,8 @@ -using Util.Applications.Dtos; -using Util.Applications.Queries; +using Util.Applications; +using Util.Tests.Dtos; +using Util.Tests.Queries; -namespace Util.Applications.Services { +namespace Util.Tests.Services { /// /// 产品服务 /// diff --git a/test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/Services/ProductService.cs b/test/Util.TestShare/Services/ProductService.cs similarity index 61% rename from test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/Services/ProductService.cs rename to test/Util.TestShare/Services/ProductService.cs index cafd5995..dd2380ff 100644 --- a/test/Util.Application.EntityFrameworkCore.SqlServer.Tests.Integration/Services/ProductService.cs +++ b/test/Util.TestShare/Services/ProductService.cs @@ -1,11 +1,12 @@ using System; -using Util.Applications.Dtos; -using Util.Applications.Models; -using Util.Applications.Queries; -using Util.Applications.Repositories; -using Util.Applications.UnitOfWorks; +using Util.Applications; +using Util.Tests.Dtos; +using Util.Tests.Models; +using Util.Tests.Queries; +using Util.Tests.Repositories; +using Util.Tests.UnitOfWorks; -namespace Util.Applications.Services { +namespace Util.Tests.Services { /// /// 产品服务 /// @@ -16,7 +17,7 @@ namespace Util.Applications.Services { /// 服务提供器 /// 工作单元 /// 仓储 - public ProductService( IServiceProvider serviceProvider,ISqlServerUnitOfWork unitOfWork, IProductRepository repository ) : base( serviceProvider,unitOfWork, repository ) { + public ProductService( IServiceProvider serviceProvider, ITestUnitOfWork unitOfWork, IProductRepository repository ) : base( serviceProvider,unitOfWork, repository ) { } } } \ No newline at end of file diff --git a/test/Util.TestShare/UnitOfWorks/ITestUnitOfWork.cs b/test/Util.TestShare/UnitOfWorks/ITestUnitOfWork.cs new file mode 100644 index 00000000..0864ef1e --- /dev/null +++ b/test/Util.TestShare/UnitOfWorks/ITestUnitOfWork.cs @@ -0,0 +1,9 @@ +using Util.Data; + +namespace Util.Tests.UnitOfWorks { + /// + /// 工作单元 + /// + public interface ITestUnitOfWork : IUnitOfWork { + } +} \ No newline at end of file diff --git a/test/Util.TestShare/Util.TestShare.csproj b/test/Util.TestShare/Util.TestShare.csproj new file mode 100644 index 00000000..d3aa2c15 --- /dev/null +++ b/test/Util.TestShare/Util.TestShare.csproj @@ -0,0 +1,14 @@ + + + $(NetTargetFramework) + false + Util.Tests + + + + + + + + + diff --git a/test/Util.Validation.Tests/Startup.cs b/test/Util.Validation.Tests/Startup.cs index 6c39513c..14388f4c 100644 --- a/test/Util.Validation.Tests/Startup.cs +++ b/test/Util.Validation.Tests/Startup.cs @@ -1,4 +1,3 @@ -using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using Util.Aop; @@ -14,14 +13,7 @@ namespace Util.Validation.Tests { /// ÅäÖÃÖ÷»ú /// public void ConfigureHost( IHostBuilder hostBuilder ) { - hostBuilder.EnableAop(); - } - - /// - /// ÅäÖ÷þÎñ - /// - public void ConfigureServices( IServiceCollection services ) { - services.AddUtil(); + hostBuilder.AddUtil( t => t.UseAop() ); } /// diff --git a/test/Util.Validation.Tests/Util.Validation.Tests.csproj b/test/Util.Validation.Tests/Util.Validation.Tests.csproj index 80e8d1ca..7f4e6f15 100644 --- a/test/Util.Validation.Tests/Util.Validation.Tests.csproj +++ b/test/Util.Validation.Tests/Util.Validation.Tests.csproj @@ -6,16 +6,16 @@ - - - - + + + + - + runtime; build; native; contentfiles; analyzers; buildtransitive all - + runtime; build; native; contentfiles; analyzers; buildtransitive all