Skip to content

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.

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.

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))

Set the event source ID for all events:

.FromEvery(_ => _
.Set(m => m.EventSourceId).ToEventSourceId())

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())

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)

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))
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);
[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);

Set LastUpdated, ModifiedBy, or LastEventSequence for all events to track when and by whom changes were made.

Update cache keys or version numbers for all events to support cache invalidation strategies.

Track correlation IDs or sequence numbers for all events to aid in debugging and monitoring.

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.