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