2012-01-26 44 views
3

應用於實體框架中,擴展方法和Select()OrderBy()返回一個ObjectQuery,其被定義爲:什麼時候ObjectQuery真的是IOrderedQueryable?

public class ObjectQuery<T> : ObjectQuery, IOrderedQueryable<T>, 
    IQueryable<T>, <... more interfaces> 

Select()返回類型是IQueryable<T>和的OrderByIOrderedQueryable<T>。所以你可以說,兩者都返回相同的類型,但在不同的包裝。幸運的是,因爲現在我們可以在調用OrderBy之後申請ThenBy

現在我的問題。

比方說,我有這樣的:

var query = context.Plots.Where(p => p.TrialId == 21); 

這給了我一個IQueryable<Plot>,這是一個ObjectQuery<Plot>。但是,這也是一個IOrderedQueryable:

var b = query is IOrderedQueryable<Plot>; // True! 

但還是:

var query2 = query.ThenBy(p => p.Number); // Does not compile. 
// 'IQueryable<Plot>' does not contain a definition for 'ThenBy' 
// and no extension method 'ThenBy' .... 

當我這樣做:

var query2 = ((IOrderedQueryable<Plot>)query).ThenBy(p => p.Number); 

彙編,而是給出了一個運行時異常:

f類型'IQueryable`1[Plot]'的表達式不能使用或「方法的」 IOrderedQueryable`1[Plot] ThenBy[Plot,Nullable`1](IOrderedQueryable`1[Plot], Expressions.Expression`1[System.Func`2[Plot,System.Nullable`1[System.Int32]]])'IOrderedQueryable`1[Plot]類型'

鑄造被執行(我檢查),但是ThenBy參數的參數仍然被視爲IQueryable的(其困惑我一個位)。

現在假設某種方法返回ObjectQuery<Plot>給我,如IQueryable<Plot>(如Select())。如果我想知道在返回的對象上調用ThenBy是否安全,該怎麼辦?如果ObjectQuery是「真實的」或「假的」IOrderedQueryable而沒有捕捉到豁免,我怎樣才能知道它?

+2

我建議不要檢查具體類型,因爲它會將您與查詢提供程序綁定在一起,這正是IQueryable所避免的。一種方法是快速檢查表達式來檢查'SortBy()'方法,但我懷疑有人會指出一些更容易的方法。如果沒有,請在這裏留言,我會爲您提供走樹的代碼。祝你好運 – Smudge202

+0

@ Smudge202謝謝。有很多地方比表情樹更有趣,但如果你無法抗拒......但是,也許是別人。 –

+0

@ Smudge202順便說一句,檢查具體類型將無法正常工作,因爲它實現了兩個接口。令我感到困惑的是,普通的反思在這裏並沒有什麼幫助,所以如果我真的需要知道的話,那麼可能需要進行更深入的檢查。 –

回答

2

表達樹真的很好玩! (或者我可能是一個怪胎),並且如果Project Roslyn是任何事情的話,它可能會在許多開發者的未來中變得有用! =)

在你的情況下,從MSDN的ExpressionVisitor,並覆蓋的東西繼承類的VisitMethodCall方法簡單繼承,比較m.MethodInfoSortBy(也就是說,如果你不是太挑剔簡單地核對姓名,如果你想使用反射來挑剔與實際的SortBy MethodInfo進行比較

讓我知道您是否需要示例,但老實說,複製/粘貼ExpressionVisitor後,您可能需要不超過10行非-expression-tree code ;-)

希望可以幫到

+0

在那裏,你做到了。你感染了我的表達樹病毒!這是一個可行的解決方案(順便提一下,方法名稱是「OrderBy」),儘管它是特定於表達式的,你是對的,這很有趣!到目前爲止,我在公園散步:)。儘管在這裏有效,但我還會發佈一個以純C#術語來表達問題的問題。 –

+0

對於誰感興趣:[這裏](http://stackoverflow.com/questions/9063131/how-to-tell-which-interface-is-returned-by-a-method)是純粹的C#問題。 –

1

雖然表達式樹很好玩,但在這種情況下,簡單的解決方案是使用OrderBy而不是ThenBy嗎?

  • OrderByIQueryable的延伸和返回一個IOrderedQueryable
  • ThenByIOrderedQueryable的擴展,並返回IOrderedQueryable

因此,如果您有一個IQueryable(如上例中的查詢是IQueryable),並且您想要對其應用初始排序,請使用OrderByThenBy僅用於對已排序的查詢應用附加排序。

如果你有某種形式的LINQ的結果,但你不知道它是否是一個IQueryableIOrderedQueryable並想申請額外的濾波它,你也可以創建兩個方法,如:

static IOrderedQueryable<T, TKey> ApplyAdditionalOrdering<T, TKey>(this IOrderedQueryable<T, TKey> source, Expression<Func<T, TFilter>> orderBy) 
     { 
      return source.ThenBy(orderBy); 
     } 

而且

static IOrderedQueryable<T, TKey> ApplyAdditionalOrdering<T, TKey>(this IQueryable<T> source, Expression<Func<T, TFilter>> orderBy) 
     { 
      return source.OrderBy(orderBy); 
     } 

編譯器將計算出正確的調用基於您的查詢對象的編譯時類型。

+0

這是一個聰明的解決方案。一個缺點,它不能被用在*和表達式中。同時我從來沒有真正需要知道'IQueryable'是否有初始排序。只是我對這個無操作界面感到困惑。 –

相關問題