2016-11-28 71 views
3

我願做以下的事情在實體框架代碼首先:內蒙古方法

Data.GroupBy(x => x.Person.LastName) 
.Select(x => x.OtherGrouping(...)).Where(...).GroupBy(...)...etc 



public static class Extensions 
{ 

public static IQueryable<IGrouping<T, T>> OtherGrouping<T>(this IQueryable<T> collection /**** Here I want to pass consts and lambdas\expressions*****/) 
    { 
     // Grouping, filtration and other stuff here 
     return collection.GroupBy(x => x); 
    } 
} 

的問題是.NET編譯OtherGrouping方法,它並不代表類似的表達,無法轉換爲SQL。

我發現LinqKit圖書館,在這種情況下,假設有幫助,但我不知道如何將其應用於我的具體情況。它適用於簡單的情況,當我只有像x => x+2這樣的表達式,但是我得到了返回IQueryable的Stucked。大概可以用手完全寫出表達樹,但我不想太深入。

任何想法如何做或我可以在哪裏讀到它?


這裏是我試圖根據Rob的評論

void Main() 
{ 
    AddressBases.GroupBy(x => x.ParentId).Select(x => new {x.Key, Items = x.AsQueryable().OtherGrouping(a => a.Country) }).Dump(); 

} 

public static class Extensions 
{ 
    public static IQueryable<IGrouping<TKey, TSource>> OtherGrouping<TSource, TKey>(this IQueryable<TSource> source, Expression<Func<TSource, TKey>> keySelector) 
    { 
     return source.Provider.CreateQuery<IGrouping<TKey, TSource>>(
      source.GroupBy(keySelector).Expression); 
    } 
} 

要做,我有一個例外:

NotSupportedException: LINQ to Entities does not recognize the method 'System.Linq.IQueryable`1[System.Linq.IGrouping`2[System.String,InsuranceData.EF.AddressBase]] OtherGrouping[AddressBase,String](System.Linq.IQueryable`1[InsuranceData.EF.AddressBase], System.Linq.Expressions.Expression`1[System.Func`2[InsuranceData.EF.AddressBase,System.String]])' method, and this method cannot be translated into a store expression. 

無法弄清楚但爲什麼我在OtherGrouping方法表達樹? OtherGrouping方法應該只是將另一個分組附加到表達式並將其傳遞給提供者,但不會將其自身放到樹中。

+1

你會需要調用集合的查詢提供電話取代它。看一看[這裏](https://github.com/Microsoft/referencesource/blob/master/System.Core/System/Linq/IQueryable.cs#L90)作爲例子。 – Rob

+0

感謝@Rob,看看LINQ源代碼是個好主意。我試圖在EF來源和錯誤中找到我的愚蠢原因。我會立即嘗試,也許你可以發佈答案而不是評論,所以我可以接受它,它會變得更加明顯爲其他人 – Neir0

回答

1

您編輯後的當前代碼是正確的 - 您錯誤的位置是C#提供的語法糖的常見問題。

如果你寫了以下內容:

void Main() 
{ 
    var res = Containers.OtherGrouping(c => c.ContainerID); 
    res.Expression.Dump(); 
    res.Dump(); 
} 

public static class Extensions 
{ 
    public static IQueryable<IGrouping<TKey, TSource>> OtherGrouping<TSource, TKey>(this IQueryable<TSource> source, Expression<Func<TSource, TKey>> keySelector) 
    { 
     return source.Provider.CreateQuery<IGrouping<TKey, TSource>>(
      source.GroupBy(keySelector).Expression 
     ); 
    } 
} 

你會看到,我們得到的輸出:

Table(Container).GroupBy(c => c.ContainerID) 

,並將結果與​​問題執行,我們斷言正確分組。然而,當你將它傳遞給Select時,你調用OtherGrouping裏面。讓我們嘗試一個簡單的例子,而不OtherGrouping

var res = Containers.OtherGrouping(c => c.ContainerID) 
    .Select(x => new 
    { 
     x.Key, 
     Items = x.GroupBy(c => c.ContainerID), 
    }); 
res.Expression.Dump(); 

什麼你提供給Select是一個表達式樹。也就是說,GroupBy的內部方法永遠不會被調用。如果您將查詢更改爲x.AsQueryable().OtherGrouping,並在OtherGrouping中放置斷點,則只會在第一次出現。

除此之外,x是IEnumerable<T>而不是IQueryable<T>。調用AsQueryable()爲您提供了一個IQueryable,但它也爲您提供了一個新的查詢提供程序。我並不十分確定實體框架的內部工作原理,但我敢說這是無效的 - 因爲我們不再有數據庫作爲提供者的目標。事實上,使用linq2sql(使用LINQPad),我們得到一個錯誤,說不支持.AsQueryable()

那麼,你可以做什麼?不幸的是,沒有乾淨的方式來做到這一點。由於在OtherGrouping有機會之前已經構建了,因此OtherGrouping的正文是什麼並不重要。我們需要在構建表達式樹之後,但在執行之前更改表達式樹。

對於這一點,你需要編寫一個表達式遊客將尋找.OtherGrouping表達通話,並與Queryable.GroupBy

+0

可能我們可以做到以下幾點:OtherGrouping應該返回一個表達式,我們需要建立表達式用於通過Invoke調用OtherGrouping方法來選擇。然後通過它來選擇並使用LinqKit展開魔術變更調用實際表達式。 – Neir0