纽威
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

81 lines
3.6 KiB

3 years ago
  1. using System;
  2. using System.Data.SqlClient;
  3. using System.Linq;
  4. using System.Linq.Expressions;
  5. using System.Reflection;
  6. namespace NFine.Code
  7. {
  8. public static partial class ExtLinq
  9. {
  10. public static IOrderedQueryable<TEntity> SortBy<TEntity>(this IQueryable<TEntity> query, Expression<Func<TEntity, dynamic>> sortPredicate)
  11. where TEntity : class, new()
  12. {
  13. return InvokeSortBy(query, sortPredicate, SortOrder.Ascending);
  14. }
  15. public static IOrderedQueryable<TEntity> SortByDescending<TEntity>(this IQueryable<TEntity> query, Expression<Func<TEntity, dynamic>> sortPredicate)
  16. where TEntity : class, new()
  17. {
  18. return InvokeSortBy(query, sortPredicate, SortOrder.Descending);
  19. }
  20. private static IOrderedQueryable<TEntity> InvokeSortBy<TEntity>(IQueryable<TEntity> query,
  21. Expression<Func<TEntity, dynamic>> sortPredicate, SortOrder sortOrder)
  22. where TEntity : class, new()
  23. {
  24. var param = sortPredicate.Parameters[0];
  25. string propertyName = null;
  26. Type propertyType = null;
  27. Expression bodyExpression = null;
  28. if (sortPredicate.Body is UnaryExpression)
  29. {
  30. var unaryExpression = sortPredicate.Body as UnaryExpression;
  31. bodyExpression = unaryExpression.Operand;
  32. }
  33. else if (sortPredicate.Body is MemberExpression)
  34. {
  35. bodyExpression = sortPredicate.Body;
  36. }
  37. else
  38. throw new ArgumentException(@"The body of the sort predicate expression should be
  39. either UnaryExpression or MemberExpression.", "sortPredicate");
  40. var memberExpression = (MemberExpression)bodyExpression;
  41. propertyName = memberExpression.Member.Name;
  42. if (memberExpression.Member.MemberType == MemberTypes.Property)
  43. {
  44. var propertyInfo = memberExpression.Member as PropertyInfo;
  45. if (propertyInfo != null) propertyType = propertyInfo.PropertyType;
  46. }
  47. else
  48. throw new InvalidOperationException(@"Cannot evaluate the type of property since the member expression
  49. represented by the sort predicate expression does not contain a PropertyInfo object.");
  50. var funcType = typeof(Func<,>).MakeGenericType(typeof(TEntity), propertyType);
  51. var convertedExpression = Expression.Lambda(funcType,
  52. Expression.Convert(Expression.Property(param, propertyName), propertyType), param);
  53. var sortingMethods = typeof(Queryable).GetMethods(BindingFlags.Public | BindingFlags.Static);
  54. var sortingMethodName = GetSortingMethodName(sortOrder);
  55. var sortingMethod = sortingMethods.First(sm => sm.Name == sortingMethodName &&
  56. sm.GetParameters().Length == 2);
  57. return (IOrderedQueryable<TEntity>)sortingMethod
  58. .MakeGenericMethod(typeof(TEntity), propertyType)
  59. .Invoke(null, new object[] { query, convertedExpression });
  60. }
  61. private static string GetSortingMethodName(SortOrder sortOrder)
  62. {
  63. switch (sortOrder)
  64. {
  65. case SortOrder.Ascending:
  66. return "OrderBy";
  67. case SortOrder.Descending:
  68. return "OrderByDescending";
  69. default:
  70. throw new ArgumentException("Sort Order must be specified as either Ascending or Descending.",
  71. "sortOrder");
  72. }
  73. }
  74. }
  75. }