dotnet / dotnet/efcore

Avoid OrderBy with Include query duplication

Open
#29,942 2 comments 1 reaction 0 assignees View on GitHub
area-perf area-query customer-reported
Dominant language
C#
Stars
14.8k
Forks
3.4k
PR merge metrics
PR metrics pending

Description

### Include your code

Given entities which look like these

```C#
public class ContactFormSubmission {
[Key]
public int Id { get; set; }

public ICollection? Variables { get; set; }
}

public class ContactFormSubmissionVariable {
// Composite key
public int SubmissionId { get; set; } // ContactFormSubmission
public int VariableId { get; set; } // ContactFormVariable

[Required]
public string? Value { get; set; }
}

public class ContactFormVariable {
[Key]
public int Id { get; set; }

[Required]
public string? Name { get; set; }
}
```

If I use the following expression I get this resulting query
```C#
db.Set()
.OrderBy(s => s.Variables!.Single(v => v.VariableId == 4).Value)
.Take(3).ToList();
```
```SQL
SELECT TOP(@__p_0) [c].[Id]
FROM [ContactFormSubmissions] AS [c]
ORDER BY (
SELECT TOP(1) [c0].[Value]
FROM [ContactFormSubmissionVariable] AS [c0]
WHERE ([c].[Id] = [c0].[SubmissionId]) AND ([c0].[VariableId] = 4))
```

Which is good.
However if I use the following expression to include a collection I get another query
```C#
db.Set()
.Include(s => s.Variables)
.OrderBy(s => s.Variables!.Single(v => v.VariableId == 4).Value)
.Take(3).ToList();
```
```SQL
SELECT [t].[Id], [c1].[SubmissionId], [c1].[VariableId], [c1].[Value]
FROM (
SELECT TOP(@__p_0) [c].[Id], (
SELECT TOP(1) [c0].[Value]
FROM [ContactFormSubmissionVariable] AS [c0]
WHERE ([c].[Id] = [c0].[SubmissionId]) AND ([c0].[VariableId] = 4)) AS [c]
FROM [ContactFormSubmissions] AS [c]
ORDER BY (
SELECT TOP(1) [c0].[Value]
FROM [ContactFormSubmissionVariable] AS [c0]
WHERE ([c].[Id] = [c0].[SubmissionId]) AND ([c0].[VariableId] = 4))
) AS [t]
LEFT JOIN [ContactFormSubmissionVariable] AS [c1] ON [t].[Id] = [c1].[SubmissionId]
ORDER BY [t].[c], [t].[Id], [c1].[SubmissionId]
```

As you can see the nested SELECT and the following ORDER BY contain a duplicate expression.
The ORDER BY could use the alias created by the SELECT above it, like this:
```SQL
SELECT [t].[Id], [c1].[SubmissionId], [c1].[VariableId], [c1].[Value]
FROM (
SELECT TOP(@__p_0) [c].[Id], (
SELECT TOP(1) [c0].[Value]
FROM [ContactFormSubmissionVariable] AS [c0]
WHERE ([c].[Id] = [c0].[SubmissionId]) AND ([c0].[VariableId] = 4)) AS [c]
FROM [ContactFormSubmissions] AS [c]
ORDER BY [c]
) AS [t]
LEFT JOIN [ContactFormSubmissionVariable] AS [c1] ON [t].[Id] = [c1].[SubmissionId]
ORDER BY [t].[c], [t].[Id], [c1].[SubmissionId]
```
### Include provider and version information

EF Core version: 6.0.3
Database provider: Microsoft.EntityFrameworkCore.SqlServer
Target framework: .NET 6.0

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.