Skip to content

A Compare over ranges in a query runs another method, or runs in SQL, when it isn't IComparer's own #464

Closed

Description

@CaffeinatedCoder

Found by an outside pre-tag review of release/10.x at 15085f9. The reproduction found two more cases.

Problem

RangeComparerRewriter (in ValueRangesQueryExpressionInterceptor, from #396 and #452) keeps a Compare(x, y) over ranges or sets out of SQL, because EF Core reads any int Compare(T, T) as the natural order (dotnet/efcore#39402). It replaces the call with RangeComparerCall.RunInMemory, which calls IComparer<T>.Compare or IComparer.Compare rather than the method the code called. Three cases answer differently from memory, and none raises an error:

  1. A different method runs. Take a comparer class whose public Compare differs from its explicit IComparer<T>.Compare. In a Select, split.Compare(r.Period, p) returns 0, which is the explicit implementation's answer. Memory returns 1.
  2. A Compare on a class that implements no IComparer. RunInMemory finds no interface, so the call reaches EF Core unchanged and runs in SQL in the range order. This happens in a projection and also in a filter. Select(r => helper.Compare(r.Period, p)) returns -1 where memory returns 7, and Where(… == 7) becomes WHERE CASE WHEN r."Period" = @p THEN 0 … END = 7.
  3. A static Compare(DateRange, DateRange). The rewriter only handles instance calls, so it skips this one, and EF Core translates it the same way as case 2.

All three are reproduced on PostgreSQL 16 through the integration test project, over a DateRange column with p = [2026-03-01,2026-03-09].

Expected

Any Compare(x, y) over a range, a range set or a value set runs in memory as the method the code called, whatever type declares it. It fails translation in a filter or an ordering and gives memory's answer in a final projection. docs/efcore.md#what-runs-where and #396's changelog row already promise this for comparers.

Done when

Activity

  1. added this to the 10.3.0 milestone on Oct 25, 2026
  2. 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
    area/value-setsValue set families and wrapper arities
    package/efcoreAffects CodoMetis.ValueRanges.EFCore.PostgreSQL
    severity/mediumInconsistency or failure in a narrow scenario
    on Oct 25, 2026
  3. added a commit that references this issue on Oct 25, 2026
  4. added a commit that references this issue on Oct 25, 2026
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 enginesarea/value-setsValue set families and wrapper aritiesbugSomething isn't workingpackage/efcoreAffects CodoMetis.ValueRanges.EFCore.PostgreSQLseverity/mediumInconsistency or failure in a narrow scenariosilentAnswers 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