Skip to content

EF Core: refuse a hand-written ordering on the translated SQL tree, not the LINQ tree (spike first) #238

Open

Description

@CaffeinatedCoder

Why

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.

Activity

  1. added this to the 2.4.0 milestone on Oct 31, 2026
  2. added
    enhancementNew feature or request
    package/efcoreAffects CodoMetis.TypeKit.EntityFrameworkCore
    area/value-objectsValue-object contracts and what the aspects generate for them
    on Oct 31, 2026
  3. CaffeinatedCoder commented on Oct 31, 2026

    @CaffeinatedCoder
    OwnerAuthor

    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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area/value-objectsValue-object contracts and what the aspects generate for themenhancementNew feature or requestpackage/efcoreAffects CodoMetis.TypeKit.EntityFrameworkCore

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions