4

We're using EFCore 3.1 and trying to build a query using Exists by means of .Any() which spans 2 properties.

var selectionCriteria = someHugeList.Select(sh => new { sh.Id, sh.StatusCode }).ToList()
var resultsQry = _myContext.SomeClass
                           .Include(sc => sc.DetailRecords)
                           .Where(sc => selectionCriteria.Any(crit => crit.Id == sc.Id 
                                                                   && crit.StatusCode == sc.StatusCode));

var results = await resultsQry.ToListAsync()

When running this query (even with a small amount (5 items) of selection criteria items it provides the following error message;

System.InvalidOperationException: LINQ expression 'DbSet .Where(c => __selectionCriteria_0 .Any(crit => crit.Id == sc.Id && crit.StatusCode == sc.StatusCode))' 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(). See https://go.microsoft.com/fwlink/?linkid=2101038 for more information.'

Seems the problem resides in the fact that there are 2 properties included in the .Any clause. A where exists in sql normally can do this without problem. EFCore seems to find this difficult.

Does anyone have an idea on how to solve this?

Obelix
  • 708
  • 11
  • 24

1 Answers1

1

just found this; https://learn.microsoft.com/en-us/ef/core/what-is-new/ef-core-3.0/breaking-changes#linq-queries-are-no-longer-evaluated-on-the-client

long story short; client evaluation is no longer working in EFCore 3.1 meaning this type of query (comparing a clientside list to a serverside list) doesn't work. You need to bring it to the client. My collegue pointed out to me just now that I didn't appreciate the error message to it's full potential :).

Changed my query as follows (not optimal, but no other solution yet):

var selectionCriteria = someHugeList.Select(sh => new { sh.Id, sh.StatusCode }).ToList()
var resultsQry = _myContext.SomeClass
                           .Include(sc => sc.DetailRecords)
                           .AsEnumerable() // this is the important part, pulling all the records client side so we can execute the .Any on the client.
                           .Where(sc => selectionCriteria.Any(crit => crit.Id == sc.Id 
                                                                   && crit.StatusCode == sc.StatusCode));

var results = await resultsQry.ToList() // no more async, because clientside
Obelix
  • 708
  • 11
  • 24
  • 4
    can you change ``.AsEnumerable() .Where(sc => selectionCriteria.Any(crit => crit.Id == sc.Id && crit.StatusCode == sc.StatusCode));`` by ``..Where(sc => Ids.Contains(sc.Id) && Codes.Contains(sc.StatusCode))``. ``Ids``: list of criteria id, ``Codes`` : list of status code and test it please? – Mohammed Sajid Feb 06 '20 at 11:25
  • @MohammedSajid's comment is the same as Solution 3: in this [SO](https://stackoverflow.com/questions/26198860/entityframework-contains-query-of-composite-key#answer-26201371). It will potentially result in oversampling but best to follow link and see trade offs. – ttugates Mar 20 '21 at 23:44