Динамические лямбда-выражения для фильтрации и сортировки с использованием дочерних элементов с помощью c#

привет, я следую руководству в https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/expression-trees/how-to-use-expression-trees-to-build-dynamic-queries, чтобы создать фильтр и сортировку в моем классе отношений, мне нужно фильтровать и сортировать, используя дочерний столбец «Канал»

это мой базовый класс

public class MeterTransaction : EviModelBase
{        
    public int TariffDuration { get; set; }
    public decimal? TariffPackageKwh { get; set; }
    public decimal? TariffPackagePrice { get; set; }
    public decimal? TariffRatePerKwh { get; set; }
    public decimal? TariffRateMinFee { get; set; }

    // Meter CreditBalance after transaction
    public decimal CreditBalance { get; set; }
    public DateTimeOffset? CreditExpiration { get; set; }
    [Timestamp]
    public byte[] RowVersion { get; set; }
    public Meter Meter { get; set; }
}

и это класс счетчика

public class Meter : EviModelBase
{
    public MeterVendor Vendor { get; set; }
    public string Model { get; set; }
    public string SerialNumber { get; set; }
    public string Channel { get; set; }

}

это код для фильтрации и сортировки данных:

public static IQueryable<T> OrderByNew<T>(this IQueryable<T> source, SortModel sortModel)
            {
                    ParameterExpression p = Expression.Parameter(typeof(T), "p");

                    // Construct the nested properties
                    string[] nestedProps = sortModel.ColId.Split('.');
                    Expression mbr = p;
                    for (int i = 0; i < nestedProps.Length; i++)
                            mbr = Expression.PropertyOrField(mbr, nestedProps[i]);

                    LambdaExpression pred = Expression.Lambda(
                            Expression.Equal(
                                    mbr,
                                    Expression.Constant("EVI0000101")
                                    ),
                                    p
                    );

                    var method = string.Equals(sortModel.Sort, "desc", StringComparison.OrdinalIgnoreCase) ?
                            "OrderByDescending" :
                            "OrderBy";
                    var whereCallExpression = Expression.Call(typeof(Queryable), "where", new Type[] { source.ElementType }, source.Expression, pred);
                    var orderByExpression = Expression.Lambda(mbr, p);

                    MethodCallExpression orderByCallExpression = Expression.Call(
                            typeof(Queryable),
                            method,
                            new Type[] { source.ElementType},
                            whereCallExpression,
                            Expression.Quote(orderByExpression));
                    // ***** End OrderBy *****

                    return source.Provider.CreateQuery<T>(orderByCallExpression);
            }
    }

На самом деле «whereCallExpression» работает исправно и фильтрует данные, которые я хочу, без ошибок, но логика сортировки выдает ошибку «ни один общий метод 'OrderBy' для типа 'System.Linq.Queryable' не совместим с предоставленными аргументами и аргументами типа . "

как я могу этого добиться?

С уважением

1
0
469
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вы упускаете из виду тот факт, что в отличие от Where, метод OrderBy имеет 2 аргумента универсального типа (TSource и TKey). Следовательно, вам необходимо предоставить их оба при генерации вызова:

var orderByCallExpression = Expression.Call(
    typeof(Queryable),
    method,
    new Type[] { source.ElementType, orderByExpression.Body.Type }, // <--
    whereCallExpression,
    Expression.Quote(orderByExpression));

спасибо, это решило мою проблему, кстати, есть ли способ изменить выражения фильтра с "==" на "как" или "содержит"

Terry Yulianto 12.04.2018 06:15

Конечно, вместо Expression.Equal можно использовать Expression.Call(mbr, "Contains", Type.EmptyTypes, Expression.Constant("EVI0000101")).

Ivan Stoev 12.04.2018 07:48

еще раз спасибо @Ivan Stoev, есть ли полезная документация по этому поводу? это может мне очень помочь

Terry Yulianto 12.04.2018 09:23

Не знаю. Весь мой опыт - это самообучение и эксперименты. Изучите статические методы класса Expression. Или в большинстве случаев проще создать образец выражения времени компиляции (например, Expression<Func<Foo, bool>> expr = x => x.Bar.Contains("Baz"); и изучить содержимое внутри отладчика. Затем найдите соответствующие статические методы для его динамического построения :)

Ivan Stoev 12.04.2018 09:36

Другие вопросы по теме