带布尔谓词的动态OrderBy表达式

时间:2019-06-14 08:40:33

标签: c# lambda

我有一个模型课

public class MyModel
{
    public long Id { get; set; }

    public string Name { get; set; }
}

我当前正在从数据库中返回MyModel的排序列表(按名称):

return await Db.MyModel
    .AsNoTracking()
    .OrderBy(x => x.Name)

但是,数据库中的值之一是“ N / A”,我希望通过一些选择器进行排序,最后保留“ N / A”,所以基本上:

 return await Db.MyModel
    .AsNoTracking()
    .OrderBy(x => x.Name == "N/A)
    .ThenBy(x => x.Name)

我创建了一个IQueryable扩展名,但是在Expression.Call(...)上出现了错误

  

InvalidOperationException:类型为'System.Linq.Queryable'的通用方法'OrderBy'与提供的类型实参和实参不兼容。如果方法是非泛型的,则不应该提供任何类型参数。

public static IQueryable<TSource> OrderNALast<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, string>> selector)
{
    var expression = source.Expression;
    var parameter = Expression.Parameter(typeof(TSource), "x");

    var left = (MemberExpression)selector.Body;
    var right = Expression.Constant("N/A");
    var predicateBody = Expression.Equal(left, right);

    var lambda = Expression.Lambda<Func<TSource, bool>>(predicateBody, parameter);

    expression = Expression.Call(
        typeof(Queryable), 
        "OrderBy",
        new[] { source.ElementType, left.Type },
        expression,
        lambda);

    var appendedQuery = (IOrderedQueryable<TSource>)source.Provider.CreateQuery<TSource>(expression);
    return appendedQuery.ThenBy(selector);
}

1 个答案:

答案 0 :(得分:1)

哦,我想我知道了。

在Expression.Call中,第三个参数需要静态方法的通用类型参数来调用。

Queryable.OrderBy()有两个重载:

public static System.Linq.IOrderedQueryable<TSource> OrderBy<TSource,TKey> (this System.Linq.IQueryable<TSource> source, System.Linq.Expressions.Expression<Func<TSource,TKey>> keySelector, System.Collections.Generic.IComparer<TKey> comparer);

public static System.Linq.IOrderedQueryable<TSource> OrderBy<TSource,TKey> (this System.Linq.IQueryable<TSource> source, System.Linq.Expressions.Expression<Func<TSource,TKey>> keySelector);

但不要给出

TSourcebool

作为参数,您正在提供

TSourcestring

作为参数。

应该是:

expression = Expression.Call(
        typeof(Queryable), 
        "OrderBy",
        new[] { typeof(TSource), typeof(bool) },
        expression,
        lambda);

(或者您也可以将source.ElementType用作第一种类型。)