動態地將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合法嗎? 是的,了解原因