Skip to content

Implement LINQ GroupJoin() operator for cross-document joins#4158

Merged
jeremydmiller merged 1 commit intomasterfrom
group-join
Mar 3, 2026
Merged

Implement LINQ GroupJoin() operator for cross-document joins#4158
jeremydmiller merged 1 commit intomasterfrom
group-join

Conversation

@jeremydmiller
Copy link
Member

@jeremydmiller jeremydmiller commented Mar 3, 2026

Summary

  • Adds LINQ GroupJoin() support for cross-document-type SQL JOINs between Marten document tables
  • GroupJoin + SelectMany translates to INNER JOIN
  • GroupJoin + SelectMany + DefaultIfEmpty translates to LEFT JOIN
  • Uses CTE-based SQL generation so each document table retains the standard d alias, then joins the CTEs with a jsonb_build_object projection
  • Supports duplicated fields in both join keys and projections (columns are included in CTEs via SelectClauseWithDuplicatedFields)
  • Supports Count(), First(), and other aggregation operators after joins
  • Unsupported patterns (GroupJoin as final operator, composite keys) throw NotSupportedException with clear messages

New files

File Purpose
src/Marten/Linq/GroupJoinData.cs Data carrier for parsed GroupJoin expressions
src/Marten/Linq/Parsing/Operators/GroupJoinOperator.cs Parses GroupJoin expression tree, detects DefaultIfEmpty for LEFT JOIN
src/Marten/Linq/SqlGeneration/JoinSelectClause.cs ISelectClause rendering JOIN SQL between CTEs
src/Marten/Linq/Parsing/JoinSelectParser.cs Builds jsonb_build_object projection across two joined collections
src/LinqTests/Operators/group_join_operator.cs 16 integration tests
docs/documents/querying/linq/group-join.md VitePress documentation with examples

Modified files

File Change
CollectionUsage.cs Added GroupJoinData and SelectManyCallExpression properties
CollectionUsage.Compilation.cs Added CompileGroupJoin() and GroupJoinData check in compileNext()
OperatorLibrary.cs Registered GroupJoinOperator
SelectManyOperator.cs Detects GroupJoin source, stores full expression for DefaultIfEmpty detection
LinqQueryParser.cs DocumentTypes() yields inner types from GroupJoinData
docs/.vitepress/config.mts Added nav entry for GroupJoin docs

Test plan

  • 16 integration tests covering:
    • Inner join (basic, outer-only projection, anonymous type projection, string field join)
    • Left join (DefaultIfEmpty)
    • Unsupported pattern throws NotSupportedException
    • Count and First aggregation after join
    • Duplicated inner key, outer key, both keys, Guid key, projected fields, Count with duplicated key
  • Full LinqTests suite (1216 tests) passes with 0 regressions
  • Builds cleanly with 0 errors on net9.0

🤖 Generated with Claude Code

Add support for GroupJoin + SelectMany (INNER JOIN) and
GroupJoin + SelectMany + DefaultIfEmpty (LEFT JOIN) patterns.
Uses CTE-based SQL generation so each document table retains the
standard "d" alias, then joins the CTEs in a final SELECT with
jsonb_build_object projection.

Includes support for duplicated fields in join keys and projections,
Count/First aggregation after joins, and VitePress documentation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@jeremydmiller jeremydmiller changed the title Implement LINQ GroupJoin() operator for cross-document-type joins Implement LINQ GroupJoin() operator for cross-document joins Mar 3, 2026
@jeremydmiller jeremydmiller merged commit 72a14f1 into master Mar 3, 2026
5 of 6 checks passed
@jeremydmiller jeremydmiller deleted the group-join branch March 3, 2026 18:04
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.

1 participant