posts - 0,  comments - 20,  trackbacks - 0
原文: http://www.cnblogs.com/killuakun/articles/1259389.html

最近有个项目用Linq做的,有个复合搜索模糊查询的功能,有点麻烦,绕了好几个弯,最后是解决了,在这里分享一下我的处理过程,如果大家有更好的办法也请给我介绍一下。我用Linq还不熟,好多东西边查资料边做的。

 

应用场景如下图,多条件复合搜索,很常见吧(但Linq搞这个还真是麻烦):

 

阶段一:

首先是找到了李永京(YJingLee)前辈的《LINQ体验(17)——LINQ to SQL语句之动态查询》一文,利用Lambda表达式树可以进行动态查询。

写了个方法进行复合查询,动态组合条件,生成Lambda表达式。

 

Code

 

搞了半天本来很兴奋的,之后才知道Lambda表达式是写不出.Contains()的,我的心瓦凉瓦凉的。

 

阶段二:

虽然李永京的文章没给我多少帮助,但它后面有个回复很有价值:“用微软提供的System.Linq.Dynamic方便点。”

很快找到了对应例子和Dynamic.cs,也找到了《Linq to SQL Dynamic 动态查询》,有更细致的例子,可惜Dynamic.cs也是不能使用like的,恨啊!

 

Code

代码很容易,但没什么用:(

 

阶段三:

中文的实在是找不到了,在MS的官方BBS上找到了个链接,非常有用!《dynamic linq queries / dynamic where clause (part 2) 》,这个老外扩展了Dynamic.cs,写了个PredicateExtensions类,虽然不知道他是怎么想出来的,但确实有效!

这里放出核心代码,很容易看懂,简单就是美! 

Code

 

下面是我写了注释后的PredicateExtensions,我说不清楚构造函数的True和False具体是怎么起作用的,但结果就是我的注释那样,在复合查询写条件时很重要(不过目前全写AND就完成复合查询了,我还没搞多关键词OR的那种):

Code

 

不知道这篇文章是否适合放在园子首页,我想这个是有一定价值的,我在园子里貌似没找到这样的解决方法:)

posted @ 2008-08-03 20:26 肖坤 阅读(2726) 评论(25)  编辑 收藏 网摘 所属分类: Linq

  回复  引用  查看    
#1楼 2008-08-03 20:41 | zeus2      
模糊查询不能使用Contains嘛。

多条件 多加几个WHere条件吧。
  回复  引用  查看    
#2楼 2008-08-03 20:43 | Desmend      
哎,很想学习下啊,现在没时间
  回复  引用    
#3楼 2008-08-03 20:56 | zhengming [未注册用户]
from u in Consulting.Instance.UserT_TractInfo
where u => u.B_number.Contains(condition) &&
u => u.B_address.Contains(condition) &&
u => u.B_canton.Contains(condition);
有区别吗?
  回复  引用  查看    
#4楼 2008-08-03 21:00 | 真见      
你这个图片也够强的。
  回复  引用  查看    
#5楼 2008-08-03 21:59 | 深蓝      
好复杂的代码,我眼睛要花了@_@
  回复  引用  查看    
#6楼 2008-08-03 22:14 | 金色海洋(jyk)      
好像Linq并不太适合做动态查询呀。

我觉得可以放在首页的,支持。


  回复  引用  查看    
#7楼 2008-08-03 23:21 | 荔橙伊珊雨      
呵呵.支持.
  回复  引用    
#8楼 2008-08-04 09:08 | violet250 [未注册用户]
啥的。。。多几个WHERE 方法 会自动加上条件的。。估计楼主还没很好了解Linq运作方式
  回复  引用  查看    
#9楼 2008-08-04 09:48 | 杨义金      
这种查询方法太麻烦了,不好控制。

还是像HQL 这种查询语言好用点。
  回复  引用    
#10楼 2008-08-04 10:34 | 欧阳西风 [未注册用户]
@violet250
这里有个问题,当最终用户可能用一个条件,也可能用全部条件时,语句并不同,而这个组合非常多时,你怎么办...并不是你简单的加几个where,要不然楼主也不用费劲写这个东西了.
  回复  引用  查看    
#11楼 2008-08-04 14:17 | SZW      
Linq 里面的Contains要反过来用,不过不是用在模糊查询上,是批量查询
  回复  引用  查看    
#12楼 [楼主]2008-08-04 22:28 | 肖坤      
也许我这里的例子看不到它和WHERE的区别,不过请注意我外层使用的是foreach,它的条件数量是不固定的,而且它可以做到子条件中使用OR进行多关键词的查询,这个用传统的LINQ就很难做到了。
灵活性还是相当可观的。
  回复  引用    
#13楼 2008-08-05 13:58 | ico [未注册用户]
痛頭的很呀!linq沒有多表關聯,動態條件查詢目前還沒有很好的解決方案.所以我個對他沒辦法了,我的建議到把他寫在存儲過程裡,然後用linq調用存儲過程,但這個冶標不冶本,期待樓主能給我們帶來更好的文章!
  回复  引用  查看    
#14楼 [楼主]2008-08-06 18:25 | 肖坤      
@ico
如果还是要用存储过程,那干脆还是用CodeSmith生成DAL,全部回归传统吧。。。用LINQ不就是看中它的“美观大方”吗
  回复  引用  查看    
#15楼 2008-08-26 16:39 | Alex.XL      
我也刚刚才开始研究LINQ的相关的东西.
看了你的文章.然后自己又研究了下.
发现你说的阶段一和阶段二也可以实现string.Contains()的方法的.代码如下.

NorthwindDataContext d = new NorthwindDataContext();
//linq
var cas = from s in d.Categories
where s.CategoryID > 1 && s.CategoryName.Contains("Con")
select s;

Response.Write("LinQ:<br/>");
foreach (Categories c in cas)
{
Response.Write(string.Format("{0}:{1}<br/>", c.CategoryID, c.CategoryName));
}

//linq.Dynamic
List<Categories> li = d.Categories.Where("CategoryID > 1 and CategoryName.Contains(\"Con\")").ToList();

Response.Write("<br/>Dynamic LinQ:<br/>");
foreach(Categories c in li)
{
Response.Write(string.Format("{0}:{1}<br/>", c.CategoryID, c.CategoryName));
}


//Expression Tree
IQueryable<Categories> categories = d.Categories;
//构造 s => s.CategoryID > 1 && s.CategoryName.Contains("Con")
ParameterExpression param = Expression.Parameter(typeof(Categories), "s");
//选择s.CategoryID
Expression selector = Expression.Property(param, typeof(Categories).GetProperty("CategoryID"));
//组合条件 s.CategoryID > 1
Expression FirstCondition = Expression.GreaterThan(selector, Expression.Constant(1, typeof(int)));

//组合条件 s.CategoryName.Contains("Con")
Expression SecondCondition = Expression.Call(
Expression.Property(param, typeof(Categories).GetProperty("CategoryName"))
, typeof(string).GetMethod("Contains")
, Expression.Constant("Con", typeof(string)));
//组合条件 s.CategoryID > 1 && s.CategoryName.Contains("Con")
Expression Condition = Expression.And(FirstCondition, SecondCondition);
Expression pred = Expression.Lambda(Condition, param);
//调用Where
Expression expr = Expression.Call(typeof(Queryable), "Where",
new Type[] { typeof(Categories) },
Expression.Constant(categories), pred);
li = d.Categories.AsQueryable()
.Provider.CreateQuery<Categories>(expr).ToList();

Response.Write("<br/>Expression Tree:<br/>");
foreach (Categories c in li)
{
Response.Write(string.Format("{0}:{1}<br/>", c.CategoryID, c.CategoryName));
}
如果有什么不对,请见谅.我也是个新手.
  回复  引用  查看    
#16楼 2008-08-26 16:54 | Alex.XL      
忘记写输出了..
用的是SQL SERVER里面的自带库-Northwind.
下面是上面代码的输出
--------------------------
LinQ:
2:Condiments
3:Confections

Dynamic LinQ:
2:Condiments
3:Confections

Expression Tree:
2:Condiments
3:Confections


  回复  引用  查看    
#17楼 [楼主]2008-08-26 17:32 | 肖坤      
@Alex.XL

这个方法是可以的,但好象还做不到多条件组合的查询。



我的主要目标是,在查询条件的关键词、数量都不确定的时候,可以有一种较优美的方法实现,而不必搞一大段if{}else if{}else if{}else{}这样的语句出来。



我查询的环境是,通过类似

/search.aspx?b_number=p&b_canton=%行政区&a_status=4&b_area=片区&c_clinchdate=2006&order=UnitPrice

这样一次传N个不同字段名的参数来动态实现复合查询,传统的组合SQL语句也有些判断语句的,而且条件越多就越难以进行测试。我的这篇POST意义就是说明我自己是如何解决这个问题的。
  回复  引用  查看    
#18楼 2008-08-26 18:09 | Alex.XL      
@肖坤
哦..原来如此..
不过.那么长的SWITCH语句...
也可以进行继续优化把.

  回复  引用  查看    
#19楼 [楼主]2008-08-28 09:17 | 肖坤      
@Alex.XL
switch里每个case中只有2条语句,很美了:)
  回复  引用    
#20楼 2008-09-04 10:03 | -可乐 [未注册用户]
请问nvcParam是不是二位数组,我是LINQ新学者,楼主能不能把完整的例子贴上来啊,谢谢了
  回复  引用  查看    
#21楼 [楼主]2008-09-04 12:19 | 肖坤      
@-可乐
nvcParam是NameValueCollection类型,是键值对的一种,用它可以传递key和value,你可以查查相关的信息
  回复  引用  查看    
#22楼 2008-10-21 13:10 | XHero Liu      
正做呢,从楼主这借点经验...
  回复  引用    
#23楼 2008-12-02 10:46 | panpeng [未注册用户]
--引用--------------------------------------------------
-可乐: 请问nvcParam是不是二位数组,我是LINQ新学者,楼主能不能把完整的例子贴上来啊,谢谢了
--------------------------------------------------------

  回复  引用    
#24楼 2008-12-11 20:38 | dony [未注册用户]
ExameThemeDataContext lDB = new ExameThemeDataContext();
List<Model.ET_COURSE_MSTR> lList = new List<Model.ET_COURSE_MSTR>();
var lLqList = lDB.ET_COURSE_MSTR.Where(condition).Select("New(vcCOURS_CODE,nvcNAME,nvcDESC,nvcPUBLISH,vcREG_CODE,vcUSER_ID,dtDO_TIME)").GetEnumerator();

while (lLqList.MoveNext())
{
Model.ET_COURSE_MSTR lModel = new Model.ET_COURSE_MSTR();
ET_LINQ.ET_COURSE_MSTR lLqModel = (ET_LINQ.ET_COURSE_MSTR)lLqList.Current;
lModel.vcCOURS_CODE = lLqModel.vcCOURS_CODE;
lList.Add(lModel);
}

无法将类型为“DynamicClass1”的对象强制转换为类型“ET_LINQ.ET_COURSE_MSTR”。
  回复  引用  查看    
#25楼 2008-12-11 21:01 | 木刀      
太复杂了。。。。我的想法可能是比较简单,但是我想肯定会有人更愿意用我这种方法的:
var rs=from p in ... select new{p.C1,p.C2};
//假定有两个文本框
if(txt1.Text!="")
rs=rs.Where(p.C1.Contains(txt1.Text));
if(txt2.Text!="")
rs=rs.Where(p.C2==txt2.Text);

更多的动态条件也是一样。 其中contains 会被翻译成like。
posted on 2008-12-17 18:11 Documents 阅读(2974) 评论(0)  编辑  收藏 所属分类: LinqASP.NET

只有注册用户登录后才能发表评论。


网站导航:
 
<2024年4月>
31123456
78910111213
14151617181920
21222324252627
2829301234
567891011

留言簿

文章分类

文章档案

J2EE

搜索

  •  

最新评论