Chapter85:GenericLambdaQueryBuilder

No Comments

Section85.1:QueryFilterclass

Thisclassholdspredicatefiltersvalues.

publicclassQueryFilter

{

publicstringPropertyName{get;set;}

publicstringValue{get;set;}

publicOperatorOperator{get;set;}

//Inthequery{a=>a.Name.Equals(“Pedro”)}

//Propertynametofilter-propertyName=”Name”

//Filtervalue-value=”Pedro”

//Operationtoperform-operation=enumOperator.Equals

publicQueryFilter(stringpropertyName,stringvalue,OperatoroperatorValue)

{

PropertyName=propertyName;

Value=value;

Operator=operatorValue;

}

}

Enumtoholdtheoperationsvalues:

publicenumOperator

{

Contains, GreaterThan,

GreaterThanOrEqual,

LessThan,

LessThanOrEqualTo,

StartsWith,EndsWith,

Equals,

NotEqual

}

Section85.2:GetExpressionMethod

publicstaticExpression<Func<T,bool>>GetExpression<T>(IList<QueryFilter>filters)

{

Expressionexp=null;

//Representsanamedparameterexpression.{parm=>parm.Name.Equals()},itistheparampart

//TocreateaParameterExpressionneedthetypeoftheentitythatthequeryisagainstana

name

//ThetypeispossibletofindwiththegenericTandthenameisfixedparm

ParameterExpressionparam=Expression.Parameter(typeof(T),”parm”);

//Itisgoodparcticenevertrustintheclient,soitiswisetovalidate.

if(filters.Count==0)

returnnull;

//Theexpressioncreationdifferifthereisone,twoormorefilters.

if(filters.Count!=1)

{

if(filters.Count==2)

//Itisresultfromdirectcall.

//Forsimplicitysaketheprivateoverloadswillbeexplainedinanotherexample.

exp=GetExpression<T>(param,filters[0],filters[1]);

else

{

//Asthereisnomethodformorethantwofilters,

//IiteratethroughallthefiltersandputIinthequerytwoatatime

while(filters.Count>0)

{

//Retrievethefirsttwofilters

varf1=filters[0];

varf2=filters[1];

//TobuildaexpressionwithaconditionalANDoperationthatevaluates

//thesecondoperandonlyifthefirstoperandevaluatestotrue.

//ItneededtousetheBinaryExpressionaExpressionderivedclass

//ThathastheAndAlsomethodthatjointwoexpressiontogether

exp=exp==null?GetExpression<T>(param, filters[0], filters[1]):

Expression.AndAlso(exp,GetExpression<T>(param, filters[0], filters[1]));

nextfilters

//Removethetwojustusedfilters,forthemethodinthenextiterationfindsthe

filters.Remove(f1); filters.Remove(f2);

//Ifitisthatlastfilter,addthelastoneandremoveit

if(filters.Count==1)

{

exp=Expression.AndAlso(exp,GetExpression<T>(param,filters[0])); filters.RemoveAt(0);

}

}

}

}

else

//Itisresultfromdirectcall.

exp=GetExpression<T>(param,filters[0]);

//convertstheExpressionintoLambdaandretunsthequery

returnExpression.Lambda<Func<T,bool>>(exp,param);

}

Section85.3:GetExpressionPrivateoverload

Forone filter:

Hereiswherethequeryiscreated,itreceivesaexpressionparameterandafilter.

privatestaticExpressionGetExpression<T>(ParameterExpressionparam,QueryFilterqueryFilter)

{

//Representsaccessingafieldorproperty,sohereweareaccessingforexample:

//theproperty“Name”oftheentity

MemberExpressionmember=Expression.Property(param,queryFilter.PropertyName);

//Representsanexpressionthathasaconstantvalue,sohereweareaccessingforexample:

//thevaluesoftheProperty”Name”.

//AlsoforclaritysaketheGetConstantwillbeexplainedinanotherexample.

ConstantExpressionconstant=GetConstant(member.Type,queryFilter.Value);

//Withthesetwo,nowIcanbuildtheexpression

//everyoperatorhasitonewaytocall,sotheswitchwilldo.

switch(queryFilter.Operator)

{

caseOperator.Equals:

returnExpression.Equal(member,constant);

caseOperator.Contains:

returnExpression.Call(member,ContainsMethod,constant);

caseOperator.GreaterThan:

returnExpression.GreaterThan(member,constant);

caseOperator.GreaterThanOrEqual:

returnExpression.GreaterThanOrEqual(member,constant);

caseOperator.LessThan:

returnExpression.LessThan(member,constant);

caseOperator.LessThanOrEqualTo:

returnExpression.LessThanOrEqual(member,constant);

caseOperator.StartsWith:

returnExpression.Call(member,StartsWithMethod,constant);

caseOperator.EndsWith:

returnExpression.Call(member,EndsWithMethod,constant);

}

returnnull;

}

Fortwofilters:

ItreturnstheBinaryExpresioninstanceinsteadofthesimpleExpression.

privatestaticBinaryExpressionGetExpression<T>(ParameterExpressionparam,QueryFilterfilter1, QueryFilterfilter2)

{

//Builttwoseparatedexpressionandjointhemafter.

Expressionresult1=GetExpression<T>(param,filter1);

Expressionresult2=GetExpression<T>(param,filter2);

returnExpression.AndAlso(result1,result2);

}

Section85.4:ConstantExpressionMethod

ConstantExpressionmustbethesametypeoftheMemberExpression.Thevalueinthisexampleisastring,whichis converted before creating the ConstantExpressioninstance.

privatestaticConstantExpressionGetConstant(Typetype,stringvalue)

{

//Discoverthetype,convertit,andcreateConstantExpression

ConstantExpressionconstant=null;

if(type==typeof(int))

{

intnum;

int.TryParse(value,outnum);

constant=Expression.Constant(num);

}

elseif(type==typeof(string))

{

constant=Expression.Constant(value);

}

elseif(type==typeof(DateTime))

{

DateTimedate;

DateTime.TryParse(value,outdate);

constant=Expression.Constant(date);

}

elseif(type==typeof(bool))

{

boolflag;

if(bool.TryParse(value,outflag))

{

flag=true;

}

constant=Expression.Constant(flag);

}

elseif(type==typeof(decimal))

{

decimalnumber;decimal.TryParse(value,outnumber);

constant=Expression.Constant(number);

}

returnconstant;

}

Section85.5:Usage

Collectionfilters=newList();QueryFilterfilter=newQueryFilter(“Name”,”Burger”,Operator.StartsWith); filters.Add(filter);

Expression<Func<Food,bool>>query=ExpressionBuilder.GetExpression<Food>(filters);

Inthiscase,itisaqueryagainsttheFoodentity,thatwanttofindallfoodsthatstartwith”Burger”inthename.

Output:

query={parm=>a.parm.StartsWith(“Burger”)}

Expression<Func<T,bool>>GetExpression<T>(IList<QueryFilter>filters)

About us and this blog

We are a digital marketing company with a focus on helping our customers achieve great results across several key areas.

Request a free quote

We offer professional SEO services that help websites increase their organic search score drastically in order to compete for the highest rankings even when it comes to highly competitive keywords.

Subscribe to our newsletter!

More from our blog

See all posts
No Comments