Calling custom IQueryable extension methods on an IGrouping

223 Views Asked by At

I have code very much like this:

Context.History.GroupBy(d => new { d.Category, d.Month })
    .Select(group => new
    {
        Category = group.Key.Category,
        Month = group.Key.Month,
        // Geometric mean:
        Value = Math.Exp(group.Average(a => Math.Log(a.Value)))
    })
    .GroupBy(d => d.Month)
    .Select(monthly => new Dto {
         Month = monthly.Month,
         Average = monthly.Average(a => a.Value)
    });

There's a few other places I calculate the geometric mean, so I would like to put that in an extension method, so the line after the comment would look like Value = group.GeometricMean(a => a.Value).

  • If I write a regular extension method on IEnumerable<T>, Entity Framework complains that it can't convert it to a query.

  • If I write a method operating on IQueryable<T>, I'm informed that group is, in fact, not an IQueryable<T>, but rather an IGrouping<TKey, T>.

  • Trying to call it as Value = group.AsQueryable().GeometricMean(a => a.Value) leads to an ArgumentException saying 'Expression of type IGrouping cannot be used for parameter of type IQueryable (Parameter arg0)'.

It seems to me I must somehow turn that IGrouping into IQueryable for my extension method to work, but I can't figure out how. There's a few questions on SO that wander near that subject, but none that I've found that are applicable here. It might be that this is simply not supported in EF as of now.

More information: replacing the whole Select body with some function is a no-go, as the point is to make the geometric mean calculation reusable - the rest is simply not reusable. It needs to be done in SQL, as it's been shown to be far too slow to fetch the data and do the calculation in C#.

Looking at the source of some IQueryable extension methods, it seems the body of the extension method would build up some expression tree and pass that to source.Provider.Execute. I think I may already have managed that part, but I've been unable to properly test it due to the above issues.

0

There are 0 best solutions below