M
Marcel Müller
I have a query provider and I want to track usage statistics of query
expressions.
Input is as usual some expression tree.
The IQueryable<T> in the innermost Where expression is then replaced by
some data source that contains a set of potentially matching objects.
But the number ob objects is still too large (only indices are applied
so far), so the filtering by the original Where expression is still
required.
Everything is working fine so far.
But now I want to track the selectivity of the .Where Expression
relative to the number of objects retrieved by the query provider. E.g.:
var objects = new [] { 1,2,3,4,5 };
objects.AsQueryable(); // fake
var result = objects.Where(obj => obj >= 3 && (obj & 1) = 0);
Let's say the query provider only understands the sub expression "obj >=
3" but not "(obj & 1) = 0". It will then retrieve the objects 3 to 5,
effectively executing
result = new [] { 3,4,5 }
.AsQueryable()
.Where(obj => obj >= 3 && (obj & 1) = 0); // OK obj >= 3 could be removed
(Of course, I needed to rewrite the expression tree to this one.)
So to track the counts I want to add visitor functions:
int count_before_where = 0;
int count_after_where = 0;
result = new [] { 3,4,5 }
.Select(obj =>
{ ++count_before_where;
return obj;
})
.AsQueryable()
.Where(obj => obj >= 3 && (obj & 1) = 0)
.Select(obj =>
{ ++count_after_where;
return obj;
});
The first one works fine.
Unfortunately the second one does not compile because of the Type
IQueryable<T> and I failed to create an equivalent expression tree
manually with Expression.Lambda and so on.
And to make things a bit more complicated I also need to track
Enumerator.Dispose at the second visitor, because that's the only point
where I know that count_before_where and count_after_where are complete.
Any ideas how to get that working?
I should note that executing immediately is not an option because not
all enumerators are read to the end and reading object could take long
(web services, several seconds per object). So I need deferred execution.
Marcel
expressions.
Input is as usual some expression tree.
The IQueryable<T> in the innermost Where expression is then replaced by
some data source that contains a set of potentially matching objects.
But the number ob objects is still too large (only indices are applied
so far), so the filtering by the original Where expression is still
required.
Everything is working fine so far.
But now I want to track the selectivity of the .Where Expression
relative to the number of objects retrieved by the query provider. E.g.:
var objects = new [] { 1,2,3,4,5 };
objects.AsQueryable(); // fake
var result = objects.Where(obj => obj >= 3 && (obj & 1) = 0);
Let's say the query provider only understands the sub expression "obj >=
3" but not "(obj & 1) = 0". It will then retrieve the objects 3 to 5,
effectively executing
result = new [] { 3,4,5 }
.AsQueryable()
.Where(obj => obj >= 3 && (obj & 1) = 0); // OK obj >= 3 could be removed
(Of course, I needed to rewrite the expression tree to this one.)
So to track the counts I want to add visitor functions:
int count_before_where = 0;
int count_after_where = 0;
result = new [] { 3,4,5 }
.Select(obj =>
{ ++count_before_where;
return obj;
})
.AsQueryable()
.Where(obj => obj >= 3 && (obj & 1) = 0)
.Select(obj =>
{ ++count_after_where;
return obj;
});
The first one works fine.
Unfortunately the second one does not compile because of the Type
IQueryable<T> and I failed to create an equivalent expression tree
manually with Expression.Lambda and so on.
And to make things a bit more complicated I also need to track
Enumerator.Dispose at the second visitor, because that's the only point
where I know that count_before_where and count_after_where are complete.
Any ideas how to get that working?
I should note that executing immediately is not an option because not
all enumerators are read to the end and reading object could take long
(web services, several seconds per object). So I need deferred execution.
Marcel