-
Notifications
You must be signed in to change notification settings - Fork 233
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Missing ordering on ORDINALITY column when projecting out primitive collections with composed LINQ operators #3207
Comments
@pinkfloydx33 thanks for the report and for the repro - I can confirm there's a bug here (see at the bottom for a minimal repro). I'll do my best to fix this ASAP for an upcoming 8.0 patch release. When a primitive collection is unnested to a rowset for composition of LINQ operators, we use the PostgreSQL WITH ORDINALITY clause to add an ordering column to preserve the ordering of the original array. However, when the results of that query is projected out, we don't order by the ordinality column, so the arrayordering is lost. Query: _ = await context.Blogs
.Select(b => b.Ints.Select(i => i + 1).ToArray())
.ToListAsync(); SQL produced: SELECT b."Id", i.value + 1, i.ordinality
FROM "Blogs" AS b
LEFT JOIN LATERAL unnest(b."Ints") WITH ORDINALITY AS i(value) ON TRUE
ORDER BY b."Id" -- missing ordering by i.ordinality The SQL Server provider doesn't have this issue (the SELECT [b].[Id], CAST([i].[value] AS int) + 1, [i].[key]
FROM [Blogs] AS [b]
OUTER APPLY OPENJSON([b].[Ints]) AS [i]
ORDER BY [b].[Id], CAST([i].[key] AS int) Full minimal reproawait using var context = new BlogContext();
await context.Database.EnsureDeletedAsync();
await context.Database.EnsureCreatedAsync();
_ = await context.Blogs
.Select(b => b.Ints.Select(i => i + 1).ToArray())
.ToListAsync();
public class BlogContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder
.UseNpgsql("Host=localhost;Username=test;Password=test")
.LogTo(Console.WriteLine, LogLevel.Information)
.EnableSensitiveDataLogging();
}
public class Blog
{
public int Id { get; set; }
public List<int> Ints { get; set; }
} |
Thanks @roji. If/when you have a nightly build I'm more than happy to verify expected results |
Note: we currently don't add an ordering by the ordinality column, since PG's unnest is documented to return values in storage order. However, the moment one integrates the unnest into a SELECT via a JOIN, that "natural" ordering is lost and an explicit ordering must be present. I'll add an explicit ordering just like for the other providers. |
Backported to 8.0.5 via 8a4c25b |
@pinkfloydx33 I've pushed a fix and backported to 8.0.5; can you please try version 8.0.5-ci.20240623T224824.nupkg from the stable feed and confirm that the bug is gone for you? |
@roji it worked as expected. Thanks for looking into this so quick. When's the expected release of the 8.0.5 package? |
@pinkfloydx33 great. I'll probably do a patch release in the next few weeks, based on what's pending also in Npgsql - stay tuned (and don't hesitate to use the prerelease nuget in the meantime). |
@roji any updated estimate on an official 8.0.5 release? |
I am not sure if this is an EF issue or a efcore.pg issue so I am starting here.
We have an entity with a primitive collection represented as a Postgres array column. We have found an issue in EF Core wherein the collection order is not preserved by EF. In our case, the incorrect ordering seems dependent upon various combinations of:
OrderBy
on the main queryToList
In our actual application any one of the first three items seems to have an impact; we whittled our queries down such that we were only dealing with one of
1
,2
, or3
at a time and each would reproduce depending on the number of items in the related collections (4
).For the sake of this bug report, I've boiled it down to a minimal reproducible example (see below). However I've only been able to reproduce it when
OrderBy
is involved. I've not be able to reproduce it otherwise, so will continue trying to reduce our real application down until I can.Entity and DTO Types
Context
Here is the application code/reproduction.
Application code
Run the code once, as is. The expected result is that the output of the primitive collection matches the original order, despite the ordering of the main query itself. Meaning that (order of this list aside), the values should always be print to the console as:
Instead, under result sets
#2
,#4
, and#5
you will see that the ordering for items with Id's1
and4
are incorrectly output as:Now run the code again, this time with the
alt
variable set totrue
. This adds a fourth entity to the database with an empty primitive collection. The outputs of tests#2
and#4
are as expected this time, while#5
remains incorrect.Output with alt=false
Output with alt=true
We were getting random reports of incorrect ordering from customers. Two of us spent a combined 48 hours trying to debug into this and figure out what was going on. Every time we thought we had a solution, a new test case would start failing because ultimately it all seemed dependent on ordering, filtering, and total counts. We ended up working around this by writing a Postgres function that preserved and sorted by the Ordinality of the array collection, unnesting it into the type we were trying to project to.
While we have the workaround, we are concerned the issue may creep up in other forms. We'd also like to ultimately remove the workaround since a function manually added into migrations won't benefit from changes to the model.
Versions used
The text was updated successfully, but these errors were encountered: