LINQ DYNAMIC SEARCH体会

 

1.     前言      

一直以来,ORM被认为是企业应用架构中不可或缺的一环,是面向对象程序设计的代表,是关系型数据库与程序对象连接桥梁。在众多的ORM开源框架中,Hibernate是最著名最耀眼的那个,我也曾在多个系统中都应用了Nhibernate。可惜的是,Nhibernate向下兼容性不好,2.0无法兼容1.1的应用,给我们项目组带来了困扰。数据库与对象的映射主流的方式包括两种:一种是xml,一种是Attribute反射。早期主流的是xml形式,个人认为xml文件太多,不便于管理,同时除了xml文件之外,还是需要建立Entity类,所以一直寻找一种比较简便的方法。后来我自己实现了后一种方式,不过是轻量级的,再后来linq出现了,其中linq2sql便是采用这种方式。

我们的目的是为了实现数据持久化,用什么框架都无所谓。为了以后升级的方便,所以我决定绑定微软这艘大船,采用linq

2.     Linq2sql

Linq是什么,园子里很多大牛都已经阐述的非常清楚了,我就不赘述了。我主要用到的是linq2sql,而最为常见的应用在园子里也是数不胜数,我主要介绍的是在实际应用经常用到的Dynamic Search动态查询。这将会用到微软提供的一个类库,在他提供的LinqSamples中,叫做Dynamic.cs

3.     动态查询

3.1.    like/in

linqlike通常用Contains来实现,示例如下

var query = from a in _ctx.A Where a.Name. Contains(condition) select a;
//或者
var query 
= _ctx.A.Where(a => a.Name. Contains(condition));

 

而用Dynamic的语法如下

var query = from a in _ctx.A Where("Name. Contains(\""+ condition +"\")");
//或者
var query = _ctx.A.Where("Name. Contains(\""+ condition +"\")");

linqin通常也用Contains来实现,示例如下

var objIds = new int[]{1,3,5};
var query 
= from a in _ctx.A Where objIds. Contains(a.ObjId) select a;

 

这里如果aobjid字段为int型,则采用int数组,如果为string型,则采用string数组,以此类推。

而采用Dynamic就没有那么方便了,需要将数组拆分并组合成or语句,示例如下

var objIds = new int[]{1,3,5};
StringBuilder sqlClause 
= new StringBuilder();
Foreach(
int objId in objIds)
      sqlClause.Append(“ ObjId 
= ”+objId+” or ”);

if(sqlClause.Length > 0)
{
         
string temp = sqlClause.ToString();
         temp 
= temp.Substring(0, temp.LastIndexOf("or"));
         var query 
= _ctx.A.Where(temp);
}

 

3.2.    复杂查询

通常情况下,由于用户输入的条件是未知的,所以查询时字段也是未知,如果还存在与其他表关联查询的话,则更为复杂。这种情况下,推荐使用Dynamic,示例如下

StringBuilder sqlClause = new StringBuilder();
if (condition.investNum > 0)
    sqlClause.Append(
" and Invest ="+ condition.investNum);


if (condition.benefitNum > 0)
    sqlClause.Append(
" and ContractBenefits ="+ condition.benefitNum);


if (condition.startTime != DateTime.MinValue)
     sqlClause.Append(
" and StartTime = DateTime(" + condition.startTime.Year + "," + condition.startTime.Month + "," + condition.startTime.Day + ")");

if (condition.endTime != DateTime.MinValue)
      sqlClause.Append(
" and EndTime =DateTime(" + condition.endTime.Year + "," + condition.endTime.Month + "," + condition.endTime.Day + ")");

if (!string.IsNullOrEmpty(condition.desc))
      sqlClause.Append(
" and Description.Contains("\""+condition.desc+"\"")");

var query 
= from a in _ctx.A.Where(sqlClause.ToString()) 
            join b 
in _ctx.B.Where(sqlClause.ToString())
            on a.ObjId equals b.AId
            select a;

//如果关联C查询

query = from a in query

        join c in _ctx.C.Where(condition)

        on a.ObjId equals c.AId

        select a;

 

在使用Dynamic是需要注意的是时间型,当数据采用时间型式,采用上述方案时,如果直接使用 endtime >= time的方式,Dynamic类则会抛出异常,认为数据类型匹配不上,所以在上述方案中,最好采用endtime >= DateTime(int年,int月,int)的方式。如果没有动态组装查询string,也可以采用如下方式

var query = from a in _ctx.A.Where(“EndTime >= @0”,time) select a;

 

      总的来说,绝大部分的动态查询(结合Intersect求交、Union求并等方法)用linq都能实现,笔者在项目中为了实现一个报表曾经实现过关联7张表左右的联合查询,关键看自己能否灵活运用linq的查询。

 

posted @ 2009-06-22 12:08  Yu Wang  阅读(704)  评论(1编辑  收藏  举报