SelectMany subquery not applying OrderBy
See original GitHub issueApplying an OrderBy to a subquery in a SelectMany statement does not appear to work unless either a skip or take call is applied as well.
Database Structure
public class AppDbContext : DbContext
{
public AppDbContext(DbContextOptions<AppDbContext> options) : base(options)
{
}
public DbSet<Thread> Threads { get; set; }
public DbSet<Post> Posts { get; set; }
}
public class Thread
{
public Guid Id { get; set; }
public ICollection<Post> Posts { get; set; }
}
public class Post
{
public Guid Id { get; set; }
public string Message { get; set; }
public Guid ThreadId { get; set; }
public Thread Thread { get; set; }
}
Query
This query will produce the following SQL.
using var dbContext = new AppDbContext(dbOptions.Options);
var query = dbContext.Posts;
var data = query
.Select(x => x.ThreadId)
.Distinct()
.SelectMany(x => query
.Where(y => y.ThreadId == x)
.OrderBy(y => y.Message))
.ToList();
Will make
SELECT "t0"."Id", "t0"."Message", "t0"."ThreadId"
FROM (
SELECT DISTINCT "p"."ThreadId"
FROM "Posts" AS "p"
) AS "t"
INNER JOIN (
SELECT "p0"."Id", "p0"."Message", "p0"."ThreadId"
FROM "Posts" AS "p0"
) AS "t0" ON "t"."ThreadId" = "t0"."ThreadId"
You can see that there is no ORDER BY added to the generated SQL, However if I add a .Skip(0)
to the subquery then an order by is generated in the sql.
using var dbContext = new AppDbContext(dbOptions.Options);
var query = dbContext.Posts;
var data = query
.Select(x => x.ThreadId)
.Distinct()
.SelectMany(x => query
.Where(y => y.ThreadId == x)
.OrderBy(y => y.Message)
.Skip(0))
.ToList();
Will make
SELECT "t1"."Id", "t1"."Message", "t1"."ThreadId"
FROM (
SELECT DISTINCT "p"."ThreadId"
FROM "Posts" AS "p"
) AS "t"
INNER JOIN (
SELECT "t0"."Id", "t0"."Message", "t0"."ThreadId"
FROM (
SELECT "p0"."Id", "p0"."Message", "p0"."ThreadId", ROW_NUMBER() OVER(PARTITION BY "p0"."ThreadId" ORDER BY "p0"."Message") AS "row"
FROM "Posts" AS "p0"
) AS "t0"
WHERE 0 < "t0"."row"
) AS "t1" ON "t"."ThreadId" = "t1"."ThreadId"
We can see that now the order by over the partitions is working correctly. I have also observed that if there is a Take on the subquery instead of a Skip then it will also add the order by to the sql correctly as well.
Version Info
EF Core version: Database provider: Have observed in both Microsoft.EntityFrameworkCore.Sqlite 5.0.5 and Npgsql.EntityFrameworkCore.PostgreSQL 5.0.2 Target framework: .NET 5.0 Operating system: Windows 10, Ubuntu 20.04 IDE: Rider, VS Code
Full example project here: https://github.com/jack775544/EfOrder
Issue Analytics
- State:
- Created 2 years ago
- Comments:7 (7 by maintainers)
ORDER BY lifting specification from the past (EF6 & LINQ-to-SQL) also explicitly noted that the ordering from right side of a join cannot be lifted.
Also see https://github.com/dotnet/efcore/issues/16226 Specifically https://github.com/dotnet/efcore/issues/16086#issuecomment-509832520 for our work in new query pipeline in 3.1 era