Efcore: Anything applied to query when cast as IEnumerable seems to run client-side

Created on 8 Oct 2016  路  4Comments  路  Source: dotnet/efcore

I have been using extension methods similar to the following:

    public static class ApplicationWithClientId {

        public static IEnumerable<Application> WithClientId(this IEnumerable<Application> query, Guid id) {
            return query.Where(a => a.ClientId == id);
        }

    }

The main reason why I'm using IEnumerable here is so that these extension methods can remain as generic as possible and live alongside my domain.

Something I've noticed however is that when I call these extension methods, they are always run on the client, rather than being compiled as part of the query that gets sent to the server.

I guess from what I'm seeing, the main issue is that I can't leverage polymorphism to insulate my domain layer from EF specifics. It seems like when I change IEnumerable above to IQueryable, the clauses start appearing in my queries again. Which I'm not sure makes sense considering it's the same object, just using the same signature from a less derived type.

closed-question

All 4 comments

That's because its running IEnumerable methods on it rather than IQueryable methods?

http://stackoverflow.com/a/23359554/1109918

You could do something like

public static IEnumerable<Application> WithClientId(this IEnumerable<Application> query, Guid id) {
    var iquery = query as IQueryable<Application>;
    if (iquery != null)
    {
        return iquery.Where(a => a.ClientId == id);
    }
    else
    {
        return query.Where(a => a.ClientId == id);
    }
}

But that will be slower than writing two methods with the two different interfaces and your IEnumerable path will be slower.

This is a good explanation of _why_ they differ http://stackoverflow.com/a/28513685/1109918

So I guess I'm surprised that it even has an opportunity to run IEnumerable methods in an IEnumerable way, given that regardless of the type it's cast as, it's still an instance of IQueryable...

Totally possible that I'm missing something about the behaviour here, and that's why I cited polymorphism in my initial description.

You are calling two different methods:

For IQueryable you are calling

.Where(Expression<Func<Application, bool>> predicate)

For IEnumerable you are calling

.Where(Func<Application, bool> predicate)

They both just happen to look like

.Where(a => a.ClientId == id)

Gotcha!

Was this page helpful?
0 / 5 - 0 ratings