Skip to content

10.x: RangeLowerBoundComparer.Compare in a query runs in the range order (port of #385) #396

Closed

Description

@CaffeinatedCoder

Problem

The same defect as #385, on release/10.x. RangeLowerBoundComparer<TRange, T>.Instance.Compare(a, b) (and RangeSet<TRange, T>.LowerBoundComparer, the same instance) runs as SQL in the range order inside an EF Core query, because EF Core rewrites any Compare(a, b) to the natural comparison (dotnet/efcore#39402). A filter selects different rows than the same LINQ over the loaded rows, without an error.

Measured 2026-10-24 on release/10.x (9af5842), PostgreSQL 16, on EF Core 10.0.0 and on 10.0.13 with Npgsql 10.0.3, with p = [2026-03-01,2026-03-10]:

Row Period Memory SQL
1 [2026-03-01,2026-03-10] 0 0
2 [2026-03-01,) 0 1
3 [2026-03-01,2026-03-03] 0 -1
4 [2026-03-05,2026-03-06] 1 1

Where(r => comparer.Compare(r.Period, p) == 0) becomes WHERE r."Period" = @p and selects row 1, where memory selects rows 1, 2 and 3. The same through IComparer<DateRange>. Identical to main.

Change

Port whichever fix #385 lands on main (refuse or translate), with a regression test of its own. Remove the known-difference entry from docs/efcore.md#what-runs-where that 10.2.0 adds (#397).

Release

silent: one row under ### Changed answers in the 10.x minor it ships in. Fixed only on release/10.x, so close it by hand.

Activity

  1. added
    bugSomething isn't working
    silentAnswers wrongly without throwing — fixes go in the next major, never deferred
    area/rangesRange unions, variants and the shape engines
    package/efcoreAffects CodoMetis.ValueRanges.EFCore.PostgreSQL
    severity/lowCosmetic, message or documentation-level difference
    on Oct 24, 2026
  2. added this to the 10.3.0 milestone on Oct 25, 2026
  3. CaffeinatedCoder commented on Oct 25, 2026

    @CaffeinatedCoder
    OwnerAuthor

    Scheduled for 10.3.0 (#408), on condition that the main fix lands first. Otherwise it moves to the next 10.x minor.

  4. CaffeinatedCoder commented on Oct 25, 2026

    @CaffeinatedCoder
    OwnerAuthor

    #385 is fixed on main (PR #444, merged) by refusing the call. The port is PR #446 against release/10.x, stacked on the #395 port (#445) because both add rows at the same places in the changelogs and docs/migration.md. Any IComparer over a range or set, RangeSet.LowerBoundComparer and Comparer<T>.Default included, now runs in memory only in a query: a filter or an ordering fails translation, and a final Select runs the comparer on the loaded rows. LowerBoundComparerQueryTests is this line's regression test; the #396 candidate is removed, and Known differences in 10.2.0 now says 10.3.0 fixes both entries. Full 10.x integration suite passes on PostgreSQL 16 (304). Close this by hand once #446 merges.

  5. added a commit that references this issue on Oct 25, 2026
  6. CaffeinatedCoder commented on Oct 25, 2026

    @CaffeinatedCoder
    OwnerAuthor

    Fixed on release/10.x by PR #446 (merged as a8ad482), shipping in 10.3.0. Closed by hand, since Closes #n acts only on main.

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/rangesRange unions, variants and the shape enginesbugSomething isn't workingpackage/efcoreAffects CodoMetis.ValueRanges.EFCore.PostgreSQLseverity/lowCosmetic, message or documentation-level differencesilentAnswers wrongly without throwing — fixes go in the next major, never deferred

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions