Динамическое выражение OrderBy с предикатом bool - PullRequest
1 голос
/ 14 июня 2019

У меня есть класс модели

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: универсальный метод OrderBy типа «System.Linq.Queryable» не совместим с предоставленными аргументами и аргументами типа.Аргументы типа не должны предоставляться, если метод не является универсальным.

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 Ответ

1 голос
/ 14 июня 2019

О, мне кажется, я вижу проблему.

В 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);

Но вместо предоставления

TSource и bool

в качестве аргументов,вы даете это

TSource и string

в качестве аргументов.

Так должно быть:

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

(Или вы можететакже используйте source.ElementType для первого типа.)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...