diff --git a/src/ShardingCore/Core/VirtualRoutes/ShardingOperatorEnum.cs b/src/ShardingCore/Core/VirtualRoutes/ShardingOperatorEnum.cs index f2f126d1..cc3a399f 100644 --- a/src/ShardingCore/Core/VirtualRoutes/ShardingOperatorEnum.cs +++ b/src/ShardingCore/Core/VirtualRoutes/ShardingOperatorEnum.cs @@ -24,12 +24,12 @@ namespace ShardingCore.Core.VirtualRoutes Equal, [Description("!=")] NotEqual, - // [Description("%w%")] - // AllLike, - // [Description("%w")] - // StartLike, - // [Description("w%")] - // EndLike + [Description("%w%")] + AllLike, + [Description("%w")] + StartLike, + [Description("w%")] + EndLike // [Description("Contains")] // BeContains } diff --git a/src/ShardingCore/Extensions/CommonExtension.cs b/src/ShardingCore/Extensions/CommonExtension.cs index 5674e246..54c9d567 100644 --- a/src/ShardingCore/Extensions/CommonExtension.cs +++ b/src/ShardingCore/Extensions/CommonExtension.cs @@ -80,11 +80,26 @@ namespace ShardingCore.Extensions /// 是否是集合contains方法 /// /// - /// /// - public static bool IsEnumerableContains(this MethodCallExpression express, string methodName) + public static bool IsEnumerableContains(this MethodCallExpression express) { - return express.Method.DeclaringType.Namespace.IsIn("System.Linq", "System.Collections.Generic") && methodName == nameof(IList.Contains); + var methodName = express.Method.Name; + return methodName == nameof(IList.Contains)&& (express.Method.DeclaringType?.Namespace.IsInEnumerable()??false); + } + public static bool IsStringContains(this MethodCallExpression express) + { + var methodName = express.Method.Name; + return methodName == nameof(string.Contains)&& (express.Method.DeclaringType==typeof(string)); + } + public static bool IsStringStartWith(this MethodCallExpression express) + { + var methodName = express.Method.Name; + return methodName == nameof(string.StartsWith)&& (express.Method.DeclaringType==typeof(string)); + } + public static bool IsStringEndWith(this MethodCallExpression express) + { + var methodName = express.Method.Name; + return methodName == nameof(string.EndsWith)&& (express.Method.DeclaringType==typeof(string)); } /// /// 是否是equal方法 diff --git a/src/ShardingCore/Extensions/LinqExtension.cs b/src/ShardingCore/Extensions/LinqExtension.cs index 8522f07b..0e6f06b3 100644 --- a/src/ShardingCore/Extensions/LinqExtension.cs +++ b/src/ShardingCore/Extensions/LinqExtension.cs @@ -47,9 +47,14 @@ namespace ShardingCore.Extensions { return !source.IsEmpty(); } - public static bool IsIn(this T thisValue, params T[] values) + + private static readonly HashSet _enumerableContainsNamespace = new HashSet() { - return values.Contains(thisValue); + "System.Linq", "System.Collections.Generic" + }; + public static bool IsInEnumerable(this string thisValue) + { + return _enumerableContainsNamespace.Contains(thisValue); } /// /// 按size分区,每个区size个数目 diff --git a/src/ShardingCore/Sharding/Visitors/QueryableRouteDiscoverVisitor.cs b/src/ShardingCore/Sharding/Visitors/QueryableRouteDiscoverVisitor.cs index 2e3a3e5c..67d2867a 100644 --- a/src/ShardingCore/Sharding/Visitors/QueryableRouteDiscoverVisitor.cs +++ b/src/ShardingCore/Sharding/Visitors/QueryableRouteDiscoverVisitor.cs @@ -25,19 +25,45 @@ namespace ShardingCore.Core.Internal.Visitors */ public class QueryableRouteShardingTableDiscoverVisitor : ShardingExpressionVisitor { + private static readonly Func _shardingOperatorFunc = + (conditionOnRight, nodeType) => + { + var op = nodeType switch + { + ExpressionType.GreaterThan => conditionOnRight + ? ShardingOperatorEnum.GreaterThan + : ShardingOperatorEnum.LessThan, + ExpressionType.GreaterThanOrEqual => conditionOnRight + ? ShardingOperatorEnum.GreaterThanOrEqual + : ShardingOperatorEnum.LessThanOrEqual, + ExpressionType.LessThan => conditionOnRight + ? ShardingOperatorEnum.LessThan + : ShardingOperatorEnum.GreaterThan, + ExpressionType.LessThanOrEqual => conditionOnRight + ? ShardingOperatorEnum.LessThanOrEqual + : ShardingOperatorEnum.GreaterThanOrEqual, + ExpressionType.Equal => ShardingOperatorEnum.Equal, + ExpressionType.NotEqual => ShardingOperatorEnum.NotEqual, + _ => ShardingOperatorEnum.UnKnown + }; + return op; + }; private readonly EntityMetadata _entityMetadata; private readonly Func> _keyToTailWithFilter; + /// /// 是否是分表路由 /// private readonly bool _shardingTableRoute; + private LambdaExpression _entityLambdaExpression; private readonly ShardingPredicateResult _noShardingPredicateResult = new ShardingPredicateResult(false, null); private bool isIgnoreQueryFilter; - private RoutePredicateExpression _where = RoutePredicateExpression.Default; + private RoutePredicateExpression _where = RoutePredicateExpression.Default; - public QueryableRouteShardingTableDiscoverVisitor(EntityMetadata entityMetadata, Func> keyToTailWithFilter, bool shardingTableRoute) + public QueryableRouteShardingTableDiscoverVisitor(EntityMetadata entityMetadata, + Func> keyToTailWithFilter, bool shardingTableRoute) { _entityMetadata = entityMetadata; _keyToTailWithFilter = keyToTailWithFilter; @@ -50,7 +76,6 @@ namespace ShardingCore.Core.Internal.Visitors /// public RoutePredicateExpression GetRouteParseExpression() { - if (_entityMetadata.QueryFilterExpression != null && !isIgnoreQueryFilter) { if (_entityLambdaExpression == null) @@ -59,7 +84,8 @@ namespace ShardingCore.Core.Internal.Visitors } else { - var body = Expression.AndAlso(_entityLambdaExpression.Body, _entityMetadata.QueryFilterExpression.Body); + var body = Expression.AndAlso(_entityLambdaExpression.Body, + _entityMetadata.QueryFilterExpression.Body); _entityLambdaExpression = Expression.Lambda(body, _entityLambdaExpression.Parameters[0]); } } @@ -69,6 +95,7 @@ namespace ShardingCore.Core.Internal.Visitors var newWhere = Resolve(_entityLambdaExpression); _where = _where.And(newWhere); } + return _where; } @@ -77,7 +104,8 @@ namespace ShardingCore.Core.Internal.Visitors { if (expression is MemberExpression member) { - if (member.Expression?.Type == _entityMetadata.EntityType|| MemberExpressionIsConvertAndOriginalIsEntityType(member)) + if (member.Expression?.Type == _entityMetadata.EntityType || + MemberExpressionIsConvertAndOriginalIsEntityType(member)) { var isShardingKey = false; if (_shardingTableRoute) @@ -100,6 +128,7 @@ namespace ShardingCore.Core.Internal.Visitors shardingPredicateResult = _noShardingPredicateResult; return false; } + /// /// 成员表达式是强转并且强转前的类型是当前对象 /// @@ -111,6 +140,7 @@ namespace ShardingCore.Core.Internal.Visitors member.Expression is UnaryExpression unaryExpression && unaryExpression.Operand.Type == _entityMetadata.EntityType; } + /// /// 方法是否包含shardingKey xxx.invoke(shardingkey) eg. o=>new[]{}.Contains(o.Id) /// @@ -126,6 +156,7 @@ namespace ShardingCore.Core.Internal.Visitors return result; } } + return _noShardingPredicateResult; } @@ -138,14 +169,25 @@ namespace ShardingCore.Core.Internal.Visitors return result; } } + return _noShardingPredicateResult; } - private bool IsConstantOrMember(Expression expression) + + /// + /// 表达式是否可以获取值 + /// + /// + /// + private bool ExpressionCanGetValue(Expression expression) { return expression is ConstantExpression - || (expression is MemberExpression member && (member.Expression is ConstantExpression || member.Expression is MemberExpression || member.Expression is MemberExpression)) + || (expression is MemberExpression member && (member.Expression is ConstantExpression || + member.Expression is MemberExpression || + member.Expression is MemberExpression)) || expression is MethodCallExpression - || (expression is UnaryExpression unaryExpression && unaryExpression.NodeType is ExpressionType.Convert ) ; + || (expression is UnaryExpression unaryExpression && + unaryExpression.NodeType is ExpressionType.Convert) + || expression.NodeType == ExpressionType.ArrayIndex; } private bool IsMethodCall(Expression expression) @@ -157,8 +199,12 @@ namespace ShardingCore.Core.Internal.Visitors { switch (node.Method.Name) { - case nameof(EntityFrameworkQueryableExtensions.IgnoreQueryFilters): isIgnoreQueryFilter = true; break; - case nameof(Queryable.Where): CombineEntityLambdaExpression(node); break; + case nameof(EntityFrameworkQueryableExtensions.IgnoreQueryFilters): + isIgnoreQueryFilter = true; + break; + case nameof(Queryable.Where): + CombineEntityLambdaExpression(node); + break; } return base.VisitMethodCall(node); @@ -196,9 +242,10 @@ namespace ShardingCore.Core.Internal.Visitors return Resolve(expression); } + //解析左右结构属性判断 if (expression is BinaryExpression binaryExpression) //解析二元运算符 { - return ParseGetWhere(binaryExpression); + return ParsePropertyCondition(binaryExpression); } if (expression is UnaryExpression unary) //解析一元运算符 @@ -214,12 +261,13 @@ namespace ShardingCore.Core.Internal.Visitors { return ResolveInFunc(methodCallExpression, true); } + return RoutePredicateExpression.Default; } private RoutePredicateExpression ResolveInFunc(MethodCallExpression methodCallExpression, bool @in) { - if (methodCallExpression.IsEnumerableContains(methodCallExpression.Method.Name)) + if (methodCallExpression.IsEnumerableContains()) { var shardingPredicateResult = IsMethodWrapShardingKey(methodCallExpression); if (shardingPredicateResult.IsShardingKey) @@ -247,26 +295,67 @@ namespace ShardingCore.Core.Internal.Visitors if (arrayObject != null) { - var contains=@in ? RoutePredicateExpression.DefaultFalse : RoutePredicateExpression.Default; - + var contains = @in ? RoutePredicateExpression.DefaultFalse : RoutePredicateExpression.Default; + if (arrayObject is IEnumerable enumerableObj) { foreach (var shardingValue in enumerableObj) { - var eq = _keyToTailWithFilter(shardingValue, @in ? ShardingOperatorEnum.Equal : ShardingOperatorEnum.NotEqual, shardingPredicateResult.ShardingPropertyName); + var eq = _keyToTailWithFilter(shardingValue, + @in ? ShardingOperatorEnum.Equal : ShardingOperatorEnum.NotEqual, + shardingPredicateResult.ShardingPropertyName); if (@in) contains = contains.Or(new RoutePredicateExpression(eq)); else contains = contains.And(new RoutePredicateExpression(eq)); } } + return contains; } } } - - if (methodCallExpression.IsNamedEquals()) + else if (methodCallExpression.IsStringContains()) + { + if (IsShardingKey(methodCallExpression.Object, out var shardingPredicateResult)) + { + if (methodCallExpression.Arguments.Count == 1) + { + var shardingValue = GetExpressionValue(methodCallExpression.Arguments[0]); + var keyToTailWithFilter = _keyToTailWithFilter(shardingValue, ShardingOperatorEnum.AllLike, + shardingPredicateResult.ShardingPropertyName); + return new RoutePredicateExpression(keyToTailWithFilter); + } + } + } + else if (methodCallExpression.IsStringStartWith()) + { + if (IsShardingKey(methodCallExpression.Object, out var shardingPredicateResult)) + { + if (methodCallExpression.Arguments.Count == 1) + { + var shardingValue = GetExpressionValue(methodCallExpression.Arguments[0]); + var keyToTailWithFilter = _keyToTailWithFilter(shardingValue, ShardingOperatorEnum.StartLike, + shardingPredicateResult.ShardingPropertyName); + return new RoutePredicateExpression(keyToTailWithFilter); + } + } + } + else if (methodCallExpression.IsStringEndWith()) + { + if (IsShardingKey(methodCallExpression.Object, out var shardingPredicateResult)) + { + if (methodCallExpression.Arguments.Count == 1) + { + var shardingValue = GetExpressionValue(methodCallExpression.Arguments[0]); + var keyToTailWithFilter = _keyToTailWithFilter(shardingValue, ShardingOperatorEnum.EndLike, + shardingPredicateResult.ShardingPropertyName); + return new RoutePredicateExpression(keyToTailWithFilter); + } + } + } + else if (methodCallExpression.IsNamedEquals()) { //"".equals(o.id) var shardingPredicateResult = IsMethodWrapShardingKey(methodCallExpression); @@ -275,7 +364,8 @@ namespace ShardingCore.Core.Internal.Visitors var shardingValue = GetExpressionValue(methodCallExpression.Object); if (shardingValue != null) { - var keyToTailWithFilter = _keyToTailWithFilter(shardingValue, ShardingOperatorEnum.Equal, shardingPredicateResult.ShardingPropertyName); + var keyToTailWithFilter = _keyToTailWithFilter(shardingValue, ShardingOperatorEnum.Equal, + shardingPredicateResult.ShardingPropertyName); return new RoutePredicateExpression(keyToTailWithFilter); } } @@ -297,7 +387,8 @@ namespace ShardingCore.Core.Internal.Visitors if (shardingValue != default) { - var keyToTailWithFilter = _keyToTailWithFilter(shardingValue, ShardingOperatorEnum.Equal, shardingPredicateResult.ShardingPropertyName); + var keyToTailWithFilter = _keyToTailWithFilter(shardingValue, ShardingOperatorEnum.Equal, + shardingPredicateResult.ShardingPropertyName); return new RoutePredicateExpression(keyToTailWithFilter); } } @@ -313,30 +404,45 @@ namespace ShardingCore.Core.Internal.Visitors return RoutePredicateExpression.Default; } - private ShardingOperatorEnum GetParseCompareShardingOperatorEnum(bool conditionOnRight, ExpressionType expressionType, int compare) + private ShardingOperatorEnum GetParseCompareShardingOperatorEnum(bool conditionOnRight, + ExpressionType expressionType, int compare) { if (compare == 1) { return expressionType switch { - ExpressionType.GreaterThanOrEqual => conditionOnRight ? ShardingOperatorEnum.GreaterThan : ShardingOperatorEnum.LessThan,//1 - ExpressionType.GreaterThan => ShardingOperatorEnum.UnKnown,//无 - ExpressionType.LessThanOrEqual => ShardingOperatorEnum.UnKnown,//1,0,-1 = 无 - ExpressionType.LessThan => conditionOnRight ? ShardingOperatorEnum.LessThanOrEqual : ShardingOperatorEnum.GreaterThanOrEqual,//0,-1 - ExpressionType.Equal => conditionOnRight ? ShardingOperatorEnum.GreaterThan : ShardingOperatorEnum.LessThan,//1 + ExpressionType.GreaterThanOrEqual => conditionOnRight + ? ShardingOperatorEnum.GreaterThan + : ShardingOperatorEnum.LessThan, //1 + ExpressionType.GreaterThan => ShardingOperatorEnum.UnKnown, //无 + ExpressionType.LessThanOrEqual => ShardingOperatorEnum.UnKnown, //1,0,-1 = 无 + ExpressionType.LessThan => conditionOnRight + ? ShardingOperatorEnum.LessThanOrEqual + : ShardingOperatorEnum.GreaterThanOrEqual, //0,-1 + ExpressionType.Equal => conditionOnRight + ? ShardingOperatorEnum.GreaterThan + : ShardingOperatorEnum.LessThan, //1 ExpressionType.NotEqual => ShardingOperatorEnum.NotEqual, _ => ShardingOperatorEnum.UnKnown }; - } + if (compare == 0) { return expressionType switch { - ExpressionType.GreaterThanOrEqual => conditionOnRight ? ShardingOperatorEnum.GreaterThanOrEqual : ShardingOperatorEnum.LessThanOrEqual,//0,1 - ExpressionType.GreaterThan => conditionOnRight ? ShardingOperatorEnum.GreaterThan: ShardingOperatorEnum.LessThan,//1 - ExpressionType.LessThanOrEqual => conditionOnRight ? ShardingOperatorEnum.LessThanOrEqual : ShardingOperatorEnum.GreaterThanOrEqual,//0,-1 - ExpressionType.LessThan => conditionOnRight ? ShardingOperatorEnum.LessThan : ShardingOperatorEnum.GreaterThan,//-1 + ExpressionType.GreaterThanOrEqual => conditionOnRight + ? ShardingOperatorEnum.GreaterThanOrEqual + : ShardingOperatorEnum.LessThanOrEqual, //0,1 + ExpressionType.GreaterThan => conditionOnRight + ? ShardingOperatorEnum.GreaterThan + : ShardingOperatorEnum.LessThan, //1 + ExpressionType.LessThanOrEqual => conditionOnRight + ? ShardingOperatorEnum.LessThanOrEqual + : ShardingOperatorEnum.GreaterThanOrEqual, //0,-1 + ExpressionType.LessThan => conditionOnRight + ? ShardingOperatorEnum.LessThan + : ShardingOperatorEnum.GreaterThan, //-1 ExpressionType.Equal => ShardingOperatorEnum.Equal, ExpressionType.NotEqual => ShardingOperatorEnum.NotEqual, _ => ShardingOperatorEnum.UnKnown @@ -347,146 +453,155 @@ namespace ShardingCore.Core.Internal.Visitors { return expressionType switch { - ExpressionType.GreaterThanOrEqual => ShardingOperatorEnum.UnKnown,//-1,0,1 - ExpressionType.GreaterThan => conditionOnRight? ShardingOperatorEnum.GreaterThanOrEqual: ShardingOperatorEnum.LessThanOrEqual,//0,1 - ExpressionType.LessThanOrEqual => conditionOnRight? ShardingOperatorEnum.LessThan:ShardingOperatorEnum.GreaterThan,//-1 - ExpressionType.LessThan =>ShardingOperatorEnum.UnKnown,//无 - ExpressionType.Equal => conditionOnRight ? ShardingOperatorEnum.LessThan : ShardingOperatorEnum.GreaterThan,//1 + ExpressionType.GreaterThanOrEqual => ShardingOperatorEnum.UnKnown, //-1,0,1 + ExpressionType.GreaterThan => conditionOnRight + ? ShardingOperatorEnum.GreaterThanOrEqual + : ShardingOperatorEnum.LessThanOrEqual, //0,1 + ExpressionType.LessThanOrEqual => conditionOnRight + ? ShardingOperatorEnum.LessThan + : ShardingOperatorEnum.GreaterThan, //-1 + ExpressionType.LessThan => ShardingOperatorEnum.UnKnown, //无 + ExpressionType.Equal => conditionOnRight + ? ShardingOperatorEnum.LessThan + : ShardingOperatorEnum.GreaterThan, //1 ExpressionType.NotEqual => ShardingOperatorEnum.NotEqual, _ => ShardingOperatorEnum.UnKnown }; } + return ShardingOperatorEnum.UnKnown; } - private RoutePredicateExpression ParseCompare(MethodCallExpression methodCallExpression, Expression left,Expression right, ExpressionType expressionType, int compare) + + private RoutePredicateExpression ParseCompare(MethodCallExpression methodCallExpression, Expression left, + Expression right, ExpressionType expressionType, int compare) { if (left.Type == right.Type) { if (methodCallExpression.Method.ReturnType == typeof(int)) { - return ParseCondition0(left, right, conditionOnRight => GetParseCompareShardingOperatorEnum(conditionOnRight, expressionType, compare)); + return ParseCondition0(left, right, expressionType, + (conditionOnRight, nodeType) => + GetParseCompareShardingOperatorEnum(conditionOnRight, nodeType, compare)); } } + return RoutePredicateExpression.Default; } - private RoutePredicateExpression ParseCondition0(Expression left, Expression right,Func shardingOperatorFunc) + private RoutePredicateExpression ParseConditionOnRight0(bool conditionOnRight, + ShardingPredicateResult predicateLeftResult, + Expression conditionExpression, ExpressionType expressionType) { - - bool conditionOnRight = false; - string shardingPropertyName = null; - object value = default; - - - if (IsShardingKey(left, out var predicateLeftResult) && IsConstantOrMember(right)) + if (ExpressionCanGetValue(conditionExpression)) { - if (predicateLeftResult.IsShardingKey) - { - conditionOnRight = true; - shardingPropertyName = predicateLeftResult.ShardingPropertyName; - value = GetExpressionValue(right); - } - else - return RoutePredicateExpression.Default; - } - else if (IsShardingKey(right, out var predicateRightResult) && IsConstantOrMember(left)) - { - if (predicateRightResult.IsShardingKey) - { - conditionOnRight = false; - shardingPropertyName = predicateRightResult.ShardingPropertyName; - value = GetExpressionValue(left); - } - else + var shardingPropertyName = predicateLeftResult.ShardingPropertyName; + var value = GetExpressionValue(conditionExpression); + + if (shardingPropertyName == null || value == default) return RoutePredicateExpression.Default; + var op = _shardingOperatorFunc(conditionOnRight, expressionType); + + + return new RoutePredicateExpression(_keyToTailWithFilter(value, op, shardingPropertyName)); } else return RoutePredicateExpression.Default; - var op = shardingOperatorFunc(conditionOnRight); - - if (shardingPropertyName == null || value == default) - return RoutePredicateExpression.Default; - - - return new RoutePredicateExpression( _keyToTailWithFilter(value, op, shardingPropertyName)); } - private RoutePredicateExpression ParseCondition(BinaryExpression binaryExpression) + private RoutePredicateExpression ParseCondition0(Expression left, Expression right, + ExpressionType expressionType, Func shardingOperatorFunc) { - if (binaryExpression.IsNamedComparison(out var methodCallExpression)) + if (IsShardingKey(left, out var predicateLeftResult)) { - if (methodCallExpression.GetComparisonLeftAndRight(out var result)) - { - return ParseCompare(methodCallExpression, result.Left, result.Right, - binaryExpression.NodeType, (int)GetExpressionValue(binaryExpression.Right)); - } + return ParseConditionOnRight0(true, predicateLeftResult, right, expressionType); + } + else if (IsShardingKey(right, out var predicateRightResult)) + { + return ParseConditionOnRight0(false, predicateRightResult, left, expressionType); + } + else + return RoutePredicateExpression.Default; + } + + private RoutePredicateExpression ParseNamedComparison(BinaryExpression binaryExpression, + MethodCallExpression methodCallExpression) + { + if (methodCallExpression.GetComparisonLeftAndRight(out var result)) + { + return ParseCompare(methodCallExpression, result.Left, result.Right, + binaryExpression.NodeType, (int)GetExpressionValue(binaryExpression.Right)); + } + + return RoutePredicateExpression.Default; + } + + + private RoutePredicateExpression ParsePropertyCondition(BinaryExpression binaryExpression) + { + // RoutePredicateExpression left = RoutePredicateExpression.Default; + // RoutePredicateExpression right = RoutePredicateExpression.Default; + //左边是属性判断是否是分片的 + if (IsShardingKey(binaryExpression.Left, out var predicateLeftResult)) + { + return ParseConditionOnRight0(true, predicateLeftResult, binaryExpression.Right, + binaryExpression.NodeType); + } + else if (IsShardingKey(binaryExpression.Right, out var predicateRightResult)) + { + return ParseConditionOnRight0(false, predicateRightResult, binaryExpression.Left, + binaryExpression.NodeType); + } + else if (binaryExpression.IsNamedComparison(out var methodCallExpression)) + { + return ParseNamedComparison(binaryExpression, methodCallExpression); } else { + RoutePredicateExpression left = RoutePredicateExpression.Default; + RoutePredicateExpression right = RoutePredicateExpression.Default; - return ParseCondition0(binaryExpression.Left, binaryExpression.Right, conditionOnRight => + //递归获取 + if (binaryExpression.Left is BinaryExpression binaryExpression1) + left = ParsePropertyCondition(binaryExpression1); + if (binaryExpression.Right is BinaryExpression binaryExpression2) + right = ParsePropertyCondition(binaryExpression2); + + if (binaryExpression.Left is MethodCallExpression methodCallLeftExpression) { - var op = binaryExpression.NodeType switch + if (!methodCallLeftExpression.IsNamedComparison()) { - ExpressionType.GreaterThan => conditionOnRight ? ShardingOperatorEnum.GreaterThan : ShardingOperatorEnum.LessThan, - ExpressionType.GreaterThanOrEqual => conditionOnRight ? ShardingOperatorEnum.GreaterThanOrEqual : ShardingOperatorEnum.LessThanOrEqual, - ExpressionType.LessThan => conditionOnRight ? ShardingOperatorEnum.LessThan : ShardingOperatorEnum.GreaterThan, - ExpressionType.LessThanOrEqual => conditionOnRight ? ShardingOperatorEnum.LessThanOrEqual : ShardingOperatorEnum.GreaterThanOrEqual, - ExpressionType.Equal => ShardingOperatorEnum.Equal, - ExpressionType.NotEqual => ShardingOperatorEnum.NotEqual, - _ => ShardingOperatorEnum.UnKnown - }; - return op; - }); - } - return RoutePredicateExpression.Default; - } - - private RoutePredicateExpression ParseGetWhere(BinaryExpression binaryExpression) - { - RoutePredicateExpression left = RoutePredicateExpression.Default; - RoutePredicateExpression right = RoutePredicateExpression.Default; - - //递归获取 - if (binaryExpression.Left is BinaryExpression binaryExpression1) - left = ParseGetWhere(binaryExpression1); - if (binaryExpression.Right is BinaryExpression binaryExpression2) - right = ParseGetWhere(binaryExpression2); - - if (binaryExpression.Left is MethodCallExpression methodCallLeftExpression) - { - if (!methodCallLeftExpression.IsNamedComparison()) - { - left = Resolve(methodCallLeftExpression); + left = Resolve(methodCallLeftExpression); + } } - } - if (binaryExpression.Right is MethodCallExpression methodCallRightExpression) - { - if (!methodCallRightExpression.IsNamedComparison()) + if (binaryExpression.Right is MethodCallExpression methodCallRightExpression) { - right = Resolve(methodCallRightExpression); + if (!methodCallRightExpression.IsNamedComparison()) + { + right = Resolve(methodCallRightExpression); + } } - } - if (binaryExpression.Left is UnaryExpression unaryExpression1 && (binaryExpression.Right is MemberExpression&& !IsShardingKey(binaryExpression.Right, out var _))) - left = Resolve(unaryExpression1); - if (binaryExpression.Right is UnaryExpression unaryExpression2 && (binaryExpression.Left is MemberExpression && !IsShardingKey(binaryExpression.Left, out var _))) - right = Resolve(unaryExpression2); + if (binaryExpression.Left is UnaryExpression unaryExpression1 && + (binaryExpression.Right is MemberExpression)) + left = Resolve(unaryExpression1); + if (binaryExpression.Right is UnaryExpression unaryExpression2 && + (binaryExpression.Left is MemberExpression)) + right = Resolve(unaryExpression2); - //组合 - if (binaryExpression.NodeType == ExpressionType.AndAlso) - { - return left.And(right); - } - else if (binaryExpression.NodeType == ExpressionType.OrElse) - { - return left.Or(right); - } - //单个 - else - { - return ParseCondition(binaryExpression); + //组合 + if (binaryExpression.NodeType == ExpressionType.AndAlso) + { + return left.And(right); + } + else if (binaryExpression.NodeType == ExpressionType.OrElse) + { + return left.Or(right); + } + else + { + return RoutePredicateExpression.Default; + } } } } @@ -502,10 +617,12 @@ namespace ShardingCore.Core.Internal.Visitors IsShardingKey = isShardingKey; ShardingPropertyName = shardingPropertyName; } + /// /// 是否是分片字段 /// public bool IsShardingKey { get; } + /// /// 分片字段名称 /// diff --git a/src/ShardingCore/Sharding/Visitors/QueryableRouteDiscoverVisitorV2.cs b/src/ShardingCore/Sharding/Visitors/QueryableRouteDiscoverVisitorV2.cs index 59dd3ee4..4ccec293 100644 --- a/src/ShardingCore/Sharding/Visitors/QueryableRouteDiscoverVisitorV2.cs +++ b/src/ShardingCore/Sharding/Visitors/QueryableRouteDiscoverVisitorV2.cs @@ -1,638 +1,638 @@ -using System; -using System.Collections; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using System.Linq.Expressions; -using System.Reflection; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Query; -using ShardingCore.Core.EntityMetadatas; -using ShardingCore.Core.VirtualDatabase; -using ShardingCore.Core.VirtualRoutes; -using ShardingCore.Exceptions; -using ShardingCore.Extensions; -using ShardingCore.Sharding.Visitors; - -namespace ShardingCore.Core.Internal.Visitors -{ - /* - * @Author: xjm - * @Description: - * @Date: Monday, 28 December 2020 22:09:39 - * @Email: 326308290@qq.com - */ - public class QueryableRouteShardingTableDiscoverVisitorV2 : ShardingExpressionVisitor - { - private readonly EntityMetadata _entityMetadata; - private readonly Func> _keyToTailWithFilter; - - /// - /// 是否是分表路由 - /// - private readonly bool _shardingTableRoute; - - private LambdaExpression _entityLambdaExpression; - private readonly ShardingPredicateResult _noShardingPredicateResult = new ShardingPredicateResult(false, null); - private bool isIgnoreQueryFilter; - private RoutePredicateExpression _where = RoutePredicateExpression.Default; - - public QueryableRouteShardingTableDiscoverVisitorV2(EntityMetadata entityMetadata, - Func> keyToTailWithFilter, bool shardingTableRoute) - { - _entityMetadata = entityMetadata; - _keyToTailWithFilter = keyToTailWithFilter; - _shardingTableRoute = shardingTableRoute; - } - - /// - /// 获取路由表达式 - /// - /// - public RoutePredicateExpression GetRouteParseExpression() - { - if (_entityMetadata.QueryFilterExpression != null && !isIgnoreQueryFilter) - { - if (_entityLambdaExpression == null) - { - _entityLambdaExpression = _entityMetadata.QueryFilterExpression; - } - else - { - var body = Expression.AndAlso(_entityLambdaExpression.Body, - _entityMetadata.QueryFilterExpression.Body); - _entityLambdaExpression = Expression.Lambda(body, _entityLambdaExpression.Parameters[0]); - } - } - - if (_entityLambdaExpression != null) - { - var newWhere = Resolve(_entityLambdaExpression); - _where = _where.And(newWhere); - } - - return _where; - } - - - private bool IsShardingKey(Expression expression, out ShardingPredicateResult shardingPredicateResult) - { - if (expression is MemberExpression member) - { - if (member.Expression?.Type == _entityMetadata.EntityType || - MemberExpressionIsConvertAndOriginalIsEntityType(member)) - { - var isShardingKey = false; - if (_shardingTableRoute) - { - isShardingKey = _entityMetadata.ShardingTableProperties.ContainsKey(member.Member.Name); - } - else - { - isShardingKey = _entityMetadata.ShardingDataSourceProperties.ContainsKey(member.Member.Name); - } - - if (isShardingKey) - { - shardingPredicateResult = new ShardingPredicateResult(true, member.Member.Name); - return true; - } - } - } - - shardingPredicateResult = _noShardingPredicateResult; - return false; - } - - /// - /// 成员表达式是强转并且强转前的类型是当前对象 - /// - /// - /// - private bool MemberExpressionIsConvertAndOriginalIsEntityType(MemberExpression member) - { - return member.Expression?.NodeType == ExpressionType.Convert && - member.Expression is UnaryExpression unaryExpression && - unaryExpression.Operand.Type == _entityMetadata.EntityType; - } - - /// - /// 方法是否包含shardingKey xxx.invoke(shardingkey) eg. o=>new[]{}.Contains(o.Id) - /// - /// - /// - private ShardingPredicateResult IsMethodWrapShardingKey(MethodCallExpression methodCallExpression) - { - if (methodCallExpression.Arguments.IsNotEmpty()) - { - for (int i = 0; i < methodCallExpression.Arguments.Count; i++) - { - if (IsShardingKey(methodCallExpression.Arguments[i], out var result)) - return result; - } - } - - return _noShardingPredicateResult; - } - - private ShardingPredicateResult IsShardingWrapConstant(MethodCallExpression methodCallExpression) - { - if (methodCallExpression.Object != null) - { - if (IsShardingKey(methodCallExpression.Object, out var result)) - { - return result; - } - } - - return _noShardingPredicateResult; - } - - /// - /// 表达式是否可以获取值 - /// - /// - /// - private bool ExpressionCanGetValue(Expression expression) - { - return expression is ConstantExpression - || (expression is MemberExpression member && (member.Expression is ConstantExpression || - member.Expression is MemberExpression || - member.Expression is MemberExpression)) - || expression is MethodCallExpression - || (expression is UnaryExpression unaryExpression && - unaryExpression.NodeType is ExpressionType.Convert) - || expression.NodeType == ExpressionType.ArrayIndex; - } - - private bool IsMethodCall(Expression expression) - { - return expression is MethodCallExpression; - } - - protected override Expression VisitMethodCall(MethodCallExpression node) - { - switch (node.Method.Name) - { - case nameof(EntityFrameworkQueryableExtensions.IgnoreQueryFilters): - isIgnoreQueryFilter = true; - break; - case nameof(Queryable.Where): - CombineEntityLambdaExpression(node); - break; - } - - return base.VisitMethodCall(node); - } - - private void CombineEntityLambdaExpression(MethodCallExpression node) - { - if (node.Arguments[1] is UnaryExpression unaryExpression) - { - if (unaryExpression.Operand is LambdaExpression lambdaExpression) - { - if (lambdaExpression.Parameters[0].Type == _entityMetadata.EntityType) - { - if (_entityLambdaExpression == null) - { - _entityLambdaExpression = lambdaExpression; - } - else - { - var body = Expression.AndAlso(_entityLambdaExpression.Body, lambdaExpression.Body); - var lambda = Expression.Lambda(body, _entityLambdaExpression.Parameters[0]); - _entityLambdaExpression = lambda; - } - } - } - } - } - - - private RoutePredicateExpression Resolve(Expression expression) - { - if (expression is LambdaExpression lambda) - { - expression = lambda.Body; - return Resolve(expression); - } - - //解析左右结构属性判断 - if (expression is BinaryExpression binaryExpression) //解析二元运算符 - { - return ParsePropertyCondition(binaryExpression); - } - - if (expression is UnaryExpression unary) //解析一元运算符 - { - if (unary.Operand is MethodCallExpression unaryCallExpression) - { - // return ResolveLinqToObject(unary.Operand, false); - return ResolveInFunc(unaryCallExpression, unary.NodeType != ExpressionType.Not); - } - } - - if (expression is MethodCallExpression methodCallExpression) //解析方法 - { - return ResolveInFunc(methodCallExpression, true); - } - - return RoutePredicateExpression.Default; - } - - private RoutePredicateExpression ResolveInFunc(MethodCallExpression methodCallExpression, bool @in) - { - if (methodCallExpression.IsEnumerableContains(methodCallExpression.Method.Name)) - { - var shardingPredicateResult = IsMethodWrapShardingKey(methodCallExpression); - if (shardingPredicateResult.IsShardingKey) - { - object arrayObject = null; - if (methodCallExpression.Object != null) - { - if (methodCallExpression.Object is MemberExpression member1Expression) - { - arrayObject = GetExpressionValue(member1Expression); - } - else if (methodCallExpression.Object is ListInitExpression member2Expression) - { - arrayObject = GetExpressionValue(member2Expression); - } - } - else if (methodCallExpression.Arguments[0] is MemberExpression member2Expression) - { - arrayObject = GetExpressionValue(member2Expression); - } - else if (methodCallExpression.Arguments[0] is NewArrayExpression member3Expression) - { - arrayObject = GetExpressionValue(member3Expression); - } - - if (arrayObject != null) - { - var contains = @in ? RoutePredicateExpression.DefaultFalse : RoutePredicateExpression.Default; - - - if (arrayObject is IEnumerable enumerableObj) - { - foreach (var shardingValue in enumerableObj) - { - var eq = _keyToTailWithFilter(shardingValue, - @in ? ShardingOperatorEnum.Equal : ShardingOperatorEnum.NotEqual, - shardingPredicateResult.ShardingPropertyName); - if (@in) - contains = contains.Or(new RoutePredicateExpression(eq)); - else - contains = contains.And(new RoutePredicateExpression(eq)); - } - } - - return contains; - } - } - } - - if (methodCallExpression.IsNamedEquals()) - { - //"".equals(o.id) - var shardingPredicateResult = IsMethodWrapShardingKey(methodCallExpression); - if (shardingPredicateResult.IsShardingKey) - { - var shardingValue = GetExpressionValue(methodCallExpression.Object); - if (shardingValue != null) - { - var keyToTailWithFilter = _keyToTailWithFilter(shardingValue, ShardingOperatorEnum.Equal, - shardingPredicateResult.ShardingPropertyName); - return new RoutePredicateExpression(keyToTailWithFilter); - } - } - else - { - //o.id.equals("") - shardingPredicateResult = IsShardingWrapConstant(methodCallExpression); - if (shardingPredicateResult.IsShardingKey) - { - object shardingValue = default; - if (methodCallExpression.Arguments[0] is MemberExpression member2Expression) - { - shardingValue = GetExpressionValue(member2Expression); - } - else if (methodCallExpression.Arguments[0] is ConstantExpression constantExpression) - { - shardingValue = GetExpressionValue(constantExpression); - } - - if (shardingValue != default) - { - var keyToTailWithFilter = _keyToTailWithFilter(shardingValue, ShardingOperatorEnum.Equal, - shardingPredicateResult.ShardingPropertyName); - return new RoutePredicateExpression(keyToTailWithFilter); - } - } - } - } - - //if (methodCallExpression.IsNamedCompareOrdinal()) - //{ - - //} - - //var shardingKeyValue = GetShardingKeyValue(methodCallExpression); - return RoutePredicateExpression.Default; - } - - private ShardingOperatorEnum GetParseCompareShardingOperatorEnum(bool conditionOnRight, - ExpressionType expressionType, int compare) - { - if (compare == 1) - { - return expressionType switch - { - ExpressionType.GreaterThanOrEqual => conditionOnRight - ? ShardingOperatorEnum.GreaterThan - : ShardingOperatorEnum.LessThan, //1 - ExpressionType.GreaterThan => ShardingOperatorEnum.UnKnown, //无 - ExpressionType.LessThanOrEqual => ShardingOperatorEnum.UnKnown, //1,0,-1 = 无 - ExpressionType.LessThan => conditionOnRight - ? ShardingOperatorEnum.LessThanOrEqual - : ShardingOperatorEnum.GreaterThanOrEqual, //0,-1 - ExpressionType.Equal => conditionOnRight - ? ShardingOperatorEnum.GreaterThan - : ShardingOperatorEnum.LessThan, //1 - ExpressionType.NotEqual => ShardingOperatorEnum.NotEqual, - _ => ShardingOperatorEnum.UnKnown - }; - } - - if (compare == 0) - { - return expressionType switch - { - ExpressionType.GreaterThanOrEqual => conditionOnRight - ? ShardingOperatorEnum.GreaterThanOrEqual - : ShardingOperatorEnum.LessThanOrEqual, //0,1 - ExpressionType.GreaterThan => conditionOnRight - ? ShardingOperatorEnum.GreaterThan - : ShardingOperatorEnum.LessThan, //1 - ExpressionType.LessThanOrEqual => conditionOnRight - ? ShardingOperatorEnum.LessThanOrEqual - : ShardingOperatorEnum.GreaterThanOrEqual, //0,-1 - ExpressionType.LessThan => conditionOnRight - ? ShardingOperatorEnum.LessThan - : ShardingOperatorEnum.GreaterThan, //-1 - ExpressionType.Equal => ShardingOperatorEnum.Equal, - ExpressionType.NotEqual => ShardingOperatorEnum.NotEqual, - _ => ShardingOperatorEnum.UnKnown - }; - } - - if (compare == -1) - { - return expressionType switch - { - ExpressionType.GreaterThanOrEqual => ShardingOperatorEnum.UnKnown, //-1,0,1 - ExpressionType.GreaterThan => conditionOnRight - ? ShardingOperatorEnum.GreaterThanOrEqual - : ShardingOperatorEnum.LessThanOrEqual, //0,1 - ExpressionType.LessThanOrEqual => conditionOnRight - ? ShardingOperatorEnum.LessThan - : ShardingOperatorEnum.GreaterThan, //-1 - ExpressionType.LessThan => ShardingOperatorEnum.UnKnown, //无 - ExpressionType.Equal => conditionOnRight - ? ShardingOperatorEnum.LessThan - : ShardingOperatorEnum.GreaterThan, //1 - ExpressionType.NotEqual => ShardingOperatorEnum.NotEqual, - _ => ShardingOperatorEnum.UnKnown - }; - } - - return ShardingOperatorEnum.UnKnown; - } - - private RoutePredicateExpression ParseCompare(MethodCallExpression methodCallExpression, Expression left, - Expression right, ExpressionType expressionType, int compare) - { - if (left.Type == right.Type) - { - if (methodCallExpression.Method.ReturnType == typeof(int)) - { - return ParseCondition0(left, right, expressionType, - (conditionOnRight, nodeType) => - GetParseCompareShardingOperatorEnum(conditionOnRight, nodeType, compare)); - } - } - - return RoutePredicateExpression.Default; - } - - private RoutePredicateExpression ParseConditionOnRight0(bool conditionOnRight, - ShardingPredicateResult predicateLeftResult, - Expression conditionExpression, ExpressionType expressionType) - { - if (ExpressionCanGetValue(conditionExpression)) - { - var shardingPropertyName = predicateLeftResult.ShardingPropertyName; - var value = GetExpressionValue(conditionExpression); - - if (shardingPropertyName == null || value == default) - return RoutePredicateExpression.Default; - var op = _shardingOperatorFunc(conditionOnRight, expressionType); - - - return new RoutePredicateExpression(_keyToTailWithFilter(value, op, shardingPropertyName)); - } - else - return RoutePredicateExpression.Default; - } - - private RoutePredicateExpression ParseCondition0(Expression left, Expression right, - ExpressionType expressionType, Func shardingOperatorFunc) - { - if (IsShardingKey(left, out var predicateLeftResult)) - { - return ParseConditionOnRight0(true, predicateLeftResult, right, expressionType); - } - else if (IsShardingKey(right, out var predicateRightResult)) - { - return ParseConditionOnRight0(false, predicateRightResult, left, expressionType); - } - else - return RoutePredicateExpression.Default; - } - - private RoutePredicateExpression ParseNamedComparison(BinaryExpression binaryExpression, - MethodCallExpression methodCallExpression) - { - if (methodCallExpression.GetComparisonLeftAndRight(out var result)) - { - return ParseCompare(methodCallExpression, result.Left, result.Right, - binaryExpression.NodeType, (int)GetExpressionValue(binaryExpression.Right)); - } - - return RoutePredicateExpression.Default; - } - - private static readonly Func _shardingOperatorFunc = - (conditionOnRight, nodeType) => - { - var op = nodeType switch - { - ExpressionType.GreaterThan => conditionOnRight - ? ShardingOperatorEnum.GreaterThan - : ShardingOperatorEnum.LessThan, - ExpressionType.GreaterThanOrEqual => conditionOnRight - ? ShardingOperatorEnum.GreaterThanOrEqual - : ShardingOperatorEnum.LessThanOrEqual, - ExpressionType.LessThan => conditionOnRight - ? ShardingOperatorEnum.LessThan - : ShardingOperatorEnum.GreaterThan, - ExpressionType.LessThanOrEqual => conditionOnRight - ? ShardingOperatorEnum.LessThanOrEqual - : ShardingOperatorEnum.GreaterThanOrEqual, - ExpressionType.Equal => ShardingOperatorEnum.Equal, - ExpressionType.NotEqual => ShardingOperatorEnum.NotEqual, - _ => ShardingOperatorEnum.UnKnown - }; - return op; - }; - - // private RoutePredicateExpression ParseGetWhere(BinaryExpression binaryExpression) - // { - // RoutePredicateExpression left = RoutePredicateExpression.Default; - // RoutePredicateExpression right = RoutePredicateExpression.Default; - // - // //递归获取 - // if (binaryExpression.Left is BinaryExpression binaryExpression1) - // left = ParseGetWhere(binaryExpression1); - // if (binaryExpression.Right is BinaryExpression binaryExpression2) - // right = ParseGetWhere(binaryExpression2); - // - // if (binaryExpression.Left is MethodCallExpression methodCallLeftExpression) - // { - // if (!methodCallLeftExpression.IsNamedComparison()) - // { - // left = Resolve(methodCallLeftExpression); - // } - // } - // - // if (binaryExpression.Right is MethodCallExpression methodCallRightExpression) - // { - // if (!methodCallRightExpression.IsNamedComparison()) - // { - // right = Resolve(methodCallRightExpression); - // } - // } - // - // if (binaryExpression.Left is UnaryExpression unaryExpression1 && (binaryExpression.Right is MemberExpression&& !IsShardingKey(binaryExpression.Right, out var _))) - // left = Resolve(unaryExpression1); - // if (binaryExpression.Right is UnaryExpression unaryExpression2 && (binaryExpression.Left is MemberExpression && !IsShardingKey(binaryExpression.Left, out var _))) - // right = Resolve(unaryExpression2); - // - // //组合 - // if (binaryExpression.NodeType == ExpressionType.AndAlso) - // { - // return left.And(right); - // } - // else if (binaryExpression.NodeType == ExpressionType.OrElse) - // { - // return left.Or(right); - // } - // //单个 - // else - // { - // return ParseCondition(binaryExpression); - // } - // } - - - private RoutePredicateExpression ParsePropertyCondition(BinaryExpression binaryExpression) - { - // RoutePredicateExpression left = RoutePredicateExpression.Default; - // RoutePredicateExpression right = RoutePredicateExpression.Default; - //左边是属性判断是否是分片的 - if (IsShardingKey(binaryExpression.Left, out var predicateLeftResult)) - { - return ParseConditionOnRight0(true, predicateLeftResult, binaryExpression.Right, - binaryExpression.NodeType); - } - else if (IsShardingKey(binaryExpression.Right, out var predicateRightResult)) - { - return ParseConditionOnRight0(false, predicateRightResult, binaryExpression.Left, - binaryExpression.NodeType); - } - else if (binaryExpression.IsNamedComparison(out var methodCallExpression)) - { - return ParseNamedComparison(binaryExpression, methodCallExpression); - } - else - { - RoutePredicateExpression left = RoutePredicateExpression.Default; - RoutePredicateExpression right = RoutePredicateExpression.Default; - - //递归获取 - if (binaryExpression.Left is BinaryExpression binaryExpression1) - left = ParsePropertyCondition(binaryExpression1); - if (binaryExpression.Right is BinaryExpression binaryExpression2) - right = ParsePropertyCondition(binaryExpression2); - - if (binaryExpression.Left is MethodCallExpression methodCallLeftExpression) - { - if (!methodCallLeftExpression.IsNamedComparison()) - { - left = Resolve(methodCallLeftExpression); - } - } - - if (binaryExpression.Right is MethodCallExpression methodCallRightExpression) - { - if (!methodCallRightExpression.IsNamedComparison()) - { - right = Resolve(methodCallRightExpression); - } - } - - if (binaryExpression.Left is UnaryExpression unaryExpression1 && - (binaryExpression.Right is MemberExpression)) - left = Resolve(unaryExpression1); - if (binaryExpression.Right is UnaryExpression unaryExpression2 && - (binaryExpression.Left is MemberExpression)) - right = Resolve(unaryExpression2); - - //组合 - if (binaryExpression.NodeType == ExpressionType.AndAlso) - { - return left.And(right); - } - else if (binaryExpression.NodeType == ExpressionType.OrElse) - { - return left.Or(right); - } - else - { - return RoutePredicateExpression.Default; - } - } - } - } - - // /// - // /// 分片条件结果 - // /// - // internal class ShardingPredicateResult - // { - // public ShardingPredicateResult(bool isShardingKey, string shardingPropertyName) - // { - // IsShardingKey = isShardingKey; - // ShardingPropertyName = shardingPropertyName; - // } - // /// - // /// 是否是分片字段 - // /// - // public bool IsShardingKey { get; } - // /// - // /// 分片字段名称 - // /// - // public string ShardingPropertyName { get; } - // } -} \ No newline at end of file +// using System; +// using System.Collections; +// using System.Collections.Concurrent; +// using System.Collections.Generic; +// using System.Diagnostics; +// using System.Linq; +// using System.Linq.Expressions; +// using System.Reflection; +// using Microsoft.EntityFrameworkCore; +// using Microsoft.EntityFrameworkCore.Query; +// using ShardingCore.Core.EntityMetadatas; +// using ShardingCore.Core.VirtualDatabase; +// using ShardingCore.Core.VirtualRoutes; +// using ShardingCore.Exceptions; +// using ShardingCore.Extensions; +// using ShardingCore.Sharding.Visitors; +// +// namespace ShardingCore.Core.Internal.Visitors +// { +// /* +// * @Author: xjm +// * @Description: +// * @Date: Monday, 28 December 2020 22:09:39 +// * @Email: 326308290@qq.com +// */ +// public class QueryableRouteShardingTableDiscoverVisitorV2 : ShardingExpressionVisitor +// { +// private readonly EntityMetadata _entityMetadata; +// private readonly Func> _keyToTailWithFilter; +// +// /// +// /// 是否是分表路由 +// /// +// private readonly bool _shardingTableRoute; +// +// private LambdaExpression _entityLambdaExpression; +// private readonly ShardingPredicateResult _noShardingPredicateResult = new ShardingPredicateResult(false, null); +// private bool isIgnoreQueryFilter; +// private RoutePredicateExpression _where = RoutePredicateExpression.Default; +// +// public QueryableRouteShardingTableDiscoverVisitorV2(EntityMetadata entityMetadata, +// Func> keyToTailWithFilter, bool shardingTableRoute) +// { +// _entityMetadata = entityMetadata; +// _keyToTailWithFilter = keyToTailWithFilter; +// _shardingTableRoute = shardingTableRoute; +// } +// +// /// +// /// 获取路由表达式 +// /// +// /// +// public RoutePredicateExpression GetRouteParseExpression() +// { +// if (_entityMetadata.QueryFilterExpression != null && !isIgnoreQueryFilter) +// { +// if (_entityLambdaExpression == null) +// { +// _entityLambdaExpression = _entityMetadata.QueryFilterExpression; +// } +// else +// { +// var body = Expression.AndAlso(_entityLambdaExpression.Body, +// _entityMetadata.QueryFilterExpression.Body); +// _entityLambdaExpression = Expression.Lambda(body, _entityLambdaExpression.Parameters[0]); +// } +// } +// +// if (_entityLambdaExpression != null) +// { +// var newWhere = Resolve(_entityLambdaExpression); +// _where = _where.And(newWhere); +// } +// +// return _where; +// } +// +// +// private bool IsShardingKey(Expression expression, out ShardingPredicateResult shardingPredicateResult) +// { +// if (expression is MemberExpression member) +// { +// if (member.Expression?.Type == _entityMetadata.EntityType || +// MemberExpressionIsConvertAndOriginalIsEntityType(member)) +// { +// var isShardingKey = false; +// if (_shardingTableRoute) +// { +// isShardingKey = _entityMetadata.ShardingTableProperties.ContainsKey(member.Member.Name); +// } +// else +// { +// isShardingKey = _entityMetadata.ShardingDataSourceProperties.ContainsKey(member.Member.Name); +// } +// +// if (isShardingKey) +// { +// shardingPredicateResult = new ShardingPredicateResult(true, member.Member.Name); +// return true; +// } +// } +// } +// +// shardingPredicateResult = _noShardingPredicateResult; +// return false; +// } +// +// /// +// /// 成员表达式是强转并且强转前的类型是当前对象 +// /// +// /// +// /// +// private bool MemberExpressionIsConvertAndOriginalIsEntityType(MemberExpression member) +// { +// return member.Expression?.NodeType == ExpressionType.Convert && +// member.Expression is UnaryExpression unaryExpression && +// unaryExpression.Operand.Type == _entityMetadata.EntityType; +// } +// +// /// +// /// 方法是否包含shardingKey xxx.invoke(shardingkey) eg. o=>new[]{}.Contains(o.Id) +// /// +// /// +// /// +// private ShardingPredicateResult IsMethodWrapShardingKey(MethodCallExpression methodCallExpression) +// { +// if (methodCallExpression.Arguments.IsNotEmpty()) +// { +// for (int i = 0; i < methodCallExpression.Arguments.Count; i++) +// { +// if (IsShardingKey(methodCallExpression.Arguments[i], out var result)) +// return result; +// } +// } +// +// return _noShardingPredicateResult; +// } +// +// private ShardingPredicateResult IsShardingWrapConstant(MethodCallExpression methodCallExpression) +// { +// if (methodCallExpression.Object != null) +// { +// if (IsShardingKey(methodCallExpression.Object, out var result)) +// { +// return result; +// } +// } +// +// return _noShardingPredicateResult; +// } +// +// /// +// /// 表达式是否可以获取值 +// /// +// /// +// /// +// private bool ExpressionCanGetValue(Expression expression) +// { +// return expression is ConstantExpression +// || (expression is MemberExpression member && (member.Expression is ConstantExpression || +// member.Expression is MemberExpression || +// member.Expression is MemberExpression)) +// || expression is MethodCallExpression +// || (expression is UnaryExpression unaryExpression && +// unaryExpression.NodeType is ExpressionType.Convert) +// || expression.NodeType == ExpressionType.ArrayIndex; +// } +// +// private bool IsMethodCall(Expression expression) +// { +// return expression is MethodCallExpression; +// } +// +// protected override Expression VisitMethodCall(MethodCallExpression node) +// { +// switch (node.Method.Name) +// { +// case nameof(EntityFrameworkQueryableExtensions.IgnoreQueryFilters): +// isIgnoreQueryFilter = true; +// break; +// case nameof(Queryable.Where): +// CombineEntityLambdaExpression(node); +// break; +// } +// +// return base.VisitMethodCall(node); +// } +// +// private void CombineEntityLambdaExpression(MethodCallExpression node) +// { +// if (node.Arguments[1] is UnaryExpression unaryExpression) +// { +// if (unaryExpression.Operand is LambdaExpression lambdaExpression) +// { +// if (lambdaExpression.Parameters[0].Type == _entityMetadata.EntityType) +// { +// if (_entityLambdaExpression == null) +// { +// _entityLambdaExpression = lambdaExpression; +// } +// else +// { +// var body = Expression.AndAlso(_entityLambdaExpression.Body, lambdaExpression.Body); +// var lambda = Expression.Lambda(body, _entityLambdaExpression.Parameters[0]); +// _entityLambdaExpression = lambda; +// } +// } +// } +// } +// } +// +// +// private RoutePredicateExpression Resolve(Expression expression) +// { +// if (expression is LambdaExpression lambda) +// { +// expression = lambda.Body; +// return Resolve(expression); +// } +// +// //解析左右结构属性判断 +// if (expression is BinaryExpression binaryExpression) //解析二元运算符 +// { +// return ParsePropertyCondition(binaryExpression); +// } +// +// if (expression is UnaryExpression unary) //解析一元运算符 +// { +// if (unary.Operand is MethodCallExpression unaryCallExpression) +// { +// // return ResolveLinqToObject(unary.Operand, false); +// return ResolveInFunc(unaryCallExpression, unary.NodeType != ExpressionType.Not); +// } +// } +// +// if (expression is MethodCallExpression methodCallExpression) //解析方法 +// { +// return ResolveInFunc(methodCallExpression, true); +// } +// +// return RoutePredicateExpression.Default; +// } +// +// private RoutePredicateExpression ResolveInFunc(MethodCallExpression methodCallExpression, bool @in) +// { +// if (methodCallExpression.IsEnumerableContains(methodCallExpression.Method.Name)) +// { +// var shardingPredicateResult = IsMethodWrapShardingKey(methodCallExpression); +// if (shardingPredicateResult.IsShardingKey) +// { +// object arrayObject = null; +// if (methodCallExpression.Object != null) +// { +// if (methodCallExpression.Object is MemberExpression member1Expression) +// { +// arrayObject = GetExpressionValue(member1Expression); +// } +// else if (methodCallExpression.Object is ListInitExpression member2Expression) +// { +// arrayObject = GetExpressionValue(member2Expression); +// } +// } +// else if (methodCallExpression.Arguments[0] is MemberExpression member2Expression) +// { +// arrayObject = GetExpressionValue(member2Expression); +// } +// else if (methodCallExpression.Arguments[0] is NewArrayExpression member3Expression) +// { +// arrayObject = GetExpressionValue(member3Expression); +// } +// +// if (arrayObject != null) +// { +// var contains = @in ? RoutePredicateExpression.DefaultFalse : RoutePredicateExpression.Default; +// +// +// if (arrayObject is IEnumerable enumerableObj) +// { +// foreach (var shardingValue in enumerableObj) +// { +// var eq = _keyToTailWithFilter(shardingValue, +// @in ? ShardingOperatorEnum.Equal : ShardingOperatorEnum.NotEqual, +// shardingPredicateResult.ShardingPropertyName); +// if (@in) +// contains = contains.Or(new RoutePredicateExpression(eq)); +// else +// contains = contains.And(new RoutePredicateExpression(eq)); +// } +// } +// +// return contains; +// } +// } +// } +// +// if (methodCallExpression.IsNamedEquals()) +// { +// //"".equals(o.id) +// var shardingPredicateResult = IsMethodWrapShardingKey(methodCallExpression); +// if (shardingPredicateResult.IsShardingKey) +// { +// var shardingValue = GetExpressionValue(methodCallExpression.Object); +// if (shardingValue != null) +// { +// var keyToTailWithFilter = _keyToTailWithFilter(shardingValue, ShardingOperatorEnum.Equal, +// shardingPredicateResult.ShardingPropertyName); +// return new RoutePredicateExpression(keyToTailWithFilter); +// } +// } +// else +// { +// //o.id.equals("") +// shardingPredicateResult = IsShardingWrapConstant(methodCallExpression); +// if (shardingPredicateResult.IsShardingKey) +// { +// object shardingValue = default; +// if (methodCallExpression.Arguments[0] is MemberExpression member2Expression) +// { +// shardingValue = GetExpressionValue(member2Expression); +// } +// else if (methodCallExpression.Arguments[0] is ConstantExpression constantExpression) +// { +// shardingValue = GetExpressionValue(constantExpression); +// } +// +// if (shardingValue != default) +// { +// var keyToTailWithFilter = _keyToTailWithFilter(shardingValue, ShardingOperatorEnum.Equal, +// shardingPredicateResult.ShardingPropertyName); +// return new RoutePredicateExpression(keyToTailWithFilter); +// } +// } +// } +// } +// +// //if (methodCallExpression.IsNamedCompareOrdinal()) +// //{ +// +// //} +// +// //var shardingKeyValue = GetShardingKeyValue(methodCallExpression); +// return RoutePredicateExpression.Default; +// } +// +// private ShardingOperatorEnum GetParseCompareShardingOperatorEnum(bool conditionOnRight, +// ExpressionType expressionType, int compare) +// { +// if (compare == 1) +// { +// return expressionType switch +// { +// ExpressionType.GreaterThanOrEqual => conditionOnRight +// ? ShardingOperatorEnum.GreaterThan +// : ShardingOperatorEnum.LessThan, //1 +// ExpressionType.GreaterThan => ShardingOperatorEnum.UnKnown, //无 +// ExpressionType.LessThanOrEqual => ShardingOperatorEnum.UnKnown, //1,0,-1 = 无 +// ExpressionType.LessThan => conditionOnRight +// ? ShardingOperatorEnum.LessThanOrEqual +// : ShardingOperatorEnum.GreaterThanOrEqual, //0,-1 +// ExpressionType.Equal => conditionOnRight +// ? ShardingOperatorEnum.GreaterThan +// : ShardingOperatorEnum.LessThan, //1 +// ExpressionType.NotEqual => ShardingOperatorEnum.NotEqual, +// _ => ShardingOperatorEnum.UnKnown +// }; +// } +// +// if (compare == 0) +// { +// return expressionType switch +// { +// ExpressionType.GreaterThanOrEqual => conditionOnRight +// ? ShardingOperatorEnum.GreaterThanOrEqual +// : ShardingOperatorEnum.LessThanOrEqual, //0,1 +// ExpressionType.GreaterThan => conditionOnRight +// ? ShardingOperatorEnum.GreaterThan +// : ShardingOperatorEnum.LessThan, //1 +// ExpressionType.LessThanOrEqual => conditionOnRight +// ? ShardingOperatorEnum.LessThanOrEqual +// : ShardingOperatorEnum.GreaterThanOrEqual, //0,-1 +// ExpressionType.LessThan => conditionOnRight +// ? ShardingOperatorEnum.LessThan +// : ShardingOperatorEnum.GreaterThan, //-1 +// ExpressionType.Equal => ShardingOperatorEnum.Equal, +// ExpressionType.NotEqual => ShardingOperatorEnum.NotEqual, +// _ => ShardingOperatorEnum.UnKnown +// }; +// } +// +// if (compare == -1) +// { +// return expressionType switch +// { +// ExpressionType.GreaterThanOrEqual => ShardingOperatorEnum.UnKnown, //-1,0,1 +// ExpressionType.GreaterThan => conditionOnRight +// ? ShardingOperatorEnum.GreaterThanOrEqual +// : ShardingOperatorEnum.LessThanOrEqual, //0,1 +// ExpressionType.LessThanOrEqual => conditionOnRight +// ? ShardingOperatorEnum.LessThan +// : ShardingOperatorEnum.GreaterThan, //-1 +// ExpressionType.LessThan => ShardingOperatorEnum.UnKnown, //无 +// ExpressionType.Equal => conditionOnRight +// ? ShardingOperatorEnum.LessThan +// : ShardingOperatorEnum.GreaterThan, //1 +// ExpressionType.NotEqual => ShardingOperatorEnum.NotEqual, +// _ => ShardingOperatorEnum.UnKnown +// }; +// } +// +// return ShardingOperatorEnum.UnKnown; +// } +// +// private RoutePredicateExpression ParseCompare(MethodCallExpression methodCallExpression, Expression left, +// Expression right, ExpressionType expressionType, int compare) +// { +// if (left.Type == right.Type) +// { +// if (methodCallExpression.Method.ReturnType == typeof(int)) +// { +// return ParseCondition0(left, right, expressionType, +// (conditionOnRight, nodeType) => +// GetParseCompareShardingOperatorEnum(conditionOnRight, nodeType, compare)); +// } +// } +// +// return RoutePredicateExpression.Default; +// } +// +// private RoutePredicateExpression ParseConditionOnRight0(bool conditionOnRight, +// ShardingPredicateResult predicateLeftResult, +// Expression conditionExpression, ExpressionType expressionType) +// { +// if (ExpressionCanGetValue(conditionExpression)) +// { +// var shardingPropertyName = predicateLeftResult.ShardingPropertyName; +// var value = GetExpressionValue(conditionExpression); +// +// if (shardingPropertyName == null || value == default) +// return RoutePredicateExpression.Default; +// var op = _shardingOperatorFunc(conditionOnRight, expressionType); +// +// +// return new RoutePredicateExpression(_keyToTailWithFilter(value, op, shardingPropertyName)); +// } +// else +// return RoutePredicateExpression.Default; +// } +// +// private RoutePredicateExpression ParseCondition0(Expression left, Expression right, +// ExpressionType expressionType, Func shardingOperatorFunc) +// { +// if (IsShardingKey(left, out var predicateLeftResult)) +// { +// return ParseConditionOnRight0(true, predicateLeftResult, right, expressionType); +// } +// else if (IsShardingKey(right, out var predicateRightResult)) +// { +// return ParseConditionOnRight0(false, predicateRightResult, left, expressionType); +// } +// else +// return RoutePredicateExpression.Default; +// } +// +// private RoutePredicateExpression ParseNamedComparison(BinaryExpression binaryExpression, +// MethodCallExpression methodCallExpression) +// { +// if (methodCallExpression.GetComparisonLeftAndRight(out var result)) +// { +// return ParseCompare(methodCallExpression, result.Left, result.Right, +// binaryExpression.NodeType, (int)GetExpressionValue(binaryExpression.Right)); +// } +// +// return RoutePredicateExpression.Default; +// } +// +// private static readonly Func _shardingOperatorFunc = +// (conditionOnRight, nodeType) => +// { +// var op = nodeType switch +// { +// ExpressionType.GreaterThan => conditionOnRight +// ? ShardingOperatorEnum.GreaterThan +// : ShardingOperatorEnum.LessThan, +// ExpressionType.GreaterThanOrEqual => conditionOnRight +// ? ShardingOperatorEnum.GreaterThanOrEqual +// : ShardingOperatorEnum.LessThanOrEqual, +// ExpressionType.LessThan => conditionOnRight +// ? ShardingOperatorEnum.LessThan +// : ShardingOperatorEnum.GreaterThan, +// ExpressionType.LessThanOrEqual => conditionOnRight +// ? ShardingOperatorEnum.LessThanOrEqual +// : ShardingOperatorEnum.GreaterThanOrEqual, +// ExpressionType.Equal => ShardingOperatorEnum.Equal, +// ExpressionType.NotEqual => ShardingOperatorEnum.NotEqual, +// _ => ShardingOperatorEnum.UnKnown +// }; +// return op; +// }; +// +// // private RoutePredicateExpression ParseGetWhere(BinaryExpression binaryExpression) +// // { +// // RoutePredicateExpression left = RoutePredicateExpression.Default; +// // RoutePredicateExpression right = RoutePredicateExpression.Default; +// // +// // //递归获取 +// // if (binaryExpression.Left is BinaryExpression binaryExpression1) +// // left = ParseGetWhere(binaryExpression1); +// // if (binaryExpression.Right is BinaryExpression binaryExpression2) +// // right = ParseGetWhere(binaryExpression2); +// // +// // if (binaryExpression.Left is MethodCallExpression methodCallLeftExpression) +// // { +// // if (!methodCallLeftExpression.IsNamedComparison()) +// // { +// // left = Resolve(methodCallLeftExpression); +// // } +// // } +// // +// // if (binaryExpression.Right is MethodCallExpression methodCallRightExpression) +// // { +// // if (!methodCallRightExpression.IsNamedComparison()) +// // { +// // right = Resolve(methodCallRightExpression); +// // } +// // } +// // +// // if (binaryExpression.Left is UnaryExpression unaryExpression1 && (binaryExpression.Right is MemberExpression&& !IsShardingKey(binaryExpression.Right, out var _))) +// // left = Resolve(unaryExpression1); +// // if (binaryExpression.Right is UnaryExpression unaryExpression2 && (binaryExpression.Left is MemberExpression && !IsShardingKey(binaryExpression.Left, out var _))) +// // right = Resolve(unaryExpression2); +// // +// // //组合 +// // if (binaryExpression.NodeType == ExpressionType.AndAlso) +// // { +// // return left.And(right); +// // } +// // else if (binaryExpression.NodeType == ExpressionType.OrElse) +// // { +// // return left.Or(right); +// // } +// // //单个 +// // else +// // { +// // return ParseCondition(binaryExpression); +// // } +// // } +// +// +// private RoutePredicateExpression ParsePropertyCondition(BinaryExpression binaryExpression) +// { +// // RoutePredicateExpression left = RoutePredicateExpression.Default; +// // RoutePredicateExpression right = RoutePredicateExpression.Default; +// //左边是属性判断是否是分片的 +// if (IsShardingKey(binaryExpression.Left, out var predicateLeftResult)) +// { +// return ParseConditionOnRight0(true, predicateLeftResult, binaryExpression.Right, +// binaryExpression.NodeType); +// } +// else if (IsShardingKey(binaryExpression.Right, out var predicateRightResult)) +// { +// return ParseConditionOnRight0(false, predicateRightResult, binaryExpression.Left, +// binaryExpression.NodeType); +// } +// else if (binaryExpression.IsNamedComparison(out var methodCallExpression)) +// { +// return ParseNamedComparison(binaryExpression, methodCallExpression); +// } +// else +// { +// RoutePredicateExpression left = RoutePredicateExpression.Default; +// RoutePredicateExpression right = RoutePredicateExpression.Default; +// +// //递归获取 +// if (binaryExpression.Left is BinaryExpression binaryExpression1) +// left = ParsePropertyCondition(binaryExpression1); +// if (binaryExpression.Right is BinaryExpression binaryExpression2) +// right = ParsePropertyCondition(binaryExpression2); +// +// if (binaryExpression.Left is MethodCallExpression methodCallLeftExpression) +// { +// if (!methodCallLeftExpression.IsNamedComparison()) +// { +// left = Resolve(methodCallLeftExpression); +// } +// } +// +// if (binaryExpression.Right is MethodCallExpression methodCallRightExpression) +// { +// if (!methodCallRightExpression.IsNamedComparison()) +// { +// right = Resolve(methodCallRightExpression); +// } +// } +// +// if (binaryExpression.Left is UnaryExpression unaryExpression1 && +// (binaryExpression.Right is MemberExpression)) +// left = Resolve(unaryExpression1); +// if (binaryExpression.Right is UnaryExpression unaryExpression2 && +// (binaryExpression.Left is MemberExpression)) +// right = Resolve(unaryExpression2); +// +// //组合 +// if (binaryExpression.NodeType == ExpressionType.AndAlso) +// { +// return left.And(right); +// } +// else if (binaryExpression.NodeType == ExpressionType.OrElse) +// { +// return left.Or(right); +// } +// else +// { +// return RoutePredicateExpression.Default; +// } +// } +// } +// } +// +// // /// +// // /// 分片条件结果 +// // /// +// // internal class ShardingPredicateResult +// // { +// // public ShardingPredicateResult(bool isShardingKey, string shardingPropertyName) +// // { +// // IsShardingKey = isShardingKey; +// // ShardingPropertyName = shardingPropertyName; +// // } +// // /// +// // /// 是否是分片字段 +// // /// +// // public bool IsShardingKey { get; } +// // /// +// // /// 分片字段名称 +// // /// +// // public string ShardingPropertyName { get; } +// // } +// } \ No newline at end of file diff --git a/src/ShardingCore/Utils/ShardingUtil.cs b/src/ShardingCore/Utils/ShardingUtil.cs index 8ff5c2d6..5948b1e6 100644 --- a/src/ShardingCore/Utils/ShardingUtil.cs +++ b/src/ShardingCore/Utils/ShardingUtil.cs @@ -44,15 +44,6 @@ namespace ShardingCore.Utils return visitor.GetRouteParseExpression(); } - public static RoutePredicateExpression GetRouteParseExpressionV2(IQueryable queryable, EntityMetadata entityMetadata, Func> keyToTailExpression,bool shardingTableRoute) - { - - QueryableRouteShardingTableDiscoverVisitorV2 visitor = new QueryableRouteShardingTableDiscoverVisitorV2(entityMetadata, keyToTailExpression, shardingTableRoute); - - visitor.Visit(queryable.Expression); - - return visitor.GetRouteParseExpression(); - } } } \ No newline at end of file diff --git a/test/ShardingCore.CommonTest/ShardingDataSourceMod.cs b/test/ShardingCore.CommonTest/ShardingDataSourceMod.cs index df0b0897..81b59e92 100644 --- a/test/ShardingCore.CommonTest/ShardingDataSourceMod.cs +++ b/test/ShardingCore.CommonTest/ShardingDataSourceMod.cs @@ -12,14 +12,16 @@ namespace ShardingCore.CommonTest { private readonly EntityMetadata _testEntityMetadata; private readonly List _allDataSources; + public ShardingDataSourceMod() - { + { var entityMetadata = new EntityMetadata(typeof(TestEntity)); - var entityMetadataDataSourceBuilder = EntityMetadataDataSourceBuilder.CreateEntityMetadataDataSourceBuilder(entityMetadata); + var entityMetadataDataSourceBuilder = + EntityMetadataDataSourceBuilder.CreateEntityMetadataDataSourceBuilder(entityMetadata); entityMetadataDataSourceBuilder.ShardingProperty(o => o.Id); entityMetadata.CheckShardingDataSourceMetadata(); _testEntityMetadata = entityMetadata; - _allDataSources = Enumerable.Range(0,10).Select(o=>o.ToString()).ToList(); + _allDataSources = Enumerable.Range(0, 10).Select(o => o.ToString()).ToList(); } public static Func GetRouteFilter(object shardingValue, ShardingOperatorEnum shardingOperator, @@ -31,7 +33,7 @@ namespace ShardingCore.CommonTest } var stringHashCode = ShardingCoreHelper.GetStringHashCode(shardingValue.ToString()); - var dataSourceName = (stringHashCode%10).ToString(); + var dataSourceName = (stringHashCode % 10).ToString(); switch (shardingOperator) { case ShardingOperatorEnum.Equal: return t => t == dataSourceName; @@ -44,16 +46,17 @@ namespace ShardingCore.CommonTest private void TestId(IQueryable queryable, string[] dataSourceNames) { - var routePredicateExpression = ShardingUtil.GetRouteParseExpressionV2(queryable,_testEntityMetadata,GetRouteFilter,false); + var routePredicateExpression = + ShardingUtil.GetRouteParseExpression(queryable, _testEntityMetadata, GetRouteFilter, false); Assert.NotNull(routePredicateExpression); var routePredicate = routePredicateExpression.GetRoutePredicate(); - + var list = _allDataSources.Where(routePredicate).ToList(); Assert.NotNull(list); - Assert.Equal(dataSourceNames.Length,list.Count); + Assert.Equal(dataSourceNames.Length, list.Count); foreach (var dataSourceName in dataSourceNames) { - Assert.True(list.Any(o=>o==dataSourceName)); + Assert.True(list.Any(o => o == dataSourceName)); } } @@ -64,68 +67,81 @@ namespace ShardingCore.CommonTest TestId(queryable, dataSourceNames); } } + [Fact] public void TestSingleDataSource() { var stringHashCode = ShardingCoreHelper.GetStringHashCode("1"); - var dataSourceName = (stringHashCode%10).ToString(); - var dataSourceNames = new []{dataSourceName}; + var dataSourceName = (stringHashCode % 10).ToString(); + var dataSourceNames = new[] { dataSourceName }; + var dataSourceNames1 = Enumerable.Range(0, 10).Select(o => o.ToString()).ToArray();; var id = "1"; - var ids = new []{"1"}; - var ids1 = new List(){"1"}; - var obj1 = new {Id="1"}; - var queryables=new List>() + var ids = new[] { "1" }; + var ids1 = new List() { "1" }; + var obj1 = new { Id = "1" }; + var queryables = new List>() { - new List().AsQueryable().Where(o=>o.Id=="1"), - new List().AsQueryable().Where(o=>o.Id=="1"&&o.Id!="2"), - new List().AsQueryable().Where(o=>"1"==o.Id), - new List().AsQueryable().Where(o=>o.Id==id), - new List().AsQueryable().Where(o=>id==o.Id), - new List().AsQueryable().Where(o=>o.Id.Equals("1")), - new List().AsQueryable().Where(o=>"1".Equals(o.Id)), - new List().AsQueryable().Where(o=>o.Id.Equals(id)), - new List().AsQueryable().Where(o=>o.Id.Equals(id)), - new List().AsQueryable().Where(o=>ids.Contains(o.Id)), - new List().AsQueryable().Where(o=>new []{"1"}.Contains(o.Id)), - new List().AsQueryable().Where(o=>ids1.Contains(o.Id)), - new List().AsQueryable().Where(o=>new List(){"1"}.Contains(o.Id)), - new List().AsQueryable().Where(o=>o.Id==obj1.Id), - new List().AsQueryable().Where(o=>obj1.Id==o.Id), - new List().AsQueryable().Where(o=>o.Id.Equals(obj1.Id)), - new List().AsQueryable().Where(o=>obj1.Id.Equals(o.Id)), - new List().AsQueryable().Where(o=>new []{obj1.Id}.Contains(o.Id)) + new List().AsQueryable().Where(o => o.Id == "1"), + new List().AsQueryable().Where(o => o.Id == "1" && o.Id != "2"), + new List().AsQueryable().Where(o => "1" == o.Id), + new List().AsQueryable().Where(o => o.Id == id), + new List().AsQueryable().Where(o => id == o.Id), + new List().AsQueryable().Where(o => o.Id.Equals("1")), + new List().AsQueryable().Where(o => "1".Equals(o.Id)), + new List().AsQueryable().Where(o => o.Id.Equals(id)), + new List().AsQueryable().Where(o => o.Id.Equals(id)), + new List().AsQueryable().Where(o => ids.Contains(o.Id)), + new List().AsQueryable().Where(o => new[] { "1" }.Contains(o.Id)), + new List().AsQueryable().Where(o => ids1.Contains(o.Id)), + new List().AsQueryable().Where(o => new List() { "1" }.Contains(o.Id)), + new List().AsQueryable().Where(o => o.Id == obj1.Id), + new List().AsQueryable().Where(o => obj1.Id == o.Id), + new List().AsQueryable().Where(o => o.Id.Equals(obj1.Id)), + new List().AsQueryable().Where(o => obj1.Id.Equals(o.Id)), + new List().AsQueryable().Where(o => new[] { obj1.Id }.Contains(o.Id)) }; - TestFor(queryables,dataSourceNames); + TestFor(queryables, dataSourceNames); + var queryables1 = new List>() + { + new List().AsQueryable().Where(o => o.Id.Contains("1")), + new List().AsQueryable().Where(o => o.Id.StartsWith("1")), + new List().AsQueryable().Where(o => o.Id.EndsWith("1")) + }; + TestFor(queryables1, dataSourceNames1); } [Fact] public void TestTwoDataSource() { - var dataSourceNames = new []{( ShardingCoreHelper.GetStringHashCode("1")%10).ToString(),( ShardingCoreHelper.GetStringHashCode("2")%10).ToString()}; - var ids = new []{"1","2"}; - var ids1 = new List(){"1","2"}; - var obj1 = new {Id="1"}; - var obj2 = new {Id="2"}; - var queryables=new List>() + var dataSourceNames = new[] { - new List().AsQueryable().Where(o=>o.Id=="1"||o.Id=="2"), - new List().AsQueryable().Where(o=>(o.Id=="1"||o.Id=="2")&&o.Id!="3"), - new List().AsQueryable().Where(o=>(o.Id=="1"||o.Id=="2")&&!o.Id.Equals("3")), - new List().AsQueryable().Where(o=>"1"==o.Id||o.Id=="2"), - new List().AsQueryable().Where(o=>"1"==o.Id||"2"==o.Id), - new List().AsQueryable().Where(o=>o.Id.Equals("1")||o.Id=="2"), - new List().AsQueryable().Where(o=>o.Id.Equals("1")||o.Id.Equals("2")), - new List().AsQueryable().Where(o=>"1".Equals(o.Id)||o.Id=="2"), - new List().AsQueryable().Where(o=>"1".Equals(o.Id)||o.Id.Equals("2")), - new List().AsQueryable().Where(o=>"1".Equals(o.Id)||"2".Equals(o.Id)), - new List().AsQueryable().Where(o=>ids.Contains(o.Id)), - new List().AsQueryable().Where(o=>new []{"1","2"}.Contains(o.Id)), - new List().AsQueryable().Where(o=>ids1.Contains(o.Id)), - new List().AsQueryable().Where(o=>new List(){"1","2"}.Contains(o.Id)), - new List().AsQueryable().Where(o=>new List(){obj1.Id,obj2.Id}.Contains(o.Id)), - new List().AsQueryable().Where(o=>new []{obj1.Id,obj2.Id}.Contains(o.Id)), + (ShardingCoreHelper.GetStringHashCode("1") % 10).ToString(), + (ShardingCoreHelper.GetStringHashCode("2") % 10).ToString() }; - TestFor(queryables,dataSourceNames); + var ids = new[] { "1", "2" }; + var ids1 = new List() { "1", "2" }; + var obj1 = new { Id = "1" }; + var obj2 = new { Id = "2" }; + var queryables = new List>() + { + new List().AsQueryable().Where(o => o.Id == "1" || o.Id == "2"), + new List().AsQueryable().Where(o => (o.Id == "1" || o.Id == "2") && o.Id != "3"), + new List().AsQueryable().Where(o => (o.Id == "1" || o.Id == "2") && !o.Id.Equals("3")), + new List().AsQueryable().Where(o => "1" == o.Id || o.Id == "2"), + new List().AsQueryable().Where(o => "1" == o.Id || "2" == o.Id), + new List().AsQueryable().Where(o => o.Id.Equals("1") || o.Id == "2"), + new List().AsQueryable().Where(o => o.Id.Equals("1") || o.Id.Equals("2")), + new List().AsQueryable().Where(o => "1".Equals(o.Id) || o.Id == "2"), + new List().AsQueryable().Where(o => "1".Equals(o.Id) || o.Id.Equals("2")), + new List().AsQueryable().Where(o => "1".Equals(o.Id) || "2".Equals(o.Id)), + new List().AsQueryable().Where(o => ids.Contains(o.Id)), + new List().AsQueryable().Where(o => new[] { "1", "2" }.Contains(o.Id)), + new List().AsQueryable().Where(o => ids1.Contains(o.Id)), + new List().AsQueryable().Where(o => new List() { "1", "2" }.Contains(o.Id)), + new List().AsQueryable().Where(o => new List() { obj1.Id, obj2.Id }.Contains(o.Id)), + new List().AsQueryable().Where(o => new[] { obj1.Id, obj2.Id }.Contains(o.Id)), + }; + TestFor(queryables, dataSourceNames); } } @@ -133,4 +149,4 @@ namespace ShardingCore.CommonTest { public string Id { get; set; } } -} +} \ No newline at end of file diff --git a/test/ShardingCore.CommonTest/ShardingTableTime.cs b/test/ShardingCore.CommonTest/ShardingTableTime.cs index f723a6bb..47500f6a 100644 --- a/test/ShardingCore.CommonTest/ShardingTableTime.cs +++ b/test/ShardingCore.CommonTest/ShardingTableTime.cs @@ -59,7 +59,7 @@ namespace ShardingCore.CommonTest private void TestId(IQueryable queryable, string[] tables) { - var routePredicateExpression = ShardingUtil.GetRouteParseExpressionV2(queryable,_testEntityMetadata,GetRouteFilter,true); + var routePredicateExpression = ShardingUtil.GetRouteParseExpression(queryable,_testEntityMetadata,GetRouteFilter,true); Assert.NotNull(routePredicateExpression); var routePredicate = routePredicateExpression.GetRoutePredicate();