2011-03-28 43 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