Написание базового построителя выражений

1

Я использую Linq-to-Entities, и для одного запроса требуется, чтобы свойство загружалось динамически. Запрос выглядит так:

var found = Context.IntegrateViews.GroupBy(x => x.TypeOfBed)
                   .Select(type => new TypeCounts
                            { Name = type.Key, Count = type.Count() }).ToList();

Свойство, в котором выполняется предложение Group By, - TypeOfBed. Теперь я хочу запустить этот запрос для разных свойств, например, в следующий раз, когда я хочу его запустить, скажем, x.TypeOfChair и т.д. Для этого мне нужно иметь это свойство там динамически.

Я пытаюсь написать построитель выражений, который выглядит следующим образом.

public Expression<Func<LookupFilterItem>> PropertyLambda(string propertyName)
{
    var param = Expression.Parameter(typeof(LookupFilterItem), "lookupItem");
    //type of x in above example is LookupFilterItem
    var propertyExpression = Expression.Property(param, propertyName);

    var returnExpr = Expression.Lambda<Func<LookupFilterItem>>(propertyExpression);
    return returnExpr;
    //If I Pass string "TypeOfBed" to this method, I am expecting it to return something like
    // lookupItem => lookupItem.TypeOfBed
}

И я намерен использовать его так:

var found = Context.IntegrateViews.GroupBy(PropertyLambda("TypeOfBed"))
                   .Select(type => new TypeCounts
                            { Name = type.Key, Count = type.Count() }).ToList();

Но это не работает, я получаю ошибку времени компиляции, которая гласит:

ошибка CS0411: аргументы типа для метода "System.Linq.Queryable.GroupBy(System.Linq.IQueryable, System.Linq.Expressions.Expression>)" не могут быть выведены из использования. Попробуйте явно указать аргументы типа.

Что я здесь делаю неправильно?

Теги:
lambda
linq-to-entities

3 ответа

1
Лучший ответ

Кажется, это проблема синтаксиса. Попробуй это:

public Expression<Func<LookupFilterItem, string>> PropertyLambda(string propertyName)
    {
        var param = Expression.Parameter(typeof(LookupFilterItem), "lookupItem");
        var propertyExpression = Expression.Property(param, propertyName);
        var returnExpr = Expression.Lambda<Func<LookupFilterItem, string>>(propertyExpression, param);
        return returnExpr;
    }

И использование:

var found = Context.IntegrateViews.GroupBy(PropertyLambda("TypeOfBed").Compile())
               .Select(type => new TypeCounts
                        { Name = type.Key, Count = type.Count() }).ToList();
  • 0
    Спасибо, это сработало.
  • 0
    @Aamir Компилируя выражение, оно заставляет все делать с помощью LINQ для объектов, а не для поставщика запросов, что полностью противоречит цели использования выражений.
3

Не тестировали, но как насчет следующего метода расширения?

    private static Expression<Func<T, K>> MakeExpr<T, K>(this IQueryable<T> source, string property)
    {
        var type = typeof(T);
        var arg = Expression.Parameter(type, "x");
        var expr = Expression.Property(arg, property);
        var lambda = Expression.Lambda<Func<T, K>>(expr, arg);
        return lambda;
    }

    public static IQueryable<IGrouping<K, T>> GroupBy<T, K>(this IQueryable<T> source, string property)
    {
        return source.GroupBy(MakeExpr<T, K>(source, property));
    }
0

Другой вариант - использовать LINQ Dynamic Query Library:

using System.Linq.Dynamic;

var found = Context.IntegrateViews.AsQueryable().GroupBy("new(TypeOfBed)", "it")
                   .Select(new (Key.TypeOfBed as Name, Count() as Count)).ToList();

Ещё вопросы

Сообщество Overcoder
Наверх
Меню