Rewriting the generated SQL queries.
skurik opened this issue · comments
We are hitting the well-known issue of EF generating suboptimal queries for the IEnumerable.Contains
function, yielding a non-parameterized IN
predicate:
SELECT
[Extent1].[Id] AS [Id],
...
FROM [prod].[Address] AS [Extent1]
WHERE [Extent1].[CustomerId] IN (cast('079528a5-efbf-4844-a1d1-adea00b78ad2' as uniqueidentifier), cast('3c83b8e9-bcfb-463e-8bb3-adcb0179a83e' as uniqueidentifier), ...)
I believe even EF Core doesn't handle this well.
There are some suggested workarounds for this:
- https://erikej.github.io/ef6/sqlserver/2021/12/01/ef6-sqlserver-cache-pollution.html
- https://github.com/Dixin/EntityFramework.Functions
but we haven't been able to make them work.
Essentially, ideally the query would look like this instead:
SELECT
[Extent1].[Id] AS [Id],
...
FROM [prod].[Address] AS [Extent1]
WHERE [Extent1].[CustomerId] IN (SELECT Value FROM STRING_SPLIT(@idList, N','))
@idList = '079528a5-efbf-4844-a1d1-adea00b78ad2,3c83b8e9-bcfb-463e-8bb3-adcb0179a83e'
A single execution plan, no matter the number of values. In our case, this performs much better.
So my question is:
Is there a way to take the IQueryable
generated by EF and right before executing it, rewriting some parts of it (in our case, the IN
predicate) with a custom expression (e.g. SELECT Value FROM STRING_SPLIT(@idList, N'','')
) and at the same time, adding a parameter?
I know you can rewrite the IQueryable
to another IQueryable
, but what we need is to replace a node with a string expression. And add a parameter to the query.
You can also just stringify the queryable and modify it as string, but that's what I would like to avoid.
This issue has been closed because EF6 is no longer being actively developed. We are instead focusing on stability of the codebase, which means we will only make changes to address security issues. See the repo README for more information.