2016-07-05 59 views
5

背景

我需要能夠建立一個.INCLUDE該過濾的結果,到或特定日期之前創建的記錄。我不會知道原始LINQ語句中的對象的類型,我會找到它們(通過大量的箍環,但那是行得通的)。動態構建包括與當過濾器

我有對象的這樣一個圖:

  A -> Ac 
     /\ 
    Bc <- B \ 
    / \ 
Cc <- C  D -> Dc 

對象AcBcCc,並Dc都動態地發現(也就是寫原來的LINQ當開發者沒有鍵入這些關係聲明)。然後需要將它們添加到IQueryable表達式中,並且只返回特定DateTime的值。

到目前爲止的代碼

我試圖構建構建一個Lambda和比較日期的功能。到目前爲止,如果原始查詢是A.Include(x => x.B).Include(x => x.B.Select(y => y.C),我可以構造字符串"A.B.Bc",所以我知道A,B和Bc的類型以及它們相關的方式。

private static IQueryable<T> FilterChangeTrackerToDate<T>(this IQueryable<T> query, string includeString, DateTime targetDateTime) 
{ 
    var param = Expression.Parameter(typeof(T), "x"); 

    var prop = Expression.Property(param, includeString + ".CreatedUtc"); 

    var dateConst = Expression.Constant(targetDateTime); 

    var compare = Expression.LessThanOrEqual(prop, dateConst); 

    var lambda = Expression.Lambda<Func<T, bool>>(compare, param); 

    return query.Where(lambda); 
} 

的問題是,上面的代碼崩潰,因爲"A.B.Bc.CreatedUtc"是不加載日期屬性的正確方法 - 我需要通過.Select語句來遍歷此。

的問題

爲了既負載記錄和濾波器它們,我需要動態地建立一個.Select拉出我所需要的值(其幸運的是,是靜態的基於繼承)並將這些值置於匿名類型中,然後可以使用.Where()進行過濾。所有這些都需要用最少的泛型來完成,因爲我沒有編譯時類型來驗證,我不得不濫用反射來讓它們工作。

從本質上講,我需要創造這樣的:

.Select(x => new 
{ 
    Bc = x.B.Select(z => z.Bc.Select(y => y.CreatedUtc).Where(q => q > DateTime.UtcNow)), 
    A= x 
}) 

動態,使用字符串 「A.B.Bc」,對於任何級別的嵌套。

資源

這是我看到如何篩選的EF包括方法: LINQ To Entities Include + Where Method

有關動態創建一個選擇這篇文章的會談,但它僅選擇頂層的價值觀和似乎並不喜歡的話可以建立需要我的問題零件的其餘部分:How to create LINQ Expression Tree to select an anonymous type

動態的LINQ

使用System.Linq的。動態庫,我曾經試圖訪問的CreatedUtc值關BC的:

query = (IQueryable<T>) query.Select(includeString + ".CreatedUtc"); 

includeString = "B.Bc",但是這給了我一個例外:

Exception thrown: 'System.Linq.Dynamic.ParseException' in System.Linq.Dynamic.dll 

Additional information: No property or field 'Bc' exists in type 'List`1' 

回答

2

我相信System.Linq.Dynamic是你所需要的。它最初是從微軟寫的ScottGu庫,它可以讓你從字符串構建LINQ查詢這樣的:

IQueryable nestedQuery = query.Select("B.Bc.CreatedUtc"); 

哪裏查詢IQueryable<A>

這個圖書館有一些分叉。你可以從here開始。查詢語言文檔是here。另外here有一個版本有一些額外的功能和here是dotnet.core版本。

UPD1:擴展的SelectMany方法的 This圖書館沒有,但this一個人。因此,與後者庫,你可以做到以下幾點:

query.SelectMany("B").SelectMany("Bc").Select("CreatedUtc"); 
+0

當我包括字符串'「B.Bc.CreatedUtc」',我得到這個錯誤:'其它信息:沒有屬性或字段「BC」的類型存在「List'1''。它看起來不像是正確地探索嵌套圖形? – Max

+0

你能在這裏展示更多你的代碼嗎? –

+0

我更新了我的主帖。 – Max