Skip to content

Feature/optimize closures#180

Merged
PhenX merged 3 commits intomasterfrom
feature/optimize-closures
Mar 12, 2026
Merged

Feature/optimize closures#180
PhenX merged 3 commits intomasterfrom
feature/optimize-closures

Conversation

@PhenX
Copy link
Collaborator

@PhenX PhenX commented Mar 12, 2026

ClosureCaptureBenchmark

Before :

image

After :

image

Speed gain is huge ! CompatibilityMode Full does not add as much overhead as before.

Value closures : 118µs to 1.27µs overhead
Queryable closures : 100%s to 2.66µs overhead

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a runtime optimization to ProjectableExpressionReplacer by avoiding Expression.Compile() when attempting to inline captured IQueryable closures, and introduces new functional tests/snapshots to validate query output for several closure-capture scenarios.

Changes:

  • Replace closure-member evaluation in ProjectableExpressionReplacer.VisitMember with reflection-based access and add several static caches for common reflection lookups.
  • Add ClosureMemberAccessTests functional test coverage plus Verify snapshots for net8/net9/net10 SQL output.

Reviewed changes

Copilot reviewed 20 out of 20 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
src/EntityFrameworkCore.Projectables/Services/ProjectableExpressionReplacer.cs Reworks closure-member handling (reflection vs compile) and adds per-Type caches for performance.
tests/EntityFrameworkCore.Projectables.FunctionalTests/ClosureMemberAccessTests.cs Adds functional tests intended to validate closure member access/inlining behavior.
tests/EntityFrameworkCore.Projectables.FunctionalTests/ClosureMemberAccessTests.CapturedIntField_UsedInProjectableMethod.verified.txt Snapshot for net8 query output.
tests/EntityFrameworkCore.Projectables.FunctionalTests/ClosureMemberAccessTests.CapturedIntField_UsedInProjectableMethod.DotNet9_0.verified.txt Snapshot for net9 query output.
tests/EntityFrameworkCore.Projectables.FunctionalTests/ClosureMemberAccessTests.CapturedIntField_UsedInProjectableMethod.DotNet10_0.verified.txt Snapshot for net10 query output.
tests/EntityFrameworkCore.Projectables.FunctionalTests/ClosureMemberAccessTests.CapturedStringField_UsedInProjectableMethod.verified.txt Snapshot for net8 query output.
tests/EntityFrameworkCore.Projectables.FunctionalTests/ClosureMemberAccessTests.CapturedStringField_UsedInProjectableMethod.DotNet9_0.verified.txt Snapshot for net9 query output.
tests/EntityFrameworkCore.Projectables.FunctionalTests/ClosureMemberAccessTests.CapturedStringField_UsedInProjectableMethod.DotNet10_0.verified.txt Snapshot for net10 query output.
tests/EntityFrameworkCore.Projectables.FunctionalTests/ClosureMemberAccessTests.CapturedMultipleIntFields_UsedInProjectableMethod.verified.txt Snapshot for net8 query output.
tests/EntityFrameworkCore.Projectables.FunctionalTests/ClosureMemberAccessTests.CapturedMultipleIntFields_UsedInProjectableMethod.DotNet9_0.verified.txt Snapshot for net9 query output.
tests/EntityFrameworkCore.Projectables.FunctionalTests/ClosureMemberAccessTests.CapturedMultipleIntFields_UsedInProjectableMethod.DotNet10_0.verified.txt Snapshot for net10 query output.
tests/EntityFrameworkCore.Projectables.FunctionalTests/ClosureMemberAccessTests.CapturedIQueryableField_SubqueryInlinedViaAny.verified.txt Snapshot for net8 query output.
tests/EntityFrameworkCore.Projectables.FunctionalTests/ClosureMemberAccessTests.CapturedIQueryableField_SubqueryInlinedViaAny.DotNet9_0.verified.txt Snapshot for net9 query output.
tests/EntityFrameworkCore.Projectables.FunctionalTests/ClosureMemberAccessTests.CapturedIQueryableField_SubqueryInlinedViaAny.DotNet10_0.verified.txt Snapshot for net10 query output.
tests/EntityFrameworkCore.Projectables.FunctionalTests/ClosureMemberAccessTests.CapturedIQueryableField_SubqueryInlinedViaCount.verified.txt Snapshot for net8 query output.
tests/EntityFrameworkCore.Projectables.FunctionalTests/ClosureMemberAccessTests.CapturedIQueryableField_SubqueryInlinedViaCount.DotNet9_0.verified.txt Snapshot for net9 query output.
tests/EntityFrameworkCore.Projectables.FunctionalTests/ClosureMemberAccessTests.CapturedIQueryableField_SubqueryInlinedViaCount.DotNet10_0.verified.txt Snapshot for net10 query output.
tests/EntityFrameworkCore.Projectables.FunctionalTests/ClosureMemberAccessTests.CapturedMixedFields_IntAndIQueryable_BothResolvedCorrectly.verified.txt Snapshot for net8 query output.
tests/EntityFrameworkCore.Projectables.FunctionalTests/ClosureMemberAccessTests.CapturedMixedFields_IntAndIQueryable_BothResolvedCorrectly.DotNet9_0.verified.txt Snapshot for net9 query output.
tests/EntityFrameworkCore.Projectables.FunctionalTests/ClosureMemberAccessTests.CapturedMixedFields_IntAndIQueryable_BothResolvedCorrectly.DotNet10_0.verified.txt Snapshot for net10 query output.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 24 out of 24 changed files in this pull request and generated 2 comments.

@PhenX PhenX merged commit 0aa84fc into master Mar 12, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants