Projection with FromEvery
The FromEvery() method allows you to set properties that will be updated for every event that the projection processes, regardless of the specific event type. This is particularly useful for tracking metadata like “last updated” timestamps or common audit fields.
Basic FromEvery usage
Section titled “Basic FromEvery usage”Use FromEvery() to set properties that should be updated by all events in the projection:
public class UserProfileProjection : IProjectionFor<UserProfile>{ public void Define(IProjectionBuilderFor<UserProfile> builder) => builder .AutoMap() .FromEvery(_ => _ .Set(m => m.LastUpdated).ToEventContextProperty(c => c.Occurred)) .From<UserCreated>() .From<UserEmailChanged>() .From<UserNameChanged>();}In this example, LastUpdated will be set to the event’s occurrence time for every event that affects this projection.
Available FromEvery mappings
Section titled “Available FromEvery mappings”Event context properties
Section titled “Event context properties”Map to any event context property for all events:
.FromEvery(_ => _ .Set(m => m.LastUpdated).ToEventContextProperty(c => c.Occurred) .Set(m => m.LastEventSequence).ToEventContextProperty(c => c.SequenceNumber) .Set(m => m.LastCorrelationId).ToEventContextProperty(c => c.CorrelationId))Event source ID
Section titled “Event source ID”Set the event source ID for all events:
.FromEvery(_ => _ .Set(m => m.EventSourceId).ToEventSourceId())Excluding child projections
Section titled “Excluding child projections”By default, FromEvery() applies to events in child projections as well. You can exclude child projections:
.FromEvery(_ => _ .Set(m => m.LastUpdated).ToEventContextProperty(c => c.Occurred) .ExcludeChildProjections())FromEvery with children
Section titled “FromEvery with children”When using FromEvery() with child projections, the parent properties are updated for all events, including those that only affect children:
public class OrderProjection : IProjectionFor<Order>{ public void Define(IProjectionBuilderFor<Order> builder) => builder .AutoMap() .FromEvery(_ => _ .Set(m => m.LastModified).ToEventContextProperty(c => c.Occurred)) .From<OrderCreated>() .Children(m => m.Items, children => children .IdentifiedBy(e => e.ProductId) .AutoMap() .From<ItemAddedToOrder>(_ => _ .UsingKey(e => e.ProductId)) .From<ItemQuantityChanged>(_ => _ .UsingKey(e => e.ProductId)));}In this example, LastModified on the order will be updated when:
- The order is created (
OrderCreated) - Items are added (
ItemAddedToOrder) - Item quantities change (
ItemQuantityChanged)
Multiple FromEvery calls
Section titled “Multiple FromEvery calls”You can call FromEvery() multiple times, and the properties will be merged:
.FromEvery(_ => _ .Set(m => m.LastUpdated).ToEventContextProperty(c => c.Occurred)).FromEvery(_ => _ .Set(m => m.ModifiedBy).ToEventContextProperty(c => c.CausedBy))Read model example
Section titled “Read model example”public record UserProfile( string UserId, string Name, string Email, DateTimeOffset LastUpdated, ulong LastEventSequence, string LastCorrelationId);
public record Order( string OrderId, string OrderNumber, string CustomerId, DateTimeOffset LastModified, IEnumerable<OrderItem> Items);
public record OrderItem( string ProductId, string ProductName, int Quantity);Event definitions
Section titled “Event definitions”[EventType]public record UserCreated(string Name, string Email);
[EventType]public record UserEmailChanged(string UserId, string NewEmail);
[EventType]public record UserNameChanged(string UserId, string NewName);
[EventType]public record OrderCreated(string OrderNumber, string CustomerId);
[EventType]public record ItemAddedToOrder(string OrderId, string ProductId, string ProductName, int Quantity);
[EventType]public record ItemQuantityChanged(string OrderId, string ProductId, int NewQuantity);Common use cases
Section titled “Common use cases”Audit tracking
Section titled “Audit tracking”Set LastUpdated, ModifiedBy, or LastEventSequence for all events to track when and by whom changes were made.
Caching and invalidation
Section titled “Caching and invalidation”Update cache keys or version numbers for all events to support cache invalidation strategies.
Debugging and monitoring
Section titled “Debugging and monitoring”Track correlation IDs or sequence numbers for all events to aid in debugging and monitoring.
Event Source identification
Section titled “Event Source identification”Set the event source identifier for the event source for all events if the primary identifier of a read model is different than the EventSourceId
but you still want to have a property with which event source it is for.
The FromEvery() method provides a powerful way to maintain common properties across all events in a projection, ensuring consistency and reducing duplication in your projection definitions.