EFCore Linq Query Could not be translated and will be evaluated locally
See original GitHub issueThis is more of an enhancement. I have seen other posts, and I understand there are numerous possibilities as to why a Linq Query could not be translated. However, I believe this should not only be a fairly simple enhancement, but it should serve a great many developers. Below is the warning message provided by EF Core, then the steps to reproduce the error, then the suggested enhancement.
Warning:
Microsoft.EntityFrameworkCore.Query:Warning: The LINQ expression 'where Invoke(__isActiveItem_0, [x])' could not be translated and will be evaluated locally.
### Steps to reproduce
Create a Func and predicate scenario. It can be extremely simple:
public static class DisplayFilters
{
/// the business need here is to still use the deleted item for internal reports and looking good if the client accidentally deletes the item.
public static Func<DisplayItem, bool> isActiveItem = (x) => x.IsDeleted == false;
....
(n) number of composable filter functions. More complex functions could rely on multiple nested functions
///additional pure/transparent functions could be created not just based on filtering, but grouping/joining etc
}
Create a simple controller with get logic to use the function
using f = namespace.DisplayFilters;
...
[HttpGet]
public IActionResult Get()
{
IEnumerable<DisplayItem> xItem = _context.DisplayItem.Where(x => f.isActiveItem(x));
return Ok(xItem);
}
### Further technical details
EF Core version: (2.0.2)
Database Provider: (e.g. Microsoft.EntityFrameworkCore.SqlServer)
Operating system: Windows 10
IDE: (Visual Studio 2017)
This ultimately is a simple example. But this is the start of a larger need. An application can quickly grow where all our statements are becoming more complex, and the logic for this business rule can be strewn everywhere.
Imagine dealing with dozens of linq queries, and statically referencing x.isDeleted == false
hundreds of times, when now, the business says active items also rely on the created date property to be greater than 30 days.
Since a composable function like above will always require the object itself DisplayItem
to be passed in, a linq to sql query should always know what Where
clause to be modifying, what sub Select query or otherwise to modify.
Thank you
Issue Analytics
- State:
- Created 6 years ago
- Comments:7 (3 by maintainers)
Is there any specific reason you are using
Func<DisplayItem, bool>
instead ofExpression<Func<DisplayItem, bool>>
?The reason I ask this because, unless the expression is passed into the linq query, the function call itself would become opaque to EF Core. The Expression tree generated by compiler when you use func does not allow us to inspect what is inside of the Func, hence EF Core cannot translate the body of the func and has to do client evaluation. If you use
Expression<Func<>>
inside linq query then EF Core would translate that to Server.Thank you for taking the time to explain the issue, and provide me with enough information to research ExpressionTrees. For anyone who stumbles across this in the future, this is what I did.
The Expression:
And its usage:
This will generate the correct sql on the server side.