我已经在IQueryable上创建了扩展名,因为我想先按可为null的日期时间排序,然后仅使用属性字符串(即“ activeTo”)按日期时间本身进行排序。我创建了以下代码:
public static IQueryable<T> Sort<T>(this IQueryable<T> source, string sortBy)
{
//create the expression tree that represents the generic parameter to the predicate
var param = Expression.Parameter(typeof(T), "p");
//create an expression tree that represents the expression p=>p.SortField.HasValue
var prop = Expression.Property(param, sortBy);
var target = Expression.Constant(null, prop.Type);
var bin = Expression.Equal(prop, Expression.Convert(target, prop.Type));
var exp = Expression.Lambda(bin, param);
string method = "OrderBy";
Type[] types = new Type[] { source.ElementType, exp.Body.Type };
var orderByCallExpression = Expression.Call(typeof(Queryable), method, types, source.Expression, exp);
//now do the ThenBy bit,sending in the above expression to the Expression.Call
exp = Expression.Lambda(prop, param);
types = new Type[] { source.ElementType, exp.Body.Type };
method = "ThenBy";
var ThenByCallExpression = Expression.Call(typeof(Queryable), method, types, orderByCallExpression, exp);
return source.Provider.CreateQuery<T>(ThenByCallExpression);
}
此扩展名为:
query.Sort("activeTo");
然后给出以下响应:
{
"title": "test 5",
"activeFrom": "2019-06-08T21:26:50.2833333",
"activeTo": "2019-06-08T21:26:50.2833333",
},
{
"title": "test 2",
"activeFrom": "2019-06-08T21:28:45.65",
"activeTo": null,
}
我希望activeTo为null的记录排在第一位,
有人知道我在做什么错吗?
答案 0 :(得分:1)
从注释中看,目标似乎是动态生成一个将null
值排在最前面的表达式。
当前代码产生以下表达式OrderBy(p => p.activeTo == null).ThenBy(p => p.activeTo == null)
。这有两个缺陷:
null
,false
(它们的序数分别为0和1),因此将true
值排在最前面。因此,与null
的比较首先收集false
个案例,然后收集true
个案例。ThenBy
重复OrderBy
,但实际上是要发出ThenBy(p => p.ActiveTo)
。第一个可以通过使用Expression.NotEqual
而不是Expression.Equal
的{{1}}或通过使用p => p != p.activeTo
而不是OrderByDescending
来解决。
总的代码应该是:
OrderBy
这将产生以下表达式:
public static IQueryable<T> Sort<T>(IQueryable<T> source, string sortBy)
{
//create the expression tree that represents the generic parameter to the predicate
var param = Expression.Parameter(typeof(T), "p");
//create an expression tree that represents the expression p=>p.SortField.HasValue
var prop = Expression.Property(param, sortBy);
var target = Expression.Constant(null, prop.Type);
// NotEqual, to sort nulls before not-nulls
var bin = Expression.NotEqual(prop, Expression.Convert(target, prop.Type));
var exp = Expression.Lambda(bin, param);
// OrderBy with the null comparison expression
string method = nameof(Queryable.OrderBy);
Type[] types = new Type[] { source.ElementType, exp.Body.Type };
var orderByCallExpression = Expression.Call(typeof(Queryable), method, types, source.Expression, exp);
// ThenBy with the property expression
exp = Expression.Lambda(prop, param);
types = new Type[] { source.ElementType, exp.Body.Type };
method = nameof(Queryable.ThenBy);
var ThenByCallExpression = Expression.Call(typeof(Queryable), method, types, orderByCallExpression, exp);
return source.Provider.CreateQuery<T>(ThenByCallExpression);
}
。
备注:应注意,通常OrderBy(p => p.activeTo != null).ThenBy(p => p.activeTo)
已经将空值排序在最前面,因为这是字符串,可空值等的默认排序顺序。但是,此行为可能会被特定的类型和查询源所覆盖。因此,我像OP一样保留了它。