Conversation
Closes the LINQKit half of #94; the Projectables guide already exists. Covers the concept mapping (Invoke/[Expandable] -> [Expressive], AsExpandable -> UseExpressives), what stays on LINQKit (PredicateBuilder, expression-parameter helpers), and the runtime edge cases. All coexistence claims were verified against LinqKit.Microsoft.EntityFrameworkCore 8.1.11 on EF Core 8 / SQLite. Notably, LINQKit's global WithExpressionExpanding() alongside UseExpressives() fails to expand an [Expressive] member referenced inside an invoked expression variable, in either registration order — ExpressiveSharp expands before LINQKit inlines the variable. Four workarounds are documented. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Collaborator
Author
|
Had AI give a shot in closing #94 This needs a review from someone that has recently used linqkit |
koenbeuk
marked this pull request as draft
September 20, 2026 02:48
Contributor
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
The migration guide contains unresolved documentation inaccuracies and examples that do not compile.
Get a fresh assessment by requesting another Copilot review.
Review effort: Lite
Findings: 3
Open (3)
What changed in this PR
Adds a LINQKit migration guide describing incremental migration and coexistence with ExpressiveSharp.
Changes:
- Adds migration guidance, examples, and runtime workarounds.
- Links the new guide from the Projectables guide.
- Adds the guide to the VitePress sidebar.
| File | Summary and review notes |
|---|---|
docs/guide/migration-from-linqkit.md |
New migration guide. Nit comments identify undeclared outer and isDomestic examples, inaccurate .AsExpressive() and .AsExpandable() guidance, incomplete removal criteria, and an incorrect EF Core InMemory statement. |
docs/guide/migration-from-projectables.md |
Adds a cross-link to the LINQKit migration guide. |
docs/.vitepress/config.mts |
Adds the migration guide to the sidebar. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| |---|---|---| | ||
| | `Expression<Func<T, R>>` field + `.Invoke(x)` | `[Expressive]` property or method, called normally | [Details](#invoke-to-expressive-members) | | ||
| | `[Expandable(nameof(Impl))]` stub method | `[Expressive]` on the method itself | [Details](#expandable-attribute) | | ||
| | `.AsExpandable()` per query | Nothing -- `UseExpressives()` expands globally | Outside EF Core: `.AsExpressive()` | |
| .UseExpressives(); | ||
| ``` | ||
|
|
||
| Do not remove `LinqKit.Microsoft.EntityFrameworkCore` (or `LinqKit.Core`) yet. Remove it at the end, and only if no `PredicateBuilder`, `Invoke`, or `Expand` usage is left. |
| | Fix | Code | | ||
| |---|---| | ||
| | Use per-query `AsExpandable()` -- LINQKit then inlines *before* ExpressiveSharp expands | `db.Customers.AsExpandable().Where(c => isBig.Invoke(c))` | | ||
| | Call `Expand()` up front | `db.Customers.Where(outer.Expand())` | |
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Closes the LINQKit half of #94. The Projectables half already exists as
docs/guide/migration-from-projectables.md, so this adds the missing guide.What's here
docs/guide/migration-from-linqkit.mddocs/.vitepress/config.mtsThe guide is framed around the fact that the two libraries work from opposite directions: LINQKit composes
Expression<Func<...>>objects at runtime, ExpressiveSharp generates trees at compile time from ordinary members. So it is an incremental migration, not an all-or-nothing one, and the guide says which parts stay on LINQKit.[Expressive]InvokePredicateBuilder/ExpressionStarter<T>[Expandable]stub +Implmethod pairsExpression<...>parameterVerification
The issue author's concern was runtime edge cases, so the coexistence claims were checked in a throwaway project (outside this repo) against
LinqKit.Microsoft.EntityFrameworkCore8.1.11 /LinqKit.Core1.2.11, EF Core 8, SQLite, referencing ExpressiveSharp from source.Invokefilter and DTO projection produce byte-identical SQL before and after conversion.PredicateBuilderoutput works underUseExpressives()withoutAsExpandable(), including predicates that reference[Expressive]members andExpressionPolyfill.Createlambdas.AsExpandable()andAsExpressive()compose on one query in either order.One real failure, documented
LINQKit's global
WithExpressionExpanding()alongsideUseExpressives()fails when an[Expressive]member is referenced inside an invoked expression variable:ExpressiveSharp expands first, while
isBigis still an opaque captured variable; LINQKit then inlines it, and nothing expands the newly exposed member. Registration order makes no difference. Everything else works under the global hook: plainInvoke,[Expandable]methods, and[Expressive]members written directly in the query.Four workarounds are documented (per-query
AsExpandable(),Expand()up front, pre-expanding withExpandExpressives(), or converting the call site).Expand()andExpandExpressives()were both run and confirmed; the other two were exercised only without the global hook, which is the recommended setup anyway.This looks fixable in ExpressiveSharp itself by expanding through captured expression constants under
Invoke, but that is a behaviour change outside the scope of a docs issue — happy to open it separately.Notes
csharpblocks rather than::: expressive-sample, since the sample renderer cannot reference LinqKit.npx vitepress buildpasses with no dead links; the new page's anchors resolve in the rendered HTML.🤖 Generated with Claude Code