Reputation: 964
I'm using dynamic Linq to order a result set depending on which column is passed in. I'm using this to order a table when a user clicks on a table column.
If the property im ordering on is a class which is null the code falls over, i want to be able to dynamically orderby a string but cater for nulls if the property is a class.
This is the code from the System.Linq.Dynamic class im using.
public static IQueryable OrderBy(this IQueryable source, string ordering,
params object[] values)
{
if (source == null) { throw new ArgumentNullException("source"); }
if (ordering == null) { throw new ArgumentNullException("ordering"); }
ParameterExpression[] parameters = new ParameterExpression[1]
{
Expression.Parameter(source.ElementType, "")
};
IEnumerable<DynamicOrdering> enumerable = new ExpressionParser(
parameters, ordering, values).ParseOrdering();
Expression expression = source.Expression;
string str1 = "OrderBy";
string str2 = "OrderByDescending";
foreach (DynamicOrdering dynamicOrdering in enumerable)
{
expression = (Expression) Expression.Call(typeof (Queryable),
dynamicOrdering.Ascending ? str1 : str2, new Type[2]
{
source.ElementType,
dynamicOrdering.Selector.Type
}, new Expression[2]
{
expression,
(Expression) Expression.Quote((Expression) Expression.Lambda(
dynamicOrdering.Selector, parameters))
});
str1 = "ThenBy";
str2 = "ThenByDescending";
}
return source.Provider.CreateQuery(expression);
}
and calling it like this
if (property.PropertyType == typeof(Sitecore.Data.Items.Item))
{
orderByProperty = property.Name + ".Name";
}
else
{
orderByProperty = property.Name;
}
return tableOrder == TableOrder.az
? projects.OrderBy(orderByProperty + " ascending").ToList()
: projects.OrderBy(orderByProperty + " descending").ToList();
the property is sometimes a class, if this is the case i want to be able to order it by a field called name on the class. The above code works but if the property is a class and null then it falls over.
How do I order by a field and have the null items at the end?
Upvotes: 1
Views: 2297
Reputation: 964
I've found the answer. Replace the OrderBy query in the System.Linq.Dynamic.DynamicQueryable class with the below. It will handle nulls in a property that is an object.
public static IQueryable OrderBy(this IQueryable source, string ordering,
params object[] values)
{
//This handles nulls in a complex object
var orderingSplit = ordering.Split(new char[] {' '},
StringSplitOptions.RemoveEmptyEntries);
var sortField = orderingSplit[0];
var splitted_sortField = sortField.Split(new char[] { '.' },
StringSplitOptions.RemoveEmptyEntries);
if (splitted_sortField.Length > 1)
{
sortField = "iif(" + splitted_sortField[0] + "==null,null," + sortField + ")";
}
ordering = orderingSplit.Length == 2
? sortField + " " + orderingSplit[1]
: sortField;
if (source == null) throw new ArgumentNullException("source");
if (ordering == null) throw new ArgumentNullException("ordering");
ParameterExpression[] parameters = new ParameterExpression[] {
Expression.Parameter(source.ElementType, "") };
ExpressionParser parser = new ExpressionParser(parameters, ordering, values);
IEnumerable<DynamicOrdering> orderings = parser.ParseOrdering();
Expression queryExpr = source.Expression;
string methodAsc = "OrderBy";
string methodDesc = "OrderByDescending";
foreach (DynamicOrdering o in orderings)
{
queryExpr = Expression.Call(
typeof(Queryable), o.Ascending ? methodAsc : methodDesc,
new Type[] { source.ElementType, o.Selector.Type },
queryExpr, Expression.Quote(Expression.Lambda(o.Selector, parameters)));
methodAsc = "ThenBy";
methodDesc = "ThenByDescending";
}
return source.Provider.CreateQuery(queryExpr);
}
Taken the code from here and baked it directly into the Dynamic Linq function.
Null Reference Exception in a Dynamic LINQ Expression
Upvotes: 1