# Projections Build read models from event streams for optimized queries. ## Overview Projections transform event streams into queryable read models. They subscribe to events, build denormalized views, and maintain checkpoints for fault tolerance. **Key Features:** - ✅ **IDynamicProjection** - Interface for projection implementations - ✅ **Auto-Start** - Automatically start on application launch - ✅ **Checkpointing** - Track progress for fault tolerance - ✅ **Resettable** - Rebuild from scratch when needed - ✅ **Batch Processing** - Process events in batches for performance ## Quick Start ```csharp public class OrderSummaryProjection : IDynamicProjection { private readonly IOrderSummaryRepository _repository; private readonly ICheckpointStore _checkpointStore; private readonly IEventStreamStore _eventStore; public string ProjectionName => "order-summary"; public async Task RunAsync(CancellationToken ct) { var checkpoint = await _checkpointStore.GetCheckpointAsync(ProjectionName); await foreach (var @event in _eventStore.ReadStreamAsync( "orders", fromOffset: checkpoint + 1, cancellationToken: ct)) { await HandleEventAsync(@event); await _checkpointStore.SaveCheckpointAsync(ProjectionName, @event.Offset); } } private async Task HandleEventAsync(StoredEvent @event) { var eventData = JsonSerializer.Deserialize( @event.Data, Type.GetType(@event.EventType)); switch (eventData) { case OrderPlacedEvent placed: await _repository.AddOrderSummaryAsync(new OrderSummary { OrderId = placed.OrderId, CustomerName = placed.CustomerName, TotalAmount = placed.TotalAmount, Status = "Placed" }); break; case OrderShippedEvent shipped: await _repository.UpdateOrderStatusAsync(shipped.OrderId, "Shipped"); break; } } } ``` ## Registration ```csharp builder.Services.AddSingleton(); builder.Services.AddHostedService(); ``` ## Features ### [Creating Projections](creating-projections.md) Implement IDynamicProjection to build read models from events. ### [Resettable Projections](resettable-projections.md) Rebuild projections from scratch using IResettableProjection. ### [Checkpoint Stores](checkpoint-stores.md) Track projection progress with PostgreSQL or in-memory checkpoints. ## Common Patterns **Order Summary:** ```csharp OrderPlacedEvent → Create OrderSummary OrderShippedEvent → Update OrderSummary.Status OrderCancelledEvent → Update OrderSummary.Status ``` **Customer Analytics:** ```csharp UserRegisteredEvent → Increment TotalUsers OrderPlacedEvent → Increment CustomerOrderCount OrderPlacedEvent → Add to RevenueByCustomer ``` **Product Inventory:** ```csharp InventoryAddedEvent → Increase StockLevel OrderPlacedEvent → Decrease StockLevel (reservation) OrderCancelledEvent → Increase StockLevel (release) ``` ## Best Practices ### ✅ DO - Use checkpoints for fault tolerance - Process events idempotently - Monitor projection lag - Use batch processing for performance - Separate read and write models ### ❌ DON'T - Don't skip checkpointing - Don't modify projection logic without rebuilding - Don't ignore projection lag - Don't query write model for reads ## See Also - [Event Streaming Overview](../README.md) - [Persistent Streams](../fundamentals/persistent-streams.md) - [Event Replay](../event-replay/README.md)