编写基本的表达式构建器

时间:2015-04-01 10:15:48

标签: c# lambda linq-to-entities

我正在使用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:方法的类型参数   &#39; System.Linq.Queryable.GroupBy(System.Linq.IQueryable,   System.Linq.Expressions.Expression&GT;)&#39;不能   从用法推断。尝试指定类型参数   明确。

我在这里做错了什么?

3 个答案:

答案 0 :(得分: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));
    }

答案 1 :(得分: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();

答案 2 :(得分: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();