[#148] 支持like操作符的提取
This commit is contained in:
parent
3f44744325
commit
a7e987d163
|
@ -24,12 +24,12 @@ namespace ShardingCore.Core.VirtualRoutes
|
||||||
Equal,
|
Equal,
|
||||||
[Description("!=")]
|
[Description("!=")]
|
||||||
NotEqual,
|
NotEqual,
|
||||||
// [Description("%w%")]
|
[Description("%w%")]
|
||||||
// AllLike,
|
AllLike,
|
||||||
// [Description("%w")]
|
[Description("%w")]
|
||||||
// StartLike,
|
StartLike,
|
||||||
// [Description("w%")]
|
[Description("w%")]
|
||||||
// EndLike
|
EndLike
|
||||||
// [Description("Contains")]
|
// [Description("Contains")]
|
||||||
// BeContains
|
// BeContains
|
||||||
}
|
}
|
||||||
|
|
|
@ -80,11 +80,26 @@ namespace ShardingCore.Extensions
|
||||||
/// 是否是集合contains方法
|
/// 是否是集合contains方法
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="express"></param>
|
/// <param name="express"></param>
|
||||||
/// <param name="methodName"></param>
|
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
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));
|
||||||
}
|
}
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 是否是equal方法
|
/// 是否是equal方法
|
||||||
|
|
|
@ -47,9 +47,14 @@ namespace ShardingCore.Extensions
|
||||||
{
|
{
|
||||||
return !source.IsEmpty();
|
return !source.IsEmpty();
|
||||||
}
|
}
|
||||||
public static bool IsIn<T>(this T thisValue, params T[] values)
|
|
||||||
|
private static readonly HashSet<string> _enumerableContainsNamespace = new HashSet<string>()
|
||||||
{
|
{
|
||||||
return values.Contains(thisValue);
|
"System.Linq", "System.Collections.Generic"
|
||||||
|
};
|
||||||
|
public static bool IsInEnumerable(this string thisValue)
|
||||||
|
{
|
||||||
|
return _enumerableContainsNamespace.Contains(thisValue);
|
||||||
}
|
}
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 按size分区,每个区size个数目
|
/// 按size分区,每个区size个数目
|
||||||
|
|
|
@ -25,19 +25,45 @@ namespace ShardingCore.Core.Internal.Visitors
|
||||||
*/
|
*/
|
||||||
public class QueryableRouteShardingTableDiscoverVisitor : ShardingExpressionVisitor
|
public class QueryableRouteShardingTableDiscoverVisitor : ShardingExpressionVisitor
|
||||||
{
|
{
|
||||||
|
private static readonly Func<bool, ExpressionType, ShardingOperatorEnum> _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 EntityMetadata _entityMetadata;
|
||||||
private readonly Func<object, ShardingOperatorEnum, string, Func<string, bool>> _keyToTailWithFilter;
|
private readonly Func<object, ShardingOperatorEnum, string, Func<string, bool>> _keyToTailWithFilter;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 是否是分表路由
|
/// 是否是分表路由
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private readonly bool _shardingTableRoute;
|
private readonly bool _shardingTableRoute;
|
||||||
|
|
||||||
private LambdaExpression _entityLambdaExpression;
|
private LambdaExpression _entityLambdaExpression;
|
||||||
private readonly ShardingPredicateResult _noShardingPredicateResult = new ShardingPredicateResult(false, null);
|
private readonly ShardingPredicateResult _noShardingPredicateResult = new ShardingPredicateResult(false, null);
|
||||||
private bool isIgnoreQueryFilter;
|
private bool isIgnoreQueryFilter;
|
||||||
private RoutePredicateExpression _where = RoutePredicateExpression.Default;
|
private RoutePredicateExpression _where = RoutePredicateExpression.Default;
|
||||||
|
|
||||||
public QueryableRouteShardingTableDiscoverVisitor(EntityMetadata entityMetadata, Func<object, ShardingOperatorEnum, string, Func<string, bool>> keyToTailWithFilter, bool shardingTableRoute)
|
public QueryableRouteShardingTableDiscoverVisitor(EntityMetadata entityMetadata,
|
||||||
|
Func<object, ShardingOperatorEnum, string, Func<string, bool>> keyToTailWithFilter, bool shardingTableRoute)
|
||||||
{
|
{
|
||||||
_entityMetadata = entityMetadata;
|
_entityMetadata = entityMetadata;
|
||||||
_keyToTailWithFilter = keyToTailWithFilter;
|
_keyToTailWithFilter = keyToTailWithFilter;
|
||||||
|
@ -50,7 +76,6 @@ namespace ShardingCore.Core.Internal.Visitors
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public RoutePredicateExpression GetRouteParseExpression()
|
public RoutePredicateExpression GetRouteParseExpression()
|
||||||
{
|
{
|
||||||
|
|
||||||
if (_entityMetadata.QueryFilterExpression != null && !isIgnoreQueryFilter)
|
if (_entityMetadata.QueryFilterExpression != null && !isIgnoreQueryFilter)
|
||||||
{
|
{
|
||||||
if (_entityLambdaExpression == null)
|
if (_entityLambdaExpression == null)
|
||||||
|
@ -59,7 +84,8 @@ namespace ShardingCore.Core.Internal.Visitors
|
||||||
}
|
}
|
||||||
else
|
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]);
|
_entityLambdaExpression = Expression.Lambda(body, _entityLambdaExpression.Parameters[0]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -69,6 +95,7 @@ namespace ShardingCore.Core.Internal.Visitors
|
||||||
var newWhere = Resolve(_entityLambdaExpression);
|
var newWhere = Resolve(_entityLambdaExpression);
|
||||||
_where = _where.And(newWhere);
|
_where = _where.And(newWhere);
|
||||||
}
|
}
|
||||||
|
|
||||||
return _where;
|
return _where;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,7 +104,8 @@ namespace ShardingCore.Core.Internal.Visitors
|
||||||
{
|
{
|
||||||
if (expression is MemberExpression member)
|
if (expression is MemberExpression member)
|
||||||
{
|
{
|
||||||
if (member.Expression?.Type == _entityMetadata.EntityType|| MemberExpressionIsConvertAndOriginalIsEntityType(member))
|
if (member.Expression?.Type == _entityMetadata.EntityType ||
|
||||||
|
MemberExpressionIsConvertAndOriginalIsEntityType(member))
|
||||||
{
|
{
|
||||||
var isShardingKey = false;
|
var isShardingKey = false;
|
||||||
if (_shardingTableRoute)
|
if (_shardingTableRoute)
|
||||||
|
@ -100,6 +128,7 @@ namespace ShardingCore.Core.Internal.Visitors
|
||||||
shardingPredicateResult = _noShardingPredicateResult;
|
shardingPredicateResult = _noShardingPredicateResult;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 成员表达式是强转并且强转前的类型是当前对象
|
/// 成员表达式是强转并且强转前的类型是当前对象
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -111,6 +140,7 @@ namespace ShardingCore.Core.Internal.Visitors
|
||||||
member.Expression is UnaryExpression unaryExpression &&
|
member.Expression is UnaryExpression unaryExpression &&
|
||||||
unaryExpression.Operand.Type == _entityMetadata.EntityType;
|
unaryExpression.Operand.Type == _entityMetadata.EntityType;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 方法是否包含shardingKey xxx.invoke(shardingkey) eg. <code>o=>new[]{}.Contains(o.Id)</code>
|
/// 方法是否包含shardingKey xxx.invoke(shardingkey) eg. <code>o=>new[]{}.Contains(o.Id)</code>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -126,6 +156,7 @@ namespace ShardingCore.Core.Internal.Visitors
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return _noShardingPredicateResult;
|
return _noShardingPredicateResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -138,14 +169,25 @@ namespace ShardingCore.Core.Internal.Visitors
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return _noShardingPredicateResult;
|
return _noShardingPredicateResult;
|
||||||
}
|
}
|
||||||
private bool IsConstantOrMember(Expression expression)
|
|
||||||
|
/// <summary>
|
||||||
|
/// 表达式是否可以获取值
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="expression"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
private bool ExpressionCanGetValue(Expression expression)
|
||||||
{
|
{
|
||||||
return expression is ConstantExpression
|
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 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)
|
private bool IsMethodCall(Expression expression)
|
||||||
|
@ -157,8 +199,12 @@ namespace ShardingCore.Core.Internal.Visitors
|
||||||
{
|
{
|
||||||
switch (node.Method.Name)
|
switch (node.Method.Name)
|
||||||
{
|
{
|
||||||
case nameof(EntityFrameworkQueryableExtensions.IgnoreQueryFilters): isIgnoreQueryFilter = true; break;
|
case nameof(EntityFrameworkQueryableExtensions.IgnoreQueryFilters):
|
||||||
case nameof(Queryable.Where): CombineEntityLambdaExpression(node); break;
|
isIgnoreQueryFilter = true;
|
||||||
|
break;
|
||||||
|
case nameof(Queryable.Where):
|
||||||
|
CombineEntityLambdaExpression(node);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return base.VisitMethodCall(node);
|
return base.VisitMethodCall(node);
|
||||||
|
@ -196,9 +242,10 @@ namespace ShardingCore.Core.Internal.Visitors
|
||||||
return Resolve(expression);
|
return Resolve(expression);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//解析左右结构属性判断
|
||||||
if (expression is BinaryExpression binaryExpression) //解析二元运算符
|
if (expression is BinaryExpression binaryExpression) //解析二元运算符
|
||||||
{
|
{
|
||||||
return ParseGetWhere(binaryExpression);
|
return ParsePropertyCondition(binaryExpression);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (expression is UnaryExpression unary) //解析一元运算符
|
if (expression is UnaryExpression unary) //解析一元运算符
|
||||||
|
@ -214,12 +261,13 @@ namespace ShardingCore.Core.Internal.Visitors
|
||||||
{
|
{
|
||||||
return ResolveInFunc(methodCallExpression, true);
|
return ResolveInFunc(methodCallExpression, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
return RoutePredicateExpression.Default;
|
return RoutePredicateExpression.Default;
|
||||||
}
|
}
|
||||||
|
|
||||||
private RoutePredicateExpression ResolveInFunc(MethodCallExpression methodCallExpression, bool @in)
|
private RoutePredicateExpression ResolveInFunc(MethodCallExpression methodCallExpression, bool @in)
|
||||||
{
|
{
|
||||||
if (methodCallExpression.IsEnumerableContains(methodCallExpression.Method.Name))
|
if (methodCallExpression.IsEnumerableContains())
|
||||||
{
|
{
|
||||||
var shardingPredicateResult = IsMethodWrapShardingKey(methodCallExpression);
|
var shardingPredicateResult = IsMethodWrapShardingKey(methodCallExpression);
|
||||||
if (shardingPredicateResult.IsShardingKey)
|
if (shardingPredicateResult.IsShardingKey)
|
||||||
|
@ -254,19 +302,60 @@ namespace ShardingCore.Core.Internal.Visitors
|
||||||
{
|
{
|
||||||
foreach (var shardingValue in 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)
|
if (@in)
|
||||||
contains = contains.Or(new RoutePredicateExpression(eq));
|
contains = contains.Or(new RoutePredicateExpression(eq));
|
||||||
else
|
else
|
||||||
contains = contains.And(new RoutePredicateExpression(eq));
|
contains = contains.And(new RoutePredicateExpression(eq));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return contains;
|
return contains;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (methodCallExpression.IsStringContains())
|
||||||
if (methodCallExpression.IsNamedEquals())
|
{
|
||||||
|
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)
|
//"".equals(o.id)
|
||||||
var shardingPredicateResult = IsMethodWrapShardingKey(methodCallExpression);
|
var shardingPredicateResult = IsMethodWrapShardingKey(methodCallExpression);
|
||||||
|
@ -275,7 +364,8 @@ namespace ShardingCore.Core.Internal.Visitors
|
||||||
var shardingValue = GetExpressionValue(methodCallExpression.Object);
|
var shardingValue = GetExpressionValue(methodCallExpression.Object);
|
||||||
if (shardingValue != null)
|
if (shardingValue != null)
|
||||||
{
|
{
|
||||||
var keyToTailWithFilter = _keyToTailWithFilter(shardingValue, ShardingOperatorEnum.Equal, shardingPredicateResult.ShardingPropertyName);
|
var keyToTailWithFilter = _keyToTailWithFilter(shardingValue, ShardingOperatorEnum.Equal,
|
||||||
|
shardingPredicateResult.ShardingPropertyName);
|
||||||
return new RoutePredicateExpression(keyToTailWithFilter);
|
return new RoutePredicateExpression(keyToTailWithFilter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -297,7 +387,8 @@ namespace ShardingCore.Core.Internal.Visitors
|
||||||
|
|
||||||
if (shardingValue != default)
|
if (shardingValue != default)
|
||||||
{
|
{
|
||||||
var keyToTailWithFilter = _keyToTailWithFilter(shardingValue, ShardingOperatorEnum.Equal, shardingPredicateResult.ShardingPropertyName);
|
var keyToTailWithFilter = _keyToTailWithFilter(shardingValue, ShardingOperatorEnum.Equal,
|
||||||
|
shardingPredicateResult.ShardingPropertyName);
|
||||||
return new RoutePredicateExpression(keyToTailWithFilter);
|
return new RoutePredicateExpression(keyToTailWithFilter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -313,30 +404,45 @@ namespace ShardingCore.Core.Internal.Visitors
|
||||||
return RoutePredicateExpression.Default;
|
return RoutePredicateExpression.Default;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ShardingOperatorEnum GetParseCompareShardingOperatorEnum(bool conditionOnRight, ExpressionType expressionType, int compare)
|
private ShardingOperatorEnum GetParseCompareShardingOperatorEnum(bool conditionOnRight,
|
||||||
|
ExpressionType expressionType, int compare)
|
||||||
{
|
{
|
||||||
if (compare == 1)
|
if (compare == 1)
|
||||||
{
|
{
|
||||||
return expressionType switch
|
return expressionType switch
|
||||||
{
|
{
|
||||||
ExpressionType.GreaterThanOrEqual => conditionOnRight ? ShardingOperatorEnum.GreaterThan : ShardingOperatorEnum.LessThan,//1
|
ExpressionType.GreaterThanOrEqual => conditionOnRight
|
||||||
|
? ShardingOperatorEnum.GreaterThan
|
||||||
|
: ShardingOperatorEnum.LessThan, //1
|
||||||
ExpressionType.GreaterThan => ShardingOperatorEnum.UnKnown, //无
|
ExpressionType.GreaterThan => ShardingOperatorEnum.UnKnown, //无
|
||||||
ExpressionType.LessThanOrEqual => ShardingOperatorEnum.UnKnown, //1,0,-1 = 无
|
ExpressionType.LessThanOrEqual => ShardingOperatorEnum.UnKnown, //1,0,-1 = 无
|
||||||
ExpressionType.LessThan => conditionOnRight ? ShardingOperatorEnum.LessThanOrEqual : ShardingOperatorEnum.GreaterThanOrEqual,//0,-1
|
ExpressionType.LessThan => conditionOnRight
|
||||||
ExpressionType.Equal => conditionOnRight ? ShardingOperatorEnum.GreaterThan : ShardingOperatorEnum.LessThan,//1
|
? ShardingOperatorEnum.LessThanOrEqual
|
||||||
|
: ShardingOperatorEnum.GreaterThanOrEqual, //0,-1
|
||||||
|
ExpressionType.Equal => conditionOnRight
|
||||||
|
? ShardingOperatorEnum.GreaterThan
|
||||||
|
: ShardingOperatorEnum.LessThan, //1
|
||||||
ExpressionType.NotEqual => ShardingOperatorEnum.NotEqual,
|
ExpressionType.NotEqual => ShardingOperatorEnum.NotEqual,
|
||||||
_ => ShardingOperatorEnum.UnKnown
|
_ => ShardingOperatorEnum.UnKnown
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (compare == 0)
|
if (compare == 0)
|
||||||
{
|
{
|
||||||
return expressionType switch
|
return expressionType switch
|
||||||
{
|
{
|
||||||
ExpressionType.GreaterThanOrEqual => conditionOnRight ? ShardingOperatorEnum.GreaterThanOrEqual : ShardingOperatorEnum.LessThanOrEqual,//0,1
|
ExpressionType.GreaterThanOrEqual => conditionOnRight
|
||||||
ExpressionType.GreaterThan => conditionOnRight ? ShardingOperatorEnum.GreaterThan: ShardingOperatorEnum.LessThan,//1
|
? ShardingOperatorEnum.GreaterThanOrEqual
|
||||||
ExpressionType.LessThanOrEqual => conditionOnRight ? ShardingOperatorEnum.LessThanOrEqual : ShardingOperatorEnum.GreaterThanOrEqual,//0,-1
|
: ShardingOperatorEnum.LessThanOrEqual, //0,1
|
||||||
ExpressionType.LessThan => conditionOnRight ? ShardingOperatorEnum.LessThan : ShardingOperatorEnum.GreaterThan,//-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.Equal => ShardingOperatorEnum.Equal,
|
||||||
ExpressionType.NotEqual => ShardingOperatorEnum.NotEqual,
|
ExpressionType.NotEqual => ShardingOperatorEnum.NotEqual,
|
||||||
_ => ShardingOperatorEnum.UnKnown
|
_ => ShardingOperatorEnum.UnKnown
|
||||||
|
@ -348,110 +454,117 @@ namespace ShardingCore.Core.Internal.Visitors
|
||||||
return expressionType switch
|
return expressionType switch
|
||||||
{
|
{
|
||||||
ExpressionType.GreaterThanOrEqual => ShardingOperatorEnum.UnKnown, //-1,0,1
|
ExpressionType.GreaterThanOrEqual => ShardingOperatorEnum.UnKnown, //-1,0,1
|
||||||
ExpressionType.GreaterThan => conditionOnRight? ShardingOperatorEnum.GreaterThanOrEqual: ShardingOperatorEnum.LessThanOrEqual,//0,1
|
ExpressionType.GreaterThan => conditionOnRight
|
||||||
ExpressionType.LessThanOrEqual => conditionOnRight? ShardingOperatorEnum.LessThan:ShardingOperatorEnum.GreaterThan,//-1
|
? ShardingOperatorEnum.GreaterThanOrEqual
|
||||||
|
: ShardingOperatorEnum.LessThanOrEqual, //0,1
|
||||||
|
ExpressionType.LessThanOrEqual => conditionOnRight
|
||||||
|
? ShardingOperatorEnum.LessThan
|
||||||
|
: ShardingOperatorEnum.GreaterThan, //-1
|
||||||
ExpressionType.LessThan => ShardingOperatorEnum.UnKnown, //无
|
ExpressionType.LessThan => ShardingOperatorEnum.UnKnown, //无
|
||||||
ExpressionType.Equal => conditionOnRight ? ShardingOperatorEnum.LessThan : ShardingOperatorEnum.GreaterThan,//1
|
ExpressionType.Equal => conditionOnRight
|
||||||
|
? ShardingOperatorEnum.LessThan
|
||||||
|
: ShardingOperatorEnum.GreaterThan, //1
|
||||||
ExpressionType.NotEqual => ShardingOperatorEnum.NotEqual,
|
ExpressionType.NotEqual => ShardingOperatorEnum.NotEqual,
|
||||||
_ => ShardingOperatorEnum.UnKnown
|
_ => ShardingOperatorEnum.UnKnown
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return 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 (left.Type == right.Type)
|
||||||
{
|
{
|
||||||
if (methodCallExpression.Method.ReturnType == typeof(int))
|
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;
|
return RoutePredicateExpression.Default;
|
||||||
}
|
}
|
||||||
|
|
||||||
private RoutePredicateExpression ParseCondition0(Expression left, Expression right,Func<bool,ShardingOperatorEnum> shardingOperatorFunc)
|
private RoutePredicateExpression ParseConditionOnRight0(bool conditionOnRight,
|
||||||
|
ShardingPredicateResult predicateLeftResult,
|
||||||
|
Expression conditionExpression, ExpressionType expressionType)
|
||||||
{
|
{
|
||||||
|
if (ExpressionCanGetValue(conditionExpression))
|
||||||
bool conditionOnRight = false;
|
|
||||||
string shardingPropertyName = null;
|
|
||||||
object value = default;
|
|
||||||
|
|
||||||
|
|
||||||
if (IsShardingKey(left, out var predicateLeftResult) && IsConstantOrMember(right))
|
|
||||||
{
|
{
|
||||||
if (predicateLeftResult.IsShardingKey)
|
var shardingPropertyName = predicateLeftResult.ShardingPropertyName;
|
||||||
{
|
var value = GetExpressionValue(conditionExpression);
|
||||||
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
|
|
||||||
return RoutePredicateExpression.Default;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return RoutePredicateExpression.Default;
|
|
||||||
var op = shardingOperatorFunc(conditionOnRight);
|
|
||||||
|
|
||||||
if (shardingPropertyName == null || value == default)
|
if (shardingPropertyName == null || value == default)
|
||||||
return RoutePredicateExpression.Default;
|
return RoutePredicateExpression.Default;
|
||||||
|
var op = _shardingOperatorFunc(conditionOnRight, expressionType);
|
||||||
|
|
||||||
|
|
||||||
return new RoutePredicateExpression(_keyToTailWithFilter(value, op, shardingPropertyName));
|
return new RoutePredicateExpression(_keyToTailWithFilter(value, op, shardingPropertyName));
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
return RoutePredicateExpression.Default;
|
||||||
|
}
|
||||||
|
|
||||||
private RoutePredicateExpression ParseCondition(BinaryExpression binaryExpression)
|
private RoutePredicateExpression ParseCondition0(Expression left, Expression right,
|
||||||
|
ExpressionType expressionType, Func<bool, ExpressionType, ShardingOperatorEnum> shardingOperatorFunc)
|
||||||
{
|
{
|
||||||
if (binaryExpression.IsNamedComparison(out var methodCallExpression))
|
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))
|
if (methodCallExpression.GetComparisonLeftAndRight(out var result))
|
||||||
{
|
{
|
||||||
return ParseCompare(methodCallExpression, result.Left, result.Right,
|
return ParseCompare(methodCallExpression, result.Left, result.Right,
|
||||||
binaryExpression.NodeType, (int)GetExpressionValue(binaryExpression.Right));
|
binaryExpression.NodeType, (int)GetExpressionValue(binaryExpression.Right));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
|
|
||||||
return ParseCondition0(binaryExpression.Left, binaryExpression.Right, conditionOnRight =>
|
|
||||||
{
|
|
||||||
var op = binaryExpression.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;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return RoutePredicateExpression.Default;
|
return RoutePredicateExpression.Default;
|
||||||
}
|
}
|
||||||
|
|
||||||
private RoutePredicateExpression ParseGetWhere(BinaryExpression 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 left = RoutePredicateExpression.Default;
|
||||||
RoutePredicateExpression right = RoutePredicateExpression.Default;
|
RoutePredicateExpression right = RoutePredicateExpression.Default;
|
||||||
|
|
||||||
//递归获取
|
//递归获取
|
||||||
if (binaryExpression.Left is BinaryExpression binaryExpression1)
|
if (binaryExpression.Left is BinaryExpression binaryExpression1)
|
||||||
left = ParseGetWhere(binaryExpression1);
|
left = ParsePropertyCondition(binaryExpression1);
|
||||||
if (binaryExpression.Right is BinaryExpression binaryExpression2)
|
if (binaryExpression.Right is BinaryExpression binaryExpression2)
|
||||||
right = ParseGetWhere(binaryExpression2);
|
right = ParsePropertyCondition(binaryExpression2);
|
||||||
|
|
||||||
if (binaryExpression.Left is MethodCallExpression methodCallLeftExpression)
|
if (binaryExpression.Left is MethodCallExpression methodCallLeftExpression)
|
||||||
{
|
{
|
||||||
|
@ -469,9 +582,11 @@ namespace ShardingCore.Core.Internal.Visitors
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (binaryExpression.Left is UnaryExpression unaryExpression1 && (binaryExpression.Right is MemberExpression&& !IsShardingKey(binaryExpression.Right, out var _)))
|
if (binaryExpression.Left is UnaryExpression unaryExpression1 &&
|
||||||
|
(binaryExpression.Right is MemberExpression))
|
||||||
left = Resolve(unaryExpression1);
|
left = Resolve(unaryExpression1);
|
||||||
if (binaryExpression.Right is UnaryExpression unaryExpression2 && (binaryExpression.Left is MemberExpression && !IsShardingKey(binaryExpression.Left, out var _)))
|
if (binaryExpression.Right is UnaryExpression unaryExpression2 &&
|
||||||
|
(binaryExpression.Left is MemberExpression))
|
||||||
right = Resolve(unaryExpression2);
|
right = Resolve(unaryExpression2);
|
||||||
|
|
||||||
//组合
|
//组合
|
||||||
|
@ -483,10 +598,10 @@ namespace ShardingCore.Core.Internal.Visitors
|
||||||
{
|
{
|
||||||
return left.Or(right);
|
return left.Or(right);
|
||||||
}
|
}
|
||||||
//单个
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return ParseCondition(binaryExpression);
|
return RoutePredicateExpression.Default;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -502,10 +617,12 @@ namespace ShardingCore.Core.Internal.Visitors
|
||||||
IsShardingKey = isShardingKey;
|
IsShardingKey = isShardingKey;
|
||||||
ShardingPropertyName = shardingPropertyName;
|
ShardingPropertyName = shardingPropertyName;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 是否是分片字段
|
/// 是否是分片字段
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool IsShardingKey { get; }
|
public bool IsShardingKey { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 分片字段名称
|
/// 分片字段名称
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -44,15 +44,6 @@ namespace ShardingCore.Utils
|
||||||
|
|
||||||
return visitor.GetRouteParseExpression();
|
return visitor.GetRouteParseExpression();
|
||||||
}
|
}
|
||||||
public static RoutePredicateExpression GetRouteParseExpressionV2(IQueryable queryable, EntityMetadata entityMetadata, Func<object, ShardingOperatorEnum,string, Func<string, bool>> keyToTailExpression,bool shardingTableRoute)
|
|
||||||
{
|
|
||||||
|
|
||||||
QueryableRouteShardingTableDiscoverVisitorV2 visitor = new QueryableRouteShardingTableDiscoverVisitorV2(entityMetadata, keyToTailExpression, shardingTableRoute);
|
|
||||||
|
|
||||||
visitor.Visit(queryable.Expression);
|
|
||||||
|
|
||||||
return visitor.GetRouteParseExpression();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -12,10 +12,12 @@ namespace ShardingCore.CommonTest
|
||||||
{
|
{
|
||||||
private readonly EntityMetadata _testEntityMetadata;
|
private readonly EntityMetadata _testEntityMetadata;
|
||||||
private readonly List<string> _allDataSources;
|
private readonly List<string> _allDataSources;
|
||||||
|
|
||||||
public ShardingDataSourceMod()
|
public ShardingDataSourceMod()
|
||||||
{
|
{
|
||||||
var entityMetadata = new EntityMetadata(typeof(TestEntity));
|
var entityMetadata = new EntityMetadata(typeof(TestEntity));
|
||||||
var entityMetadataDataSourceBuilder = EntityMetadataDataSourceBuilder<TestEntity>.CreateEntityMetadataDataSourceBuilder(entityMetadata);
|
var entityMetadataDataSourceBuilder =
|
||||||
|
EntityMetadataDataSourceBuilder<TestEntity>.CreateEntityMetadataDataSourceBuilder(entityMetadata);
|
||||||
entityMetadataDataSourceBuilder.ShardingProperty(o => o.Id);
|
entityMetadataDataSourceBuilder.ShardingProperty(o => o.Id);
|
||||||
entityMetadata.CheckShardingDataSourceMetadata();
|
entityMetadata.CheckShardingDataSourceMetadata();
|
||||||
_testEntityMetadata = entityMetadata;
|
_testEntityMetadata = entityMetadata;
|
||||||
|
@ -44,7 +46,8 @@ namespace ShardingCore.CommonTest
|
||||||
|
|
||||||
private void TestId(IQueryable<TestEntity> queryable, string[] dataSourceNames)
|
private void TestId(IQueryable<TestEntity> queryable, string[] dataSourceNames)
|
||||||
{
|
{
|
||||||
var routePredicateExpression = ShardingUtil.GetRouteParseExpressionV2(queryable,_testEntityMetadata,GetRouteFilter,false);
|
var routePredicateExpression =
|
||||||
|
ShardingUtil.GetRouteParseExpression(queryable, _testEntityMetadata, GetRouteFilter, false);
|
||||||
Assert.NotNull(routePredicateExpression);
|
Assert.NotNull(routePredicateExpression);
|
||||||
var routePredicate = routePredicateExpression.GetRoutePredicate();
|
var routePredicate = routePredicateExpression.GetRoutePredicate();
|
||||||
|
|
||||||
|
@ -64,12 +67,14 @@ namespace ShardingCore.CommonTest
|
||||||
TestId(queryable, dataSourceNames);
|
TestId(queryable, dataSourceNames);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void TestSingleDataSource()
|
public void TestSingleDataSource()
|
||||||
{
|
{
|
||||||
var stringHashCode = ShardingCoreHelper.GetStringHashCode("1");
|
var stringHashCode = ShardingCoreHelper.GetStringHashCode("1");
|
||||||
var dataSourceName = (stringHashCode % 10).ToString();
|
var dataSourceName = (stringHashCode % 10).ToString();
|
||||||
var dataSourceNames = new[] { dataSourceName };
|
var dataSourceNames = new[] { dataSourceName };
|
||||||
|
var dataSourceNames1 = Enumerable.Range(0, 10).Select(o => o.ToString()).ToArray();;
|
||||||
var id = "1";
|
var id = "1";
|
||||||
var ids = new[] { "1" };
|
var ids = new[] { "1" };
|
||||||
var ids1 = new List<string>() { "1" };
|
var ids1 = new List<string>() { "1" };
|
||||||
|
@ -96,12 +101,23 @@ namespace ShardingCore.CommonTest
|
||||||
new List<TestEntity>().AsQueryable().Where(o => new[] { obj1.Id }.Contains(o.Id))
|
new List<TestEntity>().AsQueryable().Where(o => new[] { obj1.Id }.Contains(o.Id))
|
||||||
};
|
};
|
||||||
TestFor(queryables, dataSourceNames);
|
TestFor(queryables, dataSourceNames);
|
||||||
|
var queryables1 = new List<IQueryable<TestEntity>>()
|
||||||
|
{
|
||||||
|
new List<TestEntity>().AsQueryable().Where(o => o.Id.Contains("1")),
|
||||||
|
new List<TestEntity>().AsQueryable().Where(o => o.Id.StartsWith("1")),
|
||||||
|
new List<TestEntity>().AsQueryable().Where(o => o.Id.EndsWith("1"))
|
||||||
|
};
|
||||||
|
TestFor(queryables1, dataSourceNames1);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void TestTwoDataSource()
|
public void TestTwoDataSource()
|
||||||
{
|
{
|
||||||
var dataSourceNames = new []{( ShardingCoreHelper.GetStringHashCode("1")%10).ToString(),( ShardingCoreHelper.GetStringHashCode("2")%10).ToString()};
|
var dataSourceNames = new[]
|
||||||
|
{
|
||||||
|
(ShardingCoreHelper.GetStringHashCode("1") % 10).ToString(),
|
||||||
|
(ShardingCoreHelper.GetStringHashCode("2") % 10).ToString()
|
||||||
|
};
|
||||||
var ids = new[] { "1", "2" };
|
var ids = new[] { "1", "2" };
|
||||||
var ids1 = new List<string>() { "1", "2" };
|
var ids1 = new List<string>() { "1", "2" };
|
||||||
var obj1 = new { Id = "1" };
|
var obj1 = new { Id = "1" };
|
||||||
|
|
|
@ -59,7 +59,7 @@ namespace ShardingCore.CommonTest
|
||||||
|
|
||||||
private void TestId(IQueryable<TestTimeEntity> queryable, string[] tables)
|
private void TestId(IQueryable<TestTimeEntity> queryable, string[] tables)
|
||||||
{
|
{
|
||||||
var routePredicateExpression = ShardingUtil.GetRouteParseExpressionV2(queryable,_testEntityMetadata,GetRouteFilter,true);
|
var routePredicateExpression = ShardingUtil.GetRouteParseExpression(queryable,_testEntityMetadata,GetRouteFilter,true);
|
||||||
Assert.NotNull(routePredicateExpression);
|
Assert.NotNull(routePredicateExpression);
|
||||||
var routePredicate = routePredicateExpression.GetRoutePredicate();
|
var routePredicate = routePredicateExpression.GetRoutePredicate();
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue