动态地将GroupBy添加到Lambda表达式

expression-trees linq

好吧,我承认我还没有完全“获得”lambda表达式和LINQ表达式树;我正在做的很多事情就是切割和粘贴,看看哪些有效。我看了很多文档,但我还没有找到我的“啊哈”时刻。

有了这个说......

我正在尝试动态地将GroupBy表达式添加到我的Linq表达式中。我在这里关注了这个问题: 需要帮助创建Linq.Expression到Enumerable.GroupBy

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

首先,我有我的数据库的实体类,以及一个名为ObjCurLocViewNormalized的表

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

public IQueryable<ObjCurLocViewNormalized> getLocations()
{
    IQueryable<ObjCurLocViewNormalized> res = (from loc in tms.ObjCurLocViewNormalized
                               select loc);
    return res;
}

所以我可以致电:

IQueryable<MetAmericanLinqDataModel.ObjCurLocViewNormalized> locations = american.getLocations();

到目前为止没问题。

现在,我希望按任意列分组,调用如下:

var grouped = locations.addGroupBy(childLocationFieldName);

现在,我有一个方法:

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;
}

所有这些编译好了,但是当我运行它时,我得到错误:

System.ArgumentException: Expression of type 'System.Collections.Generic.IEnumerable`1[System.Linq.IGrouping`2[System.String,MetAmericanLinqDataModel.ObjCurLocViewNormalized]]' cannot be used for return type 'System.String'

并且错误来自这一行:

 var predicate = Expression.Lambda<Func<TResult, String>>(expression, arg);

我正在复制和调整这段代码,这是我在动态添加Where子句到表达式时所做的成功工作。所以我有点在黑暗中刺伤。

如果那里的任何人可以帮助阐明这一点,显然发布完整的工作代码并为我做我所有的想法将是伟大的:),但如果你可以只是列出为什么这是错的,或如何包裹我的脑袋围绕这些概念,这将是伟大的。如果你能指出可以真正帮助弥合lambda表达式基础和构建动态表达式树之间差距的文档,那就太棒了。我的知识显然有很大漏洞,但我认为这些信息可能对其他人有用。

感谢大家的时间,当然,如果我在其他地方找到答案,我会在这里发布。

再次感谢。

热门答案

解决方案应该非常简单:

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

假设像这样的示例类:

public class TestClass
{
    public string TestProperty { get; set; }
}

你这样调用它:

var list = new List<TestClass>();
var queryable = list.AsQueryable();
DynamicGroupBy<TestClass, string>(queryable, "TestProperty");


许可下: CC-BY-SA with attribution
不隶属于 Stack Overflow
这个KB合法吗? 是的,了解原因
许可下: CC-BY-SA with attribution
不隶属于 Stack Overflow
这个KB合法吗? 是的,了解原因