Linq 向Lambda表达式动态添加GroupBy

Linq 向Lambda表达式动态添加GroupBy,linq,expression-trees,Linq,Expression Trees,好吧,我承认我还没有完全“得到”lambda表达式和LINQ表达式树;我现在做的很多事情都是剪切和粘贴,然后看看效果如何。我已经查阅了很多文档,但我仍然没有找到我的“啊哈”时刻 话虽如此 我正在尝试将GroupBy表达式动态添加到我的Linq表达式中。我在这里提出了一个问题: 并试图实现我在那里看到的 首先,我的数据库有实体类,还有一个名为dobjcurlocviewnormalized的表 我有一个方法可以进行初始调用 public IQueryable<ObjCurLocViewNo

好吧,我承认我还没有完全“得到”lambda表达式和LINQ表达式树;我现在做的很多事情都是剪切和粘贴,然后看看效果如何。我已经查阅了很多文档,但我仍然没有找到我的“啊哈”时刻

话虽如此

我正在尝试将GroupBy表达式动态添加到我的Linq表达式中。我在这里提出了一个问题:

并试图实现我在那里看到的

首先,我的数据库有实体类,还有一个名为dobjcurlocviewnormalized的表

我有一个方法可以进行初始调用

public IQueryable<ObjCurLocViewNormalized> getLocations()
{
    IQueryable<ObjCurLocViewNormalized> res = (from loc in tms.ObjCurLocViewNormalized
                               select loc);
    return res;
}
现在,我有一个方法:

static public System.Linq.IQueryable<System.Linq.IGrouping<string, TResult>> addGroupBy<TResult>(this IQueryable<TResult> query, string columnName)
{

    var providerType = query.Provider.GetType();
    // Find the specific type parameter (the T in IQueryable<T>)
    var iqueryableT = providerType.FindInterfaces((ty, obj) => ty.IsGenericType && ty.GetGenericTypeDefinition() == typeof(IQueryable<>), null).FirstOrDefault();
    var tableType = iqueryableT.GetGenericArguments()[0];
    var tableName = tableType.Name;

    var data = Expression.Parameter(iqueryableT, "query");
    var arg = Expression.Parameter(tableType, tableName);
    var nameProperty = Expression.PropertyOrField(arg, columnName);
    var lambda = Expression.Lambda<Func<TResult, string>>(nameProperty, arg);

    var expression = Expression.Call(typeof(Enumerable), 
                                    "GroupBy", 
                                    new Type[] { tableType, typeof(string) },
                                    data, 
                                    lambda);
    var predicate = Expression.Lambda<Func<TResult, String>>(expression, arg); // this is the line that produces the error I describe below
    var result = query.GroupBy(predicate).AsQueryable();
    return result;
}
错误来自这一行:

 var predicate = Expression.Lambda<Func<TResult, String>>(expression, arg);
var predicate=Expression.Lambda(Expression,arg);
我正在复制和改编我在表达式中动态添加Where子句的成功工作中的代码。所以我在暗中捅了一刀

如果有人能帮我弄清楚这一点,显然,发布完整的工作代码并为我做所有的思考会很好:),但如果你能解释一下为什么这是错误的,或者如何让我的头脑围绕这些概念,那就太好了。如果您能找到真正有助于弥合lambda表达式基础知识与构建动态表达式树之间差距的文档,那就太好了。我的知识显然有很大的漏洞,但我认为这些信息可能对其他人有用

谢谢大家的时间,当然如果我在别处找到答案,我会把它贴在这里

再次感谢


Don

要使其正常工作,您需要做的是:

    static public IQueryable<IGrouping<TValue, TResult>> addGroupBy<TValue, TResult>(
                this IQueryable<TResult> query, string columnName)
            {
            var providerType = query.Provider.GetType();

            // Find the specific type parameter (the T in IQueryable<T>)
            const object EmptyfilterCriteria = null;
            var iqueryableT = providerType
                .FindInterfaces((ty, obj) => ty.IsGenericType && ty.GetGenericTypeDefinition() == typeof(IQueryable<>), EmptyfilterCriteria)
                .FirstOrDefault();
            Type tableType = iqueryableT.GetGenericArguments()[0];
            string tableName = tableType.Name;

            ParameterExpression data = Expression.Parameter(iqueryableT, "query");
            ParameterExpression arg = Expression.Parameter(tableType, tableName);
            MemberExpression nameProperty = Expression.PropertyOrField(arg, columnName);
            Expression<Func<TResult, TValue>> lambda = Expression.Lambda<Func<TResult, TValue>>(nameProperty, arg);
            //here you already have delegate in the form of "TResult => TResult.columnName"
            return query.GroupBy(lambda);

        /*var expression = Expression.Call(typeof(Enumerable), 
                                        "GroupBy", 
                                        new Type[] { tableType, typeof(string) },
                                        data, 
                                        lambda);
        var predicate = Expression.Lambda<Func<TResult, String>>(expression, arg); // this is the line that produces the error I describe below
        var result = query.GroupBy(predicate).AsQueryable();
        return result;*/
    }
var grouped = locations.addGroupBy<int, ObjCurLocViewNormalized>(someFieldNameWithTheTypeOfInt);
静态公共IQueryable addGroupBy(
此IQueryable查询,字符串columnName)
{
var providerType=query.Provider.GetType();
//查找特定类型参数(IQueryable中的T)
常量对象EmptyfilterCriteria=null;
var iqueryableT=提供程序类型
.FindInterfaces((ty,obj)=>ty.IsGenericType&&ty.GetGenericTypeDefinition()==typeof(IQueryable),EmptyfilterCriteria)
.FirstOrDefault();
类型tableType=iqueryableT.GetGenericArguments()[0];
字符串tableName=tableType.Name;
ParameterExpression数据=Expression.Parameter(iQueryTablet,“查询”);
ParameterExpression arg=Expression.Parameter(tableType,tableName);
MemberExpression-nameProperty=Expression.PropertyOrField(arg,columnName);
表达式lambda=Expression.lambda(nameProperty,arg);
//这里已经有了“TResult=>TResult.columnName”形式的委托
返回query.GroupBy(lambda);
/*var expression=expression.Call(typeof(可枚举),
“群比”,
新类型[]{tableType,typeof(string)},
数据,
lambda);
var predicate=Expression.Lambda(Expression,arg);//这是产生我下面描述的错误的行
var result=query.GroupBy(谓词).AsQueryable();
返回结果*/
}
您将按以下方式调用表达式:

var grouped = locations.addGroupBy<string, ObjCurLocViewNormalized>(childLocationFieldName);
var group=locations.addGroupBy(childLocationFieldName);
第一个泛型参数“string”用于明确表示分组所基于的元素类型。例如,您可以按“int”字段分组,方法调用如下所示:

    static public IQueryable<IGrouping<TValue, TResult>> addGroupBy<TValue, TResult>(
                this IQueryable<TResult> query, string columnName)
            {
            var providerType = query.Provider.GetType();

            // Find the specific type parameter (the T in IQueryable<T>)
            const object EmptyfilterCriteria = null;
            var iqueryableT = providerType
                .FindInterfaces((ty, obj) => ty.IsGenericType && ty.GetGenericTypeDefinition() == typeof(IQueryable<>), EmptyfilterCriteria)
                .FirstOrDefault();
            Type tableType = iqueryableT.GetGenericArguments()[0];
            string tableName = tableType.Name;

            ParameterExpression data = Expression.Parameter(iqueryableT, "query");
            ParameterExpression arg = Expression.Parameter(tableType, tableName);
            MemberExpression nameProperty = Expression.PropertyOrField(arg, columnName);
            Expression<Func<TResult, TValue>> lambda = Expression.Lambda<Func<TResult, TValue>>(nameProperty, arg);
            //here you already have delegate in the form of "TResult => TResult.columnName"
            return query.GroupBy(lambda);

        /*var expression = Expression.Call(typeof(Enumerable), 
                                        "GroupBy", 
                                        new Type[] { tableType, typeof(string) },
                                        data, 
                                        lambda);
        var predicate = Expression.Lambda<Func<TResult, String>>(expression, arg); // this is the line that produces the error I describe below
        var result = query.GroupBy(predicate).AsQueryable();
        return result;*/
    }
var grouped = locations.addGroupBy<int, ObjCurLocViewNormalized>(someFieldNameWithTheTypeOfInt);
var grouped=locations.addGroupBy(somefieldname,类型为of it);
编辑 以您的方式完成此解决方案:

//返回query.GroupBy(lambda);
MethodCallExpression表达式=表达式.Call(类型化(可枚举),
“群比”,
新[]{typeof(TResult),typeof(TValue)},
数据,
lambda);
var result=Expression.Lambda(表达式,数据).Compile().DynamicInvoke(查询);
返回((IEnumerable)结果).AsQueryable();

解决方案应该非常简单:

public static IQueryable<IGrouping<TColumn, T>> DynamicGroupBy<T, TColumn>(
    IQueryable<T> source, string column)
{
    PropertyInfo columnProperty = typeof(T).GetProperty(column);
    var sourceParm = Expression.Parameter(typeof(T), "x");
    var propertyReference = Expression.Property(sourceParm, columnProperty);
    var groupBySelector = Expression.Lambda<Func<T, TColumn>>(propertyReference, sourceParm);

    return source.GroupBy(groupBySelector);
}
您可以这样调用它:

var grouped = locations.addGroupBy(childLocationFieldName);
var list = new List<TestClass>();
var queryable = list.AsQueryable();
DynamicGroupBy<TestClass, string>(queryable, "TestProperty");
var list=newlist();
var queryable=list.AsQueryable();
DynamicGroupBy(可查询,“TestProperty”);

为什么您的
谓词
行使用
Func
?您的expersion返回一个
I分组
,它不是
字符串
。感谢kirk,我尝试了:将行更改为:var predicate=Expression.Lambda(Expression,arg);但现在我得到了编译错误:错误5无法隐式地将类型“System.Linq.IQueryable”转换为“System.Linq.IQueryable”。存在显式转换(是否缺少转换?)。这是写你告诉我的内容的错误方法吗?主要问题是你把
.GroupBy
的调用与传递给它的lambda谓词混淆了。现在没有时间进一步回答,但如果一小时后这个问题仍然没有得到回答,我将进行更彻底的尝试。啊,这个错误与返回类型不匹配有关。但是我认为我不想更改返回类型,是吗?为什么在注释
//查找特定类型参数(IQueryable中的t)
之后会有那个古怪的代码?很显然,您在
TResult
中已经有了这些信息,不是吗?我宁愿不要碰原始代码,因为问题是关于其他事情的。当然,代码是可以改进的。看起来你的答案和我的类似,但是现在很完整,代码重构=)嗯,看起来很有希望,但是“方法'Parameter'没有重载使用'1'参数。”所以它不像下面这行:var sourceParm=Expression.Parameter(typeof(t));我在3.5频道。这是一个.NET4.0瘦版吗
public class TestClass
{
    public string TestProperty { get; set; }
}
var list = new List<TestClass>();
var queryable = list.AsQueryable();
DynamicGroupBy<TestClass, string>(queryable, "TestProperty");