Attribute Reference¶
This page documents the attributes and interfaces that define an event-sourced domain model for the Event Store module.
[EventStore]¶
Marks a static partial class as the event store container. The generator discovers all [EventSourcedAggregate] and [Projection] types in the assembly.
| Property | Type | Default | Description |
|---|---|---|---|
Instrumented |
bool |
true |
Enable OpenTelemetry tracing spans via .WithActivity() |
EventBaseType |
Type? |
null |
Custom event base type (defaults to IAggregateEvent) |
Schema |
string? |
null |
PostgreSQL schema name. Defaults to store class name in snake_case (e.g., AppEventStore → app_event_store). |
[EventStore]
public static partial class AppEventStore;
// Custom schema name
[EventStore(Schema = "orders")]
public static partial class OrderingEventStore;
// Custom event base type
[EventStore(EventBaseType = typeof(IMyDomainEvent))]
public static partial class AppEventStore;
| Requirement | Diagnostic |
|---|---|
Must be partial |
DSES01 (Error) |
Should be static |
DSES02 (Warning) |
| One per assembly | DSES04 (Error) |
[EventSourcedAggregate]¶
Marks a partial class or record as an event-sourced aggregate.
| Property | Type | Default | Description |
|---|---|---|---|
PluralName |
string? |
Inferred | Override the nested class name (default: TypeName + "s") |
[EventSourcedAggregate]
public partial record Order(OrderId Id, string CustomerName, int ItemCount);
// Custom plural name
[EventSourcedAggregate(PluralName = "People")]
public partial record Person(PersonId Id, string Name);
| Requirement | Diagnostic |
|---|---|
Must be partial |
DSES03 (Error) |
Must have a [StreamId]-typed property |
DSES06 (Error) |
Requires [EventStore] in assembly |
DSES05 (Info) |
[StreamId]¶
Companion attribute for [TypedId]. Generates StreamName property and FromStreamName() parser on the ID struct.
| Property | Type | Default | Description |
|---|---|---|---|
Prefix |
string? |
Inferred | Stream name prefix (default: type name without "Id" suffix, lowercase) |
Separator |
string |
"-" |
Separator between prefix and value |
[TypedId]
[StreamId]
public readonly partial struct OrderId;
// Generated:
// orderId.StreamName → "order-550e8400-e29b-41d4-a716-446655440000"
// OrderId.FromStreamName("order-550e8400-...") → OrderId
IAggregateEvent¶
Marker interface for domain events. All events appended to aggregate streams should implement this.
public sealed record OrderCreated(OrderId OrderId, string CustomerName) : IAggregateEvent;
public sealed record OrderItemAdded(string Sku, int Quantity) : IAggregateEvent;
Event Sourcing Conventions¶
Aggregates use a convention-based Create/Apply pattern:
| Method | Signature | Purpose |
|---|---|---|
Create |
static T Create(TEvent) |
Factory — builds the aggregate from the first event |
Apply |
T Apply(TEvent) |
Updates aggregate state from subsequent events |
ShouldDelete |
bool ShouldDelete(TEvent) |
(Optional) Returns true to archive the stream |
Method resolution is cached per aggregate type via AggregateFold<T>. One Create overload per event type, one Apply overload per event type.
[EventSourcedAggregate]
public partial record Order(OrderId Id, string CustomerName, int ItemCount, bool IsCompleted)
{
// First event — creates the aggregate
public static Order Create(OrderCreated e) =>
new(e.OrderId, e.CustomerName, 0, false);
// Subsequent events — update state
public Order Apply(OrderItemAdded e) =>
this with { ItemCount = ItemCount + e.Quantity };
public Order Apply(OrderCompleted _) =>
this with { IsCompleted = true };
}
See Generated Code for the interfaces and implementations these attributes produce, or Effects for the Eff<RT, T> composition layer.