c# - Grouping Lambda Expressions by Operators and Using Them With DapperExtensions' PredicateGroups -
pursuant previous question: pulling apart expression<func<t, object>>
- trying make bit more advanced. currently, can this:
var matchingpeople = connection.get<person>(p => p.marketid == marketid);
which converted dapperextensions fieldpredicate
:
// assume i've parsed p => p.marketid == marketid constituent parts: // left = p => p.marketid, theoperator = operator.eq, right = marketid predicates.field(left, theoperator, right);
i want able this:
var matchingpeople = connection.get<person>(p => p.marketid == marketid && p.firstname == "john" || p.firstname == "jack");
and generate sql looks this:
declare @marketid int = 3 declare @firstname01 varchar(max) = 'john' declare @firstname02 varchar(max) = 'jack' select * person marketid = @marketid , (firstname = @firstname01 or firstname = @firstname02)
by using dapperextensions compound predicate groups
:
// ** code trying dynamically create based on lambda passed in ** var predicategroupand = new predicategroup {operator = groupoperator.and, predicates = new list<ipredicate>()}; // have code determine: left = p => p.marketid, theoperator = operator.eq, right = marketid predicategroupand.predicates.add(predicates.field(left, operator.eq, right)); var predicategroupor = new predicategroup {operator = groupoperator.or, predicates = new list<ipredicate>()}; // have code determine: left = p => p.firstname, theoperator = operator.eq, right = "john" predicategroupand.predicates.add(predicates.field(left, operator.eq, right)); // have code determine: left = p => p.firstname, theoperator = operator.eq, right = "jack" predicategroupor.predicates.add(predicates.field(left, operator.eq, right)); var predicategroupall = new predicategroup // passed dapperextensions' getlist<t> method { operator = groupoperator.and, // how set correctly? predicates = new list<ipredicate> {predicategroupand, predicategroupor} };
my problem seems around way expression trees parsed. assume have lambda expression:
p => p.marketid == marketid && p.firstname == "john" || p.firstname == "jack"
i can cast binaryexpression
. if use binaryexpression.left
, get
p.marketid == marketid && p.firstname == "john"
and binaryexpression.right
yields:
p.firstname == "jack"
also, nodetype
of overall binaryexpression
seems set last conditional operator of lambda, i.e. expressiontype.orelse
i feel need use recursion , traverse lambda expression right left, haven't been able create compound group predicates want. specifically, how group and
lambdas together, , or
lambdas together? thanks!
your example lambda,
p => p.marketid == marketid && p.firstname == "john" || p.firstname == "jack"
is equivilent of
p => (p.marketid == marketid && p.firstname == "john") || p.firstname == "jack"
because &&
has higher precendence ||
.
because of you'll tree &&
@ "bottom", (as needs calculated first) ||
on top:
|| / \ && firstname == "jack" / \ p.marketid == marketid p.firstname == "john"
once understand operator precedence above makes sense. if want alternative can use brackets force ||
evaluated first (making end @ bottom of expression tree).
p => p.marketid == marketid && (p.firstname == "john" || p.firstname == "jack")
your general problem you're approaching wrong. trying create 2 groups, 1 ors , 1 ands. might work in case, not in general one, example, this: (a && b) || (c && d)
?
i think should happen each , and each or should translate own predicate group. see "multiple compound predicates (predicate group)" section of linked article. you'd replace binaryexpression predicate group.
in example have (a && b) || c || @ top. want end each time have operator want create predicate group, left , right list of expressions. in logic convert binaryexpression predicate group first use same function convert left , right predicate group
i.e. code sees ||.
creates predicate group ready add expressions list
chooses left first (doesn't matter).
ok, left binary expression, calls predicategroup target library understands
recursion working on && b. chooses left first, sees simple predicate, means can add predicate group, same right
we're original call function has predicate group lower expression on left converted different predicate group , added. goes down right now, simple individual predicate , can add list.
okay, if had crazy like:
a && b || c || d && e
ok, taking account higher precedence following: ((a && b) || c) || (d && e)
note i'm not 100% sure either bracket put c first && or last, doesn't matter, logic same when visualising tree, start innermost brackets. "leaves" work outwards, using brackets work tree, arriving @ root node, in our case || right of c:
|| / \ || && / \ / \ && c d e / \ b
Comments
Post a Comment