The LINQ expression could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation

Viewed 42254

I have C# application (.NET Core 3.1) and I have written the following LINQ expression.

public ActionResult<bool> GetItems(string title)
{
     var items = _service.All.GetItems().OrderByDescending(o => o.Id).Where(w => w.Portal_Id == 1);

     if (!string.IsNullOrWhiteSpace(title))
     {
            var terms = title.Split(' ').ToList();
            items = items.Where(w => terms.Any(a => w.ItemName.Contains(a)));
     }
     // Some Other code
     return Ok();
}

whenever this expression is executed i get the following error

The LINQ expression 'DbSet<PosItem>\r\n    .Where(p => !(p.IsDeleted))\r\n    
.OrderByDescending(p => p.CreatedAt)\r\n    .Where(p => p.Portal_Id == 1)\r\n    .Where(p => __terms_1\r\n      
.Any(a => p.ItemName.Contains(a)))' 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." 

I cannot add ToList() and switch to client evaluation because the data set is too big to do so.

Please advise how can I resolve this issue without switching to client evaluation.

Thanks

2 Answers

The issue is that you are trying to do a string.Contains within an Any expression which EF will choke on trying to compose down to SQL. Cleptus is on the nose, to build a predicate for the Where clause OR-ing the term comparisons. Otherwise your code should work without the contains check, but rather an equality check:

Without Contains: (equality check rather than LIKE %name%)

var terms = title.Split(' ').ToList();
items = items.Where(w => terms.Contains(w.ItemName)); // IN clause.

Built expression:

var terms = title.Split(' ').ToList();
Expression<Func<Item, bool>> predicate = (Item) => false;
foreach(var term in terms)
    predicate = predicate.Or(x => x.ItemName.Contains(term));

items = items.Where(predicate);

So for each term in the title, we OR a match using a LIKE %term% on the ItemName.

This problem can also occur when using multiple ParameterExpression in one single Expression. Always transmit den ParameterExpression instance to all Expression.Property(argPara, "Name") values.

Related