PouryaKit
Decision guides

Stream or EF Core aggregate

Whether a Module stores its aggregates' current state with EF Core or the events they appended, as Streams on Marten.

What it decides

The write model of a Module. An EF Core aggregate stores its current state in tables the Module maps. A Stream is an aggregate whose stored state is the events it appended, kept by Marten over PostgreSQL; the Proving Sample's Ledger keeps its accounts this way, beside the EF Core Modules Catalog, Inventory and Billing.

One write model per Module

Each write model has its own Unit of Work and commits alone: a Stream Module's Operations commit through the Marten Unit of Work, an EF Core Module's through the EF Core one, and no Operation commits through both. Both kinds of Module share one Host and its one message store.

When to choose each

EF Core aggregateStream
Stored stateThe aggregate's current stateThe events it appended, folded into its state when it is loaded
FitsCurrent-state records read in many shapes, with Dapper or a repositoryA history that is the record itself, such as a ledger's entries
MigrationsOne per model change, from dotnet-efNone: Marten creates the tables
What it publishesIntegration Events, and Snapshots of its aggregatesIntegration Events only: a Stream publishes no Snapshot
What it leaves outA few features of the EF Core Unit of Work: Limits

Write one

Register the Module's write model

An EF Core Module calls UsePouryaKitPostgres in its Composition Root; a Stream Module calls AddPouryaKitStreams with its schema, and the Host registers its one Marten store with UsePouryaKitMarten, after UsePouryaKitWolverine when it also has EF Core Modules. Registering shows Ledger's.

Write the aggregate

The repository for an EF Core aggregate, or Writing a Stream.

What the Kit guarantees

Stated in
An EF Core Operation commits once, with its OutboxPersistence guarantees
A Stream's events, envelopes and Receipts commit in one transactionStream guarantees

Failure messages

Next steps

On this page