Projections
Declarative Projections in Cratis allow you to create read models from events stored in the event log. They provide different levels of complexity from simple auto-mapping to sophisticated hierarchical models with joins.
Projection recipes
| Recipe | Description |
|---|---|
| Simple projection | Basic projection using AutoMap() |
| AutoMap | Automatic property mapping at different levels |
| Passive | In-memory projections for on-demand lookups |
| Set properties | Explicit property mapping and transformations |
| Children | Hierarchical data models with child collections |
| Joins | Cross-stream projections using joins |
| Functions | Arithmetic and other functions |
| Composite keys | Multi-property key identification |
| Event context | Using event metadata in projections |
| FromEvery | Setting properties for all events in a projection |
| Initial values | Default values for read model properties |
| RemoveWithJoin | Cross-stream child removal |
| FromEventSequence | Sourcing events from specific event sequences |
| NotRewindable | Forward-only projections that cannot be replayed |
Key concepts
Auto-mapping vs explicit mapping
- Auto-mapping: Automatically maps properties with matching names between events and read models
- Use
.AutoMap()in fluent projections (IProjectionFor<T>) - Use
[FromEvent<TEvent>]in model-bound projections for the same functionality
- Use
- Explicit mapping: Gives you full control over property transformations and mappings
- Use
.Set(),.Add(), etc. in fluent projections - Use
[SetFrom<TEvent>],[AddFrom<TEvent>], etc. in model-bound projections
- Use
Event handling
- Projections can handle multiple event types
- Each event type can have its own property mappings
- Properties are updated incrementally as events are processed
Keys and identification
- EventSourceId is used as the default key for both read models and parent identification in child collections
- Child identifiers: Use
.IdentifiedBy()to specify how child items are uniquely identified within collections - Parent key resolution:
- By default, the EventSourceId is used to identify the parent when adding children
- Use
.UsingParentKey(e => e.Property)when the parent identifier is in the event content - Use
.UsingParentKeyFromContext(ctx => ctx.EventSourceId)to explicitly document default behavior
- Child key specification: Use
.UsingKey(e => e.Property)to extract the child identifier from event content - Joins: Use keys to link data from different event streams using
.On(m => m.Property)
Performance
- Projections are automatically maintained as events are appended
- The system handles indexing and query optimization
- Consider join complexity and update frequency when designing projections