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
linq中like通常用Contains来实现,示例如下
//或者
var query = _ctx.A.Where(a => a.Name. Contains(condition));
而用Dynamic的语法如下
//或者
var query = _ctx.A.Where("Name. Contains(\""+ condition +"\")");
linq中in通常也用Contains来实现,示例如下
var query = from a in _ctx.A Where objIds. Contains(a.ObjId) select a;
这里如果a的objid字段为int型,则采用int数组,如果为string型,则采用string数组,以此类推。
而采用Dynamic就没有那么方便了,需要将数组拆分并组合成or语句,示例如下
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,也可以采用如下方式
总的来说,绝大部分的动态查询(结合Intersect求交、Union求并等方法)用linq都能实现,笔者在项目中为了实现一个报表曾经实现过关联7张表左右的联合查询,关键看自己能否灵活运用linq的查询。