c# - How do I Filter one side of a DbJoinExpression -
in ef 6.1 have created defaultexpressionvisitor use idbcommandtreeinterceptor. want know how correctly override dbjoinexpression visitor filter right hand side of join perform same join on filtered set.
based on various approaches (such using bindas etc) errors such as:
- no property name 'extent2' declared type
- the referenced variable 'extent2' not defined in current scope.
but cannot mix of comparable types, variables , parameter. little documentation , no example usages of dbjoinexpressions in context.
as example have objectcontext people , animals. , person has association animals own, , pet has ownerid. explicit key relationship between person.id == animal.ownerid.
i have added association, navigation property , called "cats".
so accurate, want filter collection of animals (the right hand expression) using animaltype column discriminator.
public override dbexpression visit(dbjoinexpression expression) { //todo pull these values attributes etc var discriminatorcolumn = "animaltype"; var discriminatortype = "cat"; //people dbexpressionbinding left = this.visitexpressionbinding(expression.left); //unfiltered animals dbexpressionbinding right = this.visitexpressionbinding(expression.right); //todo filter right side using animaltype dbcolumn , re-join // right hand collection element var entitysetexpression = right.expression dbscanexpression; var variablereference = right.variable; // create property based on variable in order apply equality var discriminatorproperty = dbexpressionbuilder.property(variablereference, discriminatorcolumn); var predicateexpression = dbexpressionbuilder.equal(discriminatorproperty, dbexpression.fromstring(discriminatortype)); //filtered animals being cats var filterexpression = dbexpressionbuilder.filter(entitysetexpression.bind(),predicateexpression); var joincondition = this.visitexpression(expression.joincondition) dbcomparisonexpression; dbexpressionbinding filteredright = filterexpression.bind(); dbexpression newexpression = expression; if (!referenceequals(expression.left, left) || !referenceequals(expression.right, filteredright) || !referenceequals(expression.joincondition, joincondition)) { if (dbexpressionkind.innerjoin == expression.expressionkind) { newexpression = dbexpressionbuilder.innerjoin(left, filteredright, joincondition); } else if (dbexpressionkind.leftouterjoin == expression.expressionkind) { newexpression = dbexpressionbuilder.leftouterjoin(left, filteredright, joincondition); } else { debug.assert( expression.expressionkind == dbexpressionkind.fullouterjoin, "dbjoinexpression had expressionkind other innerjoin, leftouterjoin or fullouterjoin?"); newexpression = dbexpressionbuilder.fullouterjoin(left, filteredright, joincondition); } } return newexpression; }
essentially looking create sql join filter like:
select .... people p left join animals on p.id = a.ownerid (here ***and a.animaltype = 'cat'***) ( or here ***a.animaltype = 'cat'***)
reading source code on codeplex defaultexpressionvisitor pushing scope variables method private. might explain parameter scope issues seeing.
any appreciated.
turns out simpler thought. avoided trying filter dbscanexpression , added condition join andexpression
public override dbexpression visit(dbjoinexpression expression) { //todo pull these values attributes etc var discriminatorcolumn = "animaltype"; var discriminatortype = "cat"; //if (attribute.getcustomattributes()) //people dbexpressionbinding left = this.visitexpressionbinding(expression.left); //unfiltered animals dbexpressionbinding right = this.visitexpressionbinding(expression.right); // create property based on variable in order apply equality var discriminatorproperty = dbexpressionbuilder.property(right.variable, discriminatorcolumn); //todo create type discriminatortype match property type eg string, guid, int etc var predicateexpression = dbexpressionbuilder.equal(discriminatorproperty, dbexpression.fromstring(discriminatortype)); //use existing condition , combine new condition using , var joincondition = dbexpressionbuilder.and(expression.joincondition, predicateexpression); dbexpression newexpression = expression; //only re-create join if changed if (!referenceequals(expression.left, left) || !referenceequals(expression.right, right) || !referenceequals(expression.joincondition, joincondition)) { switch (expression.expressionkind) { case dbexpressionkind.innerjoin: newexpression = dbexpressionbuilder.innerjoin(left, right, joincondition); break; case dbexpressionkind.leftouterjoin: newexpression = dbexpressionbuilder.leftouterjoin(left, right, joincondition); break; default: debug.assert( expression.expressionkind == dbexpressionkind.fullouterjoin, "dbjoinexpression had expressionkind other innerjoin, leftouterjoin or fullouterjoin?"); newexpression = dbexpressionbuilder.fullouterjoin(left, right, joincondition); break; } } return newexpression; }
Comments
Post a Comment