dotnet / dotnet/efcore

JOIN instead of CROSS APPLY with SelectMany-nested Select

Open
#35,902 1 comment 0 reactions 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

### What problem are you trying to solve?

My code example:

```C#
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Npgsql;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace EfInvalidSql;
public class Program
{
public static async Task Main(params string[] args)
{
MyContext context = new();
context.Database.EnsureDeleted();
context.Database.EnsureCreated();

var marks = await context.Set()
.SelectMany(u => u.Marks.Select(m => new
{
UserId = u.Id,
MarkId =m.Id,
Value = m.Value
}))
.ToListAsync();
}
}

public class User
{
public int Id { get; set; }
public string Name { get; set; }
public List Marks { get; set; }
}

public class UserMark
{
public int Id { get; set; }
public int Value { get; set; }
}

public class MyContext : DbContext
{
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
NpgsqlDataSourceBuilder dataSourceBuilder = new(@"Host=localhost;Port=7435;Database=testdb;Username=admin;Password=testpass");

NpgsqlDataSource dataSource = dataSourceBuilder.Build();

//optionsBuilder
// .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Password=somepass;Database=helloappdb;Trusted_Connection=True;")
// .LogTo(Console.WriteLine, LogLevel.Information)
// .EnableSensitiveDataLogging();

optionsBuilder
.UseNpgsql(dataSource)
.LogTo(Console.WriteLine, LogLevel.Information)
.EnableSensitiveDataLogging();
}

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity();
modelBuilder.Entity();
}
}
```

SQL query (MS SQL):
```SQL
SELECT [u1].[UserId], [u1].[MarkId], [u1].[Value]
FROM [User] AS [u]
CROSS APPLY (
SELECT [u].[Id] AS [UserId], [u0].[Id] AS [MarkId], [u0].[Value]
FROM [UserMark] AS [u0]
WHERE [u].[Id] = [u0].[UserId]
) AS [u1]
```

SQL query (Postgres):
```SQL
SELECT u1."UserId", u1."MarkId", u1."Value"
FROM "User" AS u
JOIN LATERAL (
SELECT u."Id" AS "UserId", u0."Id" AS "MarkId", u0."Value"
FROM "UserMark" AS u0
WHERE u."Id" = u0."UserId"
) AS u1 ON TRUE
```

### Describe the solution you'd like

SQL can be simplified. For example, for Postgres:
```SQL
select u."Id" "UserId", m."Id" "MarkId", m."Value" "Value"
from "User" u
join "UserMark" m on m."UserId" = u."Id"
```

I use EF Core 9.0.3

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.