c# - How do I get 2 IQueryable<T> methods to implement a disjunction? -
this question has answer here:
appologies if simple question; suppose have ef query object 2 methods:
public static iqueryable<animal> fourlegged(this iqueryable<animal> query) { return query.where(r => r.numberoflegs == 4); } public static iqueryable<animal> withouttail(this iqueryable<animal> query) { return query.where(r => !r.hastail); }
now, in service layer, animals four-legged , without tail, can do:
_animalservice.query() .fourlegged() .withouttail();
that result in sql query so:
select * animal numberoflegs = 4 , hastail = 0
how use 2 query methods or instead? want animals either 4 legged or without tail
select * animal numberoflegs = 4 or hastail = 0
in nhibernate have used simple disjunction, can't find in ef.
thanks
solution: ended using linqkit predicates mentioned on answer. works quite , can reuse predicates too.
you can’t when called query.where()
. predicates there collected in iqueryable
, combined and
.
in order or
have make single query.where()
call , pass single expression covers various disjunctive predicates.
in case, combined predicate this:
query.where(r => (r.numberoflegs == 4) || (!r.hastail))
to make more dynamic, need build custom expression composition function works this:
expression<func<animal, bool>> fourlegged = r => r.numberoflegs == 4; expression<func<animal, bool>> withouttail = r => !r.hastail; query = query.where(combinedisjunctivepredicates(fourlegged, withouttail));
so let’s write combinedisjunctivepredicates
function:
public expression<func<t, bool>> combinedisjunctivepredicates<t>(params expression<func<t, bool>>[] predicates) { expression current = expression.constant(false); parameterexpression param = expression.parameter(typeof(t), "obj"); foreach (var predicate in predicates) { var visitor = new replaceexpressionvisitor(predicate.parameters[0], param); current = expression.or(current, visitor.visit(predicate.body)); } return expression.lambda<func<t, bool>>(current, param); }
this takes number of predicates , combines them combining expression bodies using boolean or. since combining different expressions may have different expression parameters, need make sure replace expression parameter references in expression bodies using common parameter. using simple replaceexpressionvisitor
, implemented this:
public class replaceexpressionvisitor : expressionvisitor { private readonly expression _original; private readonly expression _replacement; public replaceexpressionvisitor(expression original, expression replacement) { _original = original; _replacement = replacement; } public override expression visit(expression node) { return node == _original ? _replacement : base.visit(node); } }
and that’s need combine predicates. need make sure change methods don’t call query.where
return expression<func<animal, bool>>
instead.
Comments
Post a Comment