Skip to content

Marten 8.23 - DCB support, natural keys, EF Core projections#4162

Merged
jeremydmiller merged 23 commits intomasterfrom
8.23
Mar 9, 2026
Merged

Marten 8.23 - DCB support, natural keys, EF Core projections#4162
jeremydmiller merged 23 commits intomasterfrom
8.23

Conversation

@jeremydmiller
Copy link
Member

Summary

  • Add Dynamic Consistency Boundary (DCB) support with tag-based cross-stream querying and consistency
  • Add natural key support for event stream aggregates (FetchForWriting/FetchLatest by business key)
  • Add first-class EF Core projection support with custom projection storage
  • Add FetchForWritingByTags to batch querying API
  • Optimize QuickAppend+Tags by integrating tag inserts into PostgreSQL function
  • Fix DCB tag queries to use LEFT JOIN for multi-tag-type queries
  • Add stream version assertion and fix AlwaysEnforceConsistency with empty streams
  • Fix child collection queries leaking across tenants with partitioned tables
  • Convert DCB and natural key docs to use MarkdownSnippets includes
  • Replace JasperFx and Weasel project references with NuGet packages (JasperFx 1.21.0, JasperFx.Events 1.23.0, Weasel 8.9.0)
  • Use ITagTypeRegistration interface for DCB tag type registrations

Test plan

  • Marten DCB tests: 26/26 pass
  • All compilation verified with NuGet package references

🤖 Generated with Claude Code

jeremydmiller and others added 23 commits March 3, 2026 12:11
…ocal development

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Mark 33 EventProjection subclasses and 4 containing classes as partial to
enable compile-time source generation of ApplyAsync dispatch. The generator
produces code for classes with conventional Project/Create/Transform methods
and skips classes with ApplyAsync overrides, lambda registrations, or no
conventional methods.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ts to StoreOptions

Closes GH-3963

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
… Polecat via Weasel.Core

Documents analysis of overlapping types between Marten (PostgreSQL) and
Polecat (SQL Server) with prioritized recommendations for what to move
to Weasel.Core for Marten 9: metadata interfaces, serialization enums,
ISerializer base, and storage operation abstractions.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Introduces ITransactionParticipant pattern allowing EF Core DbContext to
participate in Marten's database transaction. Adds Marten.EntityFrameworkCore
project with EfCoreEventProjection, EfCoreSingleStreamProjection, and
EfCoreMultiStreamProjection base types. DbContext receives a connection
object directly from Marten's database and is enlisted in the same
transaction before commit.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…tables

DocumentMapping.TenancyStyle was only synced to QueryMembers.TenancyStyle
once during the constructor, before builder alterations ran. When tenancy
was configured via Schema.For<T>().MultiTenantedWithPartitioning(), the
builder set TenancyStyle after construction, so QueryMembers kept the
default Single value. This caused SubQueryFilter to skip adding the
tenant_id filter to the outer query, allowing ctid collisions across
partitions to return rows from other tenants.

Fix: make DocumentMapping.TenancyStyle setter always sync to
QueryMembers.TenancyStyle. Add regression tests for both hash and list
partitioning. Closes GH-4161.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…tream querying and consistency

Implements event tagging, tag-based querying (QueryByTagsAsync, AggregateByTagsAsync),
and FetchForWritingByTags with optimistic concurrency via sequence-based consistency checks.
Includes 12 integration tests and documentation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Tags are now persisted in Quick mode using INSERT...SELECT seq_id FROM mt_events WHERE id = @eventid,
avoiding the need for pre-assigned sequences. Includes 7 Quick append DCB tests.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
New IQueryHandler implementation builds tag query SQL via ICommandBuilder for
batch execution. IBatchEvents now exposes FetchForWritingByTags<T>(EventTagQuery).
Includes 2 batch query tests (happy path and concurrency violation).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…rage

Adds EfCoreSingleStreamProjection, EfCoreMultiStreamProjection, and EfCoreEventProjection
base classes that project events into EF Core DbContext entities. Introduces custom
projection storage providers so EF Core can manage its own entity persistence.
Also drops extended schema objects (EF Core tables) in document cleaner and
adds multi-tenancy validation tests.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…pty streams

Override AppendMode property in EventGraph for proper base class delegation.
UnitOfWork.HasOutstandingWork now considers streams with AlwaysEnforceConsistency
even when they have no events. Adds AssertStreamVersionById/ByKey operations
and FetchForWriting consistency tests.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…entation plan

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…function

Tag inserts are now performed inside the mt_quick_append_events PL/pgSQL
function rather than as separate IStorageOperation round-trips. For each
registered tag type, a varchar[] parameter is added to the function and
tag rows are inserted in the same loop that inserts events, using the
already-available sequence value. This eliminates N extra SQL commands
per tagged event append.

Benchmarks show Quick+Tags improved from ~681 events/sec to ~3,105
events/sec (4.6x improvement), bringing tag overhead in line with Rich
mode (~19% vs previous ~87%).

Also adds DcbLoadTest project for repeatable performance measurement
with large database seeding.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…se Append for existing streams

- Changed INNER JOIN to LEFT JOIN in BuildTagQuerySql and FetchForWritingByTagsHandler
  so events spanning multiple tag types are not filtered out
- Changed EventBoundary.RouteEventByTags to use StreamAction.Append instead of Start
  to avoid ExistingStreamIdCollisionException for pre-existing streams
- Added DCB tests and aggregation test files

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Natural keys allow domain-meaningful identifiers (e.g., OrderNumber) to be
used for FetchForWriting/FetchLatest lookups instead of raw stream ids.
Includes auto-registered inline projection, schema table with FK to
mt_streams, single-round-trip CTE fetch plan supporting both Inline and
Live lifecycles, and comprehensive tests covering Guid/string stream
identity permutations.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace inline code samples with <!-- snippet: --> includes that reference
#region sample_* markers in actual test files. This ensures documentation
code samples always compile and stay in sync with the codebase.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Update to JasperFx 1.21.0, JasperFx.Events 1.23.0,
JasperFx.Events.SourceGenerator 1.1.0, JasperFx.RuntimeCompiler 4.4.0.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The JasperFx.Events.SourceGenerator NuGet package 1.1.0 placed the DLL
in lib/netstandard2.0/ instead of analyzers/dotnet/cs/, preventing the
source generator from running. This caused all Evolve/EvolveAsync-based
aggregations to fail. Temporarily using project reference until fixed
NuGet package 1.2.0 is published.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
SourceGenerator 1.2.0 fixes NuGet package structure to place the DLL
in analyzers/dotnet/cs/ so the source generator runs correctly.
Replaces temporary project references with NuGet package references.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
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