2011-03-28 41 views
0

我有一個自定義方法獲取與jqGrid一起使用的用於搜索的選擇列表的字符串。jqGrid選擇列表的自定義Linq擴展方法

所需的字符串格式爲":All;value1:text1;value2:text2"我目前有以下方法可重複使用的方式來實現這一目標:

public static string jqGridFilterSelectList<TSource>(this IQueryable<TSource> source,Expression<Func<TSource, string>> selector) 
{ 
    return string.Join(";", source.Select(selector).Distinct().ToArray()); 
} 

該工程確定,但它需要調用是這樣的:

string filterSelectList = service.GetAllUsers().jqGridFilterSelectList(x=>x.User + ":" + x.User); 

我不喜歡使用像x=>x.User + ":" + x.User這樣的選擇器。我想這個轉換成2個重載像這(僞代碼!)

// case where we want the value and text of the select list to be the same 
public static string jqGridFilterSelectList<TSource>(this IQueryable<TSource> source,Expression<Func<TSource, string>> selector) 
{ 
    return string.Join(";", source.Select(selector + ":" + selector).Distinct().ToArray()); 
    //obviously this won't work, but is it possible in some other way while executing it on the database still? Also is it possible to insist the selector only contains 1 column. 
} 

//case where we want different text and value 
public static string jqGridFilterSelectList<TSource>(this IQueryable<TSource> source,Expression<Func<TSource, string>> textSelector,Expression<Func<TSource, string>> valueSelector) 
{ 
    return string.Join(";", source.Select(valueSelector + ":" + textSelector).Distinct().ToArray()); 
} 

我想我大概可以做到這一點使用動態LINQ,但我想知道,如果這是可能的。

回答

1

如果我理解正確的,你幾乎寫它:

public static string jqGridFilterSelectList<TSource>(
    this IQueryable<TSource> source, 
    Expression<Func<TSource, string>> selector 
) 
{ 
    var compiled = selector.Compile(); 
    return string.Join(";", 
     source.Select(x => compiled(x) + ":" + compiled(x)) 
      .Distinct().ToArray() 
    ); 
} 

//case where we want different text and value 
public static string jqGridFilterSelectList<TSource>(
    this IQueryable<TSource> source, 
    Expression<Func<TSource, string>> textSelector, 
    Expression<Func<TSource, string>> valueSelector 
) 
{ 
    return string.Join(";", 
     source.Select(x => valueSelector.Compile()(x) + ":" + textSelector.Compile()(x)) 
      .Distinct().ToArray() 
    ); 
} 

只需要調用你選擇功能來獲得的值。 如果我誤解了你的問題,請告訴我。

對於第二個問題,是有可能堅持選擇只包含1列,簡單的答案是否定的 - 選擇實際上可以是任何有效Func這需要TSource並返回string,有沒有辦法來限制可以在裏面完成(除非你想檢查提供的表達樹,但肯定會比結果更復雜)。

編輯:好的,所以這是一種SQL LINQ提供程序,實體框架?所以讓我們試試一下。我不知道是否會工作,但讓我們先嚐試獲取數據並連接上的對象:

public static string jqGridFilterSelectList<TSource>(
    this IQueryable<TSource> source, 
    Expression<Func<TSource, string>> selector 
) 
{ 
    var compiled = selector.Compile(); 
    return string.Join(";", 
     source.Distinct().AsEnumerable() 
      .Select(x => compiled(x) + ":" + compiled(x)) 
      .ToArray() 
    ); 
} 

//case where we want different text and value 
public static string jqGridFilterSelectList<TSource>(
    this IQueryable<TSource> source, 
    Expression<Func<TSource, string>> textSelector, 
    Expression<Func<TSource, string>> valueSelector 
) 
{ 
    return string.Join(";", 
     source.Distinct().AsEnumerable() 
      .Select(x => valueSelector.Compile()(x) + ":" + textSelector.Compile()(x)) 
      .ToArray() 
    ); 
} 

附加ToEnumerable調用數據庫的過程中的處理之間的切換。假設您的選擇器是確定性的並且沒有任何副作用,那麼您可以對已獲取的TSource項目進行操作。

+0

這不起作用,當嘗試'選擇器(x)'給出錯誤「選擇器是一個變量,但像方法一樣使用」。我試過'x => Expression.Invoke(選擇器)+「:」+ Expression.Invoke(選擇器)'但它拋出'InvalidOperationException:爲lambda調用提供的參數數量不正確 – 2011-03-28 15:59:21

+0

@Paul Creasey,這是一個' Expression'。所以你需要在調用之前編譯它:'var myFunc = selector.Compile(); myFunc(x)'或內聯:'selector.Compile()(x)'。答覆已更改。 – NOtherDev 2011-03-28 16:13:20

+0

無法轉換表達式'Table(Finance_RTC_MI_Data).Select(x =>((Invoke(Invoke(value(System.Func'1 [System.Func'2 [com.blah.lvis.Data.DataAccess.Finance_RTC_MI_Data,System。 String)])),x)+「:」)+ Invoke(Invoke(value(System.Func'1 [System.Func'2 [com.blah.lvis.Data.DataAccess.Finance_RTC_MI_Data,System.String]]) ),x)))'到SQL中,並不能把它當作本地表達式。 – 2011-03-28 16:39:01

1

另一種實現您需要的方法是使用searchoptionsdataUrlbuildSelect參數。

如果value字符串的形式爲「:All; value1:text1; value2:text2」,則直到確實需要(直到第一次搜索)纔會構建它。當用戶點擊搜索對話框時,jqGrid從dataUrl獲取數據。服務器方法可以有非常明確的接口並返回List<string>的JSON表示。在客戶端,您定義了buildSelect事件句柄,它將["text1", "text2", ...]轉換爲<select>。就這些。舉例說明這種方式的用法,你可以找到here。與示例相比,您只需在select元素中添加其他選項<option value="">All</option>

有時您應該另外使用ajaxSelectOptions jqGrid參數來自定義相應的$.ajax請求,該請求獲取選擇列表的數據。

方式的優點:

  1. 提供選擇列表中的數據的服務器方法可以有很清晰的界面,就回到名單。
  2. 從服務器發送的數據大小將減少,因爲您的值與您的案例中的文本相同,因此不會發送「value1」和「text1」兩次。
  3. 如果您的網格使用任何編輯方法(內聯,表單或單元格編輯),您可以使用相同的方法用於editoptions。在另一個實現buildSelect中,您應該只跳過在選擇列表中插入<option value="">All</option>
  4. select元素的數據將僅在真正需要時纔會構建:在搜索的第一次使用時。
  5. 來自服務器的用於選擇列表的HTTP GET響應可以被自動緩存,並且如果您需要在另一個網格中選擇相同的數據,則以前的服務器響應可以直接從本地瀏覽器緩存中獲取。
+0

謝謝,我已經考慮過了,我仍然可以嘗試,但我試圖儘量減少所涉及的http往返次數,因爲該網站託管在英國,但是來自世界各地的使用者可以獲得有點慢。 – 2011-03-28 16:20:37

+0

@ Paul Creasey:這是一個有點味道的問題。你可以試試這個。一般情況下,如果您在服務器響應中放置'Cache-Control:max-age:...',服務器響應可以從本地緩存中獲取很長時間,所以它將是**沒有往返**。我個人更喜歡有好的建築。它的一些小的性能問題將會有很多方法來解決服務器響應中HTTP讀取器的純粹更改所帶來的問題。 – Oleg 2011-03-28 16:33:39