I am using this snippet below for Ordering my Linq queries dynamically and works great. I am not great at reflection or complex linq queries but I need a way that when ascendin
One approach is to pass an additional expression for testing for null
into the method, and use it in an additional OrderBy
/ThenBy
clause.
Two OrderBy
clauses would be produced - the first one will be on nullOrder
, while the second one will be on the actual property.
private static IOrderedQueryable ApplyOrderBy(IQueryable collection, OrderByInfo orderByInfo, Expression> nullOrder) {
...
if (!orderByInfo.Initial && collection is IOrderedQueryable) {
if (orderByInfo.Direction == SortDirection.Ascending)
methodName = "ThenBy";
else
methodName = "ThenByDescending";
} else {
if (orderByInfo.Direction == SortDirection.Ascending)
methodName = "OrderBy";
else
methodName = "OrderByDescending";
}
if (nullOrder != null) {
collection = (IQueryable)typeof(Queryable).GetMethods().Single(
method => method.Name == methodName
&& method.IsGenericMethodDefinition
&& method.GetGenericArguments().Length == 2
&& method.GetParameters().Length == 2)
.MakeGenericMethod(typeof(T), type)
.Invoke(null, new object[] { collection, nullOrder });
// We've inserted the initial order by on nullOrder,
// so OrderBy on the property becomes a "ThenBy"
if (orderByInfo.Direction == SortDirection.Ascending)
methodName = "ThenBy";
else
methodName = "ThenByDescending";
}
// The rest of the method remains the same
return (IOrderedQueryable)typeof(Queryable).GetMethods().Single(
method => method.Name == methodName
&& method.IsGenericMethodDefinition
&& method.GetGenericArguments().Length == 2
&& method.GetParameters().Length == 2)
.MakeGenericMethod(typeof(T), type)
.Invoke(null, new object[] { collection, lambda });
}
The caller would need to pass a null checker explicitly. Passing null
for non-nullable fields should work. You can construct them once, and pass as needed:
static readonly Expression> NullStringOrder = s => s == null ? 1 : 0;
static readonly Expression> NullIntOrder = i => !i.HasValue ? 1 : 0;
static readonly Expression> NullLongOrder = i => !i.HasValue ? 1 : 0;