【发布时间】:2009-09-25 22:53:23
【问题描述】:
使用System.Linq.Dynamic 命名空间,我能够构建一个通用列列表,以根据当前用户控件中存在的列进行搜索(我们在各个地方使用的可搜索网格)。过程很简单,取当前用户可见的列列表,将列追加到where子句中的动态查询表达式中,查看整个串联序列是否包含指定的字符串。
这实现了两件事,让用户使用单个搜索框(谷歌风格)进行搜索,该搜索框在用户看到的所有网格中以相同的方式工作,以及将搜索卸载到数据库。
这是它目前的工作方式(结果 = IQueryable<T> 或 IEnumerable<T>):
var se = GetGridSearchExpression(grid);
if (se != null) result = result.Where(se, grid.SearchText.ToLower());
private static string GetGridSearchExpression(Grid grid)
{
if (grid.SearchText.IsNullOrEmpty()) return null;
var sb = new StringBuilder();
foreach (var s in grid.ColumnNames)
{
sb.AppendFormat("{0} {1} ",
sb.Length == 0 ? string.Empty : "+\"|^|\"+", s);
}
return string.Format("({0}).ToLower().Contains(@0)", sb);
}
打印出来的“|^|” string 是随机的,以防止对单个列的搜索匹配到下一个列,例如列“Bo”“Bryant”不匹配搜索“Bob”,搜索的结果是“Bo |^| Bryant”阻止匹配。
Nullables 是问题出现的地方,有一个 DateTime?或 Nullable 类型例如会导致以下错误:
Expression of type 'System.Nullable`1[System.DateTime]' cannot be used for
parameter of type 'System.Object' of method
'System.String Concat(System.Object, System.Object)'
下面是 DynamicQueryable 爆炸的部分:
Expression GenerateStringConcat(Expression left, Expression right) {
return Expression.Call(null,
typeof (string).GetMethod("Concat", new[] {typeof (object), typeof (object)}),
new[] {left, right});
}
到目前为止,我发现消除此问题的唯一方法是将表达式构建器中的附加替换为:
foreach (var s in grid.ColumnNames)
{
sb.AppendFormat("{0}({1} != null ? {1}.ToString() : string.Empty)",
sb.Length == 0 ? string.Empty : "+\"|^|\"+", s);
}
由于我们在 LINQ to SQL 中,这导致了一个臃肿的 case 语句。考虑到从数据库加载 每个 对象然后搜索的替代方法,最多 8-10 列的 case 语句是可以接受的。
是否有更简洁或更简单的方法来完成全部或部分操作?
已编辑:感谢 Marc...我从不在代码中的任何地方使用 GetEnumerator,总是使用 foreach 或 .ForEach()...但由于某种原因,它在当时让调试变得更容易了,不过我现在不记得为什么了。清除了当前代码的问题。
【问题讨论】:
-
顺便说一句;我不建议手动展开
foreach- 这太容易出错了;例如,您未能处置枚举数。只需使用foreach -
编辑显示使用 LINQ-to-Objects
标签: c# linq linq-to-sql