[#143],[#141]bug修复,发布x.4.2.14

This commit is contained in:
xuejiaming 2022-05-02 09:07:06 +08:00
parent 6d68bcf1db
commit 134cbcc7fd
40 changed files with 967 additions and 380 deletions

View File

@ -1,9 +1,9 @@
:start
::定义版本
set EFCORE2=2.4.2.13
set EFCORE3=3.4.2.13
set EFCORE5=5.4.2.13
set EFCORE6=6.4.2.13
set EFCORE2=2.4.2.14
set EFCORE3=3.4.2.14
set EFCORE5=5.4.2.14
set EFCORE6=6.4.2.14
::删除所有bin与obj下的文件
@echo off

View File

@ -1,4 +1,5 @@
using System;
using System.Diagnostics;
using System.Linq;
using System.Security.Cryptography.X509Certificates;
using System.Threading.Tasks;
@ -23,6 +24,20 @@ namespace Sample.SqlServerShardingTable.Controllers
_myDbContext = myDbContext;
_virtualDataSourceManager = virtualDataSourceManager;
}
public async Task<IActionResult> Testa()
{
Stopwatch sp=Stopwatch.StartNew();
var listAsync = await _myDbContext.Set<SysUser>().AsTracking().ToListAsync();
sp.Stop();
return Ok(sp.ElapsedMilliseconds);
}
public async Task<IActionResult> Testb()
{
Stopwatch sp = Stopwatch.StartNew();
var listAsync = await _myDbContext.Set<SysUser>().AsNoTracking().ToListAsync();
sp.Stop();
return Ok(sp.ElapsedMilliseconds);
}
public async Task<IActionResult> Query()
{
Console.WriteLine("123123");

View File

@ -5,11 +5,11 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="3.1.24" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="6.0.4" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src3x\ShardingCore.3x\ShardingCore.3x.csproj" />
<ProjectReference Include="..\..\src\ShardingCore\ShardingCore.csproj" />
</ItemGroup>
</Project>

View File

@ -12,7 +12,7 @@ namespace ShardingCore.Core.VirtualRoutes.DataSourceRoutes.RouteRuleEngine
* @Ver: 1.0
* @Email: 326308290@qq.com
*/
public class DataSourceRouteResult:IPrint
public class DataSourceRouteResult
{
public DataSourceRouteResult(ISet<string> intersectDataSources)
{
@ -23,7 +23,7 @@ namespace ShardingCore.Core.VirtualRoutes.DataSourceRoutes.RouteRuleEngine
/// </summary>
public ISet<string> IntersectDataSources { get; }
public string GetPrintInfo()
public override string ToString()
{
return $"data source route result:{string.Join(",", IntersectDataSources)}";
}

View File

@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using ShardingCore.Core.VirtualDatabase.VirtualDataSources;
using ShardingCore.Extensions;
@ -21,14 +22,14 @@ namespace ShardingCore.Core.VirtualRoutes.DataSourceRoutes.RouteRuleEngine
/// <typeparam name="T"></typeparam>
public class DataSourceRouteRuleContext
{
public DataSourceRouteRuleContext(IQueryable queryable,IShardingDbContext shardingDbContext)
public DataSourceRouteRuleContext(IQueryable queryable,IShardingDbContext shardingDbContext, Dictionary<Type, IQueryable> queryEntities)
{
Queryable = queryable;
ShardingDbContext = shardingDbContext;
VirtualDataSource = shardingDbContext.GetVirtualDataSource();
QueryEntities = queryable.ParseQueryableEntities(shardingDbContext.GetType());
QueryEntities = queryEntities;
}
public ISet<Type> QueryEntities { get; }
public Dictionary<Type, IQueryable> QueryEntities { get; }
/// <summary>
/// 查询条件
/// </summary>

View File

@ -31,21 +31,16 @@ namespace ShardingCore.Core.VirtualRoutes.DataSourceRoutes.RouteRuleEngine
{
var virtualDataSource = routeRuleContext.VirtualDataSource;
var dataSourceMaps = new Dictionary<Type, ISet<string>>();
var notShardingDataSourceEntityType = routeRuleContext.QueryEntities.FirstOrDefault(o => !_entityMetadataManager.IsShardingDataSource(o));
//存在不分库的
if (notShardingDataSourceEntityType != null)
dataSourceMaps.Add(notShardingDataSourceEntityType, new HashSet<string>() { virtualDataSource.DefaultDataSourceName });
//if (queryEntities.Count > 1)
// throw new ShardingCoreNotSupportedException($"{routeRuleContext.Queryable.ShardingPrint()}");
foreach (var queryEntity in routeRuleContext.QueryEntities)
foreach (var queryEntityKv in routeRuleContext.QueryEntities)
{
var queryEntity = queryEntityKv.Key;
if (!_entityMetadataManager.IsShardingDataSource(queryEntity))
{
dataSourceMaps.Add(queryEntity, new HashSet<string>() { virtualDataSource.DefaultDataSourceName });
continue;
}
var dataSourceConfigs = virtualDataSource.RouteTo(queryEntity,new ShardingDataSourceRouteConfig(routeRuleContext.Queryable));
var dataSourceConfigs = virtualDataSource.RouteTo(queryEntity, new ShardingDataSourceRouteConfig(queryEntityKv.Value??routeRuleContext.Queryable));
if (!dataSourceMaps.ContainsKey(queryEntity))
{
dataSourceMaps.Add(queryEntity, dataSourceConfigs.ToHashSet());

View File

@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using Microsoft.EntityFrameworkCore;
using ShardingCore.Sharding.Abstractions;
@ -31,13 +32,13 @@ namespace ShardingCore.Core.VirtualRoutes.DataSourceRoutes.RouteRuleEngine
/// <summary>
/// 通过表达式创建分库路由上下文
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="queryable"></param>
/// <param name="shardingDbContext"></param>
/// <param name="queryEntities"></param>
/// <returns></returns>
public DataSourceRouteRuleContext CreateContext(IQueryable queryable,IShardingDbContext shardingDbContext)
private DataSourceRouteRuleContext CreateContext(IQueryable queryable,IShardingDbContext shardingDbContext,Dictionary<Type,IQueryable> queryEntities)
{
return new DataSourceRouteRuleContext(queryable, shardingDbContext);
return new DataSourceRouteRuleContext(queryable, shardingDbContext, queryEntities);
}
/// <summary>
/// 路由到具体的物理数据源
@ -45,21 +46,22 @@ namespace ShardingCore.Core.VirtualRoutes.DataSourceRoutes.RouteRuleEngine
/// <typeparam name="T"></typeparam>
/// <param name="queryable"></param>
/// <param name="shardingDbContext"></param>
/// <param name="queryEntities"></param>
/// <returns></returns>
public DataSourceRouteResult Route(IQueryable queryable, IShardingDbContext shardingDbContext)
{
var ruleContext = CreateContext(queryable, shardingDbContext);
return _dataSourceRouteRuleEngine.Route(ruleContext);
}
/// <summary>
/// 路由到具体的物理数据源
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="ruleContext"></param>
/// <returns></returns>
public DataSourceRouteResult Route(DataSourceRouteRuleContext ruleContext)
public DataSourceRouteResult Route(IQueryable queryable, IShardingDbContext shardingDbContext, Dictionary<Type, IQueryable> queryEntities)
{
var ruleContext = CreateContext(queryable, shardingDbContext,queryEntities);
return _dataSourceRouteRuleEngine.Route(ruleContext);
}
///// <summary>
///// 路由到具体的物理数据源
///// </summary>
///// <typeparam name="T"></typeparam>
///// <param name="ruleContext"></param>
///// <returns></returns>
//public DataSourceRouteResult Route(DataSourceRouteRuleContext ruleContext)
//{
// return _dataSourceRouteRuleEngine.Route(ruleContext);
//}
}
}

View File

@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using Microsoft.EntityFrameworkCore;
using ShardingCore.Sharding.Abstractions;
@ -16,9 +17,8 @@ namespace ShardingCore.Core.VirtualRoutes.DataSourceRoutes.RouteRuleEngine
*/
public interface IDataSourceRouteRuleEngineFactory
{
DataSourceRouteRuleContext CreateContext(IQueryable queryable, IShardingDbContext shardingDbContext);
DataSourceRouteResult Route(IQueryable queryable, IShardingDbContext shardingDbContext);
DataSourceRouteResult Route(DataSourceRouteRuleContext ruleContext);
DataSourceRouteResult Route(IQueryable queryable, IShardingDbContext shardingDbContext, Dictionary<Type, IQueryable> queryEntities);
//DataSourceRouteResult Route(DataSourceRouteRuleContext ruleContext);
}
public interface IDataSourceRouteRuleEngineFactory<TShardingDbContext> : IDataSourceRouteRuleEngineFactory
where TShardingDbContext : DbContext, IShardingDbContext

View File

@ -14,9 +14,9 @@ namespace ShardingCore.Core.VirtualRoutes.TableRoutes.RoutingRuleEngine
*/
public interface ITableRouteRuleEngineFactory
{
TableRouteRuleContext CreateContext(IQueryable queryable);
IEnumerable<TableRouteResult> Route(IQueryable queryable);
IEnumerable<TableRouteResult> Route(TableRouteRuleContext ruleContext);
//TableRouteRuleContext CreateContext(IQueryable queryable);
IEnumerable<TableRouteResult> Route(IQueryable queryable,Dictionary<Type,IQueryable> queryEntities);
//IEnumerable<TableRouteResult> Route(TableRouteRuleContext ruleContext);
}
public interface ITableRouteRuleEngineFactory<TShardingDbContext> : ITableRouteRuleEngineFactory
where TShardingDbContext : DbContext, IShardingDbContext

View File

@ -1,3 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using ShardingCore.Core.VirtualDatabase.VirtualTables;
using ShardingCore.Core.VirtualTables;
@ -13,12 +15,13 @@ namespace ShardingCore.Core.VirtualRoutes.TableRoutes.RoutingRuleEngine
public class TableRouteRuleContext
{
public TableRouteRuleContext(IQueryable queryable)
public TableRouteRuleContext(IQueryable queryable, Dictionary<Type, IQueryable> queryEntities)
{
Queryable = queryable;
QueryEntities = queryEntities;
}
public IQueryable Queryable { get; }
public Dictionary<Type, IQueryable> QueryEntities { get; }
}
}

View File

@ -33,16 +33,17 @@ namespace ShardingCore.Core.VirtualRoutes.TableRoutes.RoutingRuleEngine
public IEnumerable<TableRouteResult> Route(TableRouteRuleContext tableRouteRuleContext)
{
Dictionary<IVirtualTable, ISet<IPhysicTable>> routeMaps = new Dictionary<IVirtualTable, ISet<IPhysicTable>>();
var queryEntities = tableRouteRuleContext.Queryable.ParseQueryableEntities(typeof(TShardingDbContext));
var queryEntities = tableRouteRuleContext.QueryEntities;
foreach (var shardingEntity in queryEntities)
foreach (var shardingEntityKv in queryEntities)
{
if(!_entityMetadataManager.IsShardingTable(shardingEntity))
var shardingEntity = shardingEntityKv.Key;
if (!_entityMetadataManager.IsShardingTable(shardingEntity))
continue;
var virtualTable = _virtualTableManager.GetVirtualTable(shardingEntity);
var physicTables = virtualTable.RouteTo(new ShardingTableRouteConfig(queryable: tableRouteRuleContext.Queryable));
var physicTables = virtualTable.RouteTo(new ShardingTableRouteConfig(shardingEntityKv.Value ?? tableRouteRuleContext.Queryable));
if (!routeMaps.ContainsKey(virtualTable))
{
routeMaps.Add(virtualTable, physicTables.ToHashSet());

View File

@ -31,18 +31,18 @@ namespace ShardingCore.Core.VirtualRoutes.TableRoutes.RoutingRuleEngine
/// <typeparam name="T"></typeparam>
/// <param name="queryable"></param>
/// <returns></returns>
public TableRouteRuleContext CreateContext(IQueryable queryable)
private TableRouteRuleContext CreateContext(IQueryable queryable, Dictionary<Type, IQueryable> queryEntities)
{
return new TableRouteRuleContext(queryable);
return new TableRouteRuleContext(queryable,queryEntities);
}
public IEnumerable<TableRouteResult> Route(IQueryable queryable)
public IEnumerable<TableRouteResult> Route(IQueryable queryable,Dictionary<Type,IQueryable> queryEntities)
{
var ruleContext = CreateContext(queryable);
var ruleContext = CreateContext(queryable, queryEntities);
return Route(ruleContext);
}
public IEnumerable<TableRouteResult> Route(TableRouteRuleContext ruleContext)
private IEnumerable<TableRouteResult> Route(TableRouteRuleContext ruleContext)
{
return _tableRouteRuleEngine.Route(ruleContext);
}

View File

@ -38,6 +38,8 @@ using ShardingCore.Core.VirtualDatabase.VirtualDataSources.Abstractions;
using ShardingCore.DynamicDataSources;
using ShardingCore.Sharding.MergeContexts;
using ShardingCore.Sharding.ParallelTables;
using ShardingCore.Sharding.Parsers;
using ShardingCore.Sharding.Parsers.Abstractions;
using ShardingCore.Sharding.ReadWriteConfigurations;
using ShardingCore.Sharding.ReadWriteConfigurations.Abstractions;
using ShardingCore.Sharding.ShardingExecutors;
@ -127,6 +129,7 @@ namespace ShardingCore
services.TryAddSingleton<IReadWriteConnectorFactory, ReadWriteConnectorFactory>();
//
services.TryAddSingleton<IPrepareParser, DefaultPrepareParser>();
services.TryAddSingleton<IQueryableParseEngine, QueryableParseEngine>();
services.TryAddSingleton<IQueryableRewriteEngine, QueryableRewriteEngine>();
services.TryAddSingleton<IQueryableOptimizeEngine, QueryableOptimizeEngine>();

View File

@ -156,10 +156,10 @@ namespace ShardingCore.Extensions
return nameof(string.CompareTo).Equals(express.Method.Name) || nameof(string.Compare).Equals(express.Method.Name);
}
public static ISet<Type> ParseQueryableEntities(this IQueryable queryable, Type dbContextType)
{
return ShardingUtil.GetQueryEntitiesFilter(queryable, dbContextType);
}
//public static ISet<Type> ParseQueryableEntities(this IQueryable queryable, Type dbContextType)
//{
// return ShardingUtil.GetQueryEntitiesFilter(queryable, dbContextType);
//}
public static bool IsMemberQueryable(this MemberExpression memberExpression)
{

View File

@ -1,4 +1,5 @@
using System;
using ShardingCore.Sharding.Parsers.Abstractions;
using ShardingCore.Sharding.ShardingExecutors.Abstractions;
/*
@ -9,17 +10,17 @@ using ShardingCore.Sharding.ShardingExecutors.Abstractions;
*/
namespace ShardingCore.Extensions
{
public static class CompileParameterExtension
public static class CompileExtension
{
/// <summary>
/// 是否存在自定义查询
/// </summary>
/// <param name="compileParameter"></param>
/// <param name="prepareParseResult"></param>
/// <returns></returns>
public static bool HasCustomerQuery(this ICompileParameter compileParameter)
public static bool HasCustomerQuery(this IPrepareParseResult prepareParseResult)
{
//compileParameter.ReadOnly().HasValue || compileParameter.GetAsRoute() != null;
return compileParameter.GetAsRoute() != null;
return prepareParseResult.GetAsRoute() != null;
}
}
}

View File

@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
namespace ShardingCore.Extensions.InternalExtensions
{
/// <summary>
///
/// </summary>
/// Author: xjm
/// Created: 2022/4/30 21:44:22
/// Email: 326308290@qq.com
internal static class InternalLogExtension
{
public static void LogLazyDebug(this ILogger logger, Func<string> msgCreator)
{
if (logger.IsEnabled(LogLevel.Debug))
{
logger.LogDebug(msgCreator());
}
}
}
}

View File

@ -4,13 +4,13 @@ using ShardingCore.Core.QueryRouteManagers;
namespace ShardingCore.Extensions.ShardingQueryableExtensions
{
/*
* @Author: xjm
* @Description:
* @Date: Monday, 31 January 2022 00:15:37
* @Email: 326308290@qq.com
*/
internal class ShardingQueryableAsRouteOptions
/*
* @Author: xjm
* @Description:
* @Date: Monday, 31 January 2022 00:15:37
* @Email: 326308290@qq.com
*/
public class ShardingQueryableAsRouteOptions
{
public Action<ShardingRouteContext> RouteConfigure { get; }

View File

@ -6,7 +6,7 @@ using System.Threading.Tasks;
namespace ShardingCore.Extensions.ShardingQueryableExtensions
{
internal class ShardingQueryableAsSequenceOptions
public class ShardingQueryableAsSequenceOptions
{
public bool SameWithShardingComparer { get; }
public bool AsSequence { get; }

View File

@ -2,13 +2,13 @@
namespace ShardingCore.Extensions.ShardingQueryableExtensions
{
/*
* @Author: xjm
* @Description:
* @Date: Tuesday, 01 February 2022 16:48:17
* @Email: 326308290@qq.com
*/
internal class ShardingQueryableReadWriteSeparationOptions
/*
* @Author: xjm
* @Description:
* @Date: Tuesday, 01 February 2022 16:48:17
* @Email: 326308290@qq.com
*/
public class ShardingQueryableReadWriteSeparationOptions
{
public bool RouteReadConnect { get; }

View File

@ -4,13 +4,13 @@ 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
/*
* @Author: xjm
* @Description:
* @Date: Monday, 31 January 2022 22:51:56
* @Email: 326308290@qq.com
*/
public class ShardingQueryableUseConnectionModeOptions
{
public ShardingQueryableUseConnectionModeOptions(int maxQueryConnectionsLimit, ConnectionModeEnum connectionMode)
{

View File

@ -4,12 +4,13 @@ using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
using ShardingCore.Sharding.Parsers.Abstractions;
using ShardingCore.Sharding.ShardingExecutors.Abstractions;
namespace ShardingCore.Sharding.Abstractions
{
public interface IQueryCompilerContextFactory
{
IQueryCompilerContext Create(ICompileParameter compileParameter);
IQueryCompilerContext Create(IPrepareParseResult prepareParseResult);
}
}

View File

@ -0,0 +1,65 @@
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.QueryRouteManagers;
using ShardingCore.Sharding.Abstractions;
namespace ShardingCore.Sharding.Parsers.Abstractions
{
/// <summary>
///
/// </summary>
/// Author: xjm
/// Created: 2022/5/1 17:37:10
/// Email: 326308290@qq.com
public interface IPrepareParseResult
{
/// <summary>
/// 获取当前分片上下文
/// </summary>
/// <returns></returns>
IShardingDbContext GetShardingDbContext();
/// <summary>
/// 获取原始的查询表达式
/// </summary>
/// <returns></returns>
Expression GetNativeQueryExpression();
/// <summary>
/// 是否使用union all 聚合
/// </summary>
/// <returns></returns>
bool UseUnionAllMerge();
/// <summary>
/// 当前查询的连接数限制
/// </summary>
/// <returns></returns>
int? GetMaxQueryConnectionsLimit();
/// <summary>
/// 当前查询的连接模式
/// </summary>
/// <returns></returns>
ConnectionModeEnum? GetConnectionMode();
/// <summary>
/// 在启用读写分离后如果设置了readonly那么就走readonly否则为null
/// </summary>
/// <returns></returns>
bool? ReadOnly();
/// <summary>
/// 自定义路由
/// </summary>
/// <returns></returns>
Action<ShardingRouteContext> GetAsRoute();
bool? IsSequence();
bool? SameWithShardingComparer();
Dictionary<Type/* 查询对象类型 */, IQueryable/* 查询对象对应的表达式 */> GetQueryEntities();
bool? IsNotracking();
bool IsIgnoreFilter();
}
}

View File

@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
using ShardingCore.Sharding.Abstractions;
namespace ShardingCore.Sharding.Parsers.Abstractions
{
/// <summary>
///
/// </summary>
/// Author: xjm
/// Created: 2022/5/1 16:02:57
/// Email: 326308290@qq.com
public interface IPrepareParser
{
IPrepareParseResult Parse(IShardingDbContext shardingDbContext, Expression query);
}
}

View File

@ -0,0 +1,29 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
using ShardingCore.Sharding.Abstractions;
using ShardingCore.Sharding.Parsers.Abstractions;
using ShardingCore.Sharding.Parsers.Visitors;
namespace ShardingCore.Sharding.Parsers
{
/// <summary>
///
/// </summary>
/// Author: xjm
/// Created: 2022/5/1 21:37:25
/// Email: 326308290@qq.com
public class DefaultPrepareParser:IPrepareParser
{
public IPrepareParseResult Parse(IShardingDbContext shardingDbContext, Expression query)
{
var shardingQueryPrepareVisitor = new ShardingQueryPrepareVisitor(shardingDbContext);
var expression = shardingQueryPrepareVisitor.Visit(query);
var shardingPrepareResult = shardingQueryPrepareVisitor.GetShardingPrepareResult();
return new PrepareParseResult(shardingDbContext, expression, shardingPrepareResult);
}
}
}

View File

@ -0,0 +1,123 @@
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.QueryRouteManagers;
using ShardingCore.Extensions;
using ShardingCore.Sharding.Abstractions;
using ShardingCore.Sharding.Parsers.Abstractions;
using ShardingCore.Sharding.Visitors.Querys;
using ShardingCore.Sharding.Visitors.ShardingExtractParameters;
namespace ShardingCore.Sharding.Parsers
{
/// <summary>
///
/// </summary>
/// Author: xjm
/// Created: 2022/5/1 16:03:25
/// Email: 326308290@qq.com
public class PrepareParseResult: IPrepareParseResult
{
private readonly IShardingDbContext _shardingDbContext;
private readonly Expression _nativeQueryExpression;
private readonly bool _useUnionAllMerge;
private readonly int? _maxQueryConnectionsLimit;
private readonly ConnectionModeEnum? _connectionMode;
private readonly bool? _readOnly;
private readonly Action<ShardingRouteContext> _shardingRouteConfigure;
private readonly bool? _isSequence;
private readonly bool? _isNoTracking;
private readonly bool _isIgnoreFilter;
private readonly bool? _sameWithShardingComparer;
private readonly Dictionary<Type, IQueryable> _queryEntities;
public PrepareParseResult(IShardingDbContext shardingDbContext,Expression nativeQueryExpression, ShardingPrepareResult shardingPrepareResult)
{
_shardingDbContext = shardingDbContext;
_nativeQueryExpression = nativeQueryExpression;
_shardingRouteConfigure = shardingPrepareResult.ShardingQueryableAsRouteOptions?.RouteConfigure;
_useUnionAllMerge = shardingPrepareResult.UseUnionAllMerge;
_maxQueryConnectionsLimit = shardingPrepareResult.ShardingQueryableUseConnectionModeOptions?.MaxQueryConnectionsLimit;
_connectionMode = shardingPrepareResult.ShardingQueryableUseConnectionModeOptions?.ConnectionMode;
if (shardingDbContext.IsUseReadWriteSeparation())
{
_readOnly = shardingPrepareResult?.ShardingQueryableReadWriteSeparationOptions?.RouteReadConnect ?? shardingDbContext.CurrentIsReadWriteSeparation();
}
_isSequence = shardingPrepareResult.ShardingQueryableAsSequenceOptions?.AsSequence;
_sameWithShardingComparer = shardingPrepareResult.ShardingQueryableAsSequenceOptions
?.SameWithShardingComparer;
_queryEntities = shardingPrepareResult.QueryEntities;
_isNoTracking = shardingPrepareResult.IsNoTracking;
_isIgnoreFilter = shardingPrepareResult.IsIgnoreFilter;
}
public IShardingDbContext GetShardingDbContext()
{
return _shardingDbContext;
}
public Expression GetNativeQueryExpression()
{
return _nativeQueryExpression;
}
public bool UseUnionAllMerge()
{
return _useUnionAllMerge;
}
public int? GetMaxQueryConnectionsLimit()
{
return _maxQueryConnectionsLimit;
}
public ConnectionModeEnum? GetConnectionMode()
{
return _connectionMode;
}
public bool? ReadOnly()
{
return _readOnly;
}
public Action<ShardingRouteContext> GetAsRoute()
{
return _shardingRouteConfigure;
}
public bool? IsSequence()
{
return _isSequence;
}
public bool? SameWithShardingComparer()
{
return _sameWithShardingComparer;
}
public Dictionary<Type, IQueryable> GetQueryEntities()
{
return _queryEntities;
}
public bool? IsNotracking()
{
return _isNoTracking;
}
public bool IsIgnoreFilter()
{
return _isIgnoreFilter;
}
public override string ToString()
{
return $"query entity types :{string.Join(",",_queryEntities.Keys)},is no tracking: {_isNoTracking},is ignore filter :{_isIgnoreFilter},is not support :{_useUnionAllMerge},max query connections limit:{_maxQueryConnectionsLimit},connection mode:{_connectionMode},readonly:{_readOnly},as route:{_shardingRouteConfigure != null},is sequence:{_isSequence},same with sharding comparer:{_sameWithShardingComparer}";
}
}
}

View File

@ -0,0 +1,44 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using ShardingCore.Extensions.ShardingQueryableExtensions;
/*
* @Author: xjm
* @Description:
* @Date: DATE TIME
* @Email: 326308290@qq.com
*/
namespace ShardingCore.Sharding.Visitors.ShardingExtractParameters
{
public class ShardingPrepareResult
{
public bool UseUnionAllMerge { get; }
public ShardingQueryableAsRouteOptions ShardingQueryableAsRouteOptions { get; }
public ShardingQueryableUseConnectionModeOptions ShardingQueryableUseConnectionModeOptions { get; }
public ShardingQueryableReadWriteSeparationOptions ShardingQueryableReadWriteSeparationOptions { get; }
public ShardingQueryableAsSequenceOptions ShardingQueryableAsSequenceOptions { get; }
public Dictionary<Type, IQueryable> QueryEntities { get; }
public bool? IsNoTracking { get; }
public bool IsIgnoreFilter { get; }
public ShardingPrepareResult(bool useUnionAllMerge,
ShardingQueryableAsRouteOptions shardingQueryableAsRouteOptions,
ShardingQueryableUseConnectionModeOptions shardingQueryableUseConnectionModeOptions,
ShardingQueryableReadWriteSeparationOptions shardingQueryableReadWriteSeparationOptions,
ShardingQueryableAsSequenceOptions shardingQueryableAsSequenceOptions, Dictionary<Type, IQueryable> queryEntities,
bool? isNoTracking, bool isIgnoreFilter)
{
UseUnionAllMerge = useUnionAllMerge;
ShardingQueryableAsRouteOptions = shardingQueryableAsRouteOptions;
ShardingQueryableUseConnectionModeOptions = shardingQueryableUseConnectionModeOptions;
ShardingQueryableReadWriteSeparationOptions = shardingQueryableReadWriteSeparationOptions;
ShardingQueryableAsSequenceOptions = shardingQueryableAsSequenceOptions;
QueryEntities = queryEntities;
IsNoTracking = isNoTracking;
IsIgnoreFilter = isIgnoreFilter;
}
}
}

View File

@ -0,0 +1,223 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Query;
using ShardingCore.Core.TrackerManagers;
using ShardingCore.Extensions;
using ShardingCore.Extensions.ShardingQueryableExtensions;
using ShardingCore.Sharding.Abstractions;
using ShardingCore.Sharding.Visitors.ShardingExtractParameters;
namespace ShardingCore.Sharding.Parsers.Visitors
{
/// <summary>
///
/// </summary>
/// Author: xjm
/// Created: 2022/5/1 21:43:12
/// Email: 326308290@qq.com
internal class ShardingQueryPrepareVisitor : ExpressionVisitor
{
private readonly IShardingDbContext _shardingDbContext;
private bool isNotSupport;
private ShardingQueryableUseConnectionModeOptions shardingQueryableUseConnectionModeOptions;
private ShardingQueryableAsRouteOptions shardingQueryableAsRouteOptions;
private ShardingQueryableReadWriteSeparationOptions shardingQueryableReadWriteSeparationOptions;
private ShardingQueryableAsSequenceOptions shardingQueryableAsSequenceOptions;
private readonly ITrackerManager _trackerManager;
private bool? isNoTracking;
private bool isIgnoreFilter;
private readonly Dictionary<Type, IQueryable> shardingEntities = new();
public ShardingQueryPrepareVisitor(IShardingDbContext shardingDbContext)
{
_shardingDbContext = shardingDbContext;
_trackerManager = ShardingContainer.GetTrackerManager(shardingDbContext.GetType());
}
public ShardingPrepareResult GetShardingPrepareResult()
{
return new ShardingPrepareResult(isNotSupport,
shardingQueryableAsRouteOptions,
shardingQueryableUseConnectionModeOptions,
shardingQueryableReadWriteSeparationOptions,
shardingQueryableAsSequenceOptions,
shardingEntities, isNoTracking, isIgnoreFilter);
}
#if EFCORE2 || EFCORE3
protected override Expression VisitConstant(ConstantExpression node)
{
if (node.Value is IQueryable queryable)
{
TryAddShardingEntities(queryable.ElementType, null);
}
return base.VisitConstant(node);
}
#endif
#if EFCORE5 || EFCORE6
protected override Expression VisitExtension(Expression node)
{
if (node is QueryRootExpression queryRootExpression)
{
TryAddShardingEntities(queryRootExpression.EntityType.ClrType, null);
}
return base.VisitExtension(node);
}
#endif
private void TryAddShardingEntities(Type entityType, IQueryable queryable)
{
if (!shardingEntities.ContainsKey(entityType))
{
shardingEntities.Add(entityType, queryable);
}
}
protected override Expression VisitMember
(MemberExpression memberExpression)
{
if (memberExpression.IsMemberQueryable()) //2x,3x 路由 单元测试 分表和不分表
{
// Recurse down to see if we can simplify...
var expression = Visit(memberExpression.Expression);
// If we've ended up with a constant, and it's a property or a field,
// we can simplify ourselves to a constant
if (expression is ConstantExpression)
{
object container = ((ConstantExpression)expression).Value;
var member = memberExpression.Member;
if (member is FieldInfo fieldInfo)
{
object value = fieldInfo.GetValue(container);
if (value is IQueryable queryable)
{
TryAddShardingEntities(queryable.ElementType, queryable);
}
//return Expression.Constant(value);
}
if (member is PropertyInfo propertyInfo)
{
object value = propertyInfo.GetValue(container, null);
if (value is IQueryable queryable)
{
TryAddShardingEntities(queryable.ElementType, queryable);
}
}
}
}
return base.VisitMember(memberExpression);
}
protected override Expression VisitMethodCall(MethodCallExpression node)
{
switch (node.Method.Name)
{
case nameof(EntityFrameworkQueryableExtensions.AsNoTracking): isNoTracking = true; break;
case nameof(EntityFrameworkQueryableExtensions.AsTracking): isNoTracking = false; break;
case nameof(EntityFrameworkQueryableExtensions.IgnoreQueryFilters): isIgnoreFilter = true; break;
case nameof(EntityFrameworkQueryableExtensions.Include):
case nameof(EntityFrameworkQueryableExtensions.ThenInclude): DiscoverQueryEntities(node); break;
default:
{
var customerExpression = DiscoverCustomerQueryEntities(node);
if (customerExpression != null)
{
return Visit(customerExpression);
}
}
; break;
}
return base.VisitMethodCall(node);
}
private Expression DiscoverCustomerQueryEntities(MethodCallExpression node)
{
if (node.Method.IsGenericMethod)
{
var genericMethodDefinition = node.Method.GetGenericMethodDefinition();
// find notsupport extention calls
if (genericMethodDefinition == EntityFrameworkShardingQueryableExtension.NotSupportMethodInfo)
{
isNotSupport = true;
// cut out extension expression
return node.Arguments[0];
}
else if (genericMethodDefinition == EntityFrameworkShardingQueryableExtension.UseConnectionModeMethodInfo)
{
shardingQueryableUseConnectionModeOptions = node.Arguments
.OfType<ConstantExpression>()
.Where(o => o.Value is ShardingQueryableUseConnectionModeOptions)
.Select(o => (ShardingQueryableUseConnectionModeOptions)o.Value)
.Last();
return node.Arguments[0];
}
else if (genericMethodDefinition == EntityFrameworkShardingQueryableExtension.AsRouteMethodInfo)
{
shardingQueryableAsRouteOptions = node.Arguments
.OfType<ConstantExpression>()
.Where(o => o.Value is ShardingQueryableAsRouteOptions)
.Select(o => (ShardingQueryableAsRouteOptions)o.Value)
.Last();
return node.Arguments[0];
}
else if (genericMethodDefinition == EntityFrameworkShardingQueryableExtension.AsSequenceModeMethodInfo)
{
shardingQueryableAsSequenceOptions = node.Arguments
.OfType<ConstantExpression>()
.Where(o => o.Value is ShardingQueryableAsSequenceOptions)
.Select(o => (ShardingQueryableAsSequenceOptions)o.Value)
.Last();
return node.Arguments[0];
}
}
return null;
}
private void DiscoverQueryEntities(MethodCallExpression node)
{
var genericArguments = node.Type.GetGenericArguments();
for (var i = 0; i < genericArguments.Length; i++)
{
var genericArgument = genericArguments[i];
if (typeof(IEnumerable).IsAssignableFrom(genericArgument))
{
var arguments = genericArgument.GetGenericArguments();
foreach (var argument in arguments)
{
//if is db context model
if (_trackerManager.IsDbContextModel(argument))
{
TryAddShardingEntities(argument, null);
}
}
}
if (!genericArgument.IsSimpleType())
{
//if is db context model
if (_trackerManager.IsDbContextModel(genericArgument))
{
TryAddShardingEntities(genericArgument, null);
}
}
}
}
}
}

View File

@ -14,7 +14,7 @@ namespace ShardingCore.Sharding.ShardingExecutors.Abstractions
{
public interface IQueryCompilerContext
{
ISet<Type> GetQueryEntities();
Dictionary<Type, IQueryable> GetQueryEntities();
IShardingDbContext GetShardingDbContext();
Expression GetQueryExpression();
IEntityMetadataManager GetEntityMetadataManager();

View File

@ -1,100 +1,100 @@
using System;
using System.Collections.Generic;
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;
//using System;
//using System.Collections.Generic;
//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,IPrint
{
private readonly IShardingDbContext _shardingDbContext;
private readonly Expression _nativeQueryExpression;
private readonly bool _useUnionAllMerge;
private readonly int? _maxQueryConnectionsLimit;
private readonly ConnectionModeEnum? _connectionMode;
private readonly bool? _readOnly;
private readonly Action<ShardingRouteContext> _shardingRouteConfigure;
private readonly bool? _isSequence;
private readonly bool? _sameWithShardingComparer;
public CompileParameter(IShardingDbContext shardingDbContext,Expression shardingQueryExpression)
{
_shardingDbContext = shardingDbContext;
var shardingQueryableExtractParameter = new ShardingQueryableExtractParameterVisitor();
_nativeQueryExpression = shardingQueryableExtractParameter.Visit(shardingQueryExpression);
var extractShardingParameter = shardingQueryableExtractParameter.ExtractShardingParameter();
_shardingRouteConfigure = extractShardingParameter.ShardingQueryableAsRouteOptions?.RouteConfigure;
_useUnionAllMerge = extractShardingParameter.UseUnionAllMerge;
_maxQueryConnectionsLimit = extractShardingParameter.ShardingQueryableUseConnectionModeOptions?.MaxQueryConnectionsLimit;
_connectionMode = extractShardingParameter.ShardingQueryableUseConnectionModeOptions?.ConnectionMode;
if (shardingDbContext.IsUseReadWriteSeparation())
{
_readOnly = extractShardingParameter?.ShardingQueryableReadWriteSeparationOptions?.RouteReadConnect??shardingDbContext.CurrentIsReadWriteSeparation();
}
///*
//* @Author: xjm
//* @Description:
//* @Date: DATE TIME
//* @Email: 326308290@qq.com
//*/
//namespace ShardingCore.ShardingExecutors
//{
// public class CompileParameter:ICompileParameter,IPrint
// {
// private readonly IShardingDbContext _shardingDbContext;
// private readonly Expression _nativeQueryExpression;
// private readonly bool _useUnionAllMerge;
// private readonly int? _maxQueryConnectionsLimit;
// private readonly ConnectionModeEnum? _connectionMode;
// private readonly bool? _readOnly;
// private readonly Action<ShardingRouteContext> _shardingRouteConfigure;
// private readonly bool? _isSequence;
// private readonly bool? _sameWithShardingComparer;
// public CompileParameter(IShardingDbContext shardingDbContext,Expression shardingQueryExpression)
// {
// _shardingDbContext = shardingDbContext;
// var shardingQueryableExtractParameter = new ShardingQueryableExtractParameterVisitor();
// _nativeQueryExpression = shardingQueryableExtractParameter.Visit(shardingQueryExpression);
// var extractShardingParameter = shardingQueryableExtractParameter.ExtractShardingParameter();
// _shardingRouteConfigure = extractShardingParameter.ShardingQueryableAsRouteOptions?.RouteConfigure;
// _useUnionAllMerge = extractShardingParameter.UseUnionAllMerge;
// _maxQueryConnectionsLimit = extractShardingParameter.ShardingQueryableUseConnectionModeOptions?.MaxQueryConnectionsLimit;
// _connectionMode = extractShardingParameter.ShardingQueryableUseConnectionModeOptions?.ConnectionMode;
// if (shardingDbContext.IsUseReadWriteSeparation())
// {
// _readOnly = extractShardingParameter?.ShardingQueryableReadWriteSeparationOptions?.RouteReadConnect??shardingDbContext.CurrentIsReadWriteSeparation();
// }
_isSequence = extractShardingParameter.ShardingQueryableAsSequenceOptions?.AsSequence;
_sameWithShardingComparer = extractShardingParameter.ShardingQueryableAsSequenceOptions
?.SameWithShardingComparer;
}
// _isSequence = extractShardingParameter.ShardingQueryableAsSequenceOptions?.AsSequence;
// _sameWithShardingComparer = extractShardingParameter.ShardingQueryableAsSequenceOptions
// ?.SameWithShardingComparer;
// }
public IShardingDbContext GetShardingDbContext()
{
return _shardingDbContext;
}
// public IShardingDbContext GetShardingDbContext()
// {
// return _shardingDbContext;
// }
public Expression GetNativeQueryExpression()
{
return _nativeQueryExpression;
}
// public Expression GetNativeQueryExpression()
// {
// return _nativeQueryExpression;
// }
public bool UseUnionAllMerge()
{
return _useUnionAllMerge;
}
// public bool UseUnionAllMerge()
// {
// return _useUnionAllMerge;
// }
public int? GetMaxQueryConnectionsLimit()
{
return _maxQueryConnectionsLimit;
}
// public int? GetMaxQueryConnectionsLimit()
// {
// return _maxQueryConnectionsLimit;
// }
public ConnectionModeEnum? GetConnectionMode()
{
return _connectionMode;
}
// public ConnectionModeEnum? GetConnectionMode()
// {
// return _connectionMode;
// }
public bool? ReadOnly()
{
return _readOnly;
}
// public bool? ReadOnly()
// {
// return _readOnly;
// }
public Action<ShardingRouteContext> GetAsRoute()
{
return _shardingRouteConfigure;
}
// public Action<ShardingRouteContext> GetAsRoute()
// {
// return _shardingRouteConfigure;
// }
public bool? IsSequence()
{
return _isSequence;
}
// public bool? IsSequence()
// {
// return _isSequence;
// }
public bool? SameWithShardingComparer()
{
return _sameWithShardingComparer;
}
// public bool? SameWithShardingComparer()
// {
// return _sameWithShardingComparer;
// }
public string GetPrintInfo()
{
return $"is not support :{_useUnionAllMerge},max query connections limit:{_maxQueryConnectionsLimit},connection mode:{_connectionMode},readonly:{_readOnly},as route:{_shardingRouteConfigure!=null},is sequence:{_isSequence},same with sharding comparer:{_sameWithShardingComparer}";
}
}
}
// public string GetPrintInfo()
// {
// return $"is not support :{_useUnionAllMerge},max query connections limit:{_maxQueryConnectionsLimit},connection mode:{_connectionMode},readonly:{_readOnly},as route:{_shardingRouteConfigure!=null},is sequence:{_isSequence},same with sharding comparer:{_sameWithShardingComparer}";
// }
// }
//}

View File

@ -2,6 +2,7 @@
using ShardingCore.Core.QueryRouteManagers;
using ShardingCore.Core.QueryRouteManagers.Abstractions;
using ShardingCore.Extensions;
using ShardingCore.Sharding.Parsers.Abstractions;
using ShardingCore.Sharding.ReadWriteConfigurations.Abstractions;
using ShardingCore.Sharding.ShardingExecutors;
using ShardingCore.Sharding.ShardingExecutors.Abstractions;
@ -18,12 +19,12 @@ namespace ShardingCore.ShardingExecutors
{
private readonly ShardingRouteScope _shardingRouteScope;
private readonly bool _hasCustomerQuery;
public CustomerQueryScope(ICompileParameter compileParameter)
public CustomerQueryScope(IPrepareParseResult prepareParseResult)
{
_hasCustomerQuery = compileParameter.HasCustomerQuery();
_hasCustomerQuery = prepareParseResult.HasCustomerQuery();
if (_hasCustomerQuery)
{
var asRoute = compileParameter.GetAsRoute();
var asRoute = prepareParseResult.GetAsRoute();
if ( asRoute!= null)
{
var shardingRouteManager = ShardingContainer.GetService<IShardingRouteManager>();

View File

@ -5,6 +5,7 @@ using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using ShardingCore.Extensions;
using ShardingCore.Sharding.Parsers.Abstractions;
using ShardingCore.Sharding.ShardingExecutors.Abstractions;
using ShardingCore.Sharding.Visitors.ShardingExtractParameters;
using ShardingCore.ShardingExecutors;
@ -16,20 +17,24 @@ namespace ShardingCore.Sharding.ShardingExecutors
private readonly ILogger<DefaultShardingComplierExecutor> _logger;
private readonly IShardingTrackQueryExecutor _shardingTrackQueryExecutor;
private readonly IQueryCompilerContextFactory _queryCompilerContextFactory;
private readonly IPrepareParser _prepareParser;
public DefaultShardingComplierExecutor(ILogger<DefaultShardingComplierExecutor> logger,IShardingTrackQueryExecutor shardingTrackQueryExecutor, IQueryCompilerContextFactory queryCompilerContextFactory)
public DefaultShardingComplierExecutor(ILogger<DefaultShardingComplierExecutor> logger,
IShardingTrackQueryExecutor shardingTrackQueryExecutor, IQueryCompilerContextFactory queryCompilerContextFactory,IPrepareParser prepareParser)
{
_logger = logger;
_shardingTrackQueryExecutor = shardingTrackQueryExecutor;
_queryCompilerContextFactory = queryCompilerContextFactory;
_prepareParser = prepareParser;
}
public TResult Execute<TResult>(IShardingDbContext shardingDbContext, Expression query)
{
var compileParameter = new CompileParameter(shardingDbContext,query);
_logger.LogDebug($"compile parameter:{compileParameter.GetPrintInfo()}");
using (new CustomerQueryScope(compileParameter))
//预解析表达式
var prepareParseResult = _prepareParser.Parse(shardingDbContext,query);
_logger.LogDebug($"compile parameter:{prepareParseResult}");
using (new CustomerQueryScope(prepareParseResult))
{
var queryCompilerContext = _queryCompilerContextFactory.Create(compileParameter);
var queryCompilerContext = _queryCompilerContextFactory.Create(prepareParseResult);
return _shardingTrackQueryExecutor.Execute<TResult>(queryCompilerContext);
}
@ -41,12 +46,13 @@ namespace ShardingCore.Sharding.ShardingExecutors
public TResult ExecuteAsync<TResult>(IShardingDbContext shardingDbContext, Expression query,
CancellationToken cancellationToken = new CancellationToken())
{
var compileParameter = new CompileParameter(shardingDbContext,query);
_logger.LogDebug($"compile parameter:{compileParameter.GetPrintInfo()}");
//预解析表达式
var prepareParseResult = _prepareParser.Parse(shardingDbContext, query);
_logger.LogDebug($"compile parameter:{prepareParseResult}");
using (new CustomerQueryScope(compileParameter))
using (new CustomerQueryScope(prepareParseResult))
{
var queryCompilerContext = _queryCompilerContextFactory.Create(compileParameter);
var queryCompilerContext = _queryCompilerContextFactory.Create(prepareParseResult);
return _shardingTrackQueryExecutor.ExecuteAsync<TResult>(queryCompilerContext);
}
}
@ -55,11 +61,12 @@ namespace ShardingCore.Sharding.ShardingExecutors
#if EFCORE2
public IAsyncEnumerable<TResult> ExecuteAsync<TResult>(IShardingDbContext shardingDbContext, Expression query)
{
var compileParameter = new CompileParameter(shardingDbContext,query);
_logger.LogDebug($"compile parameter:{compileParameter.GetPrintInfo()}");
using (new CustomerQueryScope(compileParameter))
//预解析表达式
var prepareParseResult = _prepareParser.Parse(shardingDbContext, query);
_logger.LogDebug($"compile parameter:{prepareParseResult}");
using (new CustomerQueryScope(prepareParseResult))
{
var queryCompilerContext = _queryCompilerContextFactory.Create(compileParameter);
var queryCompilerContext = _queryCompilerContextFactory.Create(prepareParseResult);
return _shardingTrackQueryExecutor.ExecuteAsync<TResult>(queryCompilerContext);
}
}
@ -67,11 +74,12 @@ namespace ShardingCore.Sharding.ShardingExecutors
public Task<TResult> ExecuteAsync<TResult>(IShardingDbContext shardingDbContext, Expression query,
CancellationToken cancellationToken)
{
var compileParameter = new CompileParameter(shardingDbContext,query);
_logger.LogDebug($"compile parameter:{compileParameter.GetPrintInfo()}");
using (new CustomerQueryScope(compileParameter))
//预解析表达式
var prepareParseResult = _prepareParser.Parse(shardingDbContext, query);
_logger.LogDebug($"compile parameter:{prepareParseResult}");
using (new CustomerQueryScope(prepareParseResult))
{
var queryCompilerContext = _queryCompilerContextFactory.Create(compileParameter);
var queryCompilerContext = _queryCompilerContextFactory.Create(prepareParseResult);
return _shardingTrackQueryExecutor.ExecuteAsync<TResult>(queryCompilerContext, cancellationToken);
}
}

View File

@ -13,6 +13,7 @@ using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using ShardingCore.Core;
using ShardingCore.Extensions.InternalExtensions;
#if EFCORE2
using Microsoft.EntityFrameworkCore.Internal;
#endif
@ -123,7 +124,7 @@ namespace ShardingCore.Sharding.ShardingQueryExecutors
var streamMergeContext= streamMergeContextMethod.MakeGenericMethod(new Type[] { resultType }).Invoke(streamMergeContextFactory, new object[] { mergeQueryCompilerContext });
if (streamMergeContext is IPrint print)
{
_logger.LogDebug(print.GetPrintInfo());
_logger.LogLazyDebug(()=> print.GetPrintInfo());
}
return streamMergeContext;
#endif

View File

@ -62,7 +62,7 @@ namespace ShardingCore.Sharding.ShardingExecutors
if (_queryCompilerContext.GetQueryEntities().Count > 1&& routeResults.Length>0)
{
var entityMetadataManager = _queryCompilerContext.GetEntityMetadataManager();
var queryShardingTables = _queryCompilerContext.GetQueryEntities().Where(o => entityMetadataManager.IsShardingTable(o)).ToArray();
var queryShardingTables = _queryCompilerContext.GetQueryEntities().Keys.Where(o => entityMetadataManager.IsShardingTable(o)).ToArray();
if (queryShardingTables.Length > 1 && _parallelTableManager.IsParallelTableQuery(queryShardingTables))
{
return routeResults.Where(o => o.ReplaceTables.Select(p => p.Tail).ToHashSet().Count == 1);
@ -75,7 +75,7 @@ namespace ShardingCore.Sharding.ShardingExecutors
{
return new MergeQueryCompilerContext(queryCompilerContext, queryCombineResult,dataSourceRouteResult, tableRouteResults);
}
public ISet<Type> GetQueryEntities()
public Dictionary<Type,IQueryable> GetQueryEntities()
{
return _queryCompilerContext.GetQueryEntities();
}

View File

@ -10,12 +10,14 @@ using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using ShardingCore.Core;
using ShardingCore.Sharding.Parsers;
using ShardingCore.Sharding.Parsers.Abstractions;
namespace ShardingCore.Sharding.ShardingExecutors
{
public class QueryCompilerContext: IQueryCompilerContext
{
private readonly ISet<Type> _queryEntities;
private readonly Dictionary<Type/* 查询对象类型 */, IQueryable/* 查询对象对应的表达式 */> _queryEntities;
private readonly IShardingDbContext _shardingDbContext;
private readonly Expression _queryExpression;
private readonly IEntityMetadataManager _entityMetadataManager;
@ -30,31 +32,31 @@ namespace ShardingCore.Sharding.ShardingExecutors
private readonly bool? _isSequence;
private readonly bool? _sameWithShardingComparer;
private QueryCompilerContext(ICompileParameter compileParameter)
private QueryCompilerContext(IPrepareParseResult prepareParseResult)
{
_shardingDbContext = compileParameter.GetShardingDbContext();
_queryExpression = compileParameter.GetNativeQueryExpression();
_shardingDbContext = prepareParseResult.GetShardingDbContext();
_queryExpression = prepareParseResult.GetNativeQueryExpression();
_shardingDbContextType = _shardingDbContext.GetType();
var compileParseResult = ShardingUtil.GetQueryCompileParseResultByExpression(_queryExpression, _shardingDbContextType);
_queryEntities = compileParseResult.QueryEntities;
_isNoTracking = compileParseResult.IsNoTracking;
_useUnionAllMerge = compileParameter.UseUnionAllMerge();
_maxQueryConnectionsLimit = compileParameter.GetMaxQueryConnectionsLimit();
_connectionMode = compileParameter.GetConnectionMode();
//var compileParseResult = ShardingUtil.GetQueryCompileParseResultByExpression(_queryExpression, _shardingDbContextType);
_queryEntities = prepareParseResult.GetQueryEntities();
_isNoTracking = prepareParseResult.IsNotracking();
_useUnionAllMerge = prepareParseResult.UseUnionAllMerge();
_maxQueryConnectionsLimit = prepareParseResult.GetMaxQueryConnectionsLimit();
_connectionMode = prepareParseResult.GetConnectionMode();
_entityMetadataManager = ShardingContainer.GetRequiredEntityMetadataManager(_shardingDbContextType);
//原生对象的原生查询如果是读写分离就需要启用并行查询
_isParallelQuery = compileParameter.ReadOnly().GetValueOrDefault();
_isSequence = compileParameter.IsSequence();
_sameWithShardingComparer = compileParameter.SameWithShardingComparer();
_isParallelQuery = prepareParseResult.ReadOnly().GetValueOrDefault();
_isSequence = prepareParseResult.IsSequence();
_sameWithShardingComparer = prepareParseResult.SameWithShardingComparer();
}
public static QueryCompilerContext Create(ICompileParameter compileParameter)
public static QueryCompilerContext Create(IPrepareParseResult prepareParseResult)
{
return new QueryCompilerContext(compileParameter);
return new QueryCompilerContext(prepareParseResult);
}
public ISet<Type> GetQueryEntities()
public Dictionary<Type, IQueryable> GetQueryEntities()
{
return _queryEntities;
}
@ -127,19 +129,19 @@ namespace ShardingCore.Sharding.ShardingExecutors
public bool IsSingleShardingEntityQuery()
{
return _queryEntities.Count(o => _entityMetadataManager.IsSharding(o)) == 1;
return _queryEntities.Keys.Where(o => _entityMetadataManager.IsSharding(o)).Take(2).Count() == 1;
}
public Type GetSingleShardingEntityType()
{
return _queryEntities.Single(o => _entityMetadataManager.IsSharding(o));
return _queryEntities.Keys.Single(o => _entityMetadataManager.IsSharding(o));
}
public QueryCompilerExecutor GetQueryCompilerExecutor()
{
if (!hasQueryCompilerExecutor.HasValue)
{
hasQueryCompilerExecutor = _queryEntities.All(o => !_entityMetadataManager.IsSharding(o));
hasQueryCompilerExecutor = _queryEntities.Keys.All(o => !_entityMetadataManager.IsSharding(o));
if (hasQueryCompilerExecutor.Value)
{
var virtualDataSource = _shardingDbContext.GetVirtualDataSource();

View File

@ -9,6 +9,8 @@ using ShardingCore.Sharding.ShardingExecutors.QueryableCombines;
using System;
using System.Linq;
using System.Linq.Expressions;
using ShardingCore.Extensions.InternalExtensions;
using ShardingCore.Sharding.Parsers.Abstractions;
namespace ShardingCore.Sharding.ShardingExecutors
{
@ -35,13 +37,13 @@ namespace ShardingCore.Sharding.ShardingExecutors
_logger = logger;
}
public IQueryCompilerContext Create(ICompileParameter compileParameter)
public IQueryCompilerContext Create(IPrepareParseResult prepareParseResult)
{
var queryCompilerContext =
QueryCompilerContext.Create(compileParameter);
QueryCompilerContext.Create(prepareParseResult);
if (queryCompilerContext.GetQueryCompilerExecutor() is not null)
{
_logger.LogDebug($"{queryCompilerContext.GetQueryExpression().ShardingPrint()} is native query");
_logger.LogLazyDebug(()=>$"{queryCompilerContext.GetQueryExpression().ShardingPrint()} is native query");
return queryCompilerContext;
}
@ -49,13 +51,13 @@ namespace ShardingCore.Sharding.ShardingExecutors
_logger.LogDebug($"queryable combine:{queryableCombine.GetType()}");
var dataSourceRouteRuleEngineFactory = (IDataSourceRouteRuleEngineFactory)ShardingContainer.GetService(typeof(IDataSourceRouteRuleEngineFactory<>).GetGenericType0(queryCompilerContext.GetShardingDbContextType()));
var tableRouteRuleEngineFactory = (ITableRouteRuleEngineFactory)ShardingContainer.GetService(typeof(ITableRouteRuleEngineFactory<>).GetGenericType0(queryCompilerContext.GetShardingDbContextType()));
_logger.LogDebug($"queryable combine before:{queryCompilerContext.GetQueryExpression().ShardingPrint()}");
_logger.LogLazyDebug(() => $"queryable combine before:{queryCompilerContext.GetQueryExpression().ShardingPrint()}");
var queryCombineResult = queryableCombine.Combine(queryCompilerContext);
_logger.LogDebug($"queryable combine after:{queryCombineResult.GetCombineQueryable().ShardingPrint()}");
var dataSourceRouteResult = dataSourceRouteRuleEngineFactory.Route(queryCombineResult.GetCombineQueryable(), compileParameter.GetShardingDbContext());
_logger.LogDebug(dataSourceRouteResult.GetPrintInfo());
var routeResults = tableRouteRuleEngineFactory.Route(queryCombineResult.GetCombineQueryable()).ToArray();
_logger.LogDebug($"table route results:{string.Join(","+Environment.NewLine,routeResults.Select(o=>o.GetPrintInfo()))}");
_logger.LogLazyDebug(() => $"queryable combine after:{queryCombineResult.GetCombineQueryable().ShardingPrint()}");
var dataSourceRouteResult = dataSourceRouteRuleEngineFactory.Route(queryCombineResult.GetCombineQueryable(), prepareParseResult.GetShardingDbContext(), prepareParseResult.GetQueryEntities());
_logger.LogLazyDebug(() => $"{dataSourceRouteResult}");
var routeResults = tableRouteRuleEngineFactory.Route(queryCombineResult.GetCombineQueryable(), prepareParseResult.GetQueryEntities()).ToArray();
_logger.LogLazyDebug(() => $"table route results:{string.Join(","+Environment.NewLine,routeResults.Select(o=>o.GetPrintInfo()))}");
var mergeCombineCompilerContext = MergeQueryCompilerContext.Create(queryCompilerContext, queryCombineResult, dataSourceRouteResult,
routeResults);
return mergeCombineCompilerContext;

View File

@ -52,7 +52,8 @@ namespace ShardingCore.Sharding
/// <summary>
/// 本次查询涉及的对象
/// </summary>
public ISet<Type> QueryEntities => MergeQueryCompilerContext.GetQueryEntities();
public ISet<Type> QueryEntities { get; }
/// <summary>
/// 本次查询跨库
@ -86,7 +87,7 @@ namespace ShardingCore.Sharding
RewriteQueryable = rewriteQueryable;
OptimizeResult = optimizeResult;
_routeTailFactory = routeTailFactory;
QueryEntities= MergeQueryCompilerContext.GetQueryEntities().Keys.ToHashSet();
_trackerManager = ShardingContainer.GetTrackerManager(mergeQueryCompilerContext.GetShardingDbContextType());
_shardingEntityConfigOptions = ShardingContainer.GetRequiredShardingEntityConfigOption(mergeQueryCompilerContext.GetShardingDbContextType());
_parallelDbContexts = new ConcurrentDictionary<DbContext, object>();
@ -184,7 +185,7 @@ namespace ShardingCore.Sharding
public bool IsSingleShardingEntityQuery()
{
return QueryEntities.Count(o => MergeQueryCompilerContext.GetEntityMetadataManager().IsSharding(o)) == 1;
return QueryEntities.Where(o => MergeQueryCompilerContext.GetEntityMetadataManager().IsSharding(o)).Take(2).Count() == 1;
}
public Type GetSingleShardingEntityType()
{

View File

@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
@ -8,7 +9,7 @@ namespace ShardingCore.Sharding.Visitors.Querys
{
public class CompileParseResult
{
public CompileParseResult(bool? isNoTracking, bool isIgnoreFilter, ISet<Type> queryEntities)
public CompileParseResult(bool? isNoTracking, bool isIgnoreFilter, Dictionary<Type, Expression> queryEntities)
{
IsNoTracking = isNoTracking;
IsIgnoreFilter = isIgnoreFilter;
@ -25,6 +26,6 @@ namespace ShardingCore.Sharding.Visitors.Querys
/// <summary>
/// 当前涉及到的查询对象
/// </summary>
public ISet<Type> QueryEntities { get; }
public Dictionary<Type, Expression> QueryEntities { get; }
}
}

View File

@ -1,131 +1,131 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Query;
using ShardingCore.Core.Internal.Visitors;
using ShardingCore.Core.TrackerManagers;
using ShardingCore.Extensions;
//using System;
//using System.Collections;
//using System.Collections.Generic;
//using System.Linq;
//using System.Linq.Expressions;
//using System.Reflection;
//using System.Text;
//using System.Threading.Tasks;
//using Microsoft.EntityFrameworkCore;
//using Microsoft.EntityFrameworkCore.Query;
//using ShardingCore.Core.Internal.Visitors;
//using ShardingCore.Core.TrackerManagers;
//using ShardingCore.Extensions;
namespace ShardingCore.Sharding.Visitors.Querys
{
internal class QueryCompileParseVisitors : ExpressionVisitor
{
private readonly ITrackerManager _trackerManager;
private bool? isNoTracking;
private bool isIgnoreFilter;
private readonly ISet<Type> shardingEntities = new HashSet<Type>();
//namespace ShardingCore.Sharding.Visitors.Querys
//{
// internal class QueryCompileParseVisitors : ExpressionVisitor
// {
// private readonly ITrackerManager _trackerManager;
// private bool? isNoTracking;
// private bool isIgnoreFilter;
// private readonly ISet<Type> shardingEntities = new HashSet<Type>();
public QueryCompileParseVisitors(ITrackerManager trackerManager)
{
_trackerManager = trackerManager;
}
// public QueryCompileParseVisitors(ITrackerManager trackerManager)
// {
// _trackerManager = trackerManager;
// }
public CompileParseResult GetCompileParseResult()
{
return new CompileParseResult(isNoTracking, isIgnoreFilter, shardingEntities);
}
#if EFCORE2 || EFCORE3
protected override Expression VisitConstant(ConstantExpression node)
{
if (node.Value is IQueryable queryable)
{
shardingEntities.Add(queryable.ElementType);
}
// public CompileParseResult GetCompileParseResult()
// {
// return new CompileParseResult(isNoTracking, isIgnoreFilter, shardingEntities);
// }
//#if EFCORE2 || EFCORE3
// protected override Expression VisitConstant(ConstantExpression node)
// {
// if (node.Value is IQueryable queryable)
// {
// shardingEntities.Add(queryable.ElementType);
// }
return base.VisitConstant(node);
}
#endif
#if EFCORE5 || EFCORE6
protected override Expression VisitExtension(Expression node)
{
if (node is QueryRootExpression queryRootExpression)
{
shardingEntities.Add(queryRootExpression.EntityType.ClrType);
}
return base.VisitExtension(node);
}
#endif
// return base.VisitConstant(node);
// }
//#endif
//#if EFCORE5 || EFCORE6
// protected override Expression VisitExtension(Expression node)
// {
// if (node is QueryRootExpression queryRootExpression)
// {
// shardingEntities.Add(queryRootExpression.EntityType.ClrType);
// }
// return base.VisitExtension(node);
// }
//#endif
protected override Expression VisitMember
(MemberExpression memberExpression)
{
// Recurse down to see if we can simplify...
var expression = Visit(memberExpression.Expression);
// protected override Expression VisitMember
// (MemberExpression memberExpression)
// {
// // Recurse down to see if we can simplify...
// var expression = Visit(memberExpression.Expression);
// If we've ended up with a constant, and it's a property or a field,
// we can simplify ourselves to a constant
if (expression is ConstantExpression)
{
object container = ((ConstantExpression)expression).Value;
var member = memberExpression.Member;
if (member is FieldInfo fieldInfo)
{
object value = fieldInfo.GetValue(container);
if (value is IQueryable queryable)
{
shardingEntities.Add(queryable.ElementType);
}
//return Expression.Constant(value);
}
if (member is PropertyInfo propertyInfo)
{
object value = propertyInfo.GetValue(container, null);
if (value is IQueryable queryable)
{
shardingEntities.Add(queryable.ElementType);
}
}
}
return base.VisitMember(memberExpression);
}
protected override Expression VisitMethodCall(MethodCallExpression node)
{
switch (node.Method.Name)
{
case nameof(EntityFrameworkQueryableExtensions.AsNoTracking): isNoTracking = true; break;
case nameof(EntityFrameworkQueryableExtensions.AsTracking): isNoTracking = false; break;
case nameof(EntityFrameworkQueryableExtensions.IgnoreQueryFilters): isIgnoreFilter = true; break;
case nameof(EntityFrameworkQueryableExtensions.Include):
case nameof(EntityFrameworkQueryableExtensions.ThenInclude): DiscoverQueryEntities(node); break;
}
// // If we've ended up with a constant, and it's a property or a field,
// // we can simplify ourselves to a constant
// if (expression is ConstantExpression)
// {
// object container = ((ConstantExpression)expression).Value;
// var member = memberExpression.Member;
// if (member is FieldInfo fieldInfo)
// {
// object value = fieldInfo.GetValue(container);
// if (value is IQueryable queryable)
// {
// shardingEntities.Add(queryable.ElementType);
// }
// //return Expression.Constant(value);
// }
// if (member is PropertyInfo propertyInfo)
// {
// object value = propertyInfo.GetValue(container, null);
// if (value is IQueryable queryable)
// {
// shardingEntities.Add(queryable.ElementType);
// }
// }
// }
// return base.VisitMember(memberExpression);
// }
// protected override Expression VisitMethodCall(MethodCallExpression node)
// {
// switch (node.Method.Name)
// {
// case nameof(EntityFrameworkQueryableExtensions.AsNoTracking): isNoTracking = true; break;
// case nameof(EntityFrameworkQueryableExtensions.AsTracking): isNoTracking = false; break;
// case nameof(EntityFrameworkQueryableExtensions.IgnoreQueryFilters): isIgnoreFilter = true; break;
// case nameof(EntityFrameworkQueryableExtensions.Include):
// case nameof(EntityFrameworkQueryableExtensions.ThenInclude): DiscoverQueryEntities(node); break;
// }
return base.VisitMethodCall(node);
}
// return base.VisitMethodCall(node);
// }
private void DiscoverQueryEntities(MethodCallExpression node)
{
var genericArguments = node.Type.GetGenericArguments();
for (var i = 0; i < genericArguments.Length; i++)
{
var genericArgument = genericArguments[i];
if (typeof(IEnumerable).IsAssignableFrom(genericArgument))
{
var arguments = genericArgument.GetGenericArguments();
foreach (var argument in arguments)
{
//if is db context model
if (_trackerManager.IsDbContextModel(argument))
{
shardingEntities.Add(argument);
}
}
}
// private void DiscoverQueryEntities(MethodCallExpression node)
// {
// var genericArguments = node.Type.GetGenericArguments();
// for (var i = 0; i < genericArguments.Length; i++)
// {
// var genericArgument = genericArguments[i];
// if (typeof(IEnumerable).IsAssignableFrom(genericArgument))
// {
// var arguments = genericArgument.GetGenericArguments();
// foreach (var argument in arguments)
// {
// //if is db context model
// if (_trackerManager.IsDbContextModel(argument))
// {
// shardingEntities.Add(argument);
// }
// }
// }
if (!genericArgument.IsSimpleType())
{
//if is db context model
if (_trackerManager.IsDbContextModel(genericArgument))
{
shardingEntities.Add(genericArgument);
}
}
}
}
}
}
// if (!genericArgument.IsSimpleType())
// {
// //if is db context model
// if (_trackerManager.IsDbContextModel(genericArgument))
// {
// shardingEntities.Add(genericArgument);
// }
// }
// }
// }
// }
//}

View File

@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ShardingCore.Sharding.Visitors
{
/// <summary>
///
/// </summary>
/// Author: xjm
/// Created: 2022/4/30 22:48:50
/// Email: 326308290@qq.com
public class SimpleQueryableParseVisitor
{
}
}

View File

@ -63,42 +63,42 @@ namespace ShardingCore.Utils
return visitor.GetRouteParseExpression();
}
/// <summary>
/// 获取本次查询的所有涉及到的对象
/// </summary>
/// <param name="queryable"></param>
/// <param name="dbContextType"></param>
/// <returns></returns>
public static ISet<Type> GetQueryEntitiesFilter(IQueryable queryable,Type dbContextType)
{
return GetQueryEntitiesByExpression(queryable.Expression, dbContextType);
}
public static ISet<Type> GetQueryEntitiesByExpression(Expression expression, Type dbContextType)
{
var trackerManager = (ITrackerManager)ShardingContainer.GetService(typeof(ITrackerManager<>).GetGenericType0(dbContextType));
///// <summary>
///// 获取本次查询的所有涉及到的对象
///// </summary>
///// <param name="queryable"></param>
///// <param name="dbContextType"></param>
///// <returns></returns>
//public static ISet<Type> GetQueryEntitiesFilter(IQueryable queryable,Type dbContextType)
//{
// return GetQueryEntitiesByExpression(queryable.Expression, dbContextType);
//}
//public static ISet<Type> GetQueryEntitiesByExpression(Expression expression, Type dbContextType)
//{
// var trackerManager = (ITrackerManager)ShardingContainer.GetService(typeof(ITrackerManager<>).GetGenericType0(dbContextType));
QueryEntitiesVisitor visitor = new QueryEntitiesVisitor(trackerManager);
// QueryEntitiesVisitor visitor = new QueryEntitiesVisitor(trackerManager);
visitor.Visit(expression);
// visitor.Visit(expression);
return visitor.GetQueryEntities();
}
/// <summary>
/// 获取次需要编译的表达式解析信息
/// </summary>
/// <param name="expression"></param>
/// <param name="dbContextType"></param>
/// <returns></returns>
public static CompileParseResult GetQueryCompileParseResultByExpression(Expression expression, Type dbContextType)
{
var trackerManager = (ITrackerManager)ShardingContainer.GetService(typeof(ITrackerManager<>).GetGenericType0(dbContextType));
// return visitor.GetQueryEntities();
//}
///// <summary>
///// 获取次需要编译的表达式解析信息
///// </summary>
///// <param name="expression"></param>
///// <param name="dbContextType"></param>
///// <returns></returns>
//public static CompileParseResult GetQueryCompileParseResultByExpression(Expression expression, Type dbContextType)
//{
// var trackerManager = (ITrackerManager)ShardingContainer.GetService(typeof(ITrackerManager<>).GetGenericType0(dbContextType));
QueryCompileParseVisitors visitor = new QueryCompileParseVisitors(trackerManager);
// QueryCompileParseVisitors visitor = new QueryCompileParseVisitors(trackerManager);
visitor.Visit(expression);
// visitor.Visit(expression);
return visitor.GetCompileParseResult();
}
// return visitor.GetCompileParseResult();
//}
}
}