You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
EF Core: refuse a hand-written ordering on the translated SQL tree, not the LINQ tree (spike first) #238
2.3.1's EF ordering bugs came in waves from one cause. HandWrittenOrdering's Finder pattern-matches the LINQ tree before EF translates it, and so has to predict what EF will order in the database. Each LINQ shape it does not model is a silent gap: #206 took three rounds in #217 (a cast to object; then ?? and projections; then groupings, joins, SelectMany, a subquery's First()). #225 hinged on EF's own evaluation of captured values (KB-058). Query filters need a second path at model building, because the interceptor never sees them.
Proposal
Refuse where the database's ordering is decided, after translation. A query-translation postprocessor visits the SQL expression tree and refuses each ORDER BY, comparison, MIN/MAX, GREATEST/LEAST and row-value comparison whose column or projection's type mapping converts a value object with a hand-written ordering. By then EF has dropped the casts, applied the query filters and evaluated what runs in memory, so every shape is covered by construction, filters included, at query time.
Spike first
Measure on SQLite, PostgreSQL and SQL Server that the type mapping survives the shapes #206 listed (a boxing cast, ??, a projection's member, a grouping key, a join, a subquery's First(), an aggregate over a navigation) and a query filter, and that a precompiled query (Native AOT, dbcontext optimize) still passes through the postprocessor. The spike's README answers whether the SQL tree can replace the LINQ-tree Finder and the model-building filter convention.
Done when
The refusal is decided on the SQL tree; the current HandWrittenOrderingTests rows and the QueryShapes ordering cases pass unchanged; the LINQ-tree bookkeeping (Bound, Elements, Members) and HandWrittenOrderingQueryFilterConvention are removed, or the spike records why one of them stays. Refusing more is no breaking change: the queries it adds answered the column's order.
Starts after v2.3.1 is tagged and main is merged into release/2.4.0: it replaces the HandWrittenOrdering code that #217 and #234 change, so it builds on them once they have landed.
Activity
CaffeinatedCoder commentedon Oct 31, 2026
Starts after
v2.3.1is tagged andmainis merged intorelease/2.4.0: it replaces theHandWrittenOrderingcode that #217 and #234 change, so it builds on them once they have landed.