diff --git a/samples/Sample.SqlServer/Controllers/ValuesController.cs b/samples/Sample.SqlServer/Controllers/ValuesController.cs index fccd5c2a..81ff87fd 100644 --- a/samples/Sample.SqlServer/Controllers/ValuesController.cs +++ b/samples/Sample.SqlServer/Controllers/ValuesController.cs @@ -14,6 +14,7 @@ using System.Threading.Tasks; using ShardingCore; using ShardingCore.Core.VirtualDatabase.VirtualTables; using ShardingCore.Core.VirtualRoutes.TableRoutes.RoutingRuleEngine; +using ShardingCore.Extensions.ShardingQueryableExtensions; namespace Sample.SqlServer.Controllers { @@ -174,6 +175,19 @@ namespace Sample.SqlServer.Controllers }); } [HttpGet] + public async Task Get2a([FromQuery] int p, [FromQuery] int s) + { + Stopwatch sp = new Stopwatch(); + sp.Start(); + var shardingPageResultAsync = await _defaultTableDbContext.Set().UseConnectionMode(1).OrderBy(o => o.Age).ToShardingPageAsync(p, s); + sp.Stop(); + return Ok(new + { + sp.ElapsedMilliseconds, + shardingPageResultAsync + }); + } + [HttpGet] public IActionResult Get2([FromQuery] int p, [FromQuery] int s) { Stopwatch sp = new Stopwatch(); diff --git a/src/ShardingCore/Core/NotSupportShardingProviders/INotSupportShardingProvider.cs b/src/ShardingCore/Core/NotSupportShardingProviders/INotSupportShardingProvider.cs index ce7ea51b..16138b16 100644 --- a/src/ShardingCore/Core/NotSupportShardingProviders/INotSupportShardingProvider.cs +++ b/src/ShardingCore/Core/NotSupportShardingProviders/INotSupportShardingProvider.cs @@ -7,10 +7,8 @@ using ShardingCore.Sharding.ShardingExecutors.Abstractions; namespace ShardingCore.Core.NotSupportShardingProviders { - [Obsolete("plz use NotSupport() eg. dbcontext.Set().NotSupport().Where(...).ToList()")] public interface INotSupportShardingProvider { - [Obsolete("plz use NotSupport() eg. dbcontext.Set().NotSupport().Where(...).ToList()")] void CheckNotSupportSharding(IQueryCompilerContext queryCompilerContext); [Obsolete("plz use NotSupport() eg. dbcontext.Set().NotSupport().Where(...).ToList()")] bool IsNotSupportSharding(IQueryCompilerContext queryCompilerContext); diff --git a/src/ShardingCore/Extensions/CompileParameterExtension.cs b/src/ShardingCore/Extensions/CompileParameterExtension.cs new file mode 100644 index 00000000..62705a4d --- /dev/null +++ b/src/ShardingCore/Extensions/CompileParameterExtension.cs @@ -0,0 +1,24 @@ +using System; +using ShardingCore.Sharding.ShardingExecutors.Abstractions; + +/* +* @Author: xjm +* @Description: +* @Date: DATE TIME +* @Email: 326308290@qq.com +*/ +namespace ShardingCore.Extensions +{ + public static class CompileParameterExtension + { + /// + /// 是否存在自定义查询 + /// + /// + /// + public static bool HasCustomerQuery(this ICompileParameter compileParameter) + { + return compileParameter.ReadOnly().HasValue || compileParameter.GetAsRoute() != null; + } + } +} \ No newline at end of file diff --git a/src/ShardingCore/Extensions/ShardingQueryableExtensions/EntityFrameworkShardingQueryableExtension.cs b/src/ShardingCore/Extensions/ShardingQueryableExtensions/EntityFrameworkShardingQueryableExtension.cs index 4c388718..5cb7320b 100644 --- a/src/ShardingCore/Extensions/ShardingQueryableExtensions/EntityFrameworkShardingQueryableExtension.cs +++ b/src/ShardingCore/Extensions/ShardingQueryableExtensions/EntityFrameworkShardingQueryableExtension.cs @@ -4,27 +4,44 @@ using System.Linq.Expressions; using System.Reflection; using Microsoft.EntityFrameworkCore.Query.Internal; using ShardingCore.Core; +using ShardingCore.Core.QueryRouteManagers; -namespace ShardingCore.Extensions.ShardingQueryableExtensions -{ /* * @Author: xjm * @Description: * @Date: Sunday, 30 January 2022 00:12:37 * @Email: 326308290@qq.com */ +namespace ShardingCore.Extensions.ShardingQueryableExtensions +{ + /// + /// 分片查询额外扩展 + /// public static class EntityFrameworkShardingQueryableExtension { internal static readonly MethodInfo NotSupportMethodInfo = typeof(EntityFrameworkShardingQueryableExtension).GetTypeInfo().GetDeclaredMethods(nameof(NotSupport)).Single(); + internal static readonly MethodInfo AsRouteMethodInfo - = typeof(EntityFrameworkShardingQueryableExtension).GetTypeInfo().GetDeclaredMethods(nameof(AsRoute)).Single(); - internal static readonly MethodInfo UseConfigMethodInfo - = typeof(EntityFrameworkShardingQueryableExtension).GetTypeInfo().GetDeclaredMethods(nameof(UseConfig)).Single(); + = typeof(EntityFrameworkShardingQueryableExtension) + .GetTypeInfo() + .GetMethods(BindingFlags.Instance | BindingFlags.Static |BindingFlags.NonPublic) + .Where(m => m.Name == nameof(AsRoute)) + .Single(m => m.GetParameters().Any(p => p.ParameterType == typeof(ShardingQueryableAsRouteOptions))); + internal static readonly MethodInfo UseConnectionModeMethodInfo - = typeof(EntityFrameworkShardingQueryableExtension).GetTypeInfo().GetDeclaredMethods(nameof(UseConnectionMode)).Single(); + = typeof(EntityFrameworkShardingQueryableExtension) + .GetTypeInfo() + .GetMethods(BindingFlags.Instance | BindingFlags.Static |BindingFlags.NonPublic) + .Where(m => m.Name == nameof(UseConnectionMode)) + .Single(m => m.GetParameters().Any(p => p.ParameterType == typeof(ShardingQueryableUseConnectionModeOptions))); + internal static readonly MethodInfo ReadWriteSeparationMethodInfo - = typeof(EntityFrameworkShardingQueryableExtension).GetTypeInfo().GetDeclaredMethods(nameof(ReadWriteSeparation)).Single(); + = typeof(EntityFrameworkShardingQueryableExtension) + .GetTypeInfo() + .GetMethods() + .Where(m => m.Name == nameof(ReadWriteSeparation)) + .Single(m => m.GetParameters().Any(p => p.ParameterType == typeof(bool))); /// /// 标记当前操作是不支持分片的可以自行才用union all @@ -45,32 +62,37 @@ namespace ShardingCore.Extensions.ShardingQueryableExtensions source.Expression)) : source; } -/// -/// 开启提示路由的前提下手动指定表、手动指定数据源 -/// -/// -/// -/// -/// - public static IQueryable AsRoute(this IQueryable source,Action routeConfigure) + + /// + /// 开启提示路由的前提下手动指定表、手动指定数据源 + /// + /// + /// + /// + /// + public static IQueryable AsRoute(this IQueryable source, Action routeConfigure) { Check.NotNull(source, nameof(source)); Check.NotNull(routeConfigure, nameof(routeConfigure)); - return source; + var shardingQueryableAsRouteOptions = new ShardingQueryableAsRouteOptions(routeConfigure); + + return source.AsRoute(shardingQueryableAsRouteOptions); } - /// - /// 使用哪个配置多配置下有效 - /// - /// - /// - /// - /// - public static IQueryable UseConfig(this IQueryable source,string configId) + internal static IQueryable AsRoute(this IQueryable source, ShardingQueryableAsRouteOptions shardingQueryableAsRouteOptions) { Check.NotNull(source, nameof(source)); - Check.NotNull(configId, nameof(configId)); - return source; + + return + source.Provider is EntityQueryProvider + ? source.Provider.CreateQuery( + Expression.Call( + (Expression)null, + AsRouteMethodInfo.MakeGenericMethod(typeof(TEntity)), + source.Expression, + Expression.Constant(shardingQueryableAsRouteOptions))) + : source; } + /// /// 设置连接而模式 /// @@ -80,13 +102,30 @@ namespace ShardingCore.Extensions.ShardingQueryableExtensions /// /// /// - public static IQueryable UseConnectionMode(this IQueryable source,int maxQueryConnectionsLimit,ConnectionModeEnum connectionMode) + public static IQueryable UseConnectionMode(this IQueryable source, int maxQueryConnectionsLimit, ConnectionModeEnum connectionMode = ConnectionModeEnum.SYSTEM_AUTO) { Check.NotNull(source, nameof(source)); if (maxQueryConnectionsLimit <= 0) throw new ArgumentException($"{nameof(UseConnectionMode)} {nameof(maxQueryConnectionsLimit)} should >=1"); - return source; + var shardingQueryableUseConnectionModeOptions = new ShardingQueryableUseConnectionModeOptions(maxQueryConnectionsLimit, connectionMode); + + return UseConnectionMode(source,shardingQueryableUseConnectionModeOptions); } + internal static IQueryable UseConnectionMode(this IQueryable source, ShardingQueryableUseConnectionModeOptions shardingQueryableUseConnectionModeOptions) + { + Check.NotNull(source, nameof(source)); + + return + source.Provider is EntityQueryProvider + ? source.Provider.CreateQuery( + Expression.Call( + (Expression)null, + UseConnectionModeMethodInfo.MakeGenericMethod(typeof(TEntity)), + source.Expression, + Expression.Constant(shardingQueryableUseConnectionModeOptions))) + : source; + } + /// /// 走读库 /// @@ -97,6 +136,7 @@ namespace ShardingCore.Extensions.ShardingQueryableExtensions { return source.ReadWriteSeparation(true); } + /// /// 走写库 /// @@ -107,6 +147,7 @@ namespace ShardingCore.Extensions.ShardingQueryableExtensions { return source.ReadWriteSeparation(false); } + /// /// 自定义读写分离走什么库 /// @@ -114,10 +155,20 @@ namespace ShardingCore.Extensions.ShardingQueryableExtensions /// /// /// - public static IQueryable ReadWriteSeparation(this IQueryable source,bool routeReadConnect) + public static IQueryable ReadWriteSeparation(this IQueryable source, bool routeReadConnect) { Check.NotNull(source, nameof(source)); - return source; + var shardingQueryableReadWriteSeparationOptions = new ShardingQueryableReadWriteSeparationOptions(routeReadConnect); + + return + source.Provider is EntityQueryProvider + ? source.Provider.CreateQuery( + Expression.Call( + (Expression)null, + ReadWriteSeparationMethodInfo.MakeGenericMethod(typeof(TEntity)), + source.Expression, + Expression.Constant(shardingQueryableReadWriteSeparationOptions))) + : source; } } } \ No newline at end of file diff --git a/src/ShardingCore/Extensions/ShardingQueryableExtensions/ShardingQueryableAsRouteOptions.cs b/src/ShardingCore/Extensions/ShardingQueryableExtensions/ShardingQueryableAsRouteOptions.cs index 278b1f40..ca996753 100644 --- a/src/ShardingCore/Extensions/ShardingQueryableExtensions/ShardingQueryableAsRouteOptions.cs +++ b/src/ShardingCore/Extensions/ShardingQueryableExtensions/ShardingQueryableAsRouteOptions.cs @@ -10,13 +10,13 @@ namespace ShardingCore.Extensions.ShardingQueryableExtensions * @Date: Monday, 31 January 2022 00:15:37 * @Email: 326308290@qq.com */ - public class ShardingQueryableAsRouteOptions + internal class ShardingQueryableAsRouteOptions { - private readonly Action _routeConfigure; + public Action RouteConfigure { get; } public ShardingQueryableAsRouteOptions(Action routeConfigure) { - _routeConfigure = routeConfigure; + RouteConfigure = routeConfigure; } } } \ No newline at end of file diff --git a/src/ShardingCore/Extensions/ShardingQueryableExtensions/ShardingQueryableReadWriteSeparationOptions.cs b/src/ShardingCore/Extensions/ShardingQueryableExtensions/ShardingQueryableReadWriteSeparationOptions.cs new file mode 100644 index 00000000..370410cf --- /dev/null +++ b/src/ShardingCore/Extensions/ShardingQueryableExtensions/ShardingQueryableReadWriteSeparationOptions.cs @@ -0,0 +1,20 @@ +using System; + +namespace ShardingCore.Extensions.ShardingQueryableExtensions +{ +/* +* @Author: xjm +* @Description: +* @Date: Tuesday, 01 February 2022 16:48:17 +* @Email: 326308290@qq.com +*/ + internal class ShardingQueryableReadWriteSeparationOptions + { + public bool RouteReadConnect { get; } + + public ShardingQueryableReadWriteSeparationOptions(bool routeReadConnect) + { + RouteReadConnect = routeReadConnect; + } + } +} \ No newline at end of file diff --git a/src/ShardingCore/Extensions/ShardingQueryableExtensions/ShardingQueryableUseConnectionModeOptions.cs b/src/ShardingCore/Extensions/ShardingQueryableExtensions/ShardingQueryableUseConnectionModeOptions.cs new file mode 100644 index 00000000..115c5e2c --- /dev/null +++ b/src/ShardingCore/Extensions/ShardingQueryableExtensions/ShardingQueryableUseConnectionModeOptions.cs @@ -0,0 +1,24 @@ +using System; +using ShardingCore.Core; + +namespace ShardingCore.Extensions.ShardingQueryableExtensions +{ + +/* +* @Author: xjm +* @Description: +* @Date: Monday, 31 January 2022 22:51:56 +* @Email: 326308290@qq.com +*/ + internal class ShardingQueryableUseConnectionModeOptions + { + public ShardingQueryableUseConnectionModeOptions(int maxQueryConnectionsLimit, ConnectionModeEnum connectionMode) + { + MaxQueryConnectionsLimit = maxQueryConnectionsLimit; + ConnectionMode = connectionMode; + } + + public int MaxQueryConnectionsLimit { get; } + public ConnectionModeEnum ConnectionMode { get; } + } +} \ No newline at end of file diff --git a/src/ShardingCore/Sharding/Abstractions/IQueryCompilerContextFactory.cs b/src/ShardingCore/Sharding/Abstractions/IQueryCompilerContextFactory.cs index 7c143773..e51e8838 100644 --- a/src/ShardingCore/Sharding/Abstractions/IQueryCompilerContextFactory.cs +++ b/src/ShardingCore/Sharding/Abstractions/IQueryCompilerContextFactory.cs @@ -10,6 +10,6 @@ namespace ShardingCore.Sharding.Abstractions { public interface IQueryCompilerContextFactory { - IQueryCompilerContext Create(IShardingDbContext shardingDbContext, Expression queryExpression); + IQueryCompilerContext Create(ICompileParameter compileParameter); } } diff --git a/src/ShardingCore/Sharding/ShardingExecutors/Abstractions/ICompileParameter.cs b/src/ShardingCore/Sharding/ShardingExecutors/Abstractions/ICompileParameter.cs new file mode 100644 index 00000000..b504fc9c --- /dev/null +++ b/src/ShardingCore/Sharding/ShardingExecutors/Abstractions/ICompileParameter.cs @@ -0,0 +1,54 @@ +using System; +using System.Linq.Expressions; +using ShardingCore.Core; +using ShardingCore.Core.QueryRouteManagers; +using ShardingCore.Sharding.Abstractions; + +namespace ShardingCore.Sharding.ShardingExecutors.Abstractions +{ +/* +* @Author: xjm +* @Description: +* @Date: Tuesday, 01 February 2022 22:55:23 +* @Email: 326308290@qq.com +*/ + public interface ICompileParameter + { + /// + /// 获取当前分片上下文 + /// + /// + IShardingDbContext GetShardingDbContext(); + /// + /// 获取原始的查询表达式 + /// + /// + Expression GetNativeQueryExpression(); + /// + /// 当前查询是否是支持的查询 + /// + /// + bool IsNotSupport(); + /// + /// 当前查询的连接数限制 + /// + /// + int? GetMaxQueryConnectionsLimit(); + /// + /// 当前查询的连接模式 + /// + /// + ConnectionModeEnum? GetConnectionMode(); + /// + /// 在启用读写分离后如果设置了readonly那么就走readonly否则为null + /// + /// + bool? ReadOnly(); + + /// + /// 自定义路由 + /// + /// + Action GetAsRoute(); + } +} \ No newline at end of file diff --git a/src/ShardingCore/Sharding/ShardingExecutors/Abstractions/IQueryCompilerContext.cs b/src/ShardingCore/Sharding/ShardingExecutors/Abstractions/IQueryCompilerContext.cs index c2c869e7..905885d8 100644 --- a/src/ShardingCore/Sharding/ShardingExecutors/Abstractions/IQueryCompilerContext.cs +++ b/src/ShardingCore/Sharding/ShardingExecutors/Abstractions/IQueryCompilerContext.cs @@ -6,6 +6,7 @@ using System.Text; using System.Threading.Tasks; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Query.Internal; +using ShardingCore.Core; using ShardingCore.Core.EntityMetadatas; using ShardingCore.Sharding.Abstractions; @@ -34,5 +35,8 @@ namespace ShardingCore.Sharding.ShardingExecutors.Abstractions [Obsolete("plz use NotSupport() eg. dbcontext.Set().NotSupport().Where(...).ToList()")] bool IsUnion(); bool IsNotSupport(); + + int? GetMaxQueryConnectionsLimit(); + ConnectionModeEnum? GetConnectionMode(); } } diff --git a/src/ShardingCore/Sharding/ShardingExecutors/CompileParameter.cs b/src/ShardingCore/Sharding/ShardingExecutors/CompileParameter.cs new file mode 100644 index 00000000..dd7a2189 --- /dev/null +++ b/src/ShardingCore/Sharding/ShardingExecutors/CompileParameter.cs @@ -0,0 +1,78 @@ +using System; +using System.Linq.Expressions; +using ShardingCore.Core; +using ShardingCore.Core.QueryRouteManagers; +using ShardingCore.Extensions; +using ShardingCore.Sharding.Abstractions; +using ShardingCore.Sharding.ShardingExecutors.Abstractions; +using ShardingCore.Sharding.Visitors.ShardingExtractParameters; + +/* +* @Author: xjm +* @Description: +* @Date: DATE TIME +* @Email: 326308290@qq.com +*/ +namespace ShardingCore.ShardingExecutors +{ + public class CompileParameter:ICompileParameter + { + private readonly IShardingDbContext _shardingDbContext; + private readonly Expression _nativeQueryExpression; + private readonly bool _isNotSupport; + private readonly int? _maxQueryConnectionsLimit; + private readonly ConnectionModeEnum? _connectionMode; + private readonly bool? _readOnly; + private readonly Action _shardingRouteConfigure; + public CompileParameter(IShardingDbContext shardingDbContext,Expression shardingQueryExpression) + { + _shardingDbContext = shardingDbContext; + var shardingQueryableExtractParameter = new ShardingQueryableExtractParameterVisitor(); + _nativeQueryExpression = shardingQueryableExtractParameter.Visit(shardingQueryExpression); + var extractShardingParameter = shardingQueryableExtractParameter.ExtractShardingParameter(); + _shardingRouteConfigure = extractShardingParameter.ShardingQueryableAsRouteOptions?.RouteConfigure; + _isNotSupport = extractShardingParameter.IsNotSupport; + _maxQueryConnectionsLimit = extractShardingParameter.ShardingQueryableUseConnectionModeOptions?.MaxQueryConnectionsLimit; + _connectionMode = extractShardingParameter.ShardingQueryableUseConnectionModeOptions?.ConnectionMode; + if (shardingDbContext.IsUseReadWriteSeparation()) + { + _readOnly = extractShardingParameter?.ShardingQueryableReadWriteSeparationOptions?.RouteReadConnect??shardingDbContext.CurrentIsReadWriteSeparation(); + } + } + + public IShardingDbContext GetShardingDbContext() + { + return _shardingDbContext; + } + + public Expression GetNativeQueryExpression() + { + return _nativeQueryExpression; + } + + public bool IsNotSupport() + { + return _isNotSupport; + } + + public int? GetMaxQueryConnectionsLimit() + { + return _maxQueryConnectionsLimit; + } + + public ConnectionModeEnum? GetConnectionMode() + { + return _connectionMode; + } + + public bool? ReadOnly() + { + return _readOnly; + } + + public Action GetAsRoute() + { + return _shardingRouteConfigure; + } + } +} \ No newline at end of file diff --git a/src/ShardingCore/Sharding/ShardingExecutors/CustomerQueryScope.cs b/src/ShardingCore/Sharding/ShardingExecutors/CustomerQueryScope.cs new file mode 100644 index 00000000..4bf99786 --- /dev/null +++ b/src/ShardingCore/Sharding/ShardingExecutors/CustomerQueryScope.cs @@ -0,0 +1,51 @@ +using System; +using ShardingCore.Core.QueryRouteManagers; +using ShardingCore.Core.QueryRouteManagers.Abstractions; +using ShardingCore.Extensions; +using ShardingCore.Sharding.ReadWriteConfigurations.Abstractions; +using ShardingCore.Sharding.ShardingExecutors; +using ShardingCore.Sharding.ShardingExecutors.Abstractions; + +/* +* @Author: xjm +* @Description: +* @Date: DATE TIME +* @Email: 326308290@qq.com +*/ +namespace ShardingCore.ShardingExecutors +{ + internal class CustomerQueryScope:IDisposable + { + private readonly ShardingRouteScope _shardingRouteScope; + private readonly CustomerReadWriteScope _customerReadWriteScope; + private readonly bool _hasCustomerQuery; + public CustomerQueryScope(ICompileParameter compileParameter) + { + _hasCustomerQuery = compileParameter.HasCustomerQuery(); + if (_hasCustomerQuery) + { + var asRoute = compileParameter.GetAsRoute(); + if ( asRoute!= null) + { + var shardingRouteManager = ShardingContainer.GetService(); + _shardingRouteScope = shardingRouteManager.CreateScope(); + asRoute.Invoke(shardingRouteManager.Current); + } + + var readOnly = compileParameter.ReadOnly(); + if (readOnly.HasValue) + { + _customerReadWriteScope = new CustomerReadWriteScope(compileParameter.GetShardingDbContext(), readOnly.Value); + } + } + } + public void Dispose() + { + if (_hasCustomerQuery) + { + _shardingRouteScope?.Dispose(); + _customerReadWriteScope?.Dispose(); + } + } + } +} \ No newline at end of file diff --git a/src/ShardingCore/Sharding/ShardingExecutors/CustomerReadWriteScope.cs b/src/ShardingCore/Sharding/ShardingExecutors/CustomerReadWriteScope.cs new file mode 100644 index 00000000..2fd31730 --- /dev/null +++ b/src/ShardingCore/Sharding/ShardingExecutors/CustomerReadWriteScope.cs @@ -0,0 +1,44 @@ +using System; +using ShardingCore.Extensions; +using ShardingCore.Sharding.Abstractions; + +/* +* @Author: xjm +* @Description: +* @Date: DATE TIME +* @Email: 326308290@qq.com +*/ +namespace ShardingCore.Sharding.ShardingExecutors +{ + internal class CustomerReadWriteScope:IDisposable + { + private readonly IShardingDbContext _shardingDbContext; + private readonly bool _readOnly; + + public CustomerReadWriteScope(IShardingDbContext shardingDbContext,bool readOnly) + { + _shardingDbContext = shardingDbContext; + _readOnly = readOnly; + if (_readOnly) + { + _shardingDbContext.ReadWriteSeparationReadOnly(); + } + else + { + _shardingDbContext.ReadWriteSeparationWriteOnly(); + } + } + + public void Dispose() + { + if (_readOnly) + { + _shardingDbContext.ReadWriteSeparationWriteOnly(); + } + else + { + _shardingDbContext.ReadWriteSeparationReadOnly(); + } + } + } +} \ No newline at end of file diff --git a/src/ShardingCore/Sharding/ShardingExecutors/DefaultShardingComplierExecutor.cs b/src/ShardingCore/Sharding/ShardingExecutors/DefaultShardingComplierExecutor.cs index 8c9652c1..3bee5d2e 100644 --- a/src/ShardingCore/Sharding/ShardingExecutors/DefaultShardingComplierExecutor.cs +++ b/src/ShardingCore/Sharding/ShardingExecutors/DefaultShardingComplierExecutor.cs @@ -3,6 +3,10 @@ using System.Collections.Generic; using System.Linq.Expressions; using System.Threading; using System.Threading.Tasks; +using ShardingCore.Extensions; +using ShardingCore.Sharding.ShardingExecutors.Abstractions; +using ShardingCore.Sharding.Visitors.ShardingExtractParameters; +using ShardingCore.ShardingExecutors; namespace ShardingCore.Sharding.ShardingExecutors { @@ -18,32 +22,51 @@ namespace ShardingCore.Sharding.ShardingExecutors } public TResult Execute(IShardingDbContext shardingDbContext, Expression query) { - var queryCompilerContext = _queryCompilerContextFactory.Create(shardingDbContext, query); - return _shardingTrackQueryExecutor.Execute(queryCompilerContext); + var compileParameter = new CompileParameter(shardingDbContext,query); + var queryCompilerContext = _queryCompilerContextFactory.Create(compileParameter); + + using (new CustomerQueryScope(compileParameter)) + { + return _shardingTrackQueryExecutor.Execute(queryCompilerContext); + } } + #if !EFCORE2 public TResult ExecuteAsync(IShardingDbContext shardingDbContext, Expression query, CancellationToken cancellationToken = new CancellationToken()) { - var queryCompilerContext = _queryCompilerContextFactory.Create(shardingDbContext, query); - return _shardingTrackQueryExecutor.ExecuteAsync(queryCompilerContext); + var compileParameter = new CompileParameter(shardingDbContext,query); + var queryCompilerContext = _queryCompilerContextFactory.Create(compileParameter); + + using (new CustomerQueryScope(compileParameter)) + { + return _shardingTrackQueryExecutor.ExecuteAsync(queryCompilerContext); + } } #endif #if EFCORE2 public IAsyncEnumerable ExecuteAsync(IShardingDbContext shardingDbContext, Expression query) { - var queryCompilerContext = _queryCompilerContextFactory.Create(shardingDbContext, query); - return _shardingTrackQueryExecutor.ExecuteAsync(queryCompilerContext); + var compileParameter = new CompileParameter(shardingDbContext,query); + var queryCompilerContext = _queryCompilerContextFactory.Create(compileParameter); + using (new CustomerQueryScope(compileParameter)) + { + return _shardingTrackQueryExecutor.ExecuteAsync(queryCompilerContext); + } } public Task ExecuteAsync(IShardingDbContext shardingDbContext, Expression query, CancellationToken cancellationToken) { - var queryCompilerContext = _queryCompilerContextFactory.Create(shardingDbContext, query); - return _shardingTrackQueryExecutor.ExecuteAsync(queryCompilerContext, cancellationToken); + var compileParameter = new CompileParameter(shardingDbContext,query); + var queryCompilerContext = _queryCompilerContextFactory.Create(compileParameter); + using (new CustomerQueryScope(compileParameter)) + { + return _shardingTrackQueryExecutor.ExecuteAsync(queryCompilerContext, cancellationToken); + } } #endif } diff --git a/src/ShardingCore/Sharding/ShardingExecutors/MergeQueryCompilerContext.cs b/src/ShardingCore/Sharding/ShardingExecutors/MergeQueryCompilerContext.cs index 34d44228..613d061d 100644 --- a/src/ShardingCore/Sharding/ShardingExecutors/MergeQueryCompilerContext.cs +++ b/src/ShardingCore/Sharding/ShardingExecutors/MergeQueryCompilerContext.cs @@ -4,6 +4,7 @@ using System.Linq; using System.Linq.Expressions; using System.Text; using System.Threading.Tasks; +using ShardingCore.Core; using ShardingCore.Core.EntityMetadatas; using ShardingCore.Core.VirtualDatabase.VirtualDataSources; using ShardingCore.Core.VirtualRoutes.DataSourceRoutes.RouteRuleEngine; @@ -114,6 +115,16 @@ namespace ShardingCore.Sharding.ShardingExecutors return _queryCompilerContext.IsNotSupport(); } + public int? GetMaxQueryConnectionsLimit() + { + return _queryCompilerContext.GetMaxQueryConnectionsLimit(); + } + + public ConnectionModeEnum? GetConnectionMode() + { + return _queryCompilerContext.GetConnectionMode(); + } + public QueryCompilerExecutor GetQueryCompilerExecutor() { if (!hasQueryCompilerExecutor.HasValue) diff --git a/src/ShardingCore/Sharding/ShardingExecutors/QueryCompilerContext.cs b/src/ShardingCore/Sharding/ShardingExecutors/QueryCompilerContext.cs index 01b4933c..6d435ca4 100644 --- a/src/ShardingCore/Sharding/ShardingExecutors/QueryCompilerContext.cs +++ b/src/ShardingCore/Sharding/ShardingExecutors/QueryCompilerContext.cs @@ -1,6 +1,5 @@ using Microsoft.EntityFrameworkCore; using ShardingCore.Core.EntityMetadatas; -using ShardingCore.Core.ShardingConfigurations.Abstractions; using ShardingCore.Core.VirtualRoutes.TableRoutes.RouteTails.Abstractions; using ShardingCore.Extensions; using ShardingCore.Sharding.Abstractions; @@ -10,7 +9,7 @@ using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; -using ShardingCore.Sharding.Visitors; +using ShardingCore.Core; namespace ShardingCore.Sharding.ShardingExecutors { @@ -27,28 +26,30 @@ namespace ShardingCore.Sharding.ShardingExecutors private readonly bool _isUnion; private readonly bool _isParallelQuery; private readonly bool _isNotSupport; + private readonly int? _maxQueryConnectionsLimit; + private readonly ConnectionModeEnum? _connectionMode; - private QueryCompilerContext(IShardingDbContext shardingDbContext, Expression queryExpression) + private QueryCompilerContext(ICompileParameter compileParameter) { - var shardingQueryableExtractParameter = new ShardingQueryableExtractParameter(); - var expression = shardingQueryableExtractParameter.Visit(queryExpression); - _shardingDbContextType = shardingDbContext.GetType(); - var compileParseResult = ShardingUtil.GetQueryCompileParseResultByExpression(expression, _shardingDbContextType); + _shardingDbContext = compileParameter.GetShardingDbContext(); + _queryExpression = compileParameter.GetNativeQueryExpression(); + _shardingDbContextType = _shardingDbContext.GetType(); + var compileParseResult = ShardingUtil.GetQueryCompileParseResultByExpression(_queryExpression, _shardingDbContextType); _queryEntities = compileParseResult.QueryEntities; _isNoTracking = compileParseResult.IsNoTracking; _isUnion = compileParseResult.IsUnion; - _shardingDbContext = shardingDbContext; - _queryExpression = expression; - _isNotSupport = shardingQueryableExtractParameter.IsNotSupportQuery(); + _isNotSupport = compileParameter.IsNotSupport(); + _maxQueryConnectionsLimit = compileParameter.GetMaxQueryConnectionsLimit(); + _connectionMode = compileParameter.GetConnectionMode(); _entityMetadataManager = ShardingContainer.GetRequiredEntityMetadataManager(_shardingDbContextType); //原生对象的原生查询如果是读写分离就需要启用并行查询 - _isParallelQuery = shardingDbContext.IsUseReadWriteSeparation() && _shardingDbContext.CurrentIsReadWriteSeparation(); + _isParallelQuery = compileParameter.ReadOnly().GetValueOrDefault(); } - public static QueryCompilerContext Create(IShardingDbContext shardingDbContext, Expression queryExpression) + public static QueryCompilerContext Create(ICompileParameter compileParameter) { - return new QueryCompilerContext(shardingDbContext, queryExpression); + return new QueryCompilerContext(compileParameter); } public ISet GetQueryEntities() @@ -107,6 +108,16 @@ namespace ShardingCore.Sharding.ShardingExecutors return _isNotSupport; } + public int? GetMaxQueryConnectionsLimit() + { + return _maxQueryConnectionsLimit; + } + + public ConnectionModeEnum? GetConnectionMode() + { + return _connectionMode; + } + public QueryCompilerExecutor GetQueryCompilerExecutor() { diff --git a/src/ShardingCore/Sharding/ShardingExecutors/QueryCompilerContextFactory.cs b/src/ShardingCore/Sharding/ShardingExecutors/QueryCompilerContextFactory.cs index 0f3432e9..d8650230 100644 --- a/src/ShardingCore/Sharding/ShardingExecutors/QueryCompilerContextFactory.cs +++ b/src/ShardingCore/Sharding/ShardingExecutors/QueryCompilerContextFactory.cs @@ -16,13 +16,14 @@ using ShardingCore.Sharding.Visitors; namespace ShardingCore.Sharding.ShardingExecutors { - public class QueryCompilerContextFactory: IQueryCompilerContextFactory + public class QueryCompilerContextFactory : IQueryCompilerContextFactory { private static readonly IQueryableCombine _enumerableQueryableCombine; private static readonly IQueryableCombine _allQueryableCombine; private static readonly IQueryableCombine _constantQueryableCombine; private static readonly IQueryableCombine _selectQueryableCombine; private static readonly IQueryableCombine _whereQueryableCombine; + static QueryCompilerContextFactory() { _enumerableQueryableCombine = new EnumerableQueryableCombine(); @@ -30,21 +31,23 @@ namespace ShardingCore.Sharding.ShardingExecutors _constantQueryableCombine = new ConstantQueryableCombine(); _selectQueryableCombine = new SelectQueryableCombine(); _whereQueryableCombine = new WhereQueryableCombine(); - } - public IQueryCompilerContext Create(IShardingDbContext shardingDbContext, Expression queryExpression) + } + + public IQueryCompilerContext Create(ICompileParameter compileParameter) { var queryCompilerContext = - QueryCompilerContext.Create(shardingDbContext, queryExpression); + QueryCompilerContext.Create(compileParameter); if (queryCompilerContext.GetQueryCompilerExecutor() is not null) { return queryCompilerContext; } + var queryableCombine = GetQueryableCombine(queryCompilerContext); var dataSourceRouteRuleEngineFactory = (IDataSourceRouteRuleEngineFactory)ShardingContainer.GetService(typeof(IDataSourceRouteRuleEngineFactory<>).GetGenericType0(queryCompilerContext.GetShardingDbContextType())); var tableRouteRuleEngineFactory = (ITableRouteRuleEngineFactory)ShardingContainer.GetService(typeof(ITableRouteRuleEngineFactory<>).GetGenericType0(queryCompilerContext.GetShardingDbContextType())); var queryCombineResult = queryableCombine.Combine(queryCompilerContext); - var dataSourceRouteResult = dataSourceRouteRuleEngineFactory.Route(queryCombineResult.GetCombineQueryable(),shardingDbContext); + var dataSourceRouteResult = dataSourceRouteRuleEngineFactory.Route(queryCombineResult.GetCombineQueryable(), compileParameter.GetShardingDbContext()); var tableRouteResults = tableRouteRuleEngineFactory.Route(queryCombineResult.GetCombineQueryable()); var routeResults = tableRouteResults as TableRouteResult[] ?? tableRouteResults.ToArray(); var mergeCombineCompilerContext = MergeQueryCompilerContext.Create(queryCompilerContext, queryCombineResult, dataSourceRouteResult, @@ -66,7 +69,6 @@ namespace ShardingCore.Sharding.ShardingExecutors private IQueryableCombine GetMethodQueryableCombine(IQueryCompilerContext queryCompilerContext) { - if (queryCompilerContext.GetQueryExpression() is MethodCallExpression methodCallExpression) { switch (methodCallExpression.Method.Name) @@ -92,7 +94,8 @@ namespace ShardingCore.Sharding.ShardingExecutors return _constantQueryableCombine; } } + throw new ShardingCoreException($"query expression:[{queryCompilerContext.GetQueryExpression().ShardingPrint()}] is not terminate operate"); } } -} +} \ No newline at end of file diff --git a/src/ShardingCore/Sharding/StreamMergeContext.cs b/src/ShardingCore/Sharding/StreamMergeContext.cs index 4ed0db53..a9436068 100644 --- a/src/ShardingCore/Sharding/StreamMergeContext.cs +++ b/src/ShardingCore/Sharding/StreamMergeContext.cs @@ -89,6 +89,7 @@ namespace ShardingCore.Sharding public bool TailComparerNeedReverse { get; } = true; private int _maxParallelExecuteCount; + private ConnectionModeEnum _connectionMode; public StreamMergeContext(IMergeQueryCompilerContext mergeQueryCompilerContext, @@ -119,8 +120,8 @@ namespace ShardingCore.Sharding _notSupportShardingProvider = ShardingContainer.GetService() ?? _defaultNotSupportShardingProvider; _parallelDbContexts = new ConcurrentDictionary(); - _maxParallelExecuteCount = _shardingDbContext.GetVirtualDataSource().ConfigurationParams.MaxQueryConnectionsLimit; - + var maxParallelExecuteCount = _shardingDbContext.GetVirtualDataSource().ConfigurationParams.MaxQueryConnectionsLimit; + var connectionMode=_shardingDbContext.GetVirtualDataSource().ConfigurationParams.ConnectionMode; if (IsSingleShardingEntityQuery() && !Skip.HasValue && IsCrossTable && !IsNotSupportSharding()) { var singleShardingEntityType = GetSingleShardingEntityType(); @@ -138,7 +139,7 @@ namespace ShardingCore.Sharding methodName = ((MethodCallExpression)MergeQueryCompilerContext.GetQueryExpression()).Method.Name; if (virtualTable.EntityQueryMetadata.TryGetConnectionsLimit(methodName, out var limit)) { - _maxParallelExecuteCount = Math.Min(limit, _maxParallelExecuteCount); + maxParallelExecuteCount = Math.Min(limit, maxParallelExecuteCount); } } @@ -154,6 +155,9 @@ namespace ShardingCore.Sharding } } } + + _maxParallelExecuteCount = mergeQueryCompilerContext.GetMaxQueryConnectionsLimit() ?? maxParallelExecuteCount; + _connectionMode = mergeQueryCompilerContext.GetConnectionMode() ?? connectionMode; } /// /// 是否需要判断order @@ -343,13 +347,13 @@ namespace ShardingCore.Sharding private ConnectionModeEnum CalcConnectionMode(int sqlCount) { - switch (_shardingDbContext.GetVirtualDataSource().ConfigurationParams.ConnectionMode) + switch (_connectionMode) { case ConnectionModeEnum.MEMORY_STRICTLY: - case ConnectionModeEnum.CONNECTION_STRICTLY: return _shardingDbContext.GetVirtualDataSource().ConfigurationParams.ConnectionMode; + case ConnectionModeEnum.CONNECTION_STRICTLY: return _connectionMode; default: { - return _shardingDbContext.GetVirtualDataSource().ConfigurationParams.MaxQueryConnectionsLimit < sqlCount + return GetMaxQueryConnectionsLimit() < sqlCount ? ConnectionModeEnum.CONNECTION_STRICTLY : ConnectionModeEnum.MEMORY_STRICTLY; ; } diff --git a/src/ShardingCore/Sharding/Visitors/ShardingExtractParameters/ShardingExtParameter.cs b/src/ShardingCore/Sharding/Visitors/ShardingExtractParameters/ShardingExtParameter.cs new file mode 100644 index 00000000..3d539050 --- /dev/null +++ b/src/ShardingCore/Sharding/Visitors/ShardingExtractParameters/ShardingExtParameter.cs @@ -0,0 +1,30 @@ +using System; +using ShardingCore.Extensions.ShardingQueryableExtensions; + +/* +* @Author: xjm +* @Description: +* @Date: DATE TIME +* @Email: 326308290@qq.com +*/ +namespace ShardingCore.Sharding.Visitors.ShardingExtractParameters +{ + internal class ShardingExtParameter + { + public bool IsNotSupport { get; } + public ShardingQueryableAsRouteOptions ShardingQueryableAsRouteOptions { get; } + public ShardingQueryableUseConnectionModeOptions ShardingQueryableUseConnectionModeOptions { get; } + public ShardingQueryableReadWriteSeparationOptions ShardingQueryableReadWriteSeparationOptions { get; } + + public ShardingExtParameter(bool isNotSupport, + ShardingQueryableAsRouteOptions shardingQueryableAsRouteOptions, + ShardingQueryableUseConnectionModeOptions shardingQueryableUseConnectionModeOptions, + ShardingQueryableReadWriteSeparationOptions shardingQueryableReadWriteSeparationOptions) + { + IsNotSupport = isNotSupport; + ShardingQueryableAsRouteOptions = shardingQueryableAsRouteOptions; + ShardingQueryableUseConnectionModeOptions = shardingQueryableUseConnectionModeOptions; + ShardingQueryableReadWriteSeparationOptions = shardingQueryableReadWriteSeparationOptions; + } + } +} \ No newline at end of file diff --git a/src/ShardingCore/Sharding/Visitors/ShardingExtractParameters/ShardingQueryableExtractParameterVisitor.cs b/src/ShardingCore/Sharding/Visitors/ShardingExtractParameters/ShardingQueryableExtractParameterVisitor.cs new file mode 100644 index 00000000..e7e62d8c --- /dev/null +++ b/src/ShardingCore/Sharding/Visitors/ShardingExtractParameters/ShardingQueryableExtractParameterVisitor.cs @@ -0,0 +1,66 @@ +using System; +using System.Linq; +using System.Linq.Expressions; +using ShardingCore.Extensions.ShardingQueryableExtensions; + +namespace ShardingCore.Sharding.Visitors.ShardingExtractParameters +{ +/* +* @Author: xjm +* @Description: +* @Date: Sunday, 30 January 2022 00:48:30 +* @Email: 326308290@qq.com +*/ + internal class ShardingQueryableExtractParameterVisitor:ExpressionVisitor + { + private bool isNotSupport; + private ShardingQueryableUseConnectionModeOptions shardingQueryableUseConnectionModeOptions; + private ShardingQueryableAsRouteOptions shardingQueryableAsRouteOptions; + private ShardingQueryableReadWriteSeparationOptions shardingQueryableReadWriteSeparationOptions; + + public ShardingExtParameter ExtractShardingParameter() + { + return new ShardingExtParameter(isNotSupport, shardingQueryableAsRouteOptions, shardingQueryableUseConnectionModeOptions, shardingQueryableReadWriteSeparationOptions); + } + protected override Expression VisitMethodCall(MethodCallExpression node) + { + if (node.Method.IsGenericMethod) + { + var genericMethodDefinition = node.Method.GetGenericMethodDefinition(); + + // find cachable query extention calls + if (genericMethodDefinition == EntityFrameworkShardingQueryableExtension.NotSupportMethodInfo) + { + isNotSupport = true; + // cut out extension expression + return Visit(node.Arguments[0]); + } else if (genericMethodDefinition == EntityFrameworkShardingQueryableExtension.UseConnectionModeMethodInfo) + { + shardingQueryableUseConnectionModeOptions = node.Arguments + .OfType() + .Where(o => o.Value is ShardingQueryableUseConnectionModeOptions) + .Select(o => (ShardingQueryableUseConnectionModeOptions)o.Value) + .Last(); + return Visit(node.Arguments[0]); + }else if (genericMethodDefinition == EntityFrameworkShardingQueryableExtension.AsRouteMethodInfo) + { + shardingQueryableAsRouteOptions = node.Arguments + .OfType() + .Where(o => o.Value is ShardingQueryableAsRouteOptions) + .Select(o => (ShardingQueryableAsRouteOptions)o.Value) + .Last(); + return Visit(node.Arguments[0]); + }else if (genericMethodDefinition == EntityFrameworkShardingQueryableExtension.ReadWriteSeparationMethodInfo) + { + shardingQueryableReadWriteSeparationOptions = node.Arguments + .OfType() + .Where(o => o.Value is ShardingQueryableReadWriteSeparationOptions) + .Select(o => (ShardingQueryableReadWriteSeparationOptions)o.Value) + .Last(); + return Visit(node.Arguments[0]); + } + } + return base.VisitMethodCall(node); + } + } +} \ No newline at end of file diff --git a/src/ShardingCore/Sharding/Visitors/ShardingQueryableExtractParameter.cs b/src/ShardingCore/Sharding/Visitors/ShardingQueryableExtractParameter.cs deleted file mode 100644 index c3c0a559..00000000 --- a/src/ShardingCore/Sharding/Visitors/ShardingQueryableExtractParameter.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System; -using System.Linq.Expressions; -using ShardingCore.Extensions.ShardingQueryableExtensions; - -namespace ShardingCore.Sharding.Visitors -{ -/* -* @Author: xjm -* @Description: -* @Date: Sunday, 30 January 2022 00:48:30 -* @Email: 326308290@qq.com -*/ - public class ShardingQueryableExtractParameter:ExpressionVisitor - { - private bool isNotSupport; - public bool IsNotSupportQuery() - { - return isNotSupport; - } - protected override Expression VisitMethodCall(MethodCallExpression node) - { - if (node.Method.IsGenericMethod) - { - var genericMethodDefinition = node.Method.GetGenericMethodDefinition(); - - // find cachable query extention calls - if (genericMethodDefinition == EntityFrameworkShardingQueryableExtension.NotSupportMethodInfo) - { - isNotSupport = true; - // cut out extension expression - return Visit(node.Arguments[0]); - } - } - return base.VisitMethodCall(node); - } - } -} \ No newline at end of file diff --git a/src2x/ShardingCore.2x/ShardingCore.2x.csproj b/src2x/ShardingCore.2x/ShardingCore.2x.csproj index e751b7e1..f8045c98 100644 --- a/src2x/ShardingCore.2x/ShardingCore.2x.csproj +++ b/src2x/ShardingCore.2x/ShardingCore.2x.csproj @@ -28,6 +28,9 @@ + + Sharding\ShardingExecutors\Abstractions\ICompileParameter.cs + diff --git a/src3x/ShardingCore.3x/ShardingCore.3x.csproj b/src3x/ShardingCore.3x/ShardingCore.3x.csproj index 9b8dd757..e3eceef3 100644 --- a/src3x/ShardingCore.3x/ShardingCore.3x.csproj +++ b/src3x/ShardingCore.3x/ShardingCore.3x.csproj @@ -28,6 +28,12 @@ + + Sharding\ShardingExecutors\CompileParameter.cs + + + Sharding\ShardingExecutors\CustomerQueryScope.cs +