dotnet-cqrs/docs/event-streaming/projections/README.md

131 lines
3.7 KiB
Markdown

# 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<IDynamicProjection, OrderSummaryProjection>();
builder.Services.AddHostedService<ProjectionHostedService>();
```
## 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)