dotnet / ef6

This is the codebase for Entity Framework 6 (previously maintained at https://entityframework.codeplex.com). Entity Framework Core is maintained at https://github.com/dotnet/efcore.

Home Page:https://docs.microsoft.com/ef/ef6

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

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:

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.