private static string GetMethodName(SortingRule sortingRule, bool isFirstSortingRule) { var method = isFirstSortingRule ? "OrderBy" : "ThenBy"; var methodWithOrder = sortingRule.SortOrder.Equals(SortOrder.Asc) ? method : method + "Descending"; return(methodWithOrder); }
private static LambdaExpression PropertyGetterExpression <T>(SortingRule sortingSettings) { var param = Expression.Parameter(typeof(T), "p"); var propertyName = string.IsNullOrEmpty(sortingSettings.Field) ? "Id" : sortingSettings.Field; var prop = Expression.Property(param, propertyName); var exp = Expression.Lambda(prop, param); return(exp); }
public IFetchBuilder <TModel> AddSorting(SortingRule sortingRule) { fetchParameters.AddSorting(sortingRule.Key, sortingRule.SortDirection); return(this); }
// https://stackoverflow.com/a/31959568/3469518 private static IQueryable <TSource> OrderBy <TSource>(this IQueryable <TSource> query, SortingRule sortingRule) { var entityType = typeof(TSource); //Create x=>x.PropName var propertyInfo = entityType.GetProperty(sortingRule.Key); if (propertyInfo == null) { throw new ArgumentException(string.Format("Sorting rule - entity doesnt contain column ({0})"), sortingRule.Key); } ParameterExpression arg = Expression.Parameter(entityType, "x"); MemberExpression property = Expression.Property(arg, sortingRule.Key); var selector = Expression.Lambda(property, new ParameterExpression[] { arg }); var desiredMethodName = sortingRule.SortDirection == SortDirectionEnum.Asc ? "OrderBy" : "OrderByDescending"; //Get System.Linq.Queryable.OrderBy() method. var enumarableType = typeof(System.Linq.Queryable); var method = enumarableType.GetMethods() .Where(m => m.Name == desiredMethodName && m.IsGenericMethodDefinition) .Where(m => { var parameters = m.GetParameters().ToList(); //Put more restriction here to ensure selecting the right overload return(parameters.Count == 2); //overload that has 2 parameters }).Single(); //The linq's OrderBy<TSource, TKey> has two generic types, which provided here MethodInfo genericMethod = method .MakeGenericMethod(entityType, propertyInfo.PropertyType); /*Call query.OrderBy(selector), with query and selector: x=> x.PropName * Note that we pass the selector as Expression to the method and we don't compile it. * By doing so EF can extract "order by" columns and generate SQL for it.*/ var newQuery = (IOrderedQueryable <TSource>)genericMethod .Invoke(genericMethod, new object[] { query, selector }); return(newQuery); }
private static IQueryable <T> ApplySortingRule <T>(IQueryable <T> query, bool isFirstSortingRule, SortingRule sortingRule) { var exp = PropertyGetterExpression <T>(sortingRule); var method = GetMethodName(sortingRule, isFirstSortingRule); var types = new[] { query.ElementType, exp.Body.Type }; var callExpression = Expression.Call(typeof(Queryable), method, types, query.Expression, exp); query = query.Provider.CreateQuery <T>(callExpression); return(query); }