c# - Tracing Linq expression evaluation -
i'm wondering if it's possible write "passthrough" extension method iqueryable write debugstring whenever queryable evaluated, in other words, debug print should side-effect of evaluation.
something like:
var qr = somesource.where(...).orderby(...).trace("somesource evaluated @ {0}", datetime.now) var qr2 = qr.where(...);
when construct linq query , pass data source object, i'd know when , how object evaluate query. suppose can achieved in other ways, example wrapping ienumerable.getenumerator, i'd generically linq query.
i've done similar, more complex (because manipulates expressions processes them). in order accomplish it, created wrapper class implemented iqueryable , contained reference thing wanted query. made pass interface members through referenced object except provider property, returned reference class created inherited iqueryprovider. iqueryprovider has methods called whenever query constructed or executed. if don't mind being forced query wrapper object(s) instead of original object(s).
you should aware, if you're using linq-to-sql, there's log property on datacontext can use route lots of debug information wherever want.
sample code:
make own iqueryable control queryprovider gets returned.
public class myqueryable(of tabletype) implements iqueryable(of tabletype) private innerqueryable iqueryable(of tabletype) private myprovider myqueryprovider = nothing public sub new(byval innerqueryable iqueryable(of tabletype)) me.innerqueryable = innerqueryable end sub public function getenumerator() system.collections.generic.ienumerator(of tabletype) implements system.collections.generic.ienumerable(of tabletype).getenumerator return innerqueryable.getenumerator() end function public function getenumerator1() system.collections.ienumerator implements system.collections.ienumerable.getenumerator return innerqueryable.getenumerator() end function public readonly property elementtype() system.type implements system.linq.iqueryable.elementtype return innerqueryable.elementtype end end property public readonly property expression() system.linq.expressions.expression implements system.linq.iqueryable.expression return innerqueryable.expression end end property public readonly property provider() system.linq.iqueryprovider implements system.linq.iqueryable.provider if myprovider nothing myprovider = new myqueryprovider(innerqueryable.provider) return myprovider end end property friend readonly property innertable() system.data.linq.itable if typeof innerqueryable system.data.linq.itable return directcast(innerqueryable, system.data.linq.itable) end if throw new invalidoperationexception("attempted treat myqueryable table not table") end end property end class
make custom query provider control expression tree gets generated.
public class myqueryprovider implements iqueryprovider private innerprovider iqueryprovider public sub new(byval innerprovider iqueryprovider) me.innerprovider = innerprovider end sub public function createquery(byval expression system.linq.expressions.expression) system.linq.iqueryable implements system.linq.iqueryprovider.createquery return innerprovider.createquery(expression) end function public function createquery1(of telement)(byval expression system.linq.expressions.expression) system.linq.iqueryable(of telement) implements system.linq.iqueryprovider.createquery dim newquery = innerprovider.createquery(of telement)(convertexpression(expression)) if typeof newquery iorderedqueryable(of telement) return new myorderedqueryable(of telement)(directcast(newquery, iorderedqueryable(of telement))) else return new myqueryable(of telement)(newquery) end if end function public shared function convertexpression(byval expression expression) expression if typeof expression methodcallexpression dim mexp = directcast(expression, methodcallexpression) return expressions.methodcallexpression.call(convertexpression(mexp.object), _ mexp.method, (from row in mexp.arguments select convertexpression(row)).toarray()) elseif typeof expression binaryexpression dim bexp binaryexpression = directcast(expression, binaryexpression) dim memberinfo nestedmember = nothing dim constexp expression = nothing dim memberonleft boolean dim doconvert = true '' [etc... lots of code generate manipulated expression tree elseif typeof expression lambdaexpression dim lexp = directcast(expression, lambdaexpression) return lambdaexpression.lambda( _ convertexpression(lexp.body), (from row in lexp.parameters select _ directcast(convertexpression(row), parameterexpression)).toarray()) elseif typeof expression conditionalexpression dim cexp = directcast(expression, conditionalexpression) return conditionalexpression.condition(convertexpression(cexp.test), _ convertexpression(cexp.iftrue), _ convertexpression(cexp.iffalse)) elseif typeof expression invocationexpression dim iexp = directcast(expression, invocationexpression) return invocationexpression.invoke( _ convertexpression(iexp.expression), (from row in iexp.arguments _ select convertexpression(row)).toarray()) elseif typeof expression memberexpression '' [etc... lots of code generate manipulated expression tree elseif typeof expression unaryexpression '' [etc... lots of code generate manipulated expression tree else return expression end if end function public function execute(byval expression system.linq.expressions.expression) object implements system.linq.iqueryprovider.execute return innerprovider.execute(expression) end function public function execute1(of tresult)(byval expression system.linq.expressions.expression) tresult implements system.linq.iqueryprovider.execute return innerprovider.execute(of tresult)(convertexpression(expression)) end function end class
then extend derived datacontext providing wrapped queryables:
partial public class mydatacontext private myqueries dictionary(of system.type, object) = new dictionary(of system.type, object) public readonly property my_accountcategories() myqueryable(of accountcategory) dim result object = nothing if (me.myqueries.trygetvalue(gettype(accountcategory), result) = false) result = new myqueryable(of accountcategory)(me.accountcategories) me.myqueries(gettype(accountcategory)) = result end if return ctype(result,myqueryable(of accountcategory)) end end property public readonly property my_accountsegmentations() myqueryable(of accountsegmentation) dim result object = nothing if (me.myqueries.trygetvalue(gettype(accountsegmentation), result) = false) result = new myqueryable(of accountsegmentation)(me.accountsegmentations) me.myqueries(gettype(accountsegmentation)) = result end if return ctype(result,myqueryable(of accountsegmentation)) end end property end class
Comments
Post a Comment