From 947d70f537a1758ab99e8d40b90e7d3dcf9c95cf Mon Sep 17 00:00:00 2001 From: xuejiaming <326308290@qq.com> Date: Fri, 4 Mar 2022 15:35:30 +0800 Subject: [PATCH] =?UTF-8?q?[#128=20]=E4=BF=AE=E5=A4=8D=E6=B2=A1=E6=9C=89?= =?UTF-8?q?=E4=B8=BB=E9=94=AE=E6=97=B6=E7=9A=84=E9=94=99=E8=AF=AF,[#127]?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E6=9F=A5=E8=AF=A2=E6=8E=92=E5=BA=8F=E5=B1=9E?= =?UTF-8?q?=E6=80=A7=E6=9C=AA=E5=87=BA=E7=8E=B0=E5=9C=A8select=E4=B8=8A?= =?UTF-8?q?=E7=9A=84null=E9=94=99=E8=AF=AF=E6=8F=90=E7=A4=BA.[#124]?= =?UTF-8?q?=E4=BF=AE=E5=A4=8Dbug,[#125],[#121]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ShardingCore.sln | 2 +- .../Controllers/ValuesController.cs | 26 +- .../Domain/Maps/SysUserModMap.cs | 3 +- .../Sample.SqlServer/Sample.SqlServer.csproj | 2 +- samples/Sample.SqlServer/Startup.cs | 44 +-- .../ShardingCoreSqlServerExtension.cs | 40 +++ .../UnionAllMergeQueryCompiler.cs} | 15 +- ...MergeSqlServerQuerySqlGeneratorFactory.cs} | 26 +- .../Bootstrapers/EntityMetadataInitializer.cs | 3 +- .../ShardingDbContextBootstrapper.cs | 3 +- .../Abstractions/INotSupportAccessor.cs | 9 - .../Abstractions/INotSupportManager.cs | 17 -- .../DefaultNotSupportShardingProvider.cs | 26 -- .../INotSupportShardingProvider.cs | 16 -- .../NotSupportAccessor.cs | 23 -- .../NotSupportContext.cs | 19 -- .../NotSupportManager.cs | 24 -- .../NotSupportScope.cs | 27 -- .../ShardingEntityConfigOptions.cs | 2 +- .../Core/TrackerManagers/ITrackerManager.cs | 2 +- .../Core/TrackerManagers/TrackerManager.cs | 15 +- .../Abstractions/IUnionAllMergeAccessor.cs | 7 + .../Abstractions/IUnionAllMergeManager.cs | 15 + .../UnionAllMergeAccessor.cs | 17 ++ .../UnionAllMergeContext.cs | 15 + .../UnionAllMergeManager.cs | 23 ++ .../UnionAllMergeScope.cs | 23 ++ src/ShardingCore/DIExtension.cs | 18 +- .../UnionAllMergeOptionsExtension.cs | 97 +++++++ .../Extensions/DbContextExtension.cs | 6 +- .../Extensions/ExpressionExtension.cs | 10 + .../Extensions/IShardingQueryableExtension.cs | 48 +++- .../InternalObjectExtension.cs | 16 ++ .../Extensions/ObjectExtension.cs | 4 +- .../Extensions/ShardingDbContextExtension.cs | 12 + ...tityFrameworkShardingQueryableExtension.cs | 4 +- .../Extensions/StringFieldOrderExtension.cs | 54 ++-- .../IUnionAllMergeQueryCompiler.cs | 12 + .../IUnionAllMergeQuerySqlGeneratorFactory.cs | 12 + .../Sharding/MergeContexts/IOptimizeResult.cs | 4 +- .../Sharding/MergeContexts/IParseResult.cs | 8 +- .../MergeContexts/IQueryableOptimizeEngine.cs | 15 + .../MergeContexts/IStreamMergeParameter.cs | 16 ++ .../Sharding/MergeContexts/OptimizeResult.cs | 58 ++++ .../Sharding/MergeContexts/OrderByContext.cs | 17 ++ .../MergeContexts/PaginationContext.cs | 23 ++ .../Sharding/MergeContexts/ParseResult.cs | 46 ++++ .../MergeContexts/QueryableOptimizeEngine.cs | 171 ++++++++++++ .../MergeContexts/QueryableParseEngine.cs | 8 +- .../MergeContexts/QueryableRewriteEngine.cs | 138 ++++++++++ .../Sharding/MergeContexts/RewriteResult.cs | 12 + .../Sharding/MergeContexts/SelectContext.cs | 2 +- .../Abstractions/AbstractBaseMergeEngine.cs | 15 +- ...hardingEnumeratorAsyncStreamMergeEngine.cs | 3 +- .../EnumeratorStreamMergeEngineFactory.cs | 2 +- ...OrderSequenceEnumeratorParallelExecutor.cs | 7 +- .../SequenceEnumeratorParallelExecutor.cs | 7 +- .../Sharding/ReWrite/ReWriteEngine.cs | 5 +- .../Abstractions/IQueryCompilerContext.cs | 6 +- .../MergeQueryCompilerContext.cs | 19 +- .../ShardingExecutors/QueryCompilerContext.cs | 24 +- .../Sharding/StreamMergeContext.cs | 259 +++--------------- .../Sharding/StreamMergeContextFactory.cs | 16 +- .../Sharding/Visitors/ExtraEntry.cs | 2 +- .../Visitors/QuerySelectDiscoverVisitor.cs | 50 ++-- .../Visitors/QueryableExtraDiscoverVisitor.cs | 47 +--- .../Visitors/QueryableRouteDiscoverVisitor.cs | 220 +++++++-------- .../Visitors/Querys/CompileParseResult.cs | 7 +- .../Querys/QueryCompileParseVisitors.cs | 4 +- .../Selects/SelectAggregateProperty.cs | 2 +- .../Visitors/Selects/SelectCountProperty.cs | 1 + .../Visitors/Selects/SelectOwnerProperty.cs | 24 ++ .../Visitors/Selects/SelectProperty.cs | 20 +- .../Visitors/ShardingExpressionVisitor.cs | 98 ++++++- src/ShardingCore/ShardingContainer.cs | 12 + src/ShardingCore/ShardingCore.csproj | 12 +- .../AbstractTableEnsureManager.cs | 11 +- test/ShardingCore.Test/ShardingTest.cs | 169 +++++++----- 78 files changed, 1471 insertions(+), 826 deletions(-) create mode 100644 samples/Sample.SqlServer/UnionAllMerge/ShardingCoreSqlServerExtension.cs rename samples/Sample.SqlServer/{NotSupportShardingCompiler.cs => UnionAllMerge/UnionAllMergeQueryCompiler.cs} (83%) rename samples/Sample.SqlServer/{NotSupportSql.cs => UnionAllMerge/UnionAllMergeSqlServerQuerySqlGeneratorFactory.cs} (69%) delete mode 100644 src/ShardingCore/Core/NotSupportShardingProviders/Abstractions/INotSupportAccessor.cs delete mode 100644 src/ShardingCore/Core/NotSupportShardingProviders/Abstractions/INotSupportManager.cs delete mode 100644 src/ShardingCore/Core/NotSupportShardingProviders/DefaultNotSupportShardingProvider.cs delete mode 100644 src/ShardingCore/Core/NotSupportShardingProviders/INotSupportShardingProvider.cs delete mode 100644 src/ShardingCore/Core/NotSupportShardingProviders/NotSupportAccessor.cs delete mode 100644 src/ShardingCore/Core/NotSupportShardingProviders/NotSupportContext.cs delete mode 100644 src/ShardingCore/Core/NotSupportShardingProviders/NotSupportManager.cs delete mode 100644 src/ShardingCore/Core/NotSupportShardingProviders/NotSupportScope.cs create mode 100644 src/ShardingCore/Core/UnionAllMergeShardingProviders/Abstractions/IUnionAllMergeAccessor.cs create mode 100644 src/ShardingCore/Core/UnionAllMergeShardingProviders/Abstractions/IUnionAllMergeManager.cs create mode 100644 src/ShardingCore/Core/UnionAllMergeShardingProviders/UnionAllMergeAccessor.cs create mode 100644 src/ShardingCore/Core/UnionAllMergeShardingProviders/UnionAllMergeContext.cs create mode 100644 src/ShardingCore/Core/UnionAllMergeShardingProviders/UnionAllMergeManager.cs create mode 100644 src/ShardingCore/Core/UnionAllMergeShardingProviders/UnionAllMergeScope.cs create mode 100644 src/ShardingCore/EFCores/OptionsExtensions/UnionAllMergeOptionsExtension.cs create mode 100644 src/ShardingCore/Extensions/InternalExtensions/InternalObjectExtension.cs create mode 100644 src/ShardingCore/Sharding/Abstractions/IUnionAllMergeQueryCompiler.cs create mode 100644 src/ShardingCore/Sharding/Abstractions/IUnionAllMergeQuerySqlGeneratorFactory.cs create mode 100644 src/ShardingCore/Sharding/MergeContexts/IQueryableOptimizeEngine.cs create mode 100644 src/ShardingCore/Sharding/MergeContexts/IStreamMergeParameter.cs create mode 100644 src/ShardingCore/Sharding/MergeContexts/OptimizeResult.cs create mode 100644 src/ShardingCore/Sharding/MergeContexts/OrderByContext.cs create mode 100644 src/ShardingCore/Sharding/MergeContexts/PaginationContext.cs create mode 100644 src/ShardingCore/Sharding/MergeContexts/ParseResult.cs create mode 100644 src/ShardingCore/Sharding/MergeContexts/QueryableOptimizeEngine.cs create mode 100644 src/ShardingCore/Sharding/MergeContexts/QueryableRewriteEngine.cs create mode 100644 src/ShardingCore/Sharding/MergeContexts/RewriteResult.cs create mode 100644 src/ShardingCore/Sharding/Visitors/Selects/SelectOwnerProperty.cs diff --git a/ShardingCore.sln b/ShardingCore.sln index f5f83e62..2044943c 100644 --- a/ShardingCore.sln +++ b/ShardingCore.sln @@ -59,7 +59,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ShardingCoreBenchmark5x", " EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sample.NoShardingMultiLevel", "samples\Sample.NoShardingMultiLevel\Sample.NoShardingMultiLevel.csproj", "{DCEBAC86-E62B-4B6C-A352-B8C1C2C6F734}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sample.MultiConfig", "samples\Sample.MultiConfig\Sample.MultiConfig.csproj", "{D839D632-4AE4-4F75-8A2C-49EE029B0787}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sample.MultiConfig", "samples\Sample.MultiConfig\Sample.MultiConfig.csproj", "{D839D632-4AE4-4F75-8A2C-49EE029B0787}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/samples/Sample.SqlServer/Controllers/ValuesController.cs b/samples/Sample.SqlServer/Controllers/ValuesController.cs index 6919c07a..55d59749 100644 --- a/samples/Sample.SqlServer/Controllers/ValuesController.cs +++ b/samples/Sample.SqlServer/Controllers/ValuesController.cs @@ -144,9 +144,9 @@ namespace Sample.SqlServer.Controllers var sresultx1121222 = await _defaultTableDbContext.Set().Where(o => o.Id == "198").MaxAsync(o => o.Age); var unionUserIds = await _defaultTableDbContext.Set().Select(o=>new UnionUserId(){UserId = o.Id}) - .Union(_defaultTableDbContext.Set().Select(o => new UnionUserId() { UserId = o.UserId })).ToListAsync(); + .Union(_defaultTableDbContext.Set().Select(o => new UnionUserId() { UserId = o.UserId })).UseUnionAllMerge().ToListAsync(); var unionUserIdCounts = await _defaultTableDbContext.Set().Select(o=>new UnionUserId(){UserId = o.Id}) - .Union(_defaultTableDbContext.Set().Select(o => new UnionUserId() { UserId = o.UserId })).CountAsync(); + .Union(_defaultTableDbContext.Set().Select(o => new UnionUserId() { UserId = o.UserId })).UseUnionAllMerge().CountAsync(); var hashSet = unionUserIds.Select(o=>o.UserId).ToHashSet(); var hashSetCount = hashSet.Count; @@ -176,7 +176,7 @@ namespace Sample.SqlServer.Controllers { Stopwatch sp = new Stopwatch(); sp.Start(); - var shardingPageResultAsync = await _defaultTableDbContext.Set().UnionMerge().OrderBy(o => o.Age).ToShardingPageAsync(p, s); + var shardingPageResultAsync = await _defaultTableDbContext.Set().UseUnionAllMerge().OrderBy(o => o.Age).ToShardingPageAsync(p, s); sp.Stop(); return Ok(new { @@ -226,8 +226,26 @@ namespace Sample.SqlServer.Controllers [HttpGet] public async Task Get2a3() { + var sql = from o in _defaultTableDbContext.Set() + orderby o.Id descending + select new + { + o.Id, + o.UserId, + o.DateOfMonth, + o.SalaryDecimal, + o.SalaryFloat + }; + var xx=await sql.ToListAsync(); Console.WriteLine("Get2a3-------------"); - var sysUserMods = await _defaultTableDbContext.Set().Skip(2).Take(2).ToListAsync(); + var sysUserMods = await _defaultTableDbContext.Set().UseConnectionMode(1).Take(2).Select(o=>new + { + o.Id, + o.UserId, + o.DateOfMonth, + o.SalaryDecimal, + o.SalaryFloat + }).OrderByDescending(o=>o.Id).ToListAsync(); return Ok(sysUserMods); } [HttpGet] diff --git a/samples/Sample.SqlServer/Domain/Maps/SysUserModMap.cs b/samples/Sample.SqlServer/Domain/Maps/SysUserModMap.cs index 0aa9b31f..cdee79dd 100644 --- a/samples/Sample.SqlServer/Domain/Maps/SysUserModMap.cs +++ b/samples/Sample.SqlServer/Domain/Maps/SysUserModMap.cs @@ -14,7 +14,8 @@ namespace Sample.SqlServer.Domain.Maps { public void Configure(EntityTypeBuilder builder) { - builder.HasKey(o => o.Id); + //builder.HasKey(o => o.Id); + builder.HasNoKey(); builder.Property(o => o.Id).IsRequired().HasMaxLength(128); builder.Property(o => o.Name).HasMaxLength(128); builder.ToTable(nameof(SysUserMod)); diff --git a/samples/Sample.SqlServer/Sample.SqlServer.csproj b/samples/Sample.SqlServer/Sample.SqlServer.csproj index 7c9905d3..2c4568bc 100644 --- a/samples/Sample.SqlServer/Sample.SqlServer.csproj +++ b/samples/Sample.SqlServer/Sample.SqlServer.csproj @@ -7,7 +7,7 @@ - + diff --git a/samples/Sample.SqlServer/Startup.cs b/samples/Sample.SqlServer/Startup.cs index 5d0a7f86..192e9ed9 100644 --- a/samples/Sample.SqlServer/Startup.cs +++ b/samples/Sample.SqlServer/Startup.cs @@ -6,21 +6,17 @@ using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using Sample.SqlServer.DbContexts; using Sample.SqlServer.Shardings; +using Sample.SqlServer.UnionAllMerge; using ShardingCore; -using ShardingCore.Sharding.ReadWriteConfigurations; -using System; -using System.Collections.Generic; -using System.Diagnostics; -using Microsoft.EntityFrameworkCore.Query; -using Microsoft.EntityFrameworkCore.Query.Internal; -using Microsoft.Extensions.DependencyInjection.Extensions; -using ShardingCore.Core; -using ShardingCore.Core.NotSupportShardingProviders; -using ShardingCore.Sharding.ShardingExecutors.Abstractions; using ShardingCore.TableExists; +using System; +using System.Diagnostics; namespace Sample.SqlServer { + public static class SEX + { + } public class Startup { public static readonly ILoggerFactory efLogger = LoggerFactory.Create(builder => @@ -42,25 +38,14 @@ namespace Sample.SqlServer o.AddShardingTableRoute(); o.AddShardingTableRoute(); o.AddShardingTableRoute(); - o.UseInnerDbContextConfigure(builder => - { - builder - .ReplaceService>() - .ReplaceService(); - }); }) .AddConfig(op => { op.ConfigId = "c1"; op.MaxQueryConnectionsLimit = 5; - op.UseShardingQuery((conStr, builder) => + op.UseSqlServer(builder => { - builder.UseSqlServer(conStr).UseLoggerFactory(efLogger).ReplaceService>(); - }); - op.UseShardingTransaction((connection, builder) => - { - builder.UseSqlServer(connection).UseLoggerFactory(efLogger).ReplaceService>(); + builder.UseLoggerFactory(efLogger).UseUnionAllMerge(); }); op.ReplaceTableEnsureManager(sp => new SqlServerTableEnsureManager()); op.AddDefaultDataSource("A", @@ -68,7 +53,6 @@ namespace Sample.SqlServer "Data Source = 101.37.117.55;persist security info=True;Initial Catalog=ShardingCoreDBXA;uid=sa;pwd=xjmumixl7610#;Max Pool Size=100;" ); }).EnsureConfig(); - services.TryAddSingleton(); //services.AddShardingDbContext( // (conn, o) => // o.UseSqlServer(conn).UseLoggerFactory(efLogger) @@ -133,16 +117,4 @@ namespace Sample.SqlServer app.DbSeed(); } } - - public class UnionSupportShardingProvider : INotSupportShardingProvider - { - public void CheckNotSupportSharding(IQueryCompilerContext queryCompilerContext) - { - } - - public bool IsNotSupportSharding(IQueryCompilerContext queryCompilerContext) - { - return queryCompilerContext.IsUnion(); - } - } } \ No newline at end of file diff --git a/samples/Sample.SqlServer/UnionAllMerge/ShardingCoreSqlServerExtension.cs b/samples/Sample.SqlServer/UnionAllMerge/ShardingCoreSqlServerExtension.cs new file mode 100644 index 00000000..6e470ec2 --- /dev/null +++ b/samples/Sample.SqlServer/UnionAllMerge/ShardingCoreSqlServerExtension.cs @@ -0,0 +1,40 @@ +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Query; +using Microsoft.EntityFrameworkCore.Query.Internal; +using ShardingCore.Core.ShardingConfigurations; +using ShardingCore.EFCores.OptionsExtensions; +using ShardingCore.Sharding.Abstractions; + +namespace Sample.SqlServer.UnionAllMerge +{ + public static class ShardingCoreSqlServerExtension + { + public static void UseSqlServer(this ShardingConfigOptions option,Action builderConfigure=null) where TShardingDbContext : DbContext, IShardingDbContext + { + option.UseShardingQuery((conStr, builder) => + { + builder.UseSqlServer(conStr); + builderConfigure?.Invoke(builder); + }); + option.UseShardingTransaction((connection, builder) => + { + builder.UseSqlServer(connection); + builderConfigure?.Invoke(builder); + }); + } + private static UnionAllMergeOptionsExtension CreateOrGetUnionAllMergeExtension(this DbContextOptionsBuilder optionsBuilder) + => optionsBuilder.Options.FindExtension() ?? + new UnionAllMergeOptionsExtension(); + public static DbContextOptionsBuilder UseUnionAllMerge(this DbContextOptionsBuilder optionsBuilder) where TShardingDbContext : DbContext, IShardingDbContext + { + var extension = optionsBuilder.CreateOrGetUnionAllMergeExtension(); + ((IDbContextOptionsBuilderInfrastructure)optionsBuilder).AddOrUpdateExtension(extension); + return optionsBuilder.ReplaceService>() + .ReplaceService(); ; + } + + } +} diff --git a/samples/Sample.SqlServer/NotSupportShardingCompiler.cs b/samples/Sample.SqlServer/UnionAllMerge/UnionAllMergeQueryCompiler.cs similarity index 83% rename from samples/Sample.SqlServer/NotSupportShardingCompiler.cs rename to samples/Sample.SqlServer/UnionAllMerge/UnionAllMergeQueryCompiler.cs index 486481c3..8ce14dcd 100644 --- a/samples/Sample.SqlServer/NotSupportShardingCompiler.cs +++ b/samples/Sample.SqlServer/UnionAllMerge/UnionAllMergeQueryCompiler.cs @@ -8,18 +8,19 @@ using Microsoft.EntityFrameworkCore.Query; using Microsoft.EntityFrameworkCore.Query.Internal; using Microsoft.EntityFrameworkCore.Storage; using ShardingCore; -using ShardingCore.Core.NotSupportShardingProviders.Abstractions; +using ShardingCore.Core.UnionAllMergeShardingProviders.Abstractions; +using ShardingCore.Sharding.Abstractions; -namespace Sample.SqlServer +namespace Sample.SqlServer.UnionAllMerge { - public class NotSupportShardingCompiler : QueryCompiler + public class UnionAllMergeQueryCompiler : QueryCompiler, IUnionAllMergeQueryCompiler { private readonly IQueryContextFactory _queryContextFactory; private readonly IDatabase _database; private readonly IDiagnosticsLogger _logger; private readonly IModel _model; - public NotSupportShardingCompiler(IQueryContextFactory queryContextFactory, ICompiledQueryCache compiledQueryCache, ICompiledQueryCacheKeyGenerator compiledQueryCacheKeyGenerator, IDatabase database, IDiagnosticsLogger logger, ICurrentDbContext currentContext, IEvaluatableExpressionFilter evaluatableExpressionFilter, IModel model) : base(queryContextFactory, compiledQueryCache, compiledQueryCacheKeyGenerator, database, logger, currentContext, evaluatableExpressionFilter, model) + public UnionAllMergeQueryCompiler(IQueryContextFactory queryContextFactory, ICompiledQueryCache compiledQueryCache, ICompiledQueryCacheKeyGenerator compiledQueryCacheKeyGenerator, IDatabase database, IDiagnosticsLogger logger, ICurrentDbContext currentContext, IEvaluatableExpressionFilter evaluatableExpressionFilter, IModel model) : base(queryContextFactory, compiledQueryCache, compiledQueryCacheKeyGenerator, database, logger, currentContext, evaluatableExpressionFilter, model) { _queryContextFactory = queryContextFactory; _database = database; @@ -29,8 +30,8 @@ namespace Sample.SqlServer public override TResult Execute(Expression query) { - var notSupportManager = ShardingContainer.GetService(); - if (notSupportManager?.Current != null) + var notSupportManager = ShardingContainer.GetService(); + if (notSupportManager?.Current != null) { return NotSupportShardingExecute(query); } @@ -57,7 +58,7 @@ namespace Sample.SqlServer public override TResult ExecuteAsync(Expression query, CancellationToken cancellationToken = new CancellationToken()) { - var notSupportManager = ShardingContainer.GetService(); + var notSupportManager = ShardingContainer.GetService(); if (notSupportManager?.Current != null) { var result = NotSupportShardingExecuteAsync(query, cancellationToken); diff --git a/samples/Sample.SqlServer/NotSupportSql.cs b/samples/Sample.SqlServer/UnionAllMerge/UnionAllMergeSqlServerQuerySqlGeneratorFactory.cs similarity index 69% rename from samples/Sample.SqlServer/NotSupportSql.cs rename to samples/Sample.SqlServer/UnionAllMerge/UnionAllMergeSqlServerQuerySqlGeneratorFactory.cs index 0848c6d1..a840de89 100644 --- a/samples/Sample.SqlServer/NotSupportSql.cs +++ b/samples/Sample.SqlServer/UnionAllMerge/UnionAllMergeSqlServerQuerySqlGeneratorFactory.cs @@ -6,29 +6,29 @@ using Microsoft.EntityFrameworkCore.Query.SqlExpressions; using Microsoft.EntityFrameworkCore.SqlServer.Query.Internal; using Microsoft.EntityFrameworkCore.Storage; using ShardingCore; -using ShardingCore.Core.NotSupportShardingProviders.Abstractions; +using ShardingCore.Core.UnionAllMergeShardingProviders.Abstractions; using ShardingCore.Core.VirtualDatabase.VirtualTables; using ShardingCore.Extensions; using ShardingCore.Sharding.Abstractions; -namespace Sample.SqlServer +namespace Sample.SqlServer.UnionAllMerge { - public class ShardingSqlServerQuerySqlGeneratorFactory : IQuerySqlGeneratorFactory - where TShardingDbContext:DbContext,IShardingDbContext + public class UnionAllMergeSqlServerQuerySqlGeneratorFactory : IQuerySqlGeneratorFactory, IUnionAllMergeQuerySqlGeneratorFactory + where TShardingDbContext : DbContext, IShardingDbContext { - public ShardingSqlServerQuerySqlGeneratorFactory(QuerySqlGeneratorDependencies dependencies) + public UnionAllMergeSqlServerQuerySqlGeneratorFactory(QuerySqlGeneratorDependencies dependencies) { Dependencies = dependencies; } public QuerySqlGeneratorDependencies Dependencies { get; } - public QuerySqlGenerator Create() => new ShardingSqlServerQuerySqlGenerator(Dependencies); + public QuerySqlGenerator Create() => new UnionAllMergeSqlServerQuerySqlGenerator(Dependencies); } - public class ShardingSqlServerQuerySqlGenerator : SqlServerQuerySqlGenerator + public class UnionAllMergeSqlServerQuerySqlGenerator : SqlServerQuerySqlGenerator where TShardingDbContext : DbContext, IShardingDbContext { - public ShardingSqlServerQuerySqlGenerator(QuerySqlGeneratorDependencies dependencies) + public UnionAllMergeSqlServerQuerySqlGenerator(QuerySqlGeneratorDependencies dependencies) : base(dependencies) { } @@ -48,14 +48,14 @@ namespace Sample.SqlServer private Expression OverrideVisitTable(TableExpression tableExpression) { - var supportManager = ShardingContainer.GetService(); + var supportManager = ShardingContainer.GetService(); if (supportManager?.Current != null) { var tableRouteResults = supportManager?.Current.TableRoutesResults.ToArray(); if (tableRouteResults.IsNotEmpty() && tableRouteResults[0].ReplaceTables.Any(o => o.OriginalName == tableExpression.Name)) { - var tails = tableRouteResults.Select(o=>o.ReplaceTables.FirstOrDefault(r=>r.OriginalName==tableExpression.Name).Tail).ToHashSet(); + var tails = tableRouteResults.Select(o => o.ReplaceTables.FirstOrDefault(r => r.OriginalName == tableExpression.Name).Tail).ToHashSet(); var sqlGenerationHelper = typeof(QuerySqlGenerator).GetTypeFieldValue(this, "_sqlGenerationHelper") as ISqlGenerationHelper; var tableManager = ShardingContainer.GetService>(); @@ -70,9 +70,9 @@ namespace Sample.SqlServer newTableName = "(" + string.Join(" union all ", tails.Select(tail => $"select * from {sqlGenerationHelper.DelimitIdentifier($"{tableExpression.Name}{virtualTable.EntityMetadata.TableSeparator}{tail}", tableExpression.Schema)}")) + ")"; } - var relationalCommandBuilder = typeof(QuerySqlGenerator).GetTypeFieldValue(this, "_relationalCommandBuilder") as IRelationalCommandBuilder; - relationalCommandBuilder.Append(newTableName).Append(this.AliasSeparator).Append(sqlGenerationHelper.DelimitIdentifier(tableExpression.Alias)); - return tableExpression; + var relationalCommandBuilder = typeof(QuerySqlGenerator).GetTypeFieldValue(this, "_relationalCommandBuilder") as IRelationalCommandBuilder; + relationalCommandBuilder.Append(newTableName).Append(this.AliasSeparator).Append(sqlGenerationHelper.DelimitIdentifier(tableExpression.Alias)); + return tableExpression; } } diff --git a/src/ShardingCore/Bootstrapers/EntityMetadataInitializer.cs b/src/ShardingCore/Bootstrapers/EntityMetadataInitializer.cs index 649ed919..faab7aea 100644 --- a/src/ShardingCore/Bootstrapers/EntityMetadataInitializer.cs +++ b/src/ShardingCore/Bootstrapers/EntityMetadataInitializer.cs @@ -16,6 +16,7 @@ using ShardingCore.Jobs; using ShardingCore.Jobs.Abstaractions; using ShardingCore.Sharding.Abstractions; using System; +using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Reflection; @@ -75,7 +76,7 @@ namespace ShardingCore.Bootstrapers public void Initialize() { var shardingEntityType = _entityType.ClrType; - var entityMetadata = new EntityMetadata(shardingEntityType, _virtualTableName,typeof(TShardingDbContext),_entityType.FindPrimaryKey().Properties.Select(o=>o.PropertyInfo).ToList(),_queryFilterExpression); + var entityMetadata = new EntityMetadata(shardingEntityType, _virtualTableName,typeof(TShardingDbContext),_entityType.FindPrimaryKey()?.Properties?.Select(o=>o.PropertyInfo)?.ToList()??new List(),_queryFilterExpression); if (!_entityMetadataManager.AddEntityMetadata(entityMetadata)) throw new ShardingCoreInvalidOperationException($"repeat add entity metadata {shardingEntityType.FullName}"); //设置标签 diff --git a/src/ShardingCore/Bootstrapers/ShardingDbContextBootstrapper.cs b/src/ShardingCore/Bootstrapers/ShardingDbContextBootstrapper.cs index 596426ac..1f2fead8 100644 --- a/src/ShardingCore/Bootstrapers/ShardingDbContextBootstrapper.cs +++ b/src/ShardingCore/Bootstrapers/ShardingDbContextBootstrapper.cs @@ -105,7 +105,8 @@ namespace ShardingCore.Bootstrapers foreach (var entity in context.Model.GetEntityTypes()) { var entityType = entity.ClrType; - _trackerManager.AddDbContextModel(entityType); + + _trackerManager.AddDbContextModel(entityType,entity.FindPrimaryKey()!=null); //entity.GetAnnotation("") if (_entityConfigOptions.HasVirtualDataSourceRoute(entityType) || _entityConfigOptions.HasVirtualTableRoute(entityType)) diff --git a/src/ShardingCore/Core/NotSupportShardingProviders/Abstractions/INotSupportAccessor.cs b/src/ShardingCore/Core/NotSupportShardingProviders/Abstractions/INotSupportAccessor.cs deleted file mode 100644 index b084b040..00000000 --- a/src/ShardingCore/Core/NotSupportShardingProviders/Abstractions/INotSupportAccessor.cs +++ /dev/null @@ -1,9 +0,0 @@ -using ShardingCore.Core.CustomerDatabaseProcessers; - -namespace ShardingCore.Core.NotSupportShardingProviders.Abstractions -{ - public interface INotSupportAccessor - { - NotSupportContext SqlSupportContext { get; set; } - } -} diff --git a/src/ShardingCore/Core/NotSupportShardingProviders/Abstractions/INotSupportManager.cs b/src/ShardingCore/Core/NotSupportShardingProviders/Abstractions/INotSupportManager.cs deleted file mode 100644 index 509170ba..00000000 --- a/src/ShardingCore/Core/NotSupportShardingProviders/Abstractions/INotSupportManager.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System.Collections.Generic; -using ShardingCore.Core.CustomerDatabaseProcessers; -using ShardingCore.Core.CustomerDatabaseSqlSupports; -using ShardingCore.Core.VirtualRoutes.TableRoutes.RoutingRuleEngine; - -namespace ShardingCore.Core.NotSupportShardingProviders.Abstractions -{ - public interface INotSupportManager - { - NotSupportContext Current { get; } - /// - /// 创建scope - /// - /// - NotSupportScope CreateScope(IEnumerable tableRouteResults); - } -} diff --git a/src/ShardingCore/Core/NotSupportShardingProviders/DefaultNotSupportShardingProvider.cs b/src/ShardingCore/Core/NotSupportShardingProviders/DefaultNotSupportShardingProvider.cs deleted file mode 100644 index 4e06748d..00000000 --- a/src/ShardingCore/Core/NotSupportShardingProviders/DefaultNotSupportShardingProvider.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using ShardingCore.Exceptions; -using ShardingCore.Extensions; -using ShardingCore.Sharding.ShardingExecutors.Abstractions; - -namespace ShardingCore.Core.NotSupportShardingProviders -{ - public class DefaultNotSupportShardingProvider: INotSupportShardingProvider - { - public void CheckNotSupportSharding(IQueryCompilerContext queryCompilerContext) - { - if (IsNotSupportSharding(queryCompilerContext)) - throw new ShardingCoreInvalidOperationException( - $"not support sharding query :[{queryCompilerContext.GetQueryExpression().ShardingPrint()}]"); - } - - public bool IsNotSupportSharding(IQueryCompilerContext queryCompilerContext) - { - return queryCompilerContext.IsUnion(); - } - } -} diff --git a/src/ShardingCore/Core/NotSupportShardingProviders/INotSupportShardingProvider.cs b/src/ShardingCore/Core/NotSupportShardingProviders/INotSupportShardingProvider.cs deleted file mode 100644 index 16138b16..00000000 --- a/src/ShardingCore/Core/NotSupportShardingProviders/INotSupportShardingProvider.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using ShardingCore.Sharding.ShardingExecutors.Abstractions; - -namespace ShardingCore.Core.NotSupportShardingProviders -{ - public interface INotSupportShardingProvider - { - void CheckNotSupportSharding(IQueryCompilerContext queryCompilerContext); - [Obsolete("plz use NotSupport() eg. dbcontext.Set().NotSupport().Where(...).ToList()")] - bool IsNotSupportSharding(IQueryCompilerContext queryCompilerContext); - } -} diff --git a/src/ShardingCore/Core/NotSupportShardingProviders/NotSupportAccessor.cs b/src/ShardingCore/Core/NotSupportShardingProviders/NotSupportAccessor.cs deleted file mode 100644 index 555e6ded..00000000 --- a/src/ShardingCore/Core/NotSupportShardingProviders/NotSupportAccessor.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading; -using System.Threading.Tasks; -using ShardingCore.Core.CustomerDatabaseProcessers; -using ShardingCore.Core.NotSupportShardingProviders.Abstractions; - -namespace ShardingCore.Core.CustomerDatabaseSqlSupports -{ - public class NotSupportAccessor: INotSupportAccessor - { - private static AsyncLocal _sqlSupportContext = new AsyncLocal(); - - - public NotSupportContext SqlSupportContext - { - get => _sqlSupportContext.Value; - set => _sqlSupportContext.Value = value; - } - } -} diff --git a/src/ShardingCore/Core/NotSupportShardingProviders/NotSupportContext.cs b/src/ShardingCore/Core/NotSupportShardingProviders/NotSupportContext.cs deleted file mode 100644 index 883c4bf0..00000000 --- a/src/ShardingCore/Core/NotSupportShardingProviders/NotSupportContext.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using ShardingCore.Core.VirtualRoutes.TableRoutes.RoutingRuleEngine; - -namespace ShardingCore.Core.CustomerDatabaseProcessers -{ - public class NotSupportContext - { - public NotSupportContext(IEnumerable tableRoutesResults) - { - TableRoutesResults = tableRoutesResults; - } - - public IEnumerable TableRoutesResults { get; } - } -} diff --git a/src/ShardingCore/Core/NotSupportShardingProviders/NotSupportManager.cs b/src/ShardingCore/Core/NotSupportShardingProviders/NotSupportManager.cs deleted file mode 100644 index 9be5cd16..00000000 --- a/src/ShardingCore/Core/NotSupportShardingProviders/NotSupportManager.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System.Collections.Generic; -using ShardingCore.Core.CustomerDatabaseProcessers; -using ShardingCore.Core.NotSupportShardingProviders.Abstractions; -using ShardingCore.Core.VirtualRoutes.TableRoutes.RoutingRuleEngine; - -namespace ShardingCore.Core.CustomerDatabaseSqlSupports -{ - public class NotSupportManager: INotSupportManager - { - private readonly INotSupportAccessor _notSupportAccessor; - public NotSupportContext Current => _notSupportAccessor.SqlSupportContext; - - public NotSupportManager(INotSupportAccessor notSupportAccessor) - { - _notSupportAccessor = notSupportAccessor; - } - public NotSupportScope CreateScope(IEnumerable tableRouteResults) - { - var scope = new NotSupportScope(_notSupportAccessor); - _notSupportAccessor.SqlSupportContext = new NotSupportContext(tableRouteResults); - return scope; - } - } -} diff --git a/src/ShardingCore/Core/NotSupportShardingProviders/NotSupportScope.cs b/src/ShardingCore/Core/NotSupportShardingProviders/NotSupportScope.cs deleted file mode 100644 index 7065e4c3..00000000 --- a/src/ShardingCore/Core/NotSupportShardingProviders/NotSupportScope.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using ShardingCore.Core.NotSupportShardingProviders.Abstractions; - -namespace ShardingCore.Core.CustomerDatabaseSqlSupports -{ - public class NotSupportScope:IDisposable - { - public INotSupportAccessor NotSupportAccessor { get; } - - /// - /// 构造函数 - /// - /// - public NotSupportScope(INotSupportAccessor notSupportAccessor) - { - NotSupportAccessor = notSupportAccessor; - } - public void Dispose() - { - NotSupportAccessor.SqlSupportContext = null; - } - } -} diff --git a/src/ShardingCore/Core/ShardingConfigurations/ShardingEntityConfigOptions.cs b/src/ShardingCore/Core/ShardingConfigurations/ShardingEntityConfigOptions.cs index 9f72e410..beae406a 100644 --- a/src/ShardingCore/Core/ShardingConfigurations/ShardingEntityConfigOptions.cs +++ b/src/ShardingCore/Core/ShardingConfigurations/ShardingEntityConfigOptions.cs @@ -180,7 +180,7 @@ namespace ShardingCore.Core.ShardingConfigurations ConnectionConfigure = transactionConfigure ?? throw new ArgumentNullException(nameof(transactionConfigure)); } /// - /// 仅内部DbContext配置的方法 + /// 仅内部真实DbContext配置的方法 /// /// /// diff --git a/src/ShardingCore/Core/TrackerManagers/ITrackerManager.cs b/src/ShardingCore/Core/TrackerManagers/ITrackerManager.cs index d10f3642..0b25ebbb 100644 --- a/src/ShardingCore/Core/TrackerManagers/ITrackerManager.cs +++ b/src/ShardingCore/Core/TrackerManagers/ITrackerManager.cs @@ -15,7 +15,7 @@ namespace ShardingCore.Core.TrackerManagers */ public interface ITrackerManager { - bool AddDbContextModel(Type entityType); + bool AddDbContextModel(Type entityType,bool hasKey); bool EntityUseTrack(Type entityType); bool IsDbContextModel(Type entityType); } diff --git a/src/ShardingCore/Core/TrackerManagers/TrackerManager.cs b/src/ShardingCore/Core/TrackerManagers/TrackerManager.cs index ad904408..bee6c190 100644 --- a/src/ShardingCore/Core/TrackerManagers/TrackerManager.cs +++ b/src/ShardingCore/Core/TrackerManagers/TrackerManager.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Text; @@ -16,21 +17,25 @@ namespace ShardingCore.Core.TrackerManagers */ public class TrackerManager: ITrackerManager where TShardingDbContext : DbContext, IShardingDbContext { - private readonly ISet _dbContextModels = new HashSet(); + private readonly ConcurrentDictionary _dbContextModels = new (); - public bool AddDbContextModel(Type entityType) + public bool AddDbContextModel(Type entityType, bool hasKey) { - return _dbContextModels.Add(entityType); + return _dbContextModels.TryAdd(entityType, hasKey); } public bool EntityUseTrack(Type entityType) { - return _dbContextModels.Contains(entityType); + if (!_dbContextModels.TryGetValue(entityType, out var hasKey)) + { + return false; + } + return hasKey; } public bool IsDbContextModel(Type entityType) { - return _dbContextModels.Contains(entityType); + return _dbContextModels.ContainsKey(entityType); } } } diff --git a/src/ShardingCore/Core/UnionAllMergeShardingProviders/Abstractions/IUnionAllMergeAccessor.cs b/src/ShardingCore/Core/UnionAllMergeShardingProviders/Abstractions/IUnionAllMergeAccessor.cs new file mode 100644 index 00000000..9001a764 --- /dev/null +++ b/src/ShardingCore/Core/UnionAllMergeShardingProviders/Abstractions/IUnionAllMergeAccessor.cs @@ -0,0 +1,7 @@ +namespace ShardingCore.Core.UnionAllMergeShardingProviders.Abstractions +{ + public interface IUnionAllMergeAccessor + { + UnionAllMergeContext SqlSupportContext { get; set; } + } +} diff --git a/src/ShardingCore/Core/UnionAllMergeShardingProviders/Abstractions/IUnionAllMergeManager.cs b/src/ShardingCore/Core/UnionAllMergeShardingProviders/Abstractions/IUnionAllMergeManager.cs new file mode 100644 index 00000000..2b86e582 --- /dev/null +++ b/src/ShardingCore/Core/UnionAllMergeShardingProviders/Abstractions/IUnionAllMergeManager.cs @@ -0,0 +1,15 @@ +using System.Collections.Generic; +using ShardingCore.Core.VirtualRoutes.TableRoutes.RoutingRuleEngine; + +namespace ShardingCore.Core.UnionAllMergeShardingProviders.Abstractions +{ + public interface IUnionAllMergeManager + { + UnionAllMergeContext Current { get; } + /// + /// 创建scope + /// + /// + UnionAllMergeScope CreateScope(IEnumerable tableRouteResults); + } +} diff --git a/src/ShardingCore/Core/UnionAllMergeShardingProviders/UnionAllMergeAccessor.cs b/src/ShardingCore/Core/UnionAllMergeShardingProviders/UnionAllMergeAccessor.cs new file mode 100644 index 00000000..2399716c --- /dev/null +++ b/src/ShardingCore/Core/UnionAllMergeShardingProviders/UnionAllMergeAccessor.cs @@ -0,0 +1,17 @@ +using System.Threading; +using ShardingCore.Core.UnionAllMergeShardingProviders.Abstractions; + +namespace ShardingCore.Core.UnionAllMergeShardingProviders +{ + public class UnionAllMergeAccessor: IUnionAllMergeAccessor + { + private static AsyncLocal _sqlSupportContext = new AsyncLocal(); + + + public UnionAllMergeContext SqlSupportContext + { + get => _sqlSupportContext.Value; + set => _sqlSupportContext.Value = value; + } + } +} diff --git a/src/ShardingCore/Core/UnionAllMergeShardingProviders/UnionAllMergeContext.cs b/src/ShardingCore/Core/UnionAllMergeShardingProviders/UnionAllMergeContext.cs new file mode 100644 index 00000000..de2a63c9 --- /dev/null +++ b/src/ShardingCore/Core/UnionAllMergeShardingProviders/UnionAllMergeContext.cs @@ -0,0 +1,15 @@ +using System.Collections.Generic; +using ShardingCore.Core.VirtualRoutes.TableRoutes.RoutingRuleEngine; + +namespace ShardingCore.Core.UnionAllMergeShardingProviders +{ + public class UnionAllMergeContext + { + public UnionAllMergeContext(IEnumerable tableRoutesResults) + { + TableRoutesResults = tableRoutesResults; + } + + public IEnumerable TableRoutesResults { get; } + } +} diff --git a/src/ShardingCore/Core/UnionAllMergeShardingProviders/UnionAllMergeManager.cs b/src/ShardingCore/Core/UnionAllMergeShardingProviders/UnionAllMergeManager.cs new file mode 100644 index 00000000..fabd10fe --- /dev/null +++ b/src/ShardingCore/Core/UnionAllMergeShardingProviders/UnionAllMergeManager.cs @@ -0,0 +1,23 @@ +using System.Collections.Generic; +using ShardingCore.Core.UnionAllMergeShardingProviders.Abstractions; +using ShardingCore.Core.VirtualRoutes.TableRoutes.RoutingRuleEngine; + +namespace ShardingCore.Core.UnionAllMergeShardingProviders +{ + public class UnionAllMergeManager: IUnionAllMergeManager + { + private readonly IUnionAllMergeAccessor _unionAllMergeAccessor; + public UnionAllMergeContext Current => _unionAllMergeAccessor.SqlSupportContext; + + public UnionAllMergeManager(IUnionAllMergeAccessor unionAllMergeAccessor) + { + _unionAllMergeAccessor = unionAllMergeAccessor; + } + public UnionAllMergeScope CreateScope(IEnumerable tableRouteResults) + { + var scope = new UnionAllMergeScope(_unionAllMergeAccessor); + _unionAllMergeAccessor.SqlSupportContext = new UnionAllMergeContext(tableRouteResults); + return scope; + } + } +} diff --git a/src/ShardingCore/Core/UnionAllMergeShardingProviders/UnionAllMergeScope.cs b/src/ShardingCore/Core/UnionAllMergeShardingProviders/UnionAllMergeScope.cs new file mode 100644 index 00000000..fa71e749 --- /dev/null +++ b/src/ShardingCore/Core/UnionAllMergeShardingProviders/UnionAllMergeScope.cs @@ -0,0 +1,23 @@ +using System; +using ShardingCore.Core.UnionAllMergeShardingProviders.Abstractions; + +namespace ShardingCore.Core.UnionAllMergeShardingProviders +{ + public class UnionAllMergeScope:IDisposable + { + public IUnionAllMergeAccessor UnionAllMergeAccessor { get; } + + /// + /// 构造函数 + /// + /// + public UnionAllMergeScope(IUnionAllMergeAccessor unionAllMergeAccessor) + { + UnionAllMergeAccessor = unionAllMergeAccessor; + } + public void Dispose() + { + UnionAllMergeAccessor.SqlSupportContext = null; + } + } +} diff --git a/src/ShardingCore/DIExtension.cs b/src/ShardingCore/DIExtension.cs index 23e0824a..3fd2f133 100644 --- a/src/ShardingCore/DIExtension.cs +++ b/src/ShardingCore/DIExtension.cs @@ -29,12 +29,14 @@ using ShardingCore.Sharding.Abstractions; using ShardingCore.Sharding.ShardingQueryExecutors; using ShardingCore.TableCreator; using System; -using ShardingCore.Core.CustomerDatabaseSqlSupports; -using ShardingCore.Core.NotSupportShardingProviders.Abstractions; +using Microsoft.EntityFrameworkCore.Query; using ShardingCore.Core.QueryTrackers; using ShardingCore.Core.ShardingConfigurations; +using ShardingCore.Core.UnionAllMergeShardingProviders; +using ShardingCore.Core.UnionAllMergeShardingProviders.Abstractions; using ShardingCore.Core.VirtualDatabase.VirtualDataSources.Abstractions; using ShardingCore.DynamicDataSources; +using ShardingCore.Sharding.MergeContexts; using ShardingCore.Sharding.ParallelTables; using ShardingCore.Sharding.ReadWriteConfigurations; using ShardingCore.Sharding.ReadWriteConfigurations.Abstractions; @@ -125,6 +127,11 @@ namespace ShardingCore services.TryAddSingleton(); services.TryAddSingleton(); + // + services.TryAddSingleton(); + services.TryAddSingleton(); + services.TryAddSingleton(); + //route manage services.TryAddSingleton(); services.TryAddSingleton(); @@ -133,14 +140,15 @@ namespace ShardingCore services.TryAddSingleton(); services.TryAddSingleton(); services.TryAddSingleton(); - services.TryAddSingleton(); - services.TryAddSingleton(); + services.TryAddSingleton(); + services.TryAddSingleton(); services.TryAddSingleton(); services.TryAddSingleton(); services.TryAddSingleton(); //读写分离手动指定 services.TryAddSingleton(); + services.TryAddShardingJob(); return services; } @@ -174,7 +182,7 @@ namespace ShardingCore - + //public static IServiceCollection AddSingleShardingDbContext(this IServiceCollection services, Action configure, // Action optionsAction = null, // ServiceLifetime contextLifetime = ServiceLifetime.Scoped, diff --git a/src/ShardingCore/EFCores/OptionsExtensions/UnionAllMergeOptionsExtension.cs b/src/ShardingCore/EFCores/OptionsExtensions/UnionAllMergeOptionsExtension.cs new file mode 100644 index 00000000..9bc32822 --- /dev/null +++ b/src/ShardingCore/EFCores/OptionsExtensions/UnionAllMergeOptionsExtension.cs @@ -0,0 +1,97 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.Extensions.DependencyInjection; + +namespace ShardingCore.EFCores.OptionsExtensions +{ + /* + * @Author: xjm + * @Description: + * @Date: 2021/10/17 20:27:12 + * @Ver: 1.0 + * @Email: 326308290@qq.com + */ + +#if EFCORE6 + public class UnionAllMergeOptionsExtension : IDbContextOptionsExtension + { + public void ApplyServices(IServiceCollection services) + { + } + + public void Validate(IDbContextOptions options) + { + } + + + public DbContextOptionsExtensionInfo Info => new UnionAllMergeDbContextOptionsExtensionInfo(this); + + private class UnionAllMergeDbContextOptionsExtensionInfo : DbContextOptionsExtensionInfo + { + public UnionAllMergeDbContextOptionsExtensionInfo(IDbContextOptionsExtension extension) : base(extension) + { + } + + public override int GetServiceProviderHashCode() => 0; + + public override bool ShouldUseSameServiceProvider(DbContextOptionsExtensionInfo other) => true; + + public override void PopulateDebugInfo(IDictionary debugInfo) + { + } + + public override bool IsDatabaseProvider => false; + public override string LogFragment => "UnionAllMergeOptionsExtension"; + } + } +#endif +#if EFCORE3 || EFCORE5 + + public class UnionAllMergeOptionsExtension: IDbContextOptionsExtension + { + public void ApplyServices(IServiceCollection services) + { + } + + public void Validate(IDbContextOptions options) + { + } + + + public DbContextOptionsExtensionInfo Info => new UnionAllMergeDbContextOptionsExtensionInfo(this); + + private class UnionAllMergeDbContextOptionsExtensionInfo : DbContextOptionsExtensionInfo + { + public UnionAllMergeDbContextOptionsExtensionInfo(IDbContextOptionsExtension extension) : base(extension) { } + + public override long GetServiceProviderHashCode() => 0; + + public override void PopulateDebugInfo(IDictionary debugInfo) { } + + public override bool IsDatabaseProvider => false; + public override string LogFragment => "UnionAllMergeOptionsExtension"; + } + } + +#endif +#if EFCORE2 + + public class UnionAllMergeOptionsExtension: IDbContextOptionsExtension + { + public bool ApplyServices(IServiceCollection services) + { + return false; + } + + public long GetServiceProviderHashCode() => 0; + + public void Validate(IDbContextOptions options) + { + } + + public string LogFragment => "UnionAllMergeOptionsExtension"; + } +#endif +} diff --git a/src/ShardingCore/Extensions/DbContextExtension.cs b/src/ShardingCore/Extensions/DbContextExtension.cs index 0c2da234..8e3a9868 100644 --- a/src/ShardingCore/Extensions/DbContextExtension.cs +++ b/src/ShardingCore/Extensions/DbContextExtension.cs @@ -273,13 +273,17 @@ namespace ShardingCore.Extensions public static IEnumerable GetPrimaryKeyValues(TEntity entity,IKey primaryKey) where TEntity : class { - return primaryKey.Properties.Select(o => entity.GetPropertyValue(o.Name)); + return primaryKey.Properties.Select(o =>entity.GetPropertyValue(o.Name)); } public static TEntity GetAttachedEntity(this DbContext context, TEntity entity) where TEntity:class { if (entity == null) { throw new ArgumentNullException(nameof(entity)); } var entityPrimaryKey = context.Model.FindEntityType(entity.GetType()).FindPrimaryKey(); + if (entityPrimaryKey == null) + { + return entity; + } var primaryKeyValue = GetPrimaryKeyValues(entity, entityPrimaryKey).ToArray(); if (primaryKeyValue.IsEmpty()) return null; diff --git a/src/ShardingCore/Extensions/ExpressionExtension.cs b/src/ShardingCore/Extensions/ExpressionExtension.cs index c2fa9482..4ac22767 100644 --- a/src/ShardingCore/Extensions/ExpressionExtension.cs +++ b/src/ShardingCore/Extensions/ExpressionExtension.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Reflection; +using ShardingCore.Exceptions; namespace ShardingCore.Extensions { @@ -59,6 +60,10 @@ namespace ShardingCore.Extensions //propertyAccess = Expression.MakeMemberAccess(parameter, property); for (int i = 1; i < childProperties.Length; i++) { + if (property == null) + { + throw new ShardingCoreException($"property:[{propertyExpression}] not in type:[{entityType}]"); + } property = property.PropertyType.GetProperty(childProperties[i]); //propertyAccess = Expression.MakeMemberAccess(propertyAccess, property); } @@ -69,6 +74,11 @@ namespace ShardingCore.Extensions //propertyAccess = Expression.MakeMemberAccess(parameter, property); } + if (property == null) + { + throw new ShardingCoreException($"property:[{propertyExpression}] not in type:[{entityType}]"); + } + return property.GetValue(obj); //var lambda = Expression.Lambda(propertyAccess, parameter); //Delegate fn = lambda.Compile(); diff --git a/src/ShardingCore/Extensions/IShardingQueryableExtension.cs b/src/ShardingCore/Extensions/IShardingQueryableExtension.cs index 7940ce92..1cd91b04 100644 --- a/src/ShardingCore/Extensions/IShardingQueryableExtension.cs +++ b/src/ShardingCore/Extensions/IShardingQueryableExtension.cs @@ -3,9 +3,11 @@ using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Linq.Expressions; +using System.Reflection; using Microsoft.EntityFrameworkCore; using ShardingCore.Core.EntityMetadatas; using ShardingCore.Core.Internal.Visitors; +using ShardingCore.Extensions.InternalExtensions; using ShardingCore.Sharding.Visitors; namespace ShardingCore.Extensions @@ -21,11 +23,15 @@ namespace ShardingCore.Extensions /// internal static class IShardingQueryableExtension { + private static readonly MethodInfo QueryableSkipMethod = typeof(Queryable).GetMethod(nameof(Queryable.Skip)); + private static readonly MethodInfo QueryableTakeMethod = typeof(Queryable).GetMethods().First( + m => m.Name == nameof(Queryable.Take) + && m.GetParameters().Length == 2 && m.GetParameters()[1].ParameterType == typeof(int)); internal static ExtraEntry GetExtraEntry(this IQueryable source) { var extraVisitor = new QueryableExtraDiscoverVisitor(); extraVisitor.Visit(source.Expression); - var extraEntry = new ExtraEntry(extraVisitor.GetSkip(), extraVisitor.GetTake(), extraVisitor.GetOrders(),extraVisitor.GetSelectContext(),extraVisitor.GetGroupByContext()); + var extraEntry = new ExtraEntry(extraVisitor.GetPaginationContext().Skip, extraVisitor.GetPaginationContext().Take, extraVisitor.GetOrderByContext().PropertyOrders,extraVisitor.GetSelectContext(),extraVisitor.GetGroupByContext()); extraEntry.ProcessGroupBySelectProperties(); return extraEntry; } @@ -35,39 +41,57 @@ namespace ShardingCore.Extensions /// 实体类型 /// 数据源 /// - internal static IQueryable RemoveSkip(this IQueryable source) + internal static IQueryable RemoveSkip(this IQueryable source) { var expression = new RemoveSkipVisitor().Visit(source.Expression); - return (IQueryable)source.Provider.CreateQuery(expression); + return source.Provider.CreateQuery(expression); } + internal static IQueryable ReSkip(this IQueryable source, int skip) + { + MethodInfo method = QueryableSkipMethod.MakeGenericMethod(source.ElementType); + var expression = Expression.Call( + method, + source.Expression, + Expression.Constant(skip)); + return source.Provider.CreateQuery(expression); + } + + internal static IQueryable ReTake(this IQueryable source, int take) + { + MethodInfo method = QueryableTakeMethod.MakeGenericMethod(source.ElementType); + var expression = Expression.Call( + method, + source.Expression, + Expression.Constant(take)); + return source.Provider.CreateQuery(expression); + } /// /// 删除Take表达式 /// - /// 实体类型 /// 数据源 /// - internal static IQueryable RemoveTake(this IQueryable source) + internal static IQueryable RemoveTake(this IQueryable source) { var expression = new RemoveTakeVisitor().Visit(source.Expression); - return (IQueryable) source.Provider.CreateQuery(expression); + return source.Provider.CreateQuery(expression); } [ExcludeFromCodeCoverage] - internal static IQueryable RemoveOrderBy(this IQueryable source) + internal static IQueryable RemoveOrderBy(this IQueryable source) { var expression = new RemoveOrderByVisitor().Visit(source.Expression); - return (IQueryable)source.Provider.CreateQuery(expression); + return source.Provider.CreateQuery(expression); } [ExcludeFromCodeCoverage] - internal static IQueryable RemoveOrderByDescending(this IQueryable source) + internal static IQueryable RemoveOrderByDescending(this IQueryable source) { var expression = new RemoveOrderByDescendingVisitor().Visit(source.Expression); - return (IQueryable)source.Provider.CreateQuery(expression); + return source.Provider.CreateQuery(expression); } - internal static IQueryable RemoveAnyOrderBy(this IQueryable source) + internal static IQueryable RemoveAnyOrderBy(this IQueryable source) { var expression = new RemoveAnyOrderVisitor().Visit(source.Expression); - return (IQueryable) source.Provider.CreateQuery(expression); + return source.Provider.CreateQuery(expression); } internal static bool? GetIsNoTracking(this IQueryable source) diff --git a/src/ShardingCore/Extensions/InternalExtensions/InternalObjectExtension.cs b/src/ShardingCore/Extensions/InternalExtensions/InternalObjectExtension.cs new file mode 100644 index 00000000..f3b846a9 --- /dev/null +++ b/src/ShardingCore/Extensions/InternalExtensions/InternalObjectExtension.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ShardingCore.Extensions.InternalExtensions +{ + internal static class InternalObjectExtension + { + public static T As(this object obj) where T : class + { + return (T)obj; + } + } +} diff --git a/src/ShardingCore/Extensions/ObjectExtension.cs b/src/ShardingCore/Extensions/ObjectExtension.cs index c6e2b5d2..81498d3a 100644 --- a/src/ShardingCore/Extensions/ObjectExtension.cs +++ b/src/ShardingCore/Extensions/ObjectExtension.cs @@ -46,7 +46,7 @@ namespace ShardingCore.Extensions var property = obj.GetType().GetProperty(propertyName, _bindingFlags); if (property != null) { - return obj.GetType().GetProperty(propertyName, _bindingFlags)?.GetValue(obj); + return property.GetValue(obj); } else { @@ -65,7 +65,7 @@ namespace ShardingCore.Extensions var property=type.GetProperty(propertyName, _bindingFlags); if (property != null) { - return type.GetProperty(propertyName, _bindingFlags)?.GetValue(obj); + return property.GetValue(obj); } else { diff --git a/src/ShardingCore/Extensions/ShardingDbContextExtension.cs b/src/ShardingCore/Extensions/ShardingDbContextExtension.cs index ceb75c51..36518eb2 100644 --- a/src/ShardingCore/Extensions/ShardingDbContextExtension.cs +++ b/src/ShardingCore/Extensions/ShardingDbContextExtension.cs @@ -3,6 +3,12 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Internal; +using Microsoft.EntityFrameworkCore.Query; +using Microsoft.EntityFrameworkCore.Query.Internal; +using ShardingCore.EFCores.OptionsExtensions; using ShardingCore.Sharding.Abstractions; namespace ShardingCore.Extensions @@ -13,5 +19,11 @@ namespace ShardingCore.Extensions { return shardingDbContext.GetVirtualDataSource().UseReadWriteSeparation; } + + public static bool SupportUnionAllMerge(this IShardingDbContext shardingDbContext) + { + var dbContext = (DbContext)shardingDbContext; + return dbContext.GetService().ContextOptions.FindExtension() is not null; + } } } diff --git a/src/ShardingCore/Extensions/ShardingQueryableExtensions/EntityFrameworkShardingQueryableExtension.cs b/src/ShardingCore/Extensions/ShardingQueryableExtensions/EntityFrameworkShardingQueryableExtension.cs index a713d025..7eebaa0a 100644 --- a/src/ShardingCore/Extensions/ShardingQueryableExtensions/EntityFrameworkShardingQueryableExtension.cs +++ b/src/ShardingCore/Extensions/ShardingQueryableExtensions/EntityFrameworkShardingQueryableExtension.cs @@ -21,7 +21,7 @@ namespace ShardingCore.Extensions.ShardingQueryableExtensions { internal static readonly MethodInfo NotSupportMethodInfo - = typeof(EntityFrameworkShardingQueryableExtension).GetTypeInfo().GetDeclaredMethods(nameof(UnionMerge)).Single(); + = typeof(EntityFrameworkShardingQueryableExtension).GetTypeInfo().GetDeclaredMethods(nameof(UseUnionAllMerge)).Single(); internal static readonly MethodInfo AsRouteMethodInfo = typeof(EntityFrameworkShardingQueryableExtension) .GetTypeInfo() @@ -57,7 +57,7 @@ namespace ShardingCore.Extensions.ShardingQueryableExtensions /// /// /// - public static IQueryable UnionMerge(this IQueryable source) + public static IQueryable UseUnionAllMerge(this IQueryable source) { Check.NotNull(source, nameof(source)); return diff --git a/src/ShardingCore/Extensions/StringFieldOrderExtension.cs b/src/ShardingCore/Extensions/StringFieldOrderExtension.cs index 346ae4d7..f0987a03 100644 --- a/src/ShardingCore/Extensions/StringFieldOrderExtension.cs +++ b/src/ShardingCore/Extensions/StringFieldOrderExtension.cs @@ -4,6 +4,7 @@ using System.Linq; using System.Linq.Expressions; using System.Reflection; using ShardingCore.Core.Internal.Visitors; +using ShardingCore.Extensions.InternalExtensions; using ShardingCore.Sharding.Abstractions; using ShardingCore.Sharding.Internals; using ShardingCore.Sharding.MergeContexts; @@ -21,16 +22,16 @@ namespace ShardingCore.Extensions { #region Private expression tree helpers - private static LambdaExpression GenerateSelector(String propertyName, out Type resultType) + private static LambdaExpression GenerateSelector(Type entityType,String propertyName, out Type resultType) { PropertyInfo property; Expression propertyAccess; - var parameter = Expression.Parameter(typeof(TEntity), "o"); + var parameter = Expression.Parameter(entityType, "o"); if (propertyName.Contains('.')) { String[] childProperties = propertyName.Split('.'); - property = typeof(TEntity).GetProperty(childProperties[0]); + property = entityType.GetProperty(childProperties[0]); propertyAccess = Expression.MakeMemberAccess(parameter, property); for (int i = 1; i < childProperties.Length; i++) { @@ -40,7 +41,7 @@ namespace ShardingCore.Extensions } else { - property = typeof(TEntity).GetProperty(propertyName); + property = entityType.GetProperty(propertyName); propertyAccess = Expression.MakeMemberAccess(parameter, property); } @@ -49,11 +50,11 @@ namespace ShardingCore.Extensions return Expression.Lambda(propertyAccess, parameter); } - private static MethodCallExpression GenerateMethodCall(IQueryable source, string methodName, String fieldName,IShardingComparer shardingComparer=null) + private static MethodCallExpression GenerateMethodCall(IQueryable source, string methodName, String fieldName,IShardingComparer shardingComparer=null) { - Type type = typeof(TEntity); + Type type = source.ElementType; Type selectorResultType; - LambdaExpression selector = GenerateSelector(fieldName, out selectorResultType); + LambdaExpression selector = GenerateSelector(type,fieldName, out selectorResultType); MethodCallExpression resultExp; if (shardingComparer == null) { @@ -73,28 +74,28 @@ namespace ShardingCore.Extensions #endregion - internal static IOrderedQueryable OrderBy(this IQueryable source, string fieldName, IShardingComparer shardingComparer = null) + internal static IOrderedQueryable OrderBy(this IQueryable source, string fieldName, IShardingComparer shardingComparer = null) { - MethodCallExpression resultExp = GenerateMethodCall(source, nameof(Queryable.OrderBy), fieldName, shardingComparer); - return source.Provider.CreateQuery(resultExp) as IOrderedQueryable; + MethodCallExpression resultExp = GenerateMethodCall(source, nameof(Queryable.OrderBy), fieldName, shardingComparer); + return source.Provider.CreateQuery(resultExp) as IOrderedQueryable; } - internal static IOrderedQueryable OrderByDescending(this IQueryable source, string fieldName, IShardingComparer shardingComparer = null) + internal static IOrderedQueryable OrderByDescending(this IQueryable source, string fieldName, IShardingComparer shardingComparer = null) { - MethodCallExpression resultExp = GenerateMethodCall(source, nameof(Queryable.OrderByDescending), fieldName, shardingComparer); - return source.Provider.CreateQuery(resultExp) as IOrderedQueryable; + MethodCallExpression resultExp = GenerateMethodCall(source, nameof(Queryable.OrderByDescending), fieldName, shardingComparer); + return source.Provider.CreateQuery(resultExp) as IOrderedQueryable; } - internal static IOrderedQueryable ThenBy(this IOrderedQueryable source, string fieldName, IShardingComparer shardingComparer = null) + internal static IOrderedQueryable ThenBy(this IOrderedQueryable source, string fieldName, IShardingComparer shardingComparer = null) { - MethodCallExpression resultExp = GenerateMethodCall(source, nameof(Queryable.ThenBy), fieldName, shardingComparer); - return source.Provider.CreateQuery(resultExp) as IOrderedQueryable; + MethodCallExpression resultExp = GenerateMethodCall(source, nameof(Queryable.ThenBy), fieldName, shardingComparer); + return source.Provider.CreateQuery(resultExp) as IOrderedQueryable; } - internal static IOrderedQueryable ThenByDescending(this IOrderedQueryable source, string fieldName, IShardingComparer shardingComparer = null) + internal static IOrderedQueryable ThenByDescending(this IOrderedQueryable source, string fieldName, IShardingComparer shardingComparer = null) { - MethodCallExpression resultExp = GenerateMethodCall(source, nameof(Queryable.ThenByDescending), fieldName, shardingComparer); - return source.Provider.CreateQuery(resultExp) as IOrderedQueryable; + MethodCallExpression resultExp = GenerateMethodCall(source, nameof(Queryable.ThenByDescending), fieldName, shardingComparer); + return source.Provider.CreateQuery(resultExp) as IOrderedQueryable; } /// /// 排序利用表达式 @@ -102,12 +103,11 @@ namespace ShardingCore.Extensions /// /// "child.name asc,child.age desc" /// - /// /// - internal static IOrderedQueryable OrderWithExpression(this IQueryable source, string sortExpression, IShardingComparer shardingComparer = null) + internal static IOrderedQueryable OrderWithExpression(this IQueryable source, string sortExpression, IShardingComparer shardingComparer = null) { String[] orderFields = sortExpression.Split(','); - IOrderedQueryable result = null; + IOrderedQueryable result = null; for (int currentFieldIndex = 0; currentFieldIndex < orderFields.Length; currentFieldIndex++) { String[] expressionPart = orderFields[currentFieldIndex].Trim().Split(' '); @@ -125,9 +125,17 @@ namespace ShardingCore.Extensions return result; } + internal static IOrderedQueryable OrderWithExpression(this IQueryable source, string sortExpression, IShardingComparer shardingComparer = null) + { + return OrderWithExpression((IQueryable)source,sortExpression,shardingComparer).As>(); + } internal static IOrderedQueryable OrderWithExpression(this IQueryable source, IEnumerable propertyOrders, IShardingComparer shardingComparer = null) { - IOrderedQueryable result = null; + return OrderWithExpression(source.As(), propertyOrders,shardingComparer).As>(); + } + internal static IOrderedQueryable OrderWithExpression(this IQueryable source, IEnumerable propertyOrders, IShardingComparer shardingComparer = null) + { + IOrderedQueryable result = null; var currentIndex = 0; foreach (var propertyOrder in propertyOrders) { diff --git a/src/ShardingCore/Sharding/Abstractions/IUnionAllMergeQueryCompiler.cs b/src/ShardingCore/Sharding/Abstractions/IUnionAllMergeQueryCompiler.cs new file mode 100644 index 00000000..f3e4e3f5 --- /dev/null +++ b/src/ShardingCore/Sharding/Abstractions/IUnionAllMergeQueryCompiler.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ShardingCore.Sharding.Abstractions +{ + public interface IUnionAllMergeQueryCompiler + { + } +} diff --git a/src/ShardingCore/Sharding/Abstractions/IUnionAllMergeQuerySqlGeneratorFactory.cs b/src/ShardingCore/Sharding/Abstractions/IUnionAllMergeQuerySqlGeneratorFactory.cs new file mode 100644 index 00000000..e8187c5f --- /dev/null +++ b/src/ShardingCore/Sharding/Abstractions/IUnionAllMergeQuerySqlGeneratorFactory.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ShardingCore.Sharding.Abstractions +{ + public interface IUnionAllMergeQuerySqlGeneratorFactory + { + } +} diff --git a/src/ShardingCore/Sharding/MergeContexts/IOptimizeResult.cs b/src/ShardingCore/Sharding/MergeContexts/IOptimizeResult.cs index 0e105291..f25a4e3f 100644 --- a/src/ShardingCore/Sharding/MergeContexts/IOptimizeResult.cs +++ b/src/ShardingCore/Sharding/MergeContexts/IOptimizeResult.cs @@ -1,4 +1,4 @@ -using System; +using System.Collections.Generic; using ShardingCore.Core; namespace ShardingCore.Sharding.MergeContexts @@ -18,5 +18,7 @@ namespace ShardingCore.Sharding.MergeContexts ConnectionModeEnum GetConnectionMode(); bool IsSequenceQuery(); bool SameWithTailComparer(); + IComparer ShardingTailComparer(); + bool CanTrip(); } } \ No newline at end of file diff --git a/src/ShardingCore/Sharding/MergeContexts/IParseResult.cs b/src/ShardingCore/Sharding/MergeContexts/IParseResult.cs index a39c3dee..b44b90e7 100644 --- a/src/ShardingCore/Sharding/MergeContexts/IParseResult.cs +++ b/src/ShardingCore/Sharding/MergeContexts/IParseResult.cs @@ -12,13 +12,11 @@ namespace ShardingCore.Sharding.MergeContexts */ public interface IParseResult { - int? GetSkip(); - int? GetTake(); - - PropertyOrder[] GetOrders(); + PaginationContext GetPaginationContext(); + OrderByContext GetOrderByContext(); SelectContext GetSelectContext(); - GroupByContext GetGroupByConteext(); + GroupByContext GetGroupByContext(); } } \ No newline at end of file diff --git a/src/ShardingCore/Sharding/MergeContexts/IQueryableOptimizeEngine.cs b/src/ShardingCore/Sharding/MergeContexts/IQueryableOptimizeEngine.cs new file mode 100644 index 00000000..a72683cb --- /dev/null +++ b/src/ShardingCore/Sharding/MergeContexts/IQueryableOptimizeEngine.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using ShardingCore.Sharding.ShardingExecutors.Abstractions; + +namespace ShardingCore.Sharding.MergeContexts +{ + public interface IQueryableOptimizeEngine + { + IOptimizeResult Optimize(IMergeQueryCompilerContext mergeQueryCompilerContext, IParseResult parseResult, + IQueryable rewriteQueryable); + } +} diff --git a/src/ShardingCore/Sharding/MergeContexts/IStreamMergeParameter.cs b/src/ShardingCore/Sharding/MergeContexts/IStreamMergeParameter.cs new file mode 100644 index 00000000..d76d7842 --- /dev/null +++ b/src/ShardingCore/Sharding/MergeContexts/IStreamMergeParameter.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ShardingCore.Sharding.MergeContexts +{ + internal interface IStreamMergeParameter + { + IParseResult GetParseResult(); + + IRewriteResult GetRewriteResult(); + IOptimizeResult GetOptimizeResult(); + } +} diff --git a/src/ShardingCore/Sharding/MergeContexts/OptimizeResult.cs b/src/ShardingCore/Sharding/MergeContexts/OptimizeResult.cs new file mode 100644 index 00000000..08a47122 --- /dev/null +++ b/src/ShardingCore/Sharding/MergeContexts/OptimizeResult.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using ShardingCore.Core; + +namespace ShardingCore.Sharding.MergeContexts +{ + public sealed class OptimizeResult: IOptimizeResult + { + private readonly int _maxQueryConnectionsLimit; + private readonly ConnectionModeEnum _connectionMode; + private readonly bool _isSequenceQuery; + private readonly bool _sameWithTailComparer; + private readonly IComparer _shardingTailComparer; + private readonly bool _canTrip; + + public OptimizeResult(int maxQueryConnectionsLimit, ConnectionModeEnum connectionMode,bool isSequenceQuery,bool sameWithTailComparer,IComparer shardingTailComparer,bool canTrip) + { + _maxQueryConnectionsLimit = maxQueryConnectionsLimit; + _connectionMode = connectionMode; + _isSequenceQuery = isSequenceQuery; + _sameWithTailComparer = sameWithTailComparer; + _shardingTailComparer = shardingTailComparer; + _canTrip = canTrip; + } + public int GetMaxQueryConnectionsLimit() + { + return _maxQueryConnectionsLimit; + } + + public ConnectionModeEnum GetConnectionMode() + { + return _connectionMode; + } + + public bool IsSequenceQuery() + { + return _isSequenceQuery; + } + + public bool SameWithTailComparer() + { + return _sameWithTailComparer; + } + + public IComparer ShardingTailComparer() + { + return _shardingTailComparer; + } + public bool CanTrip() + { + return _canTrip; + } + + } +} diff --git a/src/ShardingCore/Sharding/MergeContexts/OrderByContext.cs b/src/ShardingCore/Sharding/MergeContexts/OrderByContext.cs new file mode 100644 index 00000000..f9c8c9fa --- /dev/null +++ b/src/ShardingCore/Sharding/MergeContexts/OrderByContext.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ShardingCore.Sharding.MergeContexts +{ + public sealed class OrderByContext + { + public LinkedList PropertyOrders { get; } = new LinkedList(); + public string GetOrderExpression() + { + return string.Join(",", PropertyOrders); + } + } +} diff --git a/src/ShardingCore/Sharding/MergeContexts/PaginationContext.cs b/src/ShardingCore/Sharding/MergeContexts/PaginationContext.cs new file mode 100644 index 00000000..218288a8 --- /dev/null +++ b/src/ShardingCore/Sharding/MergeContexts/PaginationContext.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ShardingCore.Sharding.MergeContexts +{ + public sealed class PaginationContext + { + public int? Skip { get; set; } + public int? Take { get; set; } + + public bool HasSkip() + { + return Skip.HasValue; + } + public bool HasTake() + { + return Take.HasValue; + } + } +} diff --git a/src/ShardingCore/Sharding/MergeContexts/ParseResult.cs b/src/ShardingCore/Sharding/MergeContexts/ParseResult.cs new file mode 100644 index 00000000..e5098c7d --- /dev/null +++ b/src/ShardingCore/Sharding/MergeContexts/ParseResult.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using ShardingCore.Core.Internal.Visitors.Selects; + +namespace ShardingCore.Sharding.MergeContexts +{ + public sealed class ParseResult:IParseResult + { + private readonly PaginationContext _paginationContext; + private readonly OrderByContext _orderByContext; + private readonly SelectContext _selectContext; + private readonly GroupByContext _groupByContext; + + public ParseResult(PaginationContext paginationContext, OrderByContext orderByContext, SelectContext selectContext,GroupByContext groupByContext) + { + _paginationContext = paginationContext; + _orderByContext = orderByContext; + _selectContext = selectContext; + _groupByContext = groupByContext; + } + + public PaginationContext GetPaginationContext() + { + return _paginationContext; + } + + public OrderByContext GetOrderByContext() + { + return _orderByContext; + } + + + public SelectContext GetSelectContext() + { + return _selectContext; + } + + public GroupByContext GetGroupByContext() + { + return _groupByContext; + } + } +} diff --git a/src/ShardingCore/Sharding/MergeContexts/QueryableOptimizeEngine.cs b/src/ShardingCore/Sharding/MergeContexts/QueryableOptimizeEngine.cs new file mode 100644 index 00000000..35755823 --- /dev/null +++ b/src/ShardingCore/Sharding/MergeContexts/QueryableOptimizeEngine.cs @@ -0,0 +1,171 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Text; +using System.Threading.Tasks; +using ShardingCore.Core; +using ShardingCore.Core.Internal.Visitors.Selects; +using ShardingCore.Core.VirtualTables; +using ShardingCore.Sharding.EntityQueryConfigurations; +using ShardingCore.Sharding.ShardingExecutors; +using ShardingCore.Sharding.ShardingExecutors.Abstractions; + +namespace ShardingCore.Sharding.MergeContexts +{ + public sealed class QueryableOptimizeEngine: IQueryableOptimizeEngine + { + public IOptimizeResult Optimize(IMergeQueryCompilerContext mergeQueryCompilerContext, IParseResult parseResult, + IQueryable rewriteQueryable) + { + var shardingDbContext = mergeQueryCompilerContext.GetShardingDbContext(); + var maxParallelExecuteCount = shardingDbContext.GetVirtualDataSource().ConfigurationParams.MaxQueryConnectionsLimit; + var connectionMode = shardingDbContext.GetVirtualDataSource().ConfigurationParams.ConnectionMode; + IComparer shardingTailComparer = Comparer.Default; + bool sameWithTailComparer = true; + bool sequenceQuery = false; + if (mergeQueryCompilerContext.IsSingleShardingEntityQuery() && mergeQueryCompilerContext.IsCrossTable() && !mergeQueryCompilerContext.UseUnionAllMerge()) + { + var singleShardingEntityType = mergeQueryCompilerContext.GetSingleShardingEntityType(); + var virtualTableManager = ShardingContainer.GetVirtualTableManager(mergeQueryCompilerContext.GetShardingDbContextType()); + var virtualTable = virtualTableManager.GetVirtualTable(singleShardingEntityType); + if (virtualTable.EnableEntityQuery) + { + if (virtualTable.EntityQueryMetadata.DefaultTailComparer != null) + { + shardingTailComparer = virtualTable.EntityQueryMetadata.DefaultTailComparer; + } + sameWithTailComparer = virtualTable.EntityQueryMetadata.DefaultTailComparerNeedReverse; + string methodName = mergeQueryCompilerContext.IsEnumerableQuery() ? + EntityQueryMetadata.QUERY_ENUMERATOR : + ((MethodCallExpression)mergeQueryCompilerContext.GetQueryExpression()).Method.Name; + + if (virtualTable.EntityQueryMetadata.TryGetConnectionsLimit(methodName, out var limit)) + { + maxParallelExecuteCount = Math.Min(limit, maxParallelExecuteCount); + } + + var isSequence = mergeQueryCompilerContext.IsSequence(); + var sameWithShardingComparer = mergeQueryCompilerContext.SameWithShardingComparer(); + if (isSequence.HasValue && sameWithShardingComparer.HasValue) + { + sequenceQuery = isSequence.Value; + sameWithTailComparer = sameWithShardingComparer.Value; + } + else + { + if (TryGetSequenceQuery(parseResult, singleShardingEntityType, virtualTable, methodName, + out var tailComparerIsAsc)) + { + sequenceQuery = true; + if (!tailComparerIsAsc) + { + sameWithTailComparer = !sameWithTailComparer; + } + } + } + } + } + + maxParallelExecuteCount = mergeQueryCompilerContext.GetMaxQueryConnectionsLimit() ?? maxParallelExecuteCount; + + connectionMode = CalcConnectionMode(mergeQueryCompilerContext.GetDataSourceRouteResult().IntersectDataSources.Count,maxParallelExecuteCount, mergeQueryCompilerContext.GetConnectionMode() ?? connectionMode); + var canTrip = mergeQueryCompilerContext.GetTableRouteResults().Length > maxParallelExecuteCount; + return new OptimizeResult(maxParallelExecuteCount, connectionMode, sequenceQuery, sameWithTailComparer, + shardingTailComparer, canTrip); + } + + private ConnectionModeEnum CalcConnectionMode(int sqlCount,int maxQueryConnectionsLimit, ConnectionModeEnum connectionMode) + { + switch (connectionMode) + { + case ConnectionModeEnum.MEMORY_STRICTLY: + case ConnectionModeEnum.CONNECTION_STRICTLY: return connectionMode; + default: + { + return maxQueryConnectionsLimit < sqlCount + ? ConnectionModeEnum.CONNECTION_STRICTLY + : ConnectionModeEnum.MEMORY_STRICTLY; ; + } + } + } + /// + /// 是否需要判断order + /// + /// + /// + /// + private bool EffectOrder(string methodName, PropertyOrder[] propertyOrders) + { + if ((methodName == null || + nameof(Queryable.First) == methodName || + nameof(Queryable.FirstOrDefault) == methodName || + nameof(Queryable.Last) == methodName || + nameof(Queryable.LastOrDefault) == methodName || + nameof(Queryable.Single) == methodName || + nameof(Queryable.SingleOrDefault) == methodName || + EntityQueryMetadata.QUERY_ENUMERATOR == methodName) && + propertyOrders.Length > 0) + return true; + return false; + } + /// + /// 尝试获取当前方法是否采用顺序查询,如果有先判断排序没有的情况下判断默认 + /// + /// + /// + /// + /// + /// + /// + private bool TryGetSequenceQuery(IParseResult parseResult, Type singleShardingEntityType, IVirtualTable virtualTable, string methodName, out bool tailComparerIsAsc) + { + var propertyOrders = parseResult.GetOrderByContext().PropertyOrders.ToArray(); + var effectOrder = EffectOrder(methodName, propertyOrders); + + if (effectOrder) + { + var primaryOrder = propertyOrders[0]; + //不是多级order + var primaryOrderPropertyName = primaryOrder.PropertyExpression; + if (!primaryOrderPropertyName.Contains(".")) + { + if (virtualTable.EnableEntityQuery && virtualTable.EntityQueryMetadata.TryContainsComparerOrder(primaryOrderPropertyName, out var seqQueryOrderMatch) + && (primaryOrder.OwnerType == singleShardingEntityType || seqQueryOrderMatch.OrderMatch.HasFlag(SeqOrderMatchEnum.Named)))//要么必须是当前对象查询要么就是名称一样 + { + tailComparerIsAsc = seqQueryOrderMatch.IsSameAsShardingTailComparer ? primaryOrder.IsAsc : !primaryOrder.IsAsc; + //如果是获取最后一个还需要再次翻转 + if (nameof(Queryable.Last) == methodName || nameof(Queryable.LastOrDefault) == methodName) + { + tailComparerIsAsc = !tailComparerIsAsc; + } + + return true; + } + } + tailComparerIsAsc = true; + return false; + } + if (virtualTable.EnableEntityQuery && methodName != null && + virtualTable.EntityQueryMetadata.TryGetDefaultSequenceQueryTrip(methodName, out var defaultAsc)) + { + tailComparerIsAsc = defaultAsc; + return true; + } + //Max和Min + if (nameof(Queryable.Max) == methodName || nameof(Queryable.Min) == methodName) + { + //如果是max或者min + if (virtualTable.EnableEntityQuery && parseResult.GetSelectContext().SelectProperties.Count == 1 && virtualTable.EntityQueryMetadata.TryContainsComparerOrder(parseResult.GetSelectContext().SelectProperties[0].PropertyName, out var seqQueryOrderMatch) + && (parseResult.GetSelectContext().SelectProperties[0].OwnerType == singleShardingEntityType || seqQueryOrderMatch.OrderMatch.HasFlag(SeqOrderMatchEnum.Named))) + { + tailComparerIsAsc = seqQueryOrderMatch.IsSameAsShardingTailComparer ? nameof(Queryable.Min) == methodName : nameof(Queryable.Max) == methodName; + return true; + } + } + + tailComparerIsAsc = true; + return false; + } + } +} diff --git a/src/ShardingCore/Sharding/MergeContexts/QueryableParseEngine.cs b/src/ShardingCore/Sharding/MergeContexts/QueryableParseEngine.cs index f6854d39..48fca4a7 100644 --- a/src/ShardingCore/Sharding/MergeContexts/QueryableParseEngine.cs +++ b/src/ShardingCore/Sharding/MergeContexts/QueryableParseEngine.cs @@ -1,5 +1,6 @@ using System; using System.Linq; +using ShardingCore.Core.Internal.Visitors; using ShardingCore.Sharding.ShardingExecutors.Abstractions; /* @@ -14,7 +15,12 @@ namespace ShardingCore.Sharding.MergeContexts { public IParseResult Parse(IMergeQueryCompilerContext mergeQueryCompilerContext) { - throw new NotImplementedException(); + var combineQueryable = mergeQueryCompilerContext.GetQueryCombineResult().GetCombineQueryable(); + var queryableExtraDiscoverVisitor = new QueryableExtraDiscoverVisitor(); + queryableExtraDiscoverVisitor.Visit(combineQueryable.Expression); + return new ParseResult(queryableExtraDiscoverVisitor.GetPaginationContext(), + queryableExtraDiscoverVisitor.GetOrderByContext(), queryableExtraDiscoverVisitor.GetSelectContext(), + queryableExtraDiscoverVisitor.GetGroupByContext()); } } } \ No newline at end of file diff --git a/src/ShardingCore/Sharding/MergeContexts/QueryableRewriteEngine.cs b/src/ShardingCore/Sharding/MergeContexts/QueryableRewriteEngine.cs new file mode 100644 index 00000000..db057965 --- /dev/null +++ b/src/ShardingCore/Sharding/MergeContexts/QueryableRewriteEngine.cs @@ -0,0 +1,138 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore.Query; +using Microsoft.EntityFrameworkCore.Query.Internal; +using ShardingCore.Exceptions; +using ShardingCore.Extensions; +using ShardingCore.Extensions.ShardingQueryableExtensions; +using ShardingCore.Sharding.Abstractions; +using ShardingCore.Sharding.ShardingExecutors.Abstractions; +using ShardingCore.Sharding.Visitors.Selects; + +#if EFCORE2 +using Microsoft.EntityFrameworkCore.Query.Sql; +#endif + +namespace ShardingCore.Sharding.MergeContexts +{ + public sealed class QueryableRewriteEngine : IQueryableRewriteEngine + { + public IQueryable GetRewriteQueryable(IMergeQueryCompilerContext mergeQueryCompilerContext, IParseResult parseResult) + { + var paginationContext = parseResult.GetPaginationContext(); + var orderByContext = parseResult.GetOrderByContext(); + var groupByContext = parseResult.GetGroupByContext(); + var selectContext = parseResult.GetSelectContext(); + var skip = paginationContext.Skip; + var take = paginationContext.Take; + var orders = orderByContext.PropertyOrders; + + //去除分页,获取前Take+Skip数量 + var reWriteQueryable = mergeQueryCompilerContext.GetQueryCombineResult().GetCombineQueryable(); + if (take.HasValue) + { + reWriteQueryable = reWriteQueryable.RemoveTake(); + } + + if (skip.HasValue) + { + reWriteQueryable = reWriteQueryable.RemoveSkip(); + } + + if (take.HasValue) + { + if (skip.HasValue) + { + reWriteQueryable = reWriteQueryable.ReSkip(0).ReTake(take.Value + skip.GetValueOrDefault()); + } + else + { + reWriteQueryable = reWriteQueryable.ReTake(take.Value + skip.GetValueOrDefault()); + } + } + //包含group by + if (groupByContext.GroupExpression != null) + { + if (orders.IsEmpty()) + { + //将查询的属性转换成order by + var selectProperties = selectContext.SelectProperties.Where(o => !(o is SelectAggregateProperty)).ToArray(); + if (selectProperties.IsNotEmpty()) + { + var sort = string.Join(",", selectProperties.Select(o => $"{o.PropertyName} asc")); + reWriteQueryable = reWriteQueryable.OrderWithExpression(sort, null); + foreach (var orderProperty in selectProperties) + { + orders.AddLast(new PropertyOrder(orderProperty.PropertyName, true, orderProperty.OwnerType)); + } + } + } + else if (!mergeQueryCompilerContext.UseUnionAllMerge()) + { + //将查询的属性转换成order by 并且order和select的未聚合查询必须一致 + var selectProperties = selectContext.SelectProperties.Where(o => !(o is SelectAggregateProperty)); + + if (orders.Count() != selectProperties.Count()) + throw new ShardingCoreInvalidOperationException("group by query order items not equal select un-aggregate items"); + var os = orders.Select(o => o.PropertyExpression).ToList(); + var ss = selectProperties.Select(o => o.PropertyName).ToList(); + for (int i = 0; i < os.Count(); i++) + { + if (!os[i].Equals(ss[i])) + throw new ShardingCoreInvalidOperationException($"group by query order items not equal select un-aggregate items: order:[{os[i]}],select:[{ss[i]}"); + } + + } + if (selectContext.HasAverage()) + { + var averageSelectProperties = selectContext.SelectProperties.OfType().ToList(); + var selectAggregateProperties = selectContext.SelectProperties.OfType().Where(o => !(o is SelectAverageProperty)).ToList(); + foreach (var averageSelectProperty in averageSelectProperties) + { + var selectCountProperty = selectAggregateProperties.FirstOrDefault(o => o is SelectCountProperty selectCountProperty); + if (null != selectCountProperty) + { + averageSelectProperty.BindCountProperty(selectCountProperty.Property); + } + var selectSumProperty = selectAggregateProperties.FirstOrDefault(o => o is SelectSumProperty selectSumProperty && selectSumProperty.FromProperty == averageSelectProperty.FromProperty); + if (selectSumProperty != null) + { + averageSelectProperty.BindSumProperty(selectSumProperty.Property); + } + + if (averageSelectProperty.CountProperty == null && averageSelectProperty.SumProperty == null) + throw new ShardingCoreInvalidOperationException( + $"use aggregate function average error,not found count aggregate function and not found sum aggregate function that property name same as average aggregate function property name:[{averageSelectProperty.FromProperty?.Name}]"); + } + } + //else + //{ + // //将查询的属性转换成order by 并且order和select的未聚合查询必须一致 + // var selectProperties = selectContext.SelectProperties.Where(o => !(o is SelectAggregateProperty)); + + // if (orders.Count() != selectProperties.Count()) + // throw new ShardingCoreInvalidOperationException("group by query order items not equal select un-aggregate items"); + // var os = orders.Select(o => o.PropertyExpression).ToList(); + // var ss = selectProperties.Select(o => o.PropertyName).ToList(); + // for (int i = 0; i < os.Count(); i++) + // { + // if (!os[i].Equals(ss[i])) + // throw new ShardingCoreInvalidOperationException($"group by query order items not equal select un-aggregate items: order:[{os[i]}],select:[{ss[i]}"); + // } + //} + } + + if (mergeQueryCompilerContext.UseUnionAllMerge() & !mergeQueryCompilerContext.GetShardingDbContext().SupportUnionAllMerge()) + { + throw new ShardingCoreException( + $"if use {nameof(EntityFrameworkShardingQueryableExtension.UseUnionAllMerge)} plz rewrite {nameof(IQuerySqlGeneratorFactory)} with {nameof(IUnionAllMergeQuerySqlGeneratorFactory)} and {nameof(IQueryCompiler)} with {nameof(IUnionAllMergeQueryCompiler)}"); + + } + + return reWriteQueryable; + } + } +} diff --git a/src/ShardingCore/Sharding/MergeContexts/RewriteResult.cs b/src/ShardingCore/Sharding/MergeContexts/RewriteResult.cs new file mode 100644 index 00000000..08b2edd7 --- /dev/null +++ b/src/ShardingCore/Sharding/MergeContexts/RewriteResult.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ShardingCore.Sharding.MergeContexts +{ + internal class RewriteResult + { + } +} diff --git a/src/ShardingCore/Sharding/MergeContexts/SelectContext.cs b/src/ShardingCore/Sharding/MergeContexts/SelectContext.cs index 4428698d..fd052f75 100644 --- a/src/ShardingCore/Sharding/MergeContexts/SelectContext.cs +++ b/src/ShardingCore/Sharding/MergeContexts/SelectContext.cs @@ -13,7 +13,7 @@ namespace ShardingCore.Core.Internal.Visitors.Selects */ public class SelectContext { - public List SelectProperties { get; set; } = new List(); + public List SelectProperties { get; } = new List(); public bool HasAverage() { diff --git a/src/ShardingCore/Sharding/MergeEngines/Abstractions/AbstractBaseMergeEngine.cs b/src/ShardingCore/Sharding/MergeEngines/Abstractions/AbstractBaseMergeEngine.cs index 62a52841..bdb251f5 100644 --- a/src/ShardingCore/Sharding/MergeEngines/Abstractions/AbstractBaseMergeEngine.cs +++ b/src/ShardingCore/Sharding/MergeEngines/Abstractions/AbstractBaseMergeEngine.cs @@ -1,5 +1,4 @@ using ShardingCore.Core; -using ShardingCore.Core.NotSupportShardingProviders.Abstractions; using ShardingCore.Extensions.InternalExtensions; using ShardingCore.Helpers; using ShardingCore.Sharding.Abstractions.ParallelExecutors; @@ -10,6 +9,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; +using ShardingCore.Core.UnionAllMergeShardingProviders.Abstractions; using ShardingCore.Extensions; namespace ShardingCore.Sharding.MergeEngines.Abstractions @@ -24,9 +24,9 @@ namespace ShardingCore.Sharding.MergeEngines.Abstractions internal abstract class AbstractBaseMergeEngine { protected abstract StreamMergeContext GetStreamMergeContext(); - protected bool IsUnSupport() + protected bool UseUnionAllMerge() { - return GetStreamMergeContext().IsNotSupportSharding(); + return GetStreamMergeContext().UseUnionAllMerge(); } /// /// 将查询分表分库结果按每个数据源进行分组 @@ -47,9 +47,9 @@ namespace ShardingCore.Sharding.MergeEngines.Abstractions { return Task.Run(async () => { - if (IsUnSupport()) + if (UseUnionAllMerge()) { - var customerDatabaseSqlSupportManager = ShardingContainer.GetService(); + var customerDatabaseSqlSupportManager = ShardingContainer.GetService(); using (customerDatabaseSqlSupportManager.CreateScope( ((UnSupportSqlRouteUnit)dataSourceSqlExecutorUnit.SqlExecutorGroups[0].Groups[0] .RouteUnit).TableRouteResults)) @@ -74,7 +74,7 @@ namespace ShardingCore.Sharding.MergeEngines.Abstractions return streamMergeContext.DataSourceRouteResult.IntersectDataSources.SelectMany( dataSourceName => { - if (IsUnSupport()) + if (UseUnionAllMerge()) { return new []{ (ISqlRouteUnit)new UnSupportSqlRouteUnit(dataSourceName, streamMergeContext.TableRouteResults) }; } @@ -112,7 +112,6 @@ namespace ShardingCore.Sharding.MergeEngines.Abstractions { var streamMergeContext = GetStreamMergeContext(); var maxQueryConnectionsLimit = streamMergeContext.GetMaxQueryConnectionsLimit(); - var sqlCount = sqlGroups.Count(); ////根据用户配置单次查询期望并发数 //int exceptCount = // Math.Max( @@ -120,7 +119,7 @@ namespace ShardingCore.Sharding.MergeEngines.Abstractions // ? sqlCount / maxQueryConnectionsLimit // : sqlCount / maxQueryConnectionsLimit + 1, 1); //计算应该使用那种链接模式 - ConnectionModeEnum connectionMode = streamMergeContext.GetConnectionMode(sqlCount); + ConnectionModeEnum connectionMode = streamMergeContext.GetConnectionMode(); //将SqlExecutorUnit进行分区,每个区maxQueryConnectionsLimit个 //[1,2,3,4,5,6,7],maxQueryConnectionsLimit=3,结果就是[[1,2,3],[4,5,6],[7]] diff --git a/src/ShardingCore/Sharding/MergeEngines/EnumeratorStreamMergeEngines/EnumeratorAsync/ReverseShardingEnumeratorAsyncStreamMergeEngine.cs b/src/ShardingCore/Sharding/MergeEngines/EnumeratorStreamMergeEngines/EnumeratorAsync/ReverseShardingEnumeratorAsyncStreamMergeEngine.cs index 5cccd916..720872f9 100644 --- a/src/ShardingCore/Sharding/MergeEngines/EnumeratorStreamMergeEngines/EnumeratorAsync/ReverseShardingEnumeratorAsyncStreamMergeEngine.cs +++ b/src/ShardingCore/Sharding/MergeEngines/EnumeratorStreamMergeEngines/EnumeratorAsync/ReverseShardingEnumeratorAsyncStreamMergeEngine.cs @@ -10,6 +10,7 @@ using ShardingCore.Sharding.MergeEngines.ParallelExecutors; using System.Linq; using System.Threading; using System.Threading.Tasks; +using ShardingCore.Extensions.InternalExtensions; using ShardingCore.Helpers; using ShardingCore.Sharding.MergeContexts; using ShardingCore.Sharding.MergeEngines.Abstractions; @@ -36,7 +37,7 @@ namespace ShardingCore.Sharding.StreamMergeEngines.EnumeratorStreamMergeEngines. public override IStreamMergeAsyncEnumerator[] GetRouteQueryStreamMergeAsyncEnumerators(bool async, CancellationToken cancellationToken = new CancellationToken()) { cancellationToken.ThrowIfCancellationRequested(); - var noPaginationNoOrderQueryable = StreamMergeContext.GetOriginalQueryable().RemoveSkip().RemoveTake().RemoveAnyOrderBy(); + var noPaginationNoOrderQueryable = StreamMergeContext.GetOriginalQueryable().RemoveSkip().RemoveTake().RemoveAnyOrderBy().As>(); var skip = StreamMergeContext.Skip.GetValueOrDefault(); var take = StreamMergeContext.Take.HasValue ? StreamMergeContext.Take.Value : (_total - skip); if (take > int.MaxValue) diff --git a/src/ShardingCore/Sharding/MergeEngines/EnumeratorStreamMergeEngines/EnumeratorStreamMergeEngineFactory.cs b/src/ShardingCore/Sharding/MergeEngines/EnumeratorStreamMergeEngines/EnumeratorStreamMergeEngineFactory.cs index 3f58cdb6..79eccad5 100644 --- a/src/ShardingCore/Sharding/MergeEngines/EnumeratorStreamMergeEngines/EnumeratorStreamMergeEngineFactory.cs +++ b/src/ShardingCore/Sharding/MergeEngines/EnumeratorStreamMergeEngines/EnumeratorStreamMergeEngineFactory.cs @@ -65,7 +65,7 @@ namespace ShardingCore.Sharding.MergeEngines.EnumeratorStreamMergeEngines return new SingleQueryEnumeratorAsyncStreamMergeEngine(_streamMergeContext); } - if (_streamMergeContext.IsNotSupportSharding()) + if (_streamMergeContext.UseUnionAllMerge()) { return new DefaultShardingEnumeratorAsyncStreamMergeEngine(_streamMergeContext); } diff --git a/src/ShardingCore/Sharding/MergeEngines/ParallelExecutors/AppendOrderSequenceEnumeratorParallelExecutor.cs b/src/ShardingCore/Sharding/MergeEngines/ParallelExecutors/AppendOrderSequenceEnumeratorParallelExecutor.cs index 555c4c1e..bff43ab9 100644 --- a/src/ShardingCore/Sharding/MergeEngines/ParallelExecutors/AppendOrderSequenceEnumeratorParallelExecutor.cs +++ b/src/ShardingCore/Sharding/MergeEngines/ParallelExecutors/AppendOrderSequenceEnumeratorParallelExecutor.cs @@ -8,6 +8,7 @@ using Microsoft.EntityFrameworkCore; using ShardingCore.Core; using ShardingCore.Core.Internal.Visitors; using ShardingCore.Extensions; +using ShardingCore.Extensions.InternalExtensions; using ShardingCore.Sharding.Enumerators; using ShardingCore.Sharding.MergeContexts; using ShardingCore.Sharding.MergeEngines.Abstractions; @@ -25,7 +26,7 @@ namespace ShardingCore.Sharding.MergeEngines.ParallelExecutors public AppendOrderSequenceEnumeratorParallelExecutor(StreamMergeContext streamMergeContext, bool async) { _streamMergeContext = streamMergeContext; - _noPaginationQueryable = streamMergeContext.GetOriginalQueryable().RemoveSkip().RemoveTake(); ; + _noPaginationQueryable = streamMergeContext.GetOriginalQueryable().RemoveSkip().RemoveTake().As>(); ; _async = async; } public override async Task>> ExecuteAsync(SqlExecutorUnit sqlExecutorUnit, CancellationToken cancellationToken = new CancellationToken()) @@ -39,8 +40,8 @@ namespace ShardingCore.Sharding.MergeEngines.ParallelExecutors private (IQueryable, DbContext) CreateAsyncExecuteQueryable(SequenceResult sequenceResult, IEnumerable reSetOrders, ConnectionModeEnum connectionMode) { var shardingDbContext = _streamMergeContext.CreateDbContext(sequenceResult.DSName, sequenceResult.TableRouteResult, connectionMode); - var newQueryable = (IQueryable)(_noPaginationQueryable.Skip(sequenceResult.Skip).Take(sequenceResult.Take).OrderWithExpression(reSetOrders)) - .ReplaceDbContextQueryable(shardingDbContext); + var newQueryable = _noPaginationQueryable.Skip(sequenceResult.Skip).Take(sequenceResult.Take).OrderWithExpression(reSetOrders) + .ReplaceDbContextQueryable(shardingDbContext).As>(); return (newQueryable, shardingDbContext); } } diff --git a/src/ShardingCore/Sharding/MergeEngines/ParallelExecutors/SequenceEnumeratorParallelExecutor.cs b/src/ShardingCore/Sharding/MergeEngines/ParallelExecutors/SequenceEnumeratorParallelExecutor.cs index fdfb06ff..4fe28446 100644 --- a/src/ShardingCore/Sharding/MergeEngines/ParallelExecutors/SequenceEnumeratorParallelExecutor.cs +++ b/src/ShardingCore/Sharding/MergeEngines/ParallelExecutors/SequenceEnumeratorParallelExecutor.cs @@ -7,6 +7,7 @@ using System.Threading.Tasks; using Microsoft.EntityFrameworkCore; using ShardingCore.Core; using ShardingCore.Extensions; +using ShardingCore.Extensions.InternalExtensions; using ShardingCore.Sharding.Abstractions.ParallelExecutors; using ShardingCore.Sharding.Enumerators; using ShardingCore.Sharding.MergeEngines.Abstractions; @@ -25,7 +26,7 @@ namespace ShardingCore.Sharding.MergeEngines.ParallelExecutors { _streamMergeContext = streamMergeContext; _async = async; - _noPaginationQueryable = streamMergeContext.GetOriginalQueryable().RemoveSkip().RemoveTake(); + _noPaginationQueryable = streamMergeContext.GetOriginalQueryable().RemoveSkip().RemoveTake().As>(); } public override async Task>> ExecuteAsync(SqlExecutorUnit sqlExecutorUnit, CancellationToken cancellationToken = new CancellationToken()) { @@ -38,8 +39,8 @@ namespace ShardingCore.Sharding.MergeEngines.ParallelExecutors private (IQueryable, DbContext) CreateAsyncExecuteQueryable( SequenceResult sequenceResult, ConnectionModeEnum connectionMode) { var shardingDbContext = _streamMergeContext.CreateDbContext(sequenceResult.DSName, sequenceResult.TableRouteResult, connectionMode); - var newQueryable = (IQueryable)(_noPaginationQueryable.Skip(sequenceResult.Skip).Take(sequenceResult.Take)) - .ReplaceDbContextQueryable(shardingDbContext); + var newQueryable = _noPaginationQueryable.Skip(sequenceResult.Skip).Take(sequenceResult.Take) + .ReplaceDbContextQueryable(shardingDbContext).As>(); return (newQueryable, shardingDbContext); } } diff --git a/src/ShardingCore/Sharding/ReWrite/ReWriteEngine.cs b/src/ShardingCore/Sharding/ReWrite/ReWriteEngine.cs index 10a21307..477648c1 100644 --- a/src/ShardingCore/Sharding/ReWrite/ReWriteEngine.cs +++ b/src/ShardingCore/Sharding/ReWrite/ReWriteEngine.cs @@ -6,6 +6,7 @@ using ShardingCore.Core.EntityMetadatas; using ShardingCore.Core.Internal.Visitors; using ShardingCore.Exceptions; using ShardingCore.Extensions; +using ShardingCore.Extensions.InternalExtensions; using ShardingCore.Sharding.MergeContexts; using ShardingCore.Sharding.Visitors.Selects; @@ -37,12 +38,12 @@ namespace ShardingCore.Core.Internal.StreamMerge.ReWrite var reWriteQueryable = _queryable; if (take.HasValue) { - reWriteQueryable = reWriteQueryable.RemoveTake(); + reWriteQueryable = reWriteQueryable.RemoveTake().As>(); } if (skip.HasValue) { - reWriteQueryable = reWriteQueryable.RemoveSkip(); + reWriteQueryable = reWriteQueryable.RemoveSkip().As>(); } if (take.HasValue) diff --git a/src/ShardingCore/Sharding/ShardingExecutors/Abstractions/IQueryCompilerContext.cs b/src/ShardingCore/Sharding/ShardingExecutors/Abstractions/IQueryCompilerContext.cs index a3973dbd..621d89e0 100644 --- a/src/ShardingCore/Sharding/ShardingExecutors/Abstractions/IQueryCompilerContext.cs +++ b/src/ShardingCore/Sharding/ShardingExecutors/Abstractions/IQueryCompilerContext.cs @@ -32,13 +32,13 @@ namespace ShardingCore.Sharding.ShardingExecutors.Abstractions /// /// bool IsQueryTrack(); - [Obsolete("plz use NotSupport() eg. dbcontext.Set().NotSupport().Where(...).ToList()")] - bool IsUnion(); - bool IsNotSupport(); + bool UseUnionAllMerge(); int? GetMaxQueryConnectionsLimit(); ConnectionModeEnum? GetConnectionMode(); bool? IsSequence(); bool? SameWithShardingComparer(); + bool IsSingleShardingEntityQuery(); + Type GetSingleShardingEntityType(); } } diff --git a/src/ShardingCore/Sharding/ShardingExecutors/MergeQueryCompilerContext.cs b/src/ShardingCore/Sharding/ShardingExecutors/MergeQueryCompilerContext.cs index 9a1e9f01..a11de029 100644 --- a/src/ShardingCore/Sharding/ShardingExecutors/MergeQueryCompilerContext.cs +++ b/src/ShardingCore/Sharding/ShardingExecutors/MergeQueryCompilerContext.cs @@ -105,14 +105,9 @@ namespace ShardingCore.Sharding.ShardingExecutors return _queryCompilerContext.IsQueryTrack(); } - public bool IsUnion() + public bool UseUnionAllMerge() { - return _queryCompilerContext.IsUnion(); - } - - public bool IsNotSupport() - { - return _queryCompilerContext.IsNotSupport(); + return _queryCompilerContext.UseUnionAllMerge(); } public int? GetMaxQueryConnectionsLimit() @@ -135,6 +130,16 @@ namespace ShardingCore.Sharding.ShardingExecutors return _queryCompilerContext.SameWithShardingComparer(); } + public bool IsSingleShardingEntityQuery() + { + return _queryCompilerContext.IsSingleShardingEntityQuery(); + } + + public Type GetSingleShardingEntityType() + { + return _queryCompilerContext.GetSingleShardingEntityType(); + } + public QueryCompilerExecutor GetQueryCompilerExecutor() { if (!hasQueryCompilerExecutor.HasValue) diff --git a/src/ShardingCore/Sharding/ShardingExecutors/QueryCompilerContext.cs b/src/ShardingCore/Sharding/ShardingExecutors/QueryCompilerContext.cs index 659d021f..657c417c 100644 --- a/src/ShardingCore/Sharding/ShardingExecutors/QueryCompilerContext.cs +++ b/src/ShardingCore/Sharding/ShardingExecutors/QueryCompilerContext.cs @@ -23,9 +23,8 @@ namespace ShardingCore.Sharding.ShardingExecutors private QueryCompilerExecutor _queryCompilerExecutor; private bool? hasQueryCompilerExecutor; private readonly bool? _isNoTracking; - private readonly bool _isUnion; private readonly bool _isParallelQuery; - private readonly bool _isNotSupport; + private readonly bool _useUnionAllMerge; private readonly int? _maxQueryConnectionsLimit; private readonly ConnectionModeEnum? _connectionMode; private readonly bool? _isSequence; @@ -39,8 +38,7 @@ namespace ShardingCore.Sharding.ShardingExecutors var compileParseResult = ShardingUtil.GetQueryCompileParseResultByExpression(_queryExpression, _shardingDbContextType); _queryEntities = compileParseResult.QueryEntities; _isNoTracking = compileParseResult.IsNoTracking; - _isUnion = compileParseResult.IsUnion; - _isNotSupport = compileParameter.IsNotSupport(); + _useUnionAllMerge = compileParameter.IsNotSupport(); _maxQueryConnectionsLimit = compileParameter.GetMaxQueryConnectionsLimit(); _connectionMode = compileParameter.GetConnectionMode(); _entityMetadataManager = ShardingContainer.GetRequiredEntityMetadataManager(_shardingDbContextType); @@ -102,14 +100,9 @@ namespace ShardingCore.Sharding.ShardingExecutors } } - public bool IsUnion() + public bool UseUnionAllMerge() { - return _isUnion; - } - - public bool IsNotSupport() - { - return _isNotSupport; + return _useUnionAllMerge; } public int? GetMaxQueryConnectionsLimit() @@ -132,6 +125,15 @@ namespace ShardingCore.Sharding.ShardingExecutors return _sameWithShardingComparer; } + public bool IsSingleShardingEntityQuery() + { + return _queryEntities.Count(o => _entityMetadataManager.IsSharding(o)) == 1; + } + + public Type GetSingleShardingEntityType() + { + return _queryEntities.Single(o => _entityMetadataManager.IsSharding(o)); + } public QueryCompilerExecutor GetQueryCompilerExecutor() { diff --git a/src/ShardingCore/Sharding/StreamMergeContext.cs b/src/ShardingCore/Sharding/StreamMergeContext.cs index abdd7b10..d423df8c 100644 --- a/src/ShardingCore/Sharding/StreamMergeContext.cs +++ b/src/ShardingCore/Sharding/StreamMergeContext.cs @@ -1,7 +1,5 @@ using Microsoft.EntityFrameworkCore; using ShardingCore.Core; -using ShardingCore.Core.Internal.StreamMerge.ReWrite; -using ShardingCore.Core.Internal.Visitors; using ShardingCore.Core.Internal.Visitors.Selects; using ShardingCore.Core.ShardingConfigurations.Abstractions; using ShardingCore.Core.TrackerManagers; @@ -10,20 +8,16 @@ using ShardingCore.Core.VirtualRoutes.TableRoutes.RouteTails.Abstractions; using ShardingCore.Core.VirtualRoutes.TableRoutes.RoutingRuleEngine; using ShardingCore.Exceptions; using ShardingCore.Extensions; +using ShardingCore.Extensions.InternalExtensions; using ShardingCore.Sharding.Abstractions; +using ShardingCore.Sharding.MergeContexts; using ShardingCore.Sharding.ShardingComparision.Abstractions; using ShardingCore.Sharding.ShardingExecutors.Abstractions; using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; -using System.Linq.Expressions; using System.Threading.Tasks; -using ShardingCore.Core.NotSupportShardingProviders; -using ShardingCore.Core.VirtualDatabase.VirtualTables; -using ShardingCore.Core.VirtualTables; -using ShardingCore.Sharding.EntityQueryConfigurations; -using ShardingCore.Sharding.MergeContexts; namespace ShardingCore.Sharding @@ -39,212 +33,66 @@ namespace ShardingCore.Sharding , IAsyncDisposable #endif { - private readonly INotSupportShardingProvider _notSupportShardingProvider; - private static readonly INotSupportShardingProvider _defaultNotSupportShardingProvider = - new DefaultNotSupportShardingProvider(); - - public IMergeQueryCompilerContext MergeQueryCompilerContext { get; } + public IParseResult ParseResult { get; } + public IQueryable RewriteQueryable { get; } + public IOptimizeResult OptimizeResult { get; } - //private readonly IShardingScopeFactory _shardingScopeFactory; - private readonly IQueryable _source; - private readonly IShardingDbContext _shardingDbContext; private readonly IRouteTailFactory _routeTailFactory; - private readonly IQueryable _reWriteSource; - //public IEnumerable RouteResults { get; } - //public DataSourceRouteResult RoutingResult { get; } public int? Skip { get; private set; } public int? Take { get; } public IEnumerable Orders { get; private set; } - public SelectContext SelectContext { get; } - public GroupByContext GroupByContext { get; } - public TableRouteResult[] TableRouteResults { get; } - public DataSourceRouteResult DataSourceRouteResult { get; } + public SelectContext SelectContext => ParseResult.GetSelectContext(); + public GroupByContext GroupByContext => ParseResult.GetGroupByContext(); + public TableRouteResult[] TableRouteResults => MergeQueryCompilerContext.GetTableRouteResults(); + public DataSourceRouteResult DataSourceRouteResult => MergeQueryCompilerContext.GetDataSourceRouteResult(); + /// /// 本次查询涉及的对象 /// - public ISet QueryEntities { get; } + public ISet QueryEntities => MergeQueryCompilerContext.GetQueryEntities(); + /// /// 本次查询跨库 /// - public bool IsCrossDataSource { get; } + public bool IsCrossDataSource => MergeQueryCompilerContext.IsCrossDataSource(); + /// /// 本次查询跨表 /// - public bool IsCrossTable { get; } + public bool IsCrossTable => MergeQueryCompilerContext.IsCrossTable(); private readonly ITrackerManager _trackerManager; private readonly IShardingEntityConfigOptions _shardingEntityConfigOptions; private readonly ConcurrentDictionary _parallelDbContexts; - private readonly bool _seqQuery = false; + public IComparer ShardingTailComparer => OptimizeResult.ShardingTailComparer(); - public IComparer ShardingTailComparer { get; } = Comparer.Default; /// /// 分表后缀比较是否重排正序 /// - public bool TailComparerNeedReverse { get; } = true; - - private int _maxParallelExecuteCount; - private ConnectionModeEnum _connectionMode; + public bool TailComparerNeedReverse => OptimizeResult.SameWithTailComparer(); - public StreamMergeContext(IMergeQueryCompilerContext mergeQueryCompilerContext, + + public StreamMergeContext(IMergeQueryCompilerContext mergeQueryCompilerContext,IParseResult parseResult,IQueryable rewriteQueryable,IOptimizeResult optimizeResult, IRouteTailFactory routeTailFactory) { MergeQueryCompilerContext = mergeQueryCompilerContext; - QueryEntities = mergeQueryCompilerContext.GetQueryEntities(); - //_shardingScopeFactory = shardingScopeFactory; - _source = (IQueryable)mergeQueryCompilerContext.GetQueryCombineResult().GetCombineQueryable(); - _shardingDbContext = mergeQueryCompilerContext.GetShardingDbContext(); + ParseResult = parseResult; + RewriteQueryable = rewriteQueryable; + OptimizeResult = optimizeResult; _routeTailFactory = routeTailFactory; - DataSourceRouteResult = mergeQueryCompilerContext.GetDataSourceRouteResult(); - TableRouteResults = mergeQueryCompilerContext.GetTableRouteResults(); - IsCrossDataSource = mergeQueryCompilerContext.IsCrossDataSource(); - IsCrossTable = mergeQueryCompilerContext.IsCrossTable(); - var reWriteResult = new ReWriteEngine(_source).ReWrite(); - Skip = reWriteResult.Skip; - Take = reWriteResult.Take; - Orders = reWriteResult.Orders ?? Enumerable.Empty(); - SelectContext = reWriteResult.SelectContext; - GroupByContext = reWriteResult.GroupByContext; - _reWriteSource = reWriteResult.ReWriteQueryable; - _trackerManager = - (ITrackerManager)ShardingContainer.GetService( - typeof(ITrackerManager<>).GetGenericType0(mergeQueryCompilerContext.GetShardingDbContextType())); - + + _trackerManager = ShardingContainer.GetTrackerManager(mergeQueryCompilerContext.GetShardingDbContextType()); _shardingEntityConfigOptions = ShardingContainer.GetRequiredShardingEntityConfigOption(mergeQueryCompilerContext.GetShardingDbContextType()); - _notSupportShardingProvider = ShardingContainer.GetService() ?? _defaultNotSupportShardingProvider; _parallelDbContexts = new ConcurrentDictionary(); - - var maxParallelExecuteCount = _shardingDbContext.GetVirtualDataSource().ConfigurationParams.MaxQueryConnectionsLimit; - var connectionMode = _shardingDbContext.GetVirtualDataSource().ConfigurationParams.ConnectionMode; - if (IsSingleShardingEntityQuery() && IsCrossTable && !IsNotSupportSharding()) - { - var singleShardingEntityType = GetSingleShardingEntityType(); - var virtualTableManager = (IVirtualTableManager)ShardingContainer.GetService(typeof(IVirtualTableManager<>).GetGenericType0(MergeQueryCompilerContext.GetShardingDbContextType())); - var virtualTable = virtualTableManager.GetVirtualTable(singleShardingEntityType); - - if (virtualTable.EnableEntityQuery) - { - ShardingTailComparer = - virtualTable.EntityQueryMetadata.DefaultTailComparer ?? Comparer.Default; - TailComparerNeedReverse = virtualTable.EntityQueryMetadata.DefaultTailComparerNeedReverse; - string methodName = MergeQueryCompilerContext.IsEnumerableQuery() ? - EntityQueryMetadata.QUERY_ENUMERATOR : - ((MethodCallExpression)MergeQueryCompilerContext.GetQueryExpression()).Method.Name; - - if (virtualTable.EntityQueryMetadata.TryGetConnectionsLimit(methodName, out var limit)) - { - maxParallelExecuteCount = Math.Min(limit, maxParallelExecuteCount); - } - - var isSequence = mergeQueryCompilerContext.IsSequence(); - var sameWithShardingComparer = mergeQueryCompilerContext.SameWithShardingComparer(); - if (isSequence.HasValue && sameWithShardingComparer.HasValue) - { - _seqQuery = isSequence.Value; - TailComparerNeedReverse = sameWithShardingComparer.Value; - } - else - { - var propertyOrders = Orders as PropertyOrder[] ?? Orders.ToArray(); - if (TryGetSequenceQuery(propertyOrders, singleShardingEntityType, virtualTable, methodName, - out var tailComparerIsAsc)) - { - _seqQuery = true; - if (!tailComparerIsAsc) - { - TailComparerNeedReverse = !TailComparerNeedReverse; - } - } - } - - } - } - - _maxParallelExecuteCount = mergeQueryCompilerContext.GetMaxQueryConnectionsLimit() ?? maxParallelExecuteCount; - _connectionMode = mergeQueryCompilerContext.GetConnectionMode() ?? connectionMode; - } - /// - /// 是否需要判断order - /// - /// - /// - /// - private bool EffectOrder(string methodName, PropertyOrder[] propertyOrders) - { - if ((methodName == null || - nameof(Queryable.First) == methodName || - nameof(Queryable.FirstOrDefault) == methodName || - nameof(Queryable.Last) == methodName || - nameof(Queryable.LastOrDefault) == methodName || - nameof(Queryable.Single) == methodName || - nameof(Queryable.SingleOrDefault) == methodName || - EntityQueryMetadata.QUERY_ENUMERATOR == methodName) && - propertyOrders.Length > 0) - return true; - return false; - } - /// - /// 尝试获取当前方法是否采用顺序查询,如果有先判断排序没有的情况下判断默认 - /// - /// - /// - /// - /// - /// - /// - private bool TryGetSequenceQuery(PropertyOrder[] propertyOrders, Type singleShardingEntityType, IVirtualTable virtualTable, string methodName, out bool tailComparerIsAsc) - { - var effectOrder = EffectOrder(methodName, propertyOrders); - - if (effectOrder) - { - var primaryOrder = propertyOrders[0]; - //不是多级order - var primaryOrderPropertyName = primaryOrder.PropertyExpression; - if (!primaryOrderPropertyName.Contains(".")) - { - if (virtualTable.EnableEntityQuery && virtualTable.EntityQueryMetadata.TryContainsComparerOrder(primaryOrderPropertyName, out var seqQueryOrderMatch) - && (primaryOrder.OwnerType == singleShardingEntityType || seqQueryOrderMatch.OrderMatch.HasFlag(SeqOrderMatchEnum.Named)))//要么必须是当前对象查询要么就是名称一样 - { - tailComparerIsAsc = seqQueryOrderMatch.IsSameAsShardingTailComparer ? primaryOrder.IsAsc : !primaryOrder.IsAsc; - //如果是获取最后一个还需要再次翻转 - if (nameof(Queryable.Last) == methodName || nameof(Queryable.LastOrDefault) == methodName) - { - tailComparerIsAsc = !tailComparerIsAsc; - } - - return true; - } - } - tailComparerIsAsc = true; - return false; - } - if (virtualTable.EnableEntityQuery && methodName != null && - virtualTable.EntityQueryMetadata.TryGetDefaultSequenceQueryTrip(methodName, out var defaultAsc)) - { - tailComparerIsAsc = defaultAsc; - return true; - } - //Max和Min - if (nameof(Queryable.Max) == methodName || nameof(Queryable.Min) == methodName) - { - //如果是max或者min - if (virtualTable.EnableEntityQuery && SelectContext.SelectProperties.Count == 1 && virtualTable.EntityQueryMetadata.TryContainsComparerOrder(SelectContext.SelectProperties[0].PropertyName, out var seqQueryOrderMatch) - && (SelectContext.SelectProperties[0].OwnerType == singleShardingEntityType || seqQueryOrderMatch.OrderMatch.HasFlag(SeqOrderMatchEnum.Named))) - { - tailComparerIsAsc = seqQueryOrderMatch.IsSameAsShardingTailComparer ? nameof(Queryable.Min) == methodName : nameof(Queryable.Max) == methodName; - return true; - } - } - - tailComparerIsAsc = true; - return false; + Orders = parseResult.GetOrderByContext().PropertyOrders.ToArray(); + Skip = parseResult.GetPaginationContext().Skip; + Take = parseResult.GetPaginationContext().Take; } public void ReSetOrders(IEnumerable orders) @@ -268,7 +116,7 @@ namespace ShardingCore.Sharding var routeTail = _routeTailFactory.Create(tableRouteResult); //如果开启了读写分离或者本次查询是跨表的表示本次查询的dbcontext是不存储的用完后就直接dispose var parallelQuery = IsParallelQuery(); - var dbContext = _shardingDbContext.GetDbContext(dataSourceName, parallelQuery, routeTail); + var dbContext = GetShardingDbContext().GetDbContext(dataSourceName, parallelQuery, routeTail); if (parallelQuery && RealConnectionMode(connectionMode) == ConnectionModeEnum.MEMORY_STRICTLY) { _parallelDbContexts.TryAdd(dbContext, null); @@ -300,11 +148,11 @@ namespace ShardingCore.Sharding public IQueryable GetReWriteQueryable() { - return _reWriteSource; + return RewriteQueryable.As>(); } public IQueryable GetOriginalQueryable() { - return _source; + return MergeQueryCompilerContext.GetQueryCombineResult().GetCombineQueryable().As>(); } public int? GetPaginationReWriteTake() @@ -349,39 +197,25 @@ namespace ShardingCore.Sharding public IShardingDbContext GetShardingDbContext() { - return _shardingDbContext; + return MergeQueryCompilerContext.GetShardingDbContext(); } public int GetMaxQueryConnectionsLimit() { - return _maxParallelExecuteCount; + return OptimizeResult.GetMaxQueryConnectionsLimit(); } - public ConnectionModeEnum GetConnectionMode(int sqlCount) + public ConnectionModeEnum GetConnectionMode() { - return CalcConnectionMode(sqlCount); + return OptimizeResult.GetConnectionMode(); } - private ConnectionModeEnum CalcConnectionMode(int sqlCount) - { - switch (_connectionMode) - { - case ConnectionModeEnum.MEMORY_STRICTLY: - case ConnectionModeEnum.CONNECTION_STRICTLY: return _connectionMode; - default: - { - return GetMaxQueryConnectionsLimit() < sqlCount - ? ConnectionModeEnum.CONNECTION_STRICTLY - : ConnectionModeEnum.MEMORY_STRICTLY; ; - } - } - } /// /// 是否启用读写分离 /// /// private bool IsUseReadWriteSeparation() { - return _shardingDbContext.IsUseReadWriteSeparation() && _shardingDbContext.CurrentIsReadWriteSeparation(); + return GetShardingDbContext().IsUseReadWriteSeparation() && GetShardingDbContext().CurrentIsReadWriteSeparation(); } /// @@ -410,7 +244,7 @@ namespace ShardingCore.Sharding public IShardingComparer GetShardingComparer() { - return _shardingDbContext.GetVirtualDataSource().ConfigurationParams.ShardingComparer; + return GetShardingDbContext().GetVirtualDataSource().ConfigurationParams.ShardingComparer; } public TResult PreperExecute(Func emptyFunc) @@ -456,20 +290,9 @@ namespace ShardingCore.Sharding return _shardingEntityConfigOptions.ThrowIfQueryRouteNotMatch; } - private bool? _isNotSupport; - public bool IsNotSupportSharding() + public bool UseUnionAllMerge() { - if (MergeQueryCompilerContext.IsNotSupport()) - return true; - if (!_isNotSupport.HasValue) - { - _isNotSupport = _notSupportShardingProvider.IsNotSupportSharding(MergeQueryCompilerContext); - if (_isNotSupport.Value) - { - _notSupportShardingProvider.CheckNotSupportSharding(MergeQueryCompilerContext); - } - } - return _isNotSupport.Value; + return MergeQueryCompilerContext.UseUnionAllMerge(); } public void Dispose() { @@ -490,18 +313,18 @@ namespace ShardingCore.Sharding #endif public bool IsSeqQuery() { - return _seqQuery; + return OptimizeResult.IsSequenceQuery(); } public bool CanTrip() { - return TableRouteResults.Length > GetMaxQueryConnectionsLimit(); + return OptimizeResult.CanTrip(); } public string GetPrintInfo() { return - $"stream merge context:[max query connections limit:{GetMaxQueryConnectionsLimit()}],[is use read write separation:{IsUseReadWriteSeparation()}],[is parallel query:{IsParallelQuery()}],[is not support sharding:{IsNotSupportSharding()}],[is sequence query:{IsSeqQuery()}],[can trip:{CanTrip()}],[is route not match:{IsRouteNotMatch()}],[throw if query route not match:{ThrowIfQueryRouteNotMatch()}],[is pagination query:{IsPaginationQuery()}],[has group query:{HasGroupQuery()}],[is merge query:{IsMergeQuery()}],[is single sharding entity query:{IsSingleShardingEntityQuery()}]"; + $"stream merge context:[max query connections limit:{GetMaxQueryConnectionsLimit()}],[is use read write separation:{IsUseReadWriteSeparation()}],[is parallel query:{IsParallelQuery()}],[is not support sharding:{UseUnionAllMerge()}],[is sequence query:{IsSeqQuery()}],[can trip:{CanTrip()}],[is route not match:{IsRouteNotMatch()}],[throw if query route not match:{ThrowIfQueryRouteNotMatch()}],[is pagination query:{IsPaginationQuery()}],[has group query:{HasGroupQuery()}],[is merge query:{IsMergeQuery()}],[is single sharding entity query:{IsSingleShardingEntityQuery()}]"; } public int? GetSkip() diff --git a/src/ShardingCore/Sharding/StreamMergeContextFactory.cs b/src/ShardingCore/Sharding/StreamMergeContextFactory.cs index 6eaa1816..8ac5ad61 100644 --- a/src/ShardingCore/Sharding/StreamMergeContextFactory.cs +++ b/src/ShardingCore/Sharding/StreamMergeContextFactory.cs @@ -5,6 +5,7 @@ using System.Linq; using Microsoft.EntityFrameworkCore; using ShardingCore.Core.VirtualRoutes.DataSourceRoutes.RouteRuleEngine; using ShardingCore.Core.VirtualRoutes.TableRoutes.RouteTails.Abstractions; +using ShardingCore.Sharding.MergeContexts; using ShardingCore.Sharding.ShardingExecutors.Abstractions; namespace ShardingCore.Sharding @@ -18,14 +19,25 @@ namespace ShardingCore.Sharding public class StreamMergeContextFactory : IStreamMergeContextFactory where TShardingDbContext:DbContext,IShardingDbContext { private readonly IRouteTailFactory _routeTailFactory; + private readonly IQueryableParseEngine _queryableParseEngine; + private readonly IQueryableRewriteEngine _queryableRewriteEngine; + private readonly IQueryableOptimizeEngine _queryableOptimizeEngine; - public StreamMergeContextFactory(IRouteTailFactory routeTailFactory) + public StreamMergeContextFactory(IRouteTailFactory routeTailFactory + , IQueryableParseEngine queryableParseEngine, IQueryableRewriteEngine queryableRewriteEngine, IQueryableOptimizeEngine queryableOptimizeEngine + ) { _routeTailFactory = routeTailFactory; + _queryableParseEngine = queryableParseEngine; + _queryableRewriteEngine = queryableRewriteEngine; + _queryableOptimizeEngine = queryableOptimizeEngine; } public StreamMergeContext Create(IMergeQueryCompilerContext mergeQueryCompilerContext) { - return new StreamMergeContext(mergeQueryCompilerContext, _routeTailFactory); + var parseResult = _queryableParseEngine.Parse(mergeQueryCompilerContext); + var rewriteQueryable = _queryableRewriteEngine.GetRewriteQueryable(mergeQueryCompilerContext, parseResult); + var optimizeResult = _queryableOptimizeEngine.Optimize(mergeQueryCompilerContext, parseResult, rewriteQueryable); + return new StreamMergeContext(mergeQueryCompilerContext, parseResult, rewriteQueryable,optimizeResult, _routeTailFactory); } } } \ No newline at end of file diff --git a/src/ShardingCore/Sharding/Visitors/ExtraEntry.cs b/src/ShardingCore/Sharding/Visitors/ExtraEntry.cs index 4c67ab6b..9f8a7b95 100644 --- a/src/ShardingCore/Sharding/Visitors/ExtraEntry.cs +++ b/src/ShardingCore/Sharding/Visitors/ExtraEntry.cs @@ -41,7 +41,7 @@ namespace ShardingCore.Core.Internal.Visitors var selectAggregateProperties = SelectContext.SelectProperties.OfType().Where(o=>!(o is SelectAverageProperty)).ToList(); foreach (var averageSelectProperty in averageSelectProperties) { - var selectCountProperty = selectAggregateProperties.FirstOrDefault(o=>o is SelectCountProperty); + var selectCountProperty = selectAggregateProperties.FirstOrDefault(o=>o is SelectCountProperty selectCountProperty); if (null != selectCountProperty) { averageSelectProperty.BindCountProperty(selectCountProperty.Property); diff --git a/src/ShardingCore/Sharding/Visitors/QuerySelectDiscoverVisitor.cs b/src/ShardingCore/Sharding/Visitors/QuerySelectDiscoverVisitor.cs index a909c8c5..ef0b5b33 100644 --- a/src/ShardingCore/Sharding/Visitors/QuerySelectDiscoverVisitor.cs +++ b/src/ShardingCore/Sharding/Visitors/QuerySelectDiscoverVisitor.cs @@ -36,21 +36,25 @@ namespace ShardingCore.Core.Internal.Visitors private PropertyInfo GetAggregateFromProperty(MethodCallExpression aggregateMethodCallExpression) { + if (aggregateMethodCallExpression.Arguments.Count > 1) + { + var selector = aggregateMethodCallExpression.Arguments[1] as LambdaExpression; + if (selector == null) + { + return null; + } + var memberExpression = selector.Body as MemberExpression; + if (memberExpression == null) + { + return null; + } + if (memberExpression.Member.DeclaringType == null) + return null; + var fromProperty = memberExpression.Member.DeclaringType.GetProperty(memberExpression.Member.Name); + return fromProperty; + } - var selector = aggregateMethodCallExpression.Arguments[1] as LambdaExpression; - if (selector == null) - { - return null; - } - var memberExpression = selector.Body as MemberExpression; - if (memberExpression == null) - { - return null; - } - if(memberExpression.Member.DeclaringType == null) - return null; - var fromProperty = memberExpression.Member.DeclaringType.GetProperty(memberExpression.Member.Name); - return fromProperty; + throw new ShardingCoreException($"cant {nameof(GetAggregateFromProperty)},{aggregateMethodCallExpression.ShardingPrint()}"); } protected override Expression VisitNew(NewExpression node) @@ -68,46 +72,46 @@ namespace ShardingCore.Core.Internal.Visitors var method = methodCallExpression.Method; if (method.Name == nameof(Queryable.Count) || method.Name == nameof(Queryable.Sum) || method.Name == nameof(Queryable.Max) || method.Name == nameof(Queryable.Min) || method.Name == nameof(Queryable.Average)) { - SelectProperty selectProperty = null; + SelectOwnerProperty selectOwnerProperty = null; if (method.Name == nameof(Queryable.Average)) { var fromProperty = GetAggregateFromProperty(methodCallExpression); - selectProperty = new SelectAverageProperty(declaringType, + selectOwnerProperty = new SelectAverageProperty(declaringType, propertyInfo, fromProperty, true, method.Name); } else if (method.Name == nameof(Queryable.Count)) { - selectProperty = new SelectCountProperty(declaringType, + selectOwnerProperty = new SelectCountProperty(declaringType, propertyInfo, true, method.Name); } else if (method.Name == nameof(Queryable.Sum)) { var fromProperty = GetAggregateFromProperty(methodCallExpression); - selectProperty = new SelectSumProperty(declaringType, + selectOwnerProperty = new SelectSumProperty(declaringType, propertyInfo, fromProperty, true, method.Name); } else if (method.Name == nameof(Queryable.Max)) { - selectProperty = new SelectMaxProperty(declaringType, + selectOwnerProperty = new SelectMaxProperty(declaringType, propertyInfo, true, method.Name); } else if (method.Name == nameof(Queryable.Min)) { - selectProperty = new SelectMinProperty(declaringType, + selectOwnerProperty = new SelectMinProperty(declaringType, propertyInfo, true, method.Name); } else { - selectProperty = new SelectAggregateProperty(declaringType, + selectOwnerProperty = new SelectAggregateProperty(declaringType, propertyInfo, true, method.Name); } - _selectContext.SelectProperties.Add(selectProperty); + _selectContext.SelectProperties.Add(selectOwnerProperty); continue; } } - _selectContext.SelectProperties.Add(new SelectProperty(declaringType, + _selectContext.SelectProperties.Add(new SelectOwnerProperty(declaringType, propertyInfo)); } return base.VisitNew(node); diff --git a/src/ShardingCore/Sharding/Visitors/QueryableExtraDiscoverVisitor.cs b/src/ShardingCore/Sharding/Visitors/QueryableExtraDiscoverVisitor.cs index 17f02f17..e2637edd 100644 --- a/src/ShardingCore/Sharding/Visitors/QueryableExtraDiscoverVisitor.cs +++ b/src/ShardingCore/Sharding/Visitors/QueryableExtraDiscoverVisitor.cs @@ -18,11 +18,10 @@ namespace ShardingCore.Core.Internal.Visitors */ internal class QueryableExtraDiscoverVisitor : ShardingExpressionVisitor { - private int? _skip; - private int? _take; - private LinkedList _orders = new LinkedList(); private GroupByContext _groupByContext = new GroupByContext(); private SelectContext _selectContext = new SelectContext(); + private PaginationContext _paginationContext = new PaginationContext(); + private OrderByContext _orderByContext = new OrderByContext(); public SelectContext GetSelectContext() @@ -35,51 +34,29 @@ namespace ShardingCore.Core.Internal.Visitors return _groupByContext; } - public int? GetSkip() + public PaginationContext GetPaginationContext() { - return _skip; + return _paginationContext; } - - public bool HasSkip() + public OrderByContext GetOrderByContext() { - return _skip.HasValue; + return _orderByContext; } - public int? GetTake() - { - return _take; - } - - public bool HasTake() - { - return _take.HasValue; - } - - public IEnumerable GetOrders() - { - return _orders; - } - - public string GetOrderExpression() - { - return string.Join(",", _orders); - } - - protected override Expression VisitMethodCall(MethodCallExpression node) { var method = node.Method; if (node.Method.Name == nameof(Queryable.Skip)) { - if (HasSkip()) + if (_paginationContext.HasSkip()) throw new ShardingCoreInvalidOperationException("more than one skip found"); - _skip = (int)GetFieldValue(node.Arguments[1]); + _paginationContext.Skip = (int)GetExpressionValue(node.Arguments[1]); } else if (node.Method.Name == nameof(Queryable.Take)) { - if (HasTake()) + if (_paginationContext.HasTake()) throw new ShardingCoreInvalidOperationException("more than one take found"); - _take = (int)GetFieldValue(node.Arguments[1]); + _paginationContext.Take = (int)GetExpressionValue(node.Arguments[1]); } else if (method.Name == nameof(Queryable.OrderBy) || method.Name == nameof(Queryable.OrderByDescending) || method.Name == nameof(Queryable.ThenBy) || method.Name == nameof(Queryable.ThenByDescending)) { @@ -94,7 +71,7 @@ namespace ShardingCore.Core.Internal.Visitors throw new NotSupportedException("sharding order only support property expression"); properties.Reverse(); var propertyExpression = string.Join(".", properties); - _orders.AddFirst(new PropertyOrder(propertyExpression, method.Name == nameof(Queryable.OrderBy) || method.Name == nameof(Queryable.ThenBy), expression.Member.DeclaringType)); + _orderByContext.PropertyOrders.AddFirst(new PropertyOrder(propertyExpression, method.Name == nameof(Queryable.OrderBy) || method.Name == nameof(Queryable.ThenBy), expression.Member.DeclaringType)); } } @@ -123,7 +100,7 @@ namespace ShardingCore.Core.Internal.Visitors var declaringType = memberExpression.Member.DeclaringType; var memberName = memberExpression.Member.Name; var propertyInfo = declaringType.GetProperty(memberName); - _selectContext.SelectProperties.Add(new SelectProperty(declaringType, propertyInfo)); + _selectContext.SelectProperties.Add(new SelectOwnerProperty(declaringType, propertyInfo)); //memberExpression.Acc } //if (expression != null) diff --git a/src/ShardingCore/Sharding/Visitors/QueryableRouteDiscoverVisitor.cs b/src/ShardingCore/Sharding/Visitors/QueryableRouteDiscoverVisitor.cs index 08651836..4b08139b 100644 --- a/src/ShardingCore/Sharding/Visitors/QueryableRouteDiscoverVisitor.cs +++ b/src/ShardingCore/Sharding/Visitors/QueryableRouteDiscoverVisitor.cs @@ -25,7 +25,7 @@ namespace ShardingCore.Core.Internal.Visitors * @Date: Monday, 28 December 2020 22:09:39 * @Email: 326308290@qq.com */ - public class QueryableRouteShardingTableDiscoverVisitor : ExpressionVisitor + public class QueryableRouteShardingTableDiscoverVisitor : ShardingExpressionVisitor { private readonly EntityMetadata _entityMetadata; @@ -131,117 +131,117 @@ namespace ShardingCore.Core.Internal.Visitors return expression is MethodCallExpression; } - private object GetShardingKeyValue(Expression expression) - { - if (expression == null) - return null; - switch (expression) - { - case ConstantExpression e: - return e.Value; + //private object GetShardingKeyValue(Expression expression) + //{ + // if (expression == null) + // return null; + // switch (expression) + // { + // case ConstantExpression e: + // return e.Value; - case MemberExpression e when e.Member is FieldInfo field: - return field.GetValue( - GetShardingKeyValue( - e.Expression - ) - ); + // case MemberExpression e when e.Member is FieldInfo field: + // return field.GetValue( + // GetShardingKeyValue( + // e.Expression + // ) + // ); - case MemberExpression e when e.Member is PropertyInfo property: - return property.GetValue( - GetShardingKeyValue( - e.Expression - ) - ); + // case MemberExpression e when e.Member is PropertyInfo property: + // return property.GetValue( + // GetShardingKeyValue( + // e.Expression + // ) + // ); - case ListInitExpression e when e.NewExpression.Arguments.Count() == 0: - { - var collection = e.NewExpression.Constructor.Invoke(new object[0]); - foreach (var i in e.Initializers) - { - i.AddMethod.Invoke( - collection, - i.Arguments - .Select( - a => GetShardingKeyValue(a) - ) - .ToArray() - ); - } - return collection; - } - case NewArrayExpression e when e.NodeType == ExpressionType.NewArrayInit && e.Expressions.Count > 0: - { - var collection = new List(e.Expressions.Count); - foreach (var arrayItemExpression in e.Expressions) - { - collection.Add(GetShardingKeyValue(arrayItemExpression)); - } - return collection; - } + // case ListInitExpression e when e.NewExpression.Arguments.Count() == 0: + // { + // var collection = e.NewExpression.Constructor.Invoke(new object[0]); + // foreach (var i in e.Initializers) + // { + // i.AddMethod.Invoke( + // collection, + // i.Arguments + // .Select( + // a => GetShardingKeyValue(a) + // ) + // .ToArray() + // ); + // } + // return collection; + // } + // case NewArrayExpression e when e.NodeType == ExpressionType.NewArrayInit && e.Expressions.Count > 0: + // { + // var collection = new List(e.Expressions.Count); + // foreach (var arrayItemExpression in e.Expressions) + // { + // collection.Add(GetShardingKeyValue(arrayItemExpression)); + // } + // return collection; + // } - case MethodCallExpression e: - return e.Method.Invoke( - GetShardingKeyValue(e.Object), - e.Arguments - .Select( - a => GetShardingKeyValue(a) - ) - .ToArray() - ); + // case MethodCallExpression e: + // return e.Method.Invoke( + // GetShardingKeyValue(e.Object), + // e.Arguments + // .Select( + // a => GetShardingKeyValue(a) + // ) + // .ToArray() + // ); - default: - //TODO: better messaging - throw new ShardingCoreException("cant get value " + expression); - } - //if (expression is ConstantExpression constantExpression) - //{ - // return constantExpression.Value; - //} - //if (expression is UnaryExpression unaryExpression) - //{ - // return Expression.Lambda(unaryExpression.Operand).Compile().DynamicInvoke(); - //} + // default: + // //TODO: better messaging + // throw new ShardingCoreException("cant get value " + expression); + // } + // //if (expression is ConstantExpression constantExpression) + // //{ + // // return constantExpression.Value; + // //} + // //if (expression is UnaryExpression unaryExpression) + // //{ + // // return Expression.Lambda(unaryExpression.Operand).Compile().DynamicInvoke(); + // //} - //if (expression is MemberExpression member1Expression) - //{ + // //if (expression is MemberExpression member1Expression) + // //{ - // if (member1Expression.Expression is ConstantExpression memberConstantExpression) - // { - // if (member1Expression.Member is FieldInfo memberFieldInfo) - // { - // object container = memberConstantExpression.Value; - // return memberFieldInfo.GetValue(container); - // } - // if (member1Expression.Member is PropertyInfo memberPropertyInfo) - // { - // object container = memberConstantExpression.Value; - // return memberPropertyInfo.GetValue(container); - // } - // else - // { - // return memberConstantExpression.Value; - // } - // } - // return Expression.Lambda(member1Expression).Compile().DynamicInvoke(); - //} + // // if (member1Expression.Expression is ConstantExpression memberConstantExpression) + // // { + // // if (member1Expression.Member is FieldInfo memberFieldInfo) + // // { + // // object container = memberConstantExpression.Value; + // // return memberFieldInfo.GetValue(container); + // // } + // // if (member1Expression.Member is PropertyInfo memberPropertyInfo) + // // { + // // object container = memberConstantExpression.Value; + // // return memberPropertyInfo.GetValue(container); + // // } + // // else + // // { + // // return memberConstantExpression.Value; + // // } + // // } + // // return Expression.Lambda(member1Expression).Compile().DynamicInvoke(); + // //} - //if (expression is MethodCallExpression methodCallExpression) - //{ - // return Expression.Lambda(methodCallExpression).Compile().DynamicInvoke(); - // //return methodCallExpression.Method.Invoke( - // // GetShardingKeyValue(methodCallExpression.Object), - // // methodCallExpression.Arguments - // // .Select( - // // a => GetShardingKeyValue(a) - // // ) - // // .ToArray() - // //); - //} + // //if (expression is MethodCallExpression methodCallExpression) + // //{ + // // return Expression.Lambda(methodCallExpression).Compile().DynamicInvoke(); + // // //return methodCallExpression.Method.Invoke( + // // // GetShardingKeyValue(methodCallExpression.Object), + // // // methodCallExpression.Arguments + // // // .Select( + // // // a => GetShardingKeyValue(a) + // // // ) + // // // .ToArray() + // // //); + // //} - //throw new ShardingCoreException("cant get value " + expression); - } + // //throw new ShardingCoreException("cant get value " + expression); + //} protected override Expression VisitMethodCall(MethodCallExpression node) { @@ -337,20 +337,20 @@ namespace ShardingCore.Core.Internal.Visitors { if (methodCallExpression.Object is MemberExpression member1Expression) { - arrayObject = GetShardingKeyValue(member1Expression); + arrayObject = GetExpressionValue(member1Expression); } else if (methodCallExpression.Object is ListInitExpression member2Expression) { - arrayObject = GetShardingKeyValue(member2Expression); + arrayObject = GetExpressionValue(member2Expression); } } else if (methodCallExpression.Arguments[0] is MemberExpression member2Expression) { - arrayObject = GetShardingKeyValue(member2Expression); + arrayObject = GetExpressionValue(member2Expression); } else if (methodCallExpression.Arguments[0] is NewArrayExpression member3Expression) { - arrayObject = GetShardingKeyValue(member3Expression); + arrayObject = GetExpressionValue(member3Expression); } if (arrayObject != null) @@ -418,11 +418,11 @@ namespace ShardingCore.Core.Internal.Visitors object shardingValue = default; if (methodCallExpression.Arguments[0] is MemberExpression member2Expression) { - shardingValue = GetShardingKeyValue(member2Expression); + shardingValue = GetExpressionValue(member2Expression); } else if (methodCallExpression.Arguments[0] is ConstantExpression constantExpression) { - shardingValue = GetShardingKeyValue(constantExpression); + shardingValue = GetExpressionValue(constantExpression); } if (shardingValue != default) @@ -477,7 +477,7 @@ namespace ShardingCore.Core.Internal.Visitors { conditionOnRight = true; shardingPropertyName = shardingPredicateResult.ShardingPropertyName; - value = GetShardingKeyValue(binaryExpression.Right); + value = GetExpressionValue(binaryExpression.Right); } else return x => true; @@ -489,7 +489,7 @@ namespace ShardingCore.Core.Internal.Visitors { conditionOnRight = false; shardingPropertyName = shardingPredicateResult.ShardingPropertyName; - value = GetShardingKeyValue(binaryExpression.Left); + value = GetExpressionValue(binaryExpression.Left); } else return x => true; diff --git a/src/ShardingCore/Sharding/Visitors/Querys/CompileParseResult.cs b/src/ShardingCore/Sharding/Visitors/Querys/CompileParseResult.cs index a0a9322f..13df5e26 100644 --- a/src/ShardingCore/Sharding/Visitors/Querys/CompileParseResult.cs +++ b/src/ShardingCore/Sharding/Visitors/Querys/CompileParseResult.cs @@ -8,18 +8,13 @@ namespace ShardingCore.Sharding.Visitors.Querys { public class CompileParseResult { - public CompileParseResult(bool isUnion, bool? isNoTracking, bool isIgnoreFilter, ISet queryEntities) + public CompileParseResult(bool? isNoTracking, bool isIgnoreFilter, ISet queryEntities) { - IsUnion = isUnion; IsNoTracking = isNoTracking; IsIgnoreFilter = isIgnoreFilter; QueryEntities = queryEntities; } /// - /// 是否使用了union查询 - /// - public bool IsUnion { get; } - /// /// 是否使用了追踪 /// public bool? IsNoTracking { get; } diff --git a/src/ShardingCore/Sharding/Visitors/Querys/QueryCompileParseVisitors.cs b/src/ShardingCore/Sharding/Visitors/Querys/QueryCompileParseVisitors.cs index f1adc7ab..4e82c700 100644 --- a/src/ShardingCore/Sharding/Visitors/Querys/QueryCompileParseVisitors.cs +++ b/src/ShardingCore/Sharding/Visitors/Querys/QueryCompileParseVisitors.cs @@ -15,7 +15,6 @@ namespace ShardingCore.Sharding.Visitors.Querys internal class QueryCompileParseVisitors : ExpressionVisitor { private readonly ITrackerManager _trackerManager; - private bool isUnion; private bool? isNoTracking; private bool isIgnoreFilter; private readonly ISet shardingEntities = new HashSet(); @@ -27,7 +26,7 @@ namespace ShardingCore.Sharding.Visitors.Querys public CompileParseResult GetCompileParseResult() { - return new CompileParseResult(isUnion, isNoTracking, isIgnoreFilter, shardingEntities); + return new CompileParseResult(isNoTracking, isIgnoreFilter, shardingEntities); } #if EFCORE2 || EFCORE3 protected override Expression VisitConstant(ConstantExpression node) @@ -54,7 +53,6 @@ namespace ShardingCore.Sharding.Visitors.Querys { switch (node.Method.Name) { - case nameof(Queryable.Union): isUnion = true; break; case nameof(EntityFrameworkQueryableExtensions.AsNoTracking): isNoTracking = true; break; case nameof(EntityFrameworkQueryableExtensions.AsTracking): isNoTracking = false; break; case nameof(EntityFrameworkQueryableExtensions.IgnoreQueryFilters): isIgnoreFilter = true; break; diff --git a/src/ShardingCore/Sharding/Visitors/Selects/SelectAggregateProperty.cs b/src/ShardingCore/Sharding/Visitors/Selects/SelectAggregateProperty.cs index 333ffe9d..255bf0a1 100644 --- a/src/ShardingCore/Sharding/Visitors/Selects/SelectAggregateProperty.cs +++ b/src/ShardingCore/Sharding/Visitors/Selects/SelectAggregateProperty.cs @@ -8,7 +8,7 @@ using ShardingCore.Core.Internal.Visitors.Selects; namespace ShardingCore.Sharding.Visitors.Selects { - public class SelectAggregateProperty : SelectProperty + public class SelectAggregateProperty : SelectOwnerProperty { public SelectAggregateProperty(Type ownerType, PropertyInfo property, bool isAggregateMethod, string aggregateMethod):base(ownerType, property) { diff --git a/src/ShardingCore/Sharding/Visitors/Selects/SelectCountProperty.cs b/src/ShardingCore/Sharding/Visitors/Selects/SelectCountProperty.cs index 5550cd7e..04e8b2cc 100644 --- a/src/ShardingCore/Sharding/Visitors/Selects/SelectCountProperty.cs +++ b/src/ShardingCore/Sharding/Visitors/Selects/SelectCountProperty.cs @@ -9,6 +9,7 @@ namespace ShardingCore.Sharding.Visitors.Selects { public class SelectCountProperty:SelectAggregateProperty { + public SelectCountProperty(Type ownerType, PropertyInfo property, bool isAggregateMethod, string aggregateMethod) : base(ownerType, property, isAggregateMethod, aggregateMethod) { } diff --git a/src/ShardingCore/Sharding/Visitors/Selects/SelectOwnerProperty.cs b/src/ShardingCore/Sharding/Visitors/Selects/SelectOwnerProperty.cs new file mode 100644 index 00000000..a7efe3f6 --- /dev/null +++ b/src/ShardingCore/Sharding/Visitors/Selects/SelectOwnerProperty.cs @@ -0,0 +1,24 @@ +using System; +using System.Reflection; +using ShardingCore.Sharding.Visitors.Selects; + +/* +* @Author: xjm +* @Description:select +* @Date: Tuesday, 02 February 2021 08:17:48 +* @Email: 326308290@qq.com +*/ +namespace ShardingCore.Core.Internal.Visitors.Selects +{ + public class SelectOwnerProperty: SelectProperty + { + public SelectOwnerProperty(Type ownerType, PropertyInfo property) : base(property) + { + OwnerType = ownerType; + Property = property; + } + public Type OwnerType { get; } + public PropertyInfo Property { get; } + public string PropertyName => Property.Name; + } +} \ No newline at end of file diff --git a/src/ShardingCore/Sharding/Visitors/Selects/SelectProperty.cs b/src/ShardingCore/Sharding/Visitors/Selects/SelectProperty.cs index f60f1969..d982e7a7 100644 --- a/src/ShardingCore/Sharding/Visitors/Selects/SelectProperty.cs +++ b/src/ShardingCore/Sharding/Visitors/Selects/SelectProperty.cs @@ -1,23 +1,19 @@ -using System; +using System; +using System.Collections.Generic; +using System.Linq; using System.Reflection; +using System.Text; +using System.Threading.Tasks; -/* -* @Author: xjm -* @Description:select -* @Date: Tuesday, 02 February 2021 08:17:48 -* @Email: 326308290@qq.com -*/ -namespace ShardingCore.Core.Internal.Visitors.Selects +namespace ShardingCore.Sharding.Visitors.Selects { public class SelectProperty { - public SelectProperty(Type ownerType, PropertyInfo property) + public SelectProperty( PropertyInfo property) { - OwnerType = ownerType; Property = property; } - public Type OwnerType { get; } public PropertyInfo Property { get; } public string PropertyName => Property.Name; } -} \ No newline at end of file +} diff --git a/src/ShardingCore/Sharding/Visitors/ShardingExpressionVisitor.cs b/src/ShardingCore/Sharding/Visitors/ShardingExpressionVisitor.cs index aec40c1f..f0cd0765 100644 --- a/src/ShardingCore/Sharding/Visitors/ShardingExpressionVisitor.cs +++ b/src/ShardingCore/Sharding/Visitors/ShardingExpressionVisitor.cs @@ -1,5 +1,8 @@ using System; +using System.Collections.Generic; +using System.Linq; using System.Linq.Expressions; +using System.Reflection; using ShardingCore.Exceptions; namespace ShardingCore.Core.Internal.Visitors @@ -10,27 +13,92 @@ namespace ShardingCore.Core.Internal.Visitors * @Date: Wednesday, 13 January 2021 11:31:01 * @Email: 326308290@qq.com */ - internal abstract class ShardingExpressionVisitor:ExpressionVisitor + public abstract class ShardingExpressionVisitor:ExpressionVisitor { - public object GetFieldValue(Expression expression) + //public object GetFieldValue(Expression expression) + //{ + // if (expression is ConstantExpression) + // return (expression as ConstantExpression).Value; + // if (expression is UnaryExpression) + // { + // UnaryExpression unary = expression as UnaryExpression; + // LambdaExpression lambda = Expression.Lambda(unary.Operand); + // Delegate fn = lambda.Compile(); + // return fn.DynamicInvoke(null); + // } + + // if (expression is MemberExpression member1Expression) + // { + // return Expression.Lambda(member1Expression).Compile().DynamicInvoke(); + // } + + // throw new ShardingCoreException("cant get value " + expression); + //} + protected object GetExpressionValue(Expression expression) { - if (expression is ConstantExpression) - return (expression as ConstantExpression).Value; - if (expression is UnaryExpression) + if (expression == null) + return null; + switch (expression) { - UnaryExpression unary = expression as UnaryExpression; - LambdaExpression lambda = Expression.Lambda(unary.Operand); - Delegate fn = lambda.Compile(); - return fn.DynamicInvoke(null); - } + case ConstantExpression e: + return e.Value; - if (expression is MemberExpression member1Expression) - { - return Expression.Lambda(member1Expression).Compile().DynamicInvoke(); - } + case MemberExpression e when e.Member is FieldInfo field: + return field.GetValue( + GetExpressionValue( + e.Expression + ) + ); - throw new ShardingCoreException("cant get value " + expression); + case MemberExpression e when e.Member is PropertyInfo property: + return property.GetValue( + GetExpressionValue( + e.Expression + ) + ); + + case ListInitExpression e when e.NewExpression.Arguments.Count() == 0: + { + var collection = e.NewExpression.Constructor.Invoke(new object[0]); + foreach (var i in e.Initializers) + { + i.AddMethod.Invoke( + collection, + i.Arguments + .Select( + a => GetExpressionValue(a) + ) + .ToArray() + ); + } + return collection; + } + case NewArrayExpression e when e.NodeType == ExpressionType.NewArrayInit && e.Expressions.Count > 0: + { + var collection = new List(e.Expressions.Count); + foreach (var arrayItemExpression in e.Expressions) + { + collection.Add(GetExpressionValue(arrayItemExpression)); + } + return collection; + } + + + case MethodCallExpression e: + return e.Method.Invoke( + GetExpressionValue(e.Object), + e.Arguments + .Select( + a => GetExpressionValue(a) + ) + .ToArray() + ); + + default: + //TODO: better messaging + throw new ShardingCoreException("cant get value " + expression); + } } } } \ No newline at end of file diff --git a/src/ShardingCore/ShardingContainer.cs b/src/ShardingCore/ShardingContainer.cs index 0d73fec8..c322ecd3 100644 --- a/src/ShardingCore/ShardingContainer.cs +++ b/src/ShardingCore/ShardingContainer.cs @@ -11,6 +11,8 @@ using System.Collections.Generic; using System.Linq; using System.Reflection; using ShardingCore.Core.EntityMetadatas; +using ShardingCore.Core.TrackerManagers; +using ShardingCore.Core.VirtualDatabase.VirtualTables; namespace ShardingCore { @@ -160,5 +162,15 @@ namespace ShardingCore { return (IEntityMetadataManager)GetRequiredEntityMetadataManager(typeof(TShardingDbContext)); } + + public static ITrackerManager GetTrackerManager(Type shardingDbContextType) + { + return (ITrackerManager)ServiceProvider.GetService(typeof(ITrackerManager<>).GetGenericType0(shardingDbContextType)); + } + + public static IVirtualTableManager GetVirtualTableManager(Type shardingDbContextType) + { + return (IVirtualTableManager)ServiceProvider.GetService(typeof(IVirtualTableManager<>).GetGenericType0(shardingDbContextType)); + } } } \ No newline at end of file diff --git a/src/ShardingCore/ShardingCore.csproj b/src/ShardingCore/ShardingCore.csproj index 666c6e8e..7b005713 100644 --- a/src/ShardingCore/ShardingCore.csproj +++ b/src/ShardingCore/ShardingCore.csproj @@ -5,7 +5,7 @@ true TRACE;DEBUG;EFCORE6; latest - https://github.com/xuejmnet/sharding-core + https://github.com/dotnetcore/sharding-core logo.png @@ -16,6 +16,11 @@ latest + + + + + True @@ -24,12 +29,11 @@ - - + + - diff --git a/src/ShardingCore/TableExists/Abstractions/AbstractTableEnsureManager.cs b/src/ShardingCore/TableExists/Abstractions/AbstractTableEnsureManager.cs index c5d9d1b0..474a3af3 100644 --- a/src/ShardingCore/TableExists/Abstractions/AbstractTableEnsureManager.cs +++ b/src/ShardingCore/TableExists/Abstractions/AbstractTableEnsureManager.cs @@ -1,14 +1,9 @@ -using System; -using System.Collections.Generic; -using System.Data.Common; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; -using ShardingCore.Core.VirtualRoutes.TableRoutes.RouteTails; using ShardingCore.Core.VirtualRoutes.TableRoutes.RouteTails.Abstractions; using ShardingCore.Sharding.Abstractions; +using System.Collections.Generic; +using System.Data.Common; namespace ShardingCore.TableExists.Abstractions { diff --git a/test/ShardingCore.Test/ShardingTest.cs b/test/ShardingCore.Test/ShardingTest.cs index f6d18284..b56b9eb1 100644 --- a/test/ShardingCore.Test/ShardingTest.cs +++ b/test/ShardingCore.Test/ShardingTest.cs @@ -64,8 +64,8 @@ namespace ShardingCore.Test IVirtualDataSourceManager virtualDataSourceManager, IVirtualTableManager virtualTableManager, IShardingTableCreator shardingTableCreator, - IShardingReadWriteManager shardingReadWriteManager,IRouteTailFactory routeTailFactory, - IReadWriteConnectorFactory readWriteConnectorFactory,ITableRouteRuleEngineFactory tableRouteRuleEngineFactory) + IShardingReadWriteManager shardingReadWriteManager, IRouteTailFactory routeTailFactory, + IReadWriteConnectorFactory readWriteConnectorFactory, ITableRouteRuleEngineFactory tableRouteRuleEngineFactory) { _virtualDbContext = virtualDbContext; _shardingRouteManager = shardingRouteManager; @@ -91,29 +91,29 @@ namespace ShardingCore.Test var xxxx = "202102"; var queryable1 = _virtualDbContext.Set().Where(o => o.DateOfMonth >= 202102); var routeParseExpression1 = ShardingUtil.GetRouteParseExpression(queryable1, virtualTableRoute.EntityMetadata, - (i, op,propertyName) => virtualTableRoute.GetRouteFilter(i, op,propertyName), true); + (i, op, propertyName) => virtualTableRoute.GetRouteFilter(i, op, propertyName), true); var queryable2 = _virtualDbContext.Set().Where(ox => ox.DateOfMonth >= 202102); var routeParseExpression2 = ShardingUtil.GetRouteParseExpression(queryable2, virtualTableRoute.EntityMetadata, - (i, op,propertyName) => virtualTableRoute.GetRouteFilter(i, op,propertyName), true); + (i, op, propertyName) => virtualTableRoute.GetRouteFilter(i, op, propertyName), true); var xxxx1 = 202102; var queryable3 = _virtualDbContext.Set().Where(ox => ox.DateOfMonth >= xxxx1); var routeParseExpression3 = ShardingUtil.GetRouteParseExpression(queryable3, virtualTableRoute.EntityMetadata, - (i, op,propertyName) => virtualTableRoute.GetRouteFilter(i, op,propertyName), true); + (i, op, propertyName) => virtualTableRoute.GetRouteFilter(i, op, propertyName), true); var queryable4 = _virtualDbContext.Set().Where(o => o.DateOfMonth >= 202101); var routeParseExpression4 = ShardingUtil.GetRouteParseExpression(queryable4, virtualTableRoute.EntityMetadata, - (i, op,propertyName) => virtualTableRoute.GetRouteFilter(i, op,propertyName), true); + (i, op, propertyName) => virtualTableRoute.GetRouteFilter(i, op, propertyName), true); var queryable5 = _virtualDbContext.Set().Where(o => o.DateOfMonth > 202101); var routeParseExpression5 = ShardingUtil.GetRouteParseExpression(queryable5, virtualTableRoute.EntityMetadata, - (i, op,propertyName) => virtualTableRoute.GetRouteFilter(i, op,propertyName), true); + (i, op, propertyName) => virtualTableRoute.GetRouteFilter(i, op, propertyName), true); var queryable6 = _virtualDbContext.Set().Where(o => o.DateOfMonth == 202101); var routeParseExpression6 = ShardingUtil.GetRouteParseExpression(queryable6, virtualTableRoute.EntityMetadata, - (i, op,propertyName) => virtualTableRoute.GetRouteFilter(i, op,propertyName), true); + (i, op, propertyName) => virtualTableRoute.GetRouteFilter(i, op, propertyName), true); var queryable7 = _virtualDbContext.Set().Where(o => 202101 <= o.DateOfMonth); var routeParseExpression7 = ShardingUtil.GetRouteParseExpression(queryable7, virtualTableRoute.EntityMetadata, - (i, op,propertyName) => virtualTableRoute.GetRouteFilter(i, op,propertyName), true); + (i, op, propertyName) => virtualTableRoute.GetRouteFilter(i, op, propertyName), true); var queryable8 = _virtualDbContext.Set().Where(o => 202101 == o.DateOfMonth); var routeParseExpression8 = ShardingUtil.GetRouteParseExpression(queryable8, virtualTableRoute.EntityMetadata, - (i, op,propertyName) => virtualTableRoute.GetRouteFilter(i, op,propertyName), true); + (i, op, propertyName) => virtualTableRoute.GetRouteFilter(i, op, propertyName), true); Assert.Equal(expressionEqualityComparer.GetHashCode(routeParseExpression1), expressionEqualityComparer.GetHashCode(routeParseExpression2)); Assert.Equal(expressionEqualityComparer.GetHashCode(routeParseExpression1), expressionEqualityComparer.GetHashCode(routeParseExpression3)); Assert.NotEqual(expressionEqualityComparer.GetHashCode(routeParseExpression1), expressionEqualityComparer.GetHashCode(routeParseExpression4)); @@ -130,14 +130,14 @@ namespace ShardingCore.Test var a = new DefaultPhysicDataSource("aaa", "aaa", true); var b = new DefaultPhysicDataSource("aaa", "aaa1", false); Assert.Equal(a, b); - var x = new EntityMetadata(typeof(LogDay), "aa", typeof(ShardingDefaultDbContext), new List(),null); - var y = new EntityMetadata(typeof(LogDay), "aa1", typeof(ShardingDefaultDbContext), new List(),null); + var x = new EntityMetadata(typeof(LogDay), "aa", typeof(ShardingDefaultDbContext), new List(), null); + var y = new EntityMetadata(typeof(LogDay), "aa1", typeof(ShardingDefaultDbContext), new List(), null); Assert.Equal(x, y); var dateTime = new DateTime(2021, 1, 1); var logDays = Enumerable.Range(0, 100).Select(o => new LogDay() { Id = Guid.NewGuid(), LogLevel = "info", LogBody = o.ToString(), LogTime = dateTime.AddDays(o) }).ToList(); var bulkShardingTableEnumerable = _virtualDbContext.BulkShardingTableEnumerable(logDays); - + Assert.Equal(100, bulkShardingTableEnumerable.Count); var bulkShardingEnumerable = _virtualDbContext.BulkShardingEnumerable(logDays); Assert.Equal(1, bulkShardingEnumerable.Count); @@ -191,7 +191,7 @@ namespace ShardingCore.Test Assert.True(bulkShardingExpression.ContainsKey("B")); var bulkShardingTableExpression = _virtualDbContext.BulkShardingTableExpression(o => o.Id == Guid.NewGuid().ToString()); - + Assert.Equal(1, bulkShardingTableExpression.Count()); var noShardingExpression = _virtualDbContext.BulkShardingExpression(o => o.Id == "123"); @@ -210,12 +210,12 @@ namespace ShardingCore.Test var emptyTailIdentity = new SingleQueryRouteTail(string.Empty).GetRouteTailIdentity(); var aTailIdentity = new SingleQueryRouteTail("a").GetRouteTailIdentity(); var bTailIdentity = new SingleQueryRouteTail("b").GetRouteTailIdentity(); - var dics=new SortedDictionary(new NoShardingFirstComparer()); - var dicTails=new List() { emptyTailIdentity, aTailIdentity, bTailIdentity }; + var dics = new SortedDictionary(new NoShardingFirstComparer()); + var dicTails = new List() { emptyTailIdentity, aTailIdentity, bTailIdentity }; for (int i = 0; i < 10; i++) { dics.Clear(); - var reOrderList=dicTails.OrderBy(o => Guid.NewGuid()).ToList(); + var reOrderList = dicTails.OrderBy(o => Guid.NewGuid()).ToList(); foreach (var tail in reOrderList) { dics.Add(tail, null); @@ -232,7 +232,7 @@ namespace ShardingCore.Test var succeedAddConnectionString = _shardingConnectionStringResolver.AddConnectionString("X", "Data Source=localhost;Initial Catalog=ShardingCoreDBC;Integrated Security=True;"); Assert.True(succeedAddConnectionString); var connectionString = _shardingConnectionStringResolver.GetConnectionString("X"); - Assert.Equal("Data Source=localhost;Initial Catalog=ShardingCoreDBC;Integrated Security=True;",connectionString); + Assert.Equal("Data Source=localhost;Initial Catalog=ShardingCoreDBC;Integrated Security=True;", connectionString); } public class SequenceClass @@ -381,16 +381,16 @@ namespace ShardingCore.Test public async Task ToList_Join_Test() { var list111 = await (from u in _virtualDbContext.Set() - join salary in _virtualDbContext.Set() - on u.Id equals salary.UserId - select new - { - u.Id, - u.Age, - Salary = salary.Salary, - DateOfMonth = salary.DateOfMonth, - Name = u.Name - }).CountAsync(); + join salary in _virtualDbContext.Set() + on u.Id equals salary.UserId + select new + { + u.Id, + u.Age, + Salary = salary.Salary, + DateOfMonth = salary.DateOfMonth, + Name = u.Name + }).CountAsync(); var list = await (from u in _virtualDbContext.Set() join salary in _virtualDbContext.Set() on u.Id equals salary.UserId @@ -422,22 +422,22 @@ namespace ShardingCore.Test Assert.DoesNotContain(list1, o => o.Name != "name_300"); var queryable1 = (from u in _virtualDbContext.Set().Where(o => o.Id == "300") - join salary in _virtualDbContext.Set().Where(o=>o.DateOfMonth==202005) - on u.Id equals salary.UserId - select new - { - Salary = salary.Salary, - DateOfMonth = salary.DateOfMonth, - Name = u.Name - }); + join salary in _virtualDbContext.Set().Where(o => o.DateOfMonth == 202005) + on u.Id equals salary.UserId + select new + { + Salary = salary.Salary, + DateOfMonth = salary.DateOfMonth, + Name = u.Name + }); var list3 = await queryable1.ToListAsync(); Assert.Equal(1, list3.Count()); Assert.Contains(list3, o => o.Name == "name_300"); - var firstOrDefaultAsync =await queryable1.OrderBy(o => o.DateOfMonth).FirstOrDefaultAsync(); + var firstOrDefaultAsync = await queryable1.OrderBy(o => o.DateOfMonth).FirstOrDefaultAsync(); Assert.NotNull(firstOrDefaultAsync); var firstOrDefault = queryable1.OrderBy(o => o.DateOfMonth).FirstOrDefault(); Assert.NotNull(firstOrDefault); - Assert.Equal(firstOrDefaultAsync,firstOrDefault); + Assert.Equal(firstOrDefaultAsync, firstOrDefault); } [Fact] @@ -489,12 +489,12 @@ namespace ShardingCore.Test [Fact] public async Task ToList_Id_Not_Eq_Test() { - var methodValue = new MethodValue(){AA = "7"}; - var mods123 = await _virtualDbContext.Set().Where(o => o.Id== methodValue.GetAa()).FirstOrDefaultAsync(); + var methodValue = new MethodValue() { AA = "7" }; + var mods123 = await _virtualDbContext.Set().Where(o => o.Id == methodValue.GetAa()).FirstOrDefaultAsync(); Assert.NotNull(mods123); - Assert.Equal(mods123.Id,"7"); - var mods12 = await _virtualDbContext.Set().Where(o => new List{"3","4"}.Contains(o.Id) ).ToListAsync(); - Assert.Contains(mods12, o => o.Id == "3"||o.Id=="4"); + Assert.Equal(mods123.Id, "7"); + var mods12 = await _virtualDbContext.Set().Where(o => new List { "3", "4" }.Contains(o.Id)).ToListAsync(); + Assert.Contains(mods12, o => o.Id == "3" || o.Id == "4"); var mods = await _virtualDbContext.Set().Where(o => o.Id != "3").ToListAsync(); Assert.Equal(999, mods.Count); Assert.DoesNotContain(mods, o => o.Id == "3"); @@ -578,8 +578,8 @@ namespace ShardingCore.Test var next = "1"; var sysUserMod1 = await _virtualDbContext.Set().Where(o => o.Id == next).FirstOrDefaultAsync(); var sysUserModabxxx = await _virtualDbContext.Set().Where(o => o.Name == "name_2").FirstOrDefaultAsync(); - var sysUserModabxxx11 = await _virtualDbContext.Set().Where(o => o.Name == "name_2"|| o.Name == "name_3").FirstOrDefaultAsync(); - var x=new Object [] { "1", "2" }; + var sysUserModabxxx11 = await _virtualDbContext.Set().Where(o => o.Name == "name_2" || o.Name == "name_3").FirstOrDefaultAsync(); + var x = new Object[] { "1", "2" }; var sysUserModab = await _virtualDbContext.Set().Where(o => o.Id.Equals("1")).FirstOrDefaultAsync(); Assert.NotNull(sysUserModab); Assert.True(sysUserModab.Id == "1"); @@ -590,9 +590,9 @@ namespace ShardingCore.Test Assert.NotNull(sysUserMod); Assert.True(sysUserMod.Id == "1"); Assert.Equal(sysUserModaa, sysUserMod); - var sysUserModxx = await _virtualDbContext.Set().Where(o =>x.Contains(o.Id)).FirstOrDefaultAsync(); + var sysUserModxx = await _virtualDbContext.Set().Where(o => x.Contains(o.Id)).FirstOrDefaultAsync(); Assert.NotNull(sysUserModxx); - Assert.True(x.Contains(sysUserModxx.Id) ); + Assert.True(x.Contains(sysUserModxx.Id)); Assert.NotNull(sysUserMod); var userMod = _virtualDbContext.Set().Find("1"); Assert.Equal(sysUserMod, userMod); @@ -736,6 +736,49 @@ namespace ShardingCore.Test Assert.Equal(1120000, group[0].MinSalary); Assert.Equal(1140000, group[0].MaxSalary); } + + [Fact] + public async Task Group_Test1() + { + var ids = new[] { "200", "300" }; + var dateOfMonths = new[] { 202111, 202110 }; + var dateTime = DateTime.Now; + + var sql = from u in _virtualDbContext.Set() + group u by u.UserId + into g + select new + { + UI = g.Key, + x=g.Sum(o=>o.SalaryDecimal), + Now = dateTime + }; + var listAsync = await sql.ToListAsync(); + var group = await (from u in _virtualDbContext.Set() + .Where(o => ids.Contains(o.UserId) && dateOfMonths.Contains(o.DateOfMonth)) + group u by new + { + UId = u.UserId + } + into g + select new + { + GroupUserId = g.Key.UId, + Count = g.Count(), + TotalSalary = g.Sum(o => o.Salary), + AvgSalary = g.Average(o => o.Salary), + AvgSalaryDecimal = g.Average(o => o.SalaryDecimal), + MinSalary = g.Min(o => o.Salary), + MaxSalary = g.Max(o => o.Salary) + }).ToListAsync(); + Assert.Equal(2, group.Count); + Assert.Equal(2, group[0].Count); + Assert.Equal(2260000, group[0].TotalSalary); + Assert.Equal(1130000, group[0].AvgSalary); + Assert.Equal(11300, group[0].AvgSalaryDecimal); + Assert.Equal(1120000, group[0].MinSalary); + Assert.Equal(1140000, group[0].MaxSalary); + } //[Fact] //public async Task Group_Recently_Test() //{ @@ -1401,29 +1444,29 @@ namespace ShardingCore.Test await tran.RollbackAsync(); } } - logNoSharding.Body = DateTime.Now.ToString("yyyyMMdd"); - _virtualDbContext.Update(logNoSharding); + logNoSharding.Body = DateTime.Now.ToString("yyyyMMdd"); + _virtualDbContext.Update(logNoSharding); - logNoShardings.ForEach(o=>o.Body = DateTime.Now.ToString("yyyyMMdd")); - _virtualDbContext.UpdateRange(logNoShardings); + logNoShardings.ForEach(o => o.Body = DateTime.Now.ToString("yyyyMMdd")); + _virtualDbContext.UpdateRange(logNoShardings); - logNoSharding1.Body = DateTime.Now.ToString("yyyyMMdd"); - _virtualDbContext.Set().Update(logNoSharding1); + logNoSharding1.Body = DateTime.Now.ToString("yyyyMMdd"); + _virtualDbContext.Set().Update(logNoSharding1); - logNoSharding1s.ForEach(o=>o.Body = DateTime.Now.ToString("yyyyMMdd")); - _virtualDbContext.Set().UpdateRange(logNoSharding1s); - await _virtualDbContext.SaveChangesAsync(); + logNoSharding1s.ForEach(o => o.Body = DateTime.Now.ToString("yyyyMMdd")); + _virtualDbContext.Set().UpdateRange(logNoSharding1s); + await _virtualDbContext.SaveChangesAsync(); - _virtualDbContext.Remove(logNoSharding); + _virtualDbContext.Remove(logNoSharding); - _virtualDbContext.RemoveRange(logNoShardings); + _virtualDbContext.RemoveRange(logNoShardings); - _virtualDbContext.Set().Remove(logNoSharding1); + _virtualDbContext.Set().Remove(logNoSharding1); - logNoSharding1s.ForEach(o => o.Body = DateTime.Now.ToString("yyyyMMdd")); - _virtualDbContext.Set().RemoveRange(logNoSharding1s); - await _virtualDbContext.SaveChangesAsync(); + logNoSharding1s.ForEach(o => o.Body = DateTime.Now.ToString("yyyyMMdd")); + _virtualDbContext.Set().RemoveRange(logNoSharding1s); + await _virtualDbContext.SaveChangesAsync(); } [Fact] public async Task CrudTest1() @@ -1457,7 +1500,7 @@ namespace ShardingCore.Test { await _virtualDbContext.AddAsync((object)logNoSharding); - await _virtualDbContext.AddRangeAsync(logNoShardings.Select(o=>(object)o).ToArray()); + await _virtualDbContext.AddRangeAsync(logNoShardings.Select(o => (object)o).ToArray()); await _virtualDbContext.SaveChangesAsync(); await tran.CommitAsync();