2009-11-23 46 views
0

這不是關於'如何動態分類(基於任意用戶提供的字段)'的另一個問題?Linq To Sql - 使用衆所周知的靜態類型在運行時更改排序順序

問題是 - 當我知道潛在的種類時,如何改變排序順序? (因此避免反射/通常與真正的動態排序相關聯的自定義的表達構建。)一個大的查詢

就拿此子查詢(縮短本示例):

(from solutionIds in context.csExtendedQAIncident_Docs 
    where solutionIds.tiRecordStatus == 1 
    && (from solutionProductAssocation in context.csProductDocs 
      where solutionProductAssocation.iSiteId == Settings.Current.WebUtility().Onyx.SiteId 
      && (from allowedProduct in context.KB_User_Allowed_Products 
        where allowedProduct.UserId == userId 
        select allowedProduct.ModelCode 
       ).Contains(solutionProductAssocation.chModelCd) 
      select solutionProductAssocation.chIdNo).Distinct().Contains(solutionIds.chIdNo) 
).OrderByDescending(s => s.dtUpdateDate) 
.Select(s => s.chIdNo) 
.Take(count ?? Settings.Current.WCFServices().Output.HomePage.MaxRows) 

的OrderByDescending部的工作原理如我會期待。

現在 - 我想這因素出類似如下:

Expression<Func<csExtendedQAIncident_Doc, IComparable>> ordering = (s) => s.dtUpdateDate; 
if (viewType == HomepageViewType.MostViewed) 
    ordering = (s) => s.vchUserField8; 
else if (viewType == HomepageViewType.MostEffective) 
    ordering = (s) => s.vchUserField4; 

,然後使用:

OrderByDescending(ordering) 

這並不編譯,但在運行時炸燬。

Unsupported overload used for query operator 'OrderByDescending'. 

當然這來自深System.Data.Linq.SqlClient.QueryConverter的深處 - 尤其是VisitSequenceOperatorCall。反射該代碼表明OrderByDescending必須滿足以下條件才能正確評估。 'mc'是傳遞給方法的MethodCallExpression。

if (((mc.Arguments.Count != 2) || !this.IsLambda(mc.Arguments[1])) 
    || (this.GetLambda(mc.Arguments[1]).Parameters.Count != 1)) 
{ 
    break; 
} 

所以實質上是MethodCallExpression必須具有2個參數,其中第二個具有可與一個單一的參數(大概排序字段)一個Expressions.LambdaExpression。如果這個代碼發生了,我得到的異常被拋出。

很清楚,我沒有正確構建表達式。沒有深入挖掘,有沒有人知道如何正確構建排序表達式?

+0

我想是這樣 OrderByDescending(Expression.Lambda >(訂貨,ordering.Parameters)) 但是,這並不完全正確要麼... – 2009-11-23 17:01:11

回答

3

我認爲不支持部分代碼是使用IComparable作爲您的排序表達式的一般返回類型。如果考慮使用OrderByDescending,則編譯器生成的lambda表達式具有您按以下順序排序的屬性類型的返回類型:例如,字符串屬性的Expression<Func<csExtendedQAIncident_doc, string>>

一個可能的答案,雖然我不知道它是否工作在你的情況,是先創建一個無序查詢:

IQueryable<Foo> unorderedQuery = from f in db.Foo select f; 

然後,根據不同的類別:

IOrderedQueryable<Foo> orderedQuery = unorderedQuery 
    .OrderBy(f => f.DefaultSortKey); 

if (sortBy == SortByName) 
    orderedQuery = unorderedQuery.OrderBy(f => f.Name); 
else if (sortBy == SortByDate) 
    orderedQuery = unorderedQuery.OrderBy(f => f.Date); 
// etc. 
+0

這實際上是我想要/打算使用的方法,*如果*我可以將子查詢列入單獨的查詢。到目前爲止,我嘗試這樣做並不成功。我注意到Linq to Sql的一些不一致(可能與我的理解; 0)有關,爲了可讀性目的將子查詢分解爲塊 - 有時它沒有問題,而其他時候我收到意外的問題。我可能會發表另一個問題。 在這一點上,我的上述問題是純粹的學術,直到我找出子查詢問題。 – 2009-11-23 20:23:05

0

我相信這不起作用,除非兩個可能的字段有相同的類型。

然後LINQ to sql會(如果可能的話)正確地創建相關的sql。

因此,例如,如果這兩個領域都是DateTime是否:

Expression<Func<csExtendedQAIncident_Doc, DateTime>> ordering = 
    s => s.dtUpdateDate; 
if (viewType == HomepageViewType.MostViewed) 
    ordering = (s) => s.vchUserField8; // a DateTime 
else if (viewType == HomepageViewType.MostEffective) 
    ordering = (s) => s.vchUserField4; // another DateTime 

那麼這會工作得很好(我測試了它和它的工作)

您可以改爲做了每種類型以便通過任一一系列嵌套的switch/if語句通過構造一個字典或類似的結構來獲取它們。

對於LINQ to SQL中沒有明確的動態創建查詢,我相信它一定知道精確類型的查詢,而不是隻是把它作爲一個IComparable接口的工作...

+0

謝謝 - 與上面的Ben一樣的解釋。對我來說,看起來不尋常的是,我不能僅僅使用一種可比較的方式來對待這種泛泛之談。將它作爲Linq限制進行歸檔。 謝謝! – 2009-11-23 20:24:42