EF Core 3 x.Contains() in expression where x is ICollection

zola25 picture zola25 · Sep 29, 2019 · Viewed 8k times · Source

I've got the following data layer setup:

public class Repository : IRepository {

    private readonly MyDbContext _dbContext;

        public List<Meter> Search(Expression<Func<Meter,bool>> criteria)
            IQueryable<Meter> results = _dbContext.Meters;
            return results.Where(criteria).ToList();
        }
    }
}

... from a client class:

IRepository _repository;

public void ClientMethod () {

    ICollection<int> ids = new List<int>() {1, 2, 3);
    var results = _repository.Search(c=> ids.Contains(c.Id)); // This throws exception

}

This results in the exception:

expression Where(source: DbSet, predicate: (m) => (Unhandled parameter: __ids_0).Contains(m.Id))' could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to either AsEnumerable(), AsAsyncEnumerable(), ToList(), or ToListAsync()

But if I change the collection reference to IEnumerable or List, it works:

public void ClientMethod () {

    // This works
    List<int> ids = new List<int>() {1, 2, 3);
    var results = _repository.Search(c=> ids.Contains(c.Id)); 

    // This works
    IEnumerable<int> ids = new List<int>() {1, 2, 3);
    var results = _repository.Search(c=> ids.Contains(c.Id)); 
}

Why is it not working for ICollection, but it does for IEnumerable and List? Many of my client methods take an ICollection as a parameter.

I'm using EF Core 3.0 but I believe I had the same problem in 2.1, it just didn't throw as it evaluated it on the client instead.

Answer

Gergo Drazsdik picture Gergo Drazsdik · Sep 30, 2019

I've run into the same issue, when migrating to EF Core 3.0 from 2.2. I've had ef configured before to throw error on client side evaluation, and it was working fine. So I'm sure it's a new issue with 3.0, introduced when they've rewritten the linq engine.

Casting it to either IEnumerable or List works for me as well, thanks for the tip!