diff --git a/samples/Sample.SqlServerShardingTable/VirtualRoutes/OrderHashRangeVirtualTableRoute.cs b/samples/Sample.SqlServerShardingTable/VirtualRoutes/OrderHashRangeVirtualTableRoute.cs new file mode 100644 index 00000000..7f994a5e --- /dev/null +++ b/samples/Sample.SqlServerShardingTable/VirtualRoutes/OrderHashRangeVirtualTableRoute.cs @@ -0,0 +1,62 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Threading.Tasks; +using Sample.SqlServerShardingTable.Entities; +using ShardingCore.Core.VirtualRoutes; +using ShardingCore.Core.VirtualRoutes.TableRoutes.Abstractions; +using ShardingCore.Helpers; + +namespace Sample.SqlServerShardingTable.VirtualRoutes +{ + public class OrderHashRangeVirtualTableRoute:AbstractShardingOperatorVirtualTableRoute<Order,string> + { + protected override string ConvertToShardingKey(object shardingKey) + { + return shardingKey.ToString(); + } + + public override string ShardingKeyToTail(object shardingKey) + { + var stringHashCode = ShardingCoreHelper.GetStringHashCode("123"); + var hashCode = stringHashCode % 10000; + if (hashCode >= 0 && hashCode <= 3000) + { + return "A"; + } + else if (hashCode >= 3001 && hashCode <= 6000) + { + return "B"; + } + else if (hashCode >= 6001 && hashCode <= 10000) + { + return "C"; + } + else + throw new InvalidOperationException($"cant calc hash route hash code:[{stringHashCode}]"); + } + + public override List<string> GetAllTails() + { + return new List<string>() + { + "A", "B", "C" + }; + } + + protected override Expression<Func<string, bool>> GetRouteToFilter(string shardingKey, ShardingOperatorEnum shardingOperator) + { + //因为hash路由仅支持等于所以仅仅只需要写等于的情况 + var t = ShardingKeyToTail(shardingKey); + switch (shardingOperator) + { + case ShardingOperatorEnum.Equal: return tail => tail == t; + default: + { + return tail => true; + } + } + } + } +} diff --git a/src/ShardingCore/Core/EntityMetadatas/DefaultEntityMetadataManager.cs b/src/ShardingCore/Core/EntityMetadatas/DefaultEntityMetadataManager.cs index f8a2cf1a..4be36c3b 100644 --- a/src/ShardingCore/Core/EntityMetadatas/DefaultEntityMetadataManager.cs +++ b/src/ShardingCore/Core/EntityMetadatas/DefaultEntityMetadataManager.cs @@ -8,7 +8,7 @@ using ShardingCore.Sharding.Abstractions; namespace ShardingCore.Core.EntityMetadatas { /// <summary> - /// 默认分片对象原数据管理者实现 + /// 默认分片对象元数据管理者实现 /// </summary> /// <typeparam name="TShardingDbContext"></typeparam> public class DefaultEntityMetadataManager<TShardingDbContext> : IEntityMetadataManager<TShardingDbContext> where TShardingDbContext : DbContext, IShardingDbContext diff --git a/src/ShardingCore/Extensions/IShardingQueryableExtension.cs b/src/ShardingCore/Extensions/IShardingQueryableExtension.cs index eb43ab37..ae90d9ce 100644 --- a/src/ShardingCore/Extensions/IShardingQueryableExtension.cs +++ b/src/ShardingCore/Extensions/IShardingQueryableExtension.cs @@ -70,16 +70,16 @@ namespace ShardingCore.Extensions } /// <summary> - /// 切换数据源,保留原数据源中的Expression + /// 切换数据源,保留原始数据源中的Expression /// </summary> - /// <param name="source">原数据源</param> - /// <param name="newSource">新数据源</param> + /// <param name="source">元数据源</param> + /// <param name="dbContext">新数据源</param> /// <returns></returns> internal static IQueryable ReplaceDbContextQueryable(this IQueryable source, DbContext dbContext) { DbContextReplaceQueryableVisitor replaceQueryableVisitor = new DbContextReplaceQueryableVisitor(dbContext); - var newExpre = replaceQueryableVisitor.Visit(source.Expression); - return replaceQueryableVisitor.Source.Provider.CreateQuery(newExpre); + var newExpression = replaceQueryableVisitor.Visit(source.Expression); + return replaceQueryableVisitor.Source.Provider.CreateQuery(newExpression); } } } \ No newline at end of file diff --git a/src/ShardingCore/Extensions/StringFieldOrderExtension.cs b/src/ShardingCore/Extensions/StringFieldOrderExtension.cs index 39bf82a2..6f764eb1 100644 --- a/src/ShardingCore/Extensions/StringFieldOrderExtension.cs +++ b/src/ShardingCore/Extensions/StringFieldOrderExtension.cs @@ -4,6 +4,8 @@ using System.Linq; using System.Linq.Expressions; using System.Reflection; using ShardingCore.Core.Internal.Visitors; +using ShardingCore.Sharding.Abstractions; +using ShardingCore.Sharding.Internals; namespace ShardingCore.Extensions { @@ -45,40 +47,51 @@ namespace ShardingCore.Extensions return Expression.Lambda(propertyAccess, parameter); } - private static MethodCallExpression GenerateMethodCall<TEntity>(IQueryable<TEntity> source, string methodName, String fieldName) + private static MethodCallExpression GenerateMethodCall<TEntity>(IQueryable<TEntity> source, string methodName, String fieldName,IShardingComparer shardingComparer=null) { Type type = typeof(TEntity); Type selectorResultType; LambdaExpression selector = GenerateSelector<TEntity>(fieldName, out selectorResultType); - MethodCallExpression resultExp = Expression.Call(typeof(Queryable), methodName, - new Type[] {type, selectorResultType}, - source.Expression, Expression.Quote(selector)); + MethodCallExpression resultExp; + if (shardingComparer == null) + { + resultExp = Expression.Call(typeof(Queryable), methodName, + new Type[] { type, selectorResultType }, + source.Expression, Expression.Quote(selector)); + } + else + { + var comparer = Activator.CreateInstance(typeof(InMemoryShardingComparer<>).GetGenericType0(selectorResultType), shardingComparer); + resultExp = Expression.Call(typeof(Queryable), methodName, + new Type[] { type, selectorResultType }, + source.Expression, Expression.Quote(selector),Expression.Constant(comparer)); + } return resultExp; } #endregion - internal static IOrderedQueryable<TEntity> OrderBy<TEntity>(this IQueryable<TEntity> source, string fieldName) + internal static IOrderedQueryable<TEntity> OrderBy<TEntity>(this IQueryable<TEntity> source, string fieldName, IShardingComparer shardingComparer = null) { - MethodCallExpression resultExp = GenerateMethodCall<TEntity>(source, nameof(Queryable.OrderBy), fieldName); + MethodCallExpression resultExp = GenerateMethodCall<TEntity>(source, nameof(Queryable.OrderBy), fieldName, shardingComparer); return source.Provider.CreateQuery<TEntity>(resultExp) as IOrderedQueryable<TEntity>; } - internal static IOrderedQueryable<TEntity> OrderByDescending<TEntity>(this IQueryable<TEntity> source, string fieldName) + internal static IOrderedQueryable<TEntity> OrderByDescending<TEntity>(this IQueryable<TEntity> source, string fieldName, IShardingComparer shardingComparer = null) { - MethodCallExpression resultExp = GenerateMethodCall<TEntity>(source, nameof(Queryable.OrderByDescending), fieldName); + MethodCallExpression resultExp = GenerateMethodCall<TEntity>(source, nameof(Queryable.OrderByDescending), fieldName, shardingComparer); return source.Provider.CreateQuery<TEntity>(resultExp) as IOrderedQueryable<TEntity>; } - internal static IOrderedQueryable<TEntity> ThenBy<TEntity>(this IOrderedQueryable<TEntity> source, string fieldName) + internal static IOrderedQueryable<TEntity> ThenBy<TEntity>(this IOrderedQueryable<TEntity> source, string fieldName, IShardingComparer shardingComparer = null) { - MethodCallExpression resultExp = GenerateMethodCall<TEntity>(source, nameof(Queryable.ThenBy), fieldName); + MethodCallExpression resultExp = GenerateMethodCall<TEntity>(source, nameof(Queryable.ThenBy), fieldName, shardingComparer); return source.Provider.CreateQuery<TEntity>(resultExp) as IOrderedQueryable<TEntity>; } - internal static IOrderedQueryable<TEntity> ThenByDescending<TEntity>(this IOrderedQueryable<TEntity> source, string fieldName) + internal static IOrderedQueryable<TEntity> ThenByDescending<TEntity>(this IOrderedQueryable<TEntity> source, string fieldName, IShardingComparer shardingComparer = null) { - MethodCallExpression resultExp = GenerateMethodCall<TEntity>(source, nameof(Queryable.ThenByDescending), fieldName); + MethodCallExpression resultExp = GenerateMethodCall<TEntity>(source, nameof(Queryable.ThenByDescending), fieldName, shardingComparer); return source.Provider.CreateQuery<TEntity>(resultExp) as IOrderedQueryable<TEntity>; } /// <summary> @@ -86,9 +99,10 @@ namespace ShardingCore.Extensions /// </summary> /// <param name="source"></param> /// <param name="sortExpression">"child.name asc,child.age desc"</param> + /// <param name="shardingComparer"></param> /// <typeparam name="TEntity"></typeparam> /// <returns></returns> - internal static IOrderedQueryable<TEntity> OrderWithExpression<TEntity>(this IQueryable<TEntity> source, string sortExpression) + internal static IOrderedQueryable<TEntity> OrderWithExpression<TEntity>(this IQueryable<TEntity> source, string sortExpression, IShardingComparer shardingComparer = null) { String[] orderFields = sortExpression.Split(','); IOrderedQueryable<TEntity> result = null; @@ -99,17 +113,17 @@ namespace ShardingCore.Extensions Boolean sortDescending = (expressionPart.Length == 2) && (expressionPart[1].Equals("DESC", StringComparison.OrdinalIgnoreCase)); if (sortDescending) { - result = currentFieldIndex == 0 ? source.OrderByDescending(sortField) : result.ThenByDescending(sortField); + result = currentFieldIndex == 0 ? source.OrderByDescending(sortField,shardingComparer) : result.ThenByDescending(sortField, shardingComparer); } else { - result = currentFieldIndex == 0 ? source.OrderBy(sortField) : result.ThenBy(sortField); + result = currentFieldIndex == 0 ? source.OrderBy(sortField, shardingComparer) : result.ThenBy(sortField, shardingComparer); } } return result; } - internal static IOrderedQueryable<TEntity> OrderWithExpression<TEntity>(this IQueryable<TEntity> source, IEnumerable<PropertyOrder> propertyOrders) + internal static IOrderedQueryable<TEntity> OrderWithExpression<TEntity>(this IQueryable<TEntity> source, IEnumerable<PropertyOrder> propertyOrders, IShardingComparer shardingComparer = null) { IOrderedQueryable<TEntity> result = null; var currentIndex = 0; @@ -118,11 +132,11 @@ namespace ShardingCore.Extensions String sortField = propertyOrder.PropertyExpression; if (propertyOrder.IsAsc) { - result = currentIndex == 0 ? source.OrderBy(sortField) : result.ThenBy(sortField); + result = currentIndex == 0 ? source.OrderBy(sortField, shardingComparer) : result.ThenBy(sortField, shardingComparer); } else { - result = currentIndex == 0 ? source.OrderByDescending(sortField) : result.ThenByDescending(sortField); + result = currentIndex == 0 ? source.OrderByDescending(sortField, shardingComparer) : result.ThenByDescending(sortField, shardingComparer); } currentIndex++; diff --git a/src/ShardingCore/Sharding/CSharpLanguageShardingComparer.cs b/src/ShardingCore/Sharding/CSharpLanguageShardingComparer.cs index c713a0bf..33b2c355 100644 --- a/src/ShardingCore/Sharding/CSharpLanguageShardingComparer.cs +++ b/src/ShardingCore/Sharding/CSharpLanguageShardingComparer.cs @@ -13,9 +13,9 @@ namespace ShardingCore.Sharding */ public class CSharpLanguageShardingComparer<TShardingDbContext>:IShardingComparer<TShardingDbContext> where TShardingDbContext:DbContext,IShardingDbContext { - public int Compare(IComparable a, IComparable b, bool asc) + public int Compare(IComparable x, IComparable y, bool asc) { - return a.SafeCompareToWith(b, asc); + return x.SafeCompareToWith(y, asc); } } } \ No newline at end of file diff --git a/src/ShardingCore/Sharding/Internals/InMemoryShardingComparer.cs b/src/ShardingCore/Sharding/Internals/InMemoryShardingComparer.cs new file mode 100644 index 00000000..db74e692 --- /dev/null +++ b/src/ShardingCore/Sharding/Internals/InMemoryShardingComparer.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Text; +using ShardingCore.Sharding.Abstractions; + +namespace ShardingCore.Sharding.Internals +{ + public class InMemoryShardingComparer<T> : IComparer<T> + { + private readonly IShardingComparer _shardingComparer; + + public InMemoryShardingComparer(IShardingComparer shardingComparer) + { + _shardingComparer = shardingComparer; + } + public int Compare(T x, T y) + { + if (x is IComparable a && y is IComparable b) + return _shardingComparer.Compare(a, b, true); + throw new NotImplementedException($"compare :[{typeof(T).FullName}] is not IComparable"); + } + } +} diff --git a/src/ShardingCore/Sharding/MergeEngines/FirstAsyncInMemoryMergeEngine.cs b/src/ShardingCore/Sharding/MergeEngines/FirstAsyncInMemoryMergeEngine.cs index 052aab6b..c8192e3c 100644 --- a/src/ShardingCore/Sharding/MergeEngines/FirstAsyncInMemoryMergeEngine.cs +++ b/src/ShardingCore/Sharding/MergeEngines/FirstAsyncInMemoryMergeEngine.cs @@ -38,7 +38,7 @@ namespace ShardingCore.Sharding.StreamMergeEngines var streamMergeContext = GetStreamMergeContext(); if (streamMergeContext.Orders.Any()) - return q.OrderWithExpression(streamMergeContext.Orders).First(); + return q.OrderWithExpression(streamMergeContext.Orders, streamMergeContext.GetShardingComparer()).First(); return q.First(); } diff --git a/src/ShardingCore/Sharding/MergeEngines/FirstOrDefaultAsyncInMemoryMergeEngine.cs b/src/ShardingCore/Sharding/MergeEngines/FirstOrDefaultAsyncInMemoryMergeEngine.cs index 8ef20125..c03b1174 100644 --- a/src/ShardingCore/Sharding/MergeEngines/FirstOrDefaultAsyncInMemoryMergeEngine.cs +++ b/src/ShardingCore/Sharding/MergeEngines/FirstOrDefaultAsyncInMemoryMergeEngine.cs @@ -41,7 +41,7 @@ namespace ShardingCore.Sharding.StreamMergeEngines var streamMergeContext = GetStreamMergeContext(); if (streamMergeContext.Orders.Any()) - return q.OrderWithExpression(streamMergeContext.Orders).FirstOrDefault(); + return q.OrderWithExpression(streamMergeContext.Orders,streamMergeContext.GetShardingComparer()).FirstOrDefault(); return q.FirstOrDefault(); } diff --git a/src/ShardingCore/Sharding/MergeEngines/LastAsyncInMemoryMergeEngine.cs b/src/ShardingCore/Sharding/MergeEngines/LastAsyncInMemoryMergeEngine.cs index d7234977..7086af3e 100644 --- a/src/ShardingCore/Sharding/MergeEngines/LastAsyncInMemoryMergeEngine.cs +++ b/src/ShardingCore/Sharding/MergeEngines/LastAsyncInMemoryMergeEngine.cs @@ -39,7 +39,7 @@ namespace ShardingCore.Sharding.StreamMergeEngines var streamMergeContext = GetStreamMergeContext(); if (streamMergeContext.Orders.Any()) - return q.OrderWithExpression(streamMergeContext.Orders).Last(); + return q.OrderWithExpression(streamMergeContext.Orders, streamMergeContext.GetShardingComparer()).Last(); return q.Last(); } diff --git a/src/ShardingCore/Sharding/MergeEngines/LastOrDefaultAsyncInMemoryMergeEngine.cs b/src/ShardingCore/Sharding/MergeEngines/LastOrDefaultAsyncInMemoryMergeEngine.cs index 8f809429..7341aadb 100644 --- a/src/ShardingCore/Sharding/MergeEngines/LastOrDefaultAsyncInMemoryMergeEngine.cs +++ b/src/ShardingCore/Sharding/MergeEngines/LastOrDefaultAsyncInMemoryMergeEngine.cs @@ -38,7 +38,7 @@ namespace ShardingCore.Sharding.StreamMergeEngines var streamMergeContext = GetStreamMergeContext(); if (streamMergeContext.Orders.Any()) - return q.OrderWithExpression(streamMergeContext.Orders).LastOrDefault(); + return q.OrderWithExpression(streamMergeContext.Orders, streamMergeContext.GetShardingComparer()).LastOrDefault(); return q.LastOrDefault(); } diff --git a/src/ShardingCore/Sharding/MergeEngines/SingleAsyncInMemoryMergeEngine.cs b/src/ShardingCore/Sharding/MergeEngines/SingleAsyncInMemoryMergeEngine.cs index 997dd05c..81f93be0 100644 --- a/src/ShardingCore/Sharding/MergeEngines/SingleAsyncInMemoryMergeEngine.cs +++ b/src/ShardingCore/Sharding/MergeEngines/SingleAsyncInMemoryMergeEngine.cs @@ -38,7 +38,7 @@ namespace ShardingCore.Sharding.StreamMergeEngines var streamMergeContext = GetStreamMergeContext(); if (streamMergeContext.Orders.Any()) - return q.OrderWithExpression(streamMergeContext.Orders).Single(); + return q.OrderWithExpression(streamMergeContext.Orders, streamMergeContext.GetShardingComparer()).Single(); return q.Single(); } diff --git a/src/ShardingCore/Sharding/MergeEngines/SingleOrDefaultAsyncInMemoryMergeEngine.cs b/src/ShardingCore/Sharding/MergeEngines/SingleOrDefaultAsyncInMemoryMergeEngine.cs index 35713312..977d293a 100644 --- a/src/ShardingCore/Sharding/MergeEngines/SingleOrDefaultAsyncInMemoryMergeEngine.cs +++ b/src/ShardingCore/Sharding/MergeEngines/SingleOrDefaultAsyncInMemoryMergeEngine.cs @@ -39,7 +39,7 @@ namespace ShardingCore.Sharding.StreamMergeEngines var streamMergeContext = GetStreamMergeContext(); if (streamMergeContext.Orders.Any()) - return q.OrderWithExpression(streamMergeContext.Orders).SingleOrDefault(); + return q.OrderWithExpression(streamMergeContext.Orders, streamMergeContext.GetShardingComparer()).SingleOrDefault(); return q.SingleOrDefault(); } diff --git a/src/ShardingCore/Sharding/ReWrite/ReWriteEngine.cs b/src/ShardingCore/Sharding/ReWrite/ReWriteEngine.cs index 83f627cc..c1f7d7de 100644 --- a/src/ShardingCore/Sharding/ReWrite/ReWriteEngine.cs +++ b/src/ShardingCore/Sharding/ReWrite/ReWriteEngine.cs @@ -52,7 +52,7 @@ namespace ShardingCore.Core.Internal.StreamMerge.ReWrite if (selectProperties.IsNotEmpty()) { var sort = string.Join(",",selectProperties.Select(o=>$"{o.PropertyName} asc")); - reWriteQueryable = reWriteQueryable.OrderWithExpression(sort); + reWriteQueryable = reWriteQueryable.OrderWithExpression(sort,null); var reWriteOrders = new List<PropertyOrder>(selectProperties.Count()); foreach (var orderProperty in selectProperties) { diff --git a/src/ShardingCore/Sharding/Visitors/QueryableRouteDiscoverVisitor.cs b/src/ShardingCore/Sharding/Visitors/QueryableRouteDiscoverVisitor.cs index 3c805db3..36e2c1d4 100644 --- a/src/ShardingCore/Sharding/Visitors/QueryableRouteDiscoverVisitor.cs +++ b/src/ShardingCore/Sharding/Visitors/QueryableRouteDiscoverVisitor.cs @@ -242,17 +242,18 @@ namespace ShardingCore.Core.Internal.Visitors //单个 else { - bool paramterAtLeft=false; + //条件在右边 + bool conditionOnRight=false; object value = null; if (IsShardingKey(binaryExpression.Left)&&IsConstantOrMember(binaryExpression.Right)) { - paramterAtLeft = true; + conditionOnRight = true; value = GetShardingKeyValue(binaryExpression.Right); } else if (IsConstantOrMember(binaryExpression.Left) && IsShardingKey(binaryExpression.Right)) { - paramterAtLeft = false; + conditionOnRight = false; value = GetShardingKeyValue(binaryExpression.Left); } else @@ -260,10 +261,10 @@ namespace ShardingCore.Core.Internal.Visitors var op = binaryExpression.NodeType switch { - ExpressionType.GreaterThan => paramterAtLeft ? ShardingOperatorEnum.GreaterThan : ShardingOperatorEnum.LessThan, - ExpressionType.GreaterThanOrEqual => paramterAtLeft ? ShardingOperatorEnum.GreaterThanOrEqual : ShardingOperatorEnum.LessThanOrEqual, - ExpressionType.LessThan => paramterAtLeft ? ShardingOperatorEnum.LessThan : ShardingOperatorEnum.GreaterThan, - ExpressionType.LessThanOrEqual => paramterAtLeft ? ShardingOperatorEnum.LessThanOrEqual : ShardingOperatorEnum.GreaterThanOrEqual, + 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