您的位置:首页 > 其它

EntityFramework动态多条件查询与Lambda表达式树

2017-12-08 22:21 351 查看
在常规的信息系统中,我们有需要动态多条件查询的情况,例如UI上有多个选择项可供用户选择多条件查询数据.
那么在.net平台EntityFramework下,我们用Lambda表达式树如何实现,这里我们需要一个PredicateBuilder的UML类图:





实现的代码是这样的:

///<summary>

[code]///Enablestheefficient,dynamiccompositionofquerypredicates.
///</summary>

publicstaticclassPredicateBuilder

{

///<summary>

///Createsapredicatethatevaluatestotrue.

///</summary>

publicstaticExpression<Func<T,bool>>True<T>(){returnparam=>true;}


///<summary>

///Createsapredicatethatevaluatestofalse.

///</summary>

publicstaticExpression<Func<T,bool>>False<T>(){returnparam=>false;}


///<summary>

///Createsapredicateexpressionfromthespecifiedlambdaexpression.

///</summary>

publicstaticExpression<Func<T,bool>>Create<T>(Expression<Func<T,bool>>predicate){returnpredicate;}


///<summary>

///Combinesthefirstpredicatewiththesecondusingthelogical"and".

///</summary>

publicstaticExpression<Func<T,bool>>And<T>(thisExpression<Func<T,bool>>first,Expression<Func<T,bool>>second)

{

returnfirst.Compose(second,Expression.AndAlso);

}


///<summary>

///Combinesthefirstpredicatewiththesecondusingthelogical"or".

///</summary>

publicstaticExpression<Func<T,bool>>Or<T>(thisExpression<Func<T,bool>>first,Expression<Func<T,bool>>second)

{

returnfirst.Compose(second,Expression.OrElse);

}


///<summary>

///Negatesthepredicate.

///</summary>

publicstaticExpression<Func<T,bool>>Not<T>(thisExpression<Func<T,bool>>expression)

{

varnegated=Expression.Not(expression.Body);

returnExpression.Lambda<Func<T,bool>>(negated,expression.Parameters);

}


///<summary>

///Combinesthefirstexpressionwiththesecondusingthespecifiedmergefunction.

///</summary>

staticExpression<T>Compose<T>(thisExpression<T>first,Expression<T>second,Func<Expression,Expression,Expression>merge)

{

//zipparameters(mapfromparametersofsecondtoparametersoffirst)

varmap=first.Parameters

.Select((f,i)=>new{f,s=second.Parameters[i]})

.ToDictionary(p=>p.s,p=>p.f);


//replaceparametersinthesecondlambdaexpressionwiththeparametersinthefirst

varsecondBody=ParameterRebinder.ReplaceParameters(map,second.Body);


//createamergedlambdaexpressionwithparametersfromthefirstexpression

returnExpression.Lambda<T>(merge(first.Body,secondBody),first.Parameters);

}


///<summary>

///ParameterRebinder

///</summary>

classParameterRebinder:ExpressionVisitor

{

///<summary>

///TheParameterExpressionmap

///</summary>

readonlyDictionary<ParameterExpression,ParameterExpression>map;


///<summary>

///Initializesanewinstanceofthe<seecref="ParameterRebinder"/>class.

///</summary>

///<paramname="map">Themap.</param>

ParameterRebinder(Dictionary<ParameterExpression,ParameterExpression>map)

{

this.map=map??newDictionary<ParameterExpression,ParameterExpression>();

}


///<summary>

///Replacestheparameters.

///</summary>

///<paramname="map">Themap.</param>

///<paramname="exp">Theexp.</param>

///<returns>Expression</returns>

publicstaticExpressionReplaceParameters(Dictionary<ParameterExpression,ParameterExpression>map,Expressionexp)

{

returnnewParameterRebinder(map).Visit(exp);

}


///<summary>

///Visitstheparameter.

///</summary>

///<paramname="p">Thep.</param>

///<returns>Expression</returns>

protectedoverrideExpressionVisitParameter(ParameterExpressionp)

{

ParameterExpressionreplacement;


if(map.TryGetValue(p,outreplacement))

{

p=replacement;

}


returnbase.VisitParameter(p);

}

}

}

[/code]

UnitTest的片断代码,一个产品查询的场景:


varmyProduct=pr.Repository.Find(

[code]BuildFindByAllQuery(productName,beignUpdateDate,endUpdateDate),
e=>e.UpdatedTime,

pageIndex,

pageSize);


Assert.IsTrue(myProduct.Count>0);

[/code]
UnitTest使用到生成查询条件的私有方法:


///<summary>

[code]///Buildsthefindbyallquery.
///</summary>

privatestaticExpression<Func<Product,bool>>BuildFindByAllQuery(stringproductName,DateTime?beignUpdateDate,DateTime?endUpdateDate)

{


varlist=newList<Expression<Func<Product,bool>>>();


if(!string.IsNullOrEmpty(productName))list.Add(c=>c.ProductName==productName);


if(beignUpdateDate!=null)list.Add(c=>c.UpdatedTime>=beignUpdateDate);


if(endUpdateDate!=null)list.Add(c=>c.UpdatedTime<=endUpdateDate);


//Addmorecondition

Expression<Func<Product,bool>>productQueryTotal=null;


foreach(varexpressioninlist)

{

productQueryTotal=expression.And(expression);

}

returnproductQueryTotal;

}

[/code]
上面的方法中由三个条件动态组成,一个是匹配productName,另两个是beginUpdateDate与endUpdateDate.在判断它们是否为时,构建最终查询条件集合.

最后把结果传给某个Repository类,完成相应的数据访问.

http://www.cnblogs.com/wintersun/p/3948227.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: