我使用以下代码按表达式转换顺序,因此也可以对可以为空的列进行排序。
protected virtual Expression<Func<T, object>> GetSorting(string ordering)
{
Expression<Func<T, object>> expression = default(Expression<Func<T, object>>);
IEnumerable<Order> sortObjects = string.IsNullOrEmpty(ordering) ? null : JsonConvert.DeserializeObject<IEnumerable<Order>>(ordering);
if (sortObjects != null)
{
foreach (Order sortObject in sortObjects)
{
Expression<Func<T, object>> currentExpression = this.GetExpression(sortObject.Property);
expression = this.CombineExpressions(expression, currentExpression);
}
}
return expression;
}
private Expression<Func<T, object>> GetExpression(string propertyName)
{
Type type = typeof(T);
ParameterExpression parameter = Expression.Parameter(type, "x");
MemberExpression propertyReference = Expression.Property(parameter, propertyName);
Expression conversion = Expression.Convert(propertyReference, typeof(object));
Expression<Func<T, object>> currentExpression = Expression.Lambda<Func<T, object>>(conversion, new[] { parameter });
return currentExpression;
}
private Expression<Func<T, object>> CombineExpressions(Expression<Func<T, object>> expression, Expression<Func<T, object>> currentExpression)
{
if (expression == default(Expression<Func<T, object>>))
{
expression = currentExpression;
}
else
{
// Combine the two expressions' body together
BinaryExpression body = Expression.AndAlso(expression.Body, currentExpression.Body);
ParameterExpression[] parameters = new ParameterExpression[1] { Expression.Parameter(typeof(T), expression.Parameters.First().Name) };
// Convert the BinaryExpression to the requested type
Expression<Func<T, object>> lambda = Expression.Lambda<Func<T, object>>(body, parameters);
expression = lambda;
}
return expression;
}
此代码适用于所有非导航属性,但似乎不再查询导航属性。我使用Select表达式来加载导航属性,如下所示:
protected override Expression<Func<Resource, ResourceViewModel>> Selector
{
get
{
return (x) => new ResourceViewModel()
{
ResourceId = x.ResourceId,
DisplayName = x.DisplayName,
ResourceType = x.ResourceType != null ? x.ResourceType.Name : string.Empty,
}
}
}
如果我没有订购的东西,则会加载导航属性。但是只要有任何要排序的东西,导航属性就是null。如果我跳过三元操作并直接转到ResourceType.Name属性,我会得到一个异常,告诉我lambda_method抛出了NullReference异常。
我知道订购导航属性不会起作用,但这不是问题。订购常规&#39;属性导致问题。
对此有何想法?
答案 0 :(得分:0)
事实证明这个问题并不像我想象的那么复杂。问题是我创建了错误的表达式树。您可以嵌套表达式,以便导航到属性的属性。
下面的解决方案应该解释这一点(这不是我如何解决问题,但它应该说清楚):
private Expression<Func<T, object>> GetExpression(string parentClass, string propertyName)
{
Type type = typeof(T);
ParameterExpression parameter = Expression.Parameter(type, "x");
// Get parent class expression
// Will result in (x) => x.MyNavigationPropertyWhichIsAClass
MemberExpression propertyReference1 = Expression.Property(parameter, parentclass);
// Navigate to the property of the navigation property class
// Will result in (x) => x.MyNavigationPropertyWhichIsAClass.MyPropertyIWantToSort
MemberExpression propertyReference2 = Expression.Property(propertyRefernce1, propertyName);
Expression conversion = Expression.Convert(propertyReference2, typeof(object));
Expression<Func<T, object>> currentExpression = Expression.Lambda<Func<T, object>>(conversion, new[] { parameter });
return currentExpression;
}