Skip to content

FromAll Attribute

The [FromAll] attribute marks a read model property so that it is updated for every event the projection processes, regardless of event type. It is the model-bound equivalent of calling FromAll() in a fluent projection.

Unlike event-specific attributes such as [SetFrom<TEvent>], which only apply when a particular event type occurs, [FromAll] applies to all events that are part of the projection. This makes it ideal for audit metadata such as last-updated timestamps or event sequence numbers.

using Cratis.Chronicle.Events;
using Cratis.Chronicle.Keys;
using Cratis.Chronicle.Projections.ModelBound;
public record InventoryStatus(
[Key]
Guid Id,
[SetFrom<ProductRegisteredInInventory>(nameof(ProductRegisteredInInventory.ProductName))]
string ProductName,
[AddFrom<ItemsAddedToInventory>(nameof(ItemsAddedToInventory.Quantity))]
[SubtractFrom<ItemsRemovedFromInventory>(nameof(ItemsRemovedFromInventory.Quantity))]
int CurrentStock,
[FromAll(contextProperty: nameof(EventContext.Occurred))]
DateTimeOffset LastUpdated);

LastUpdated is set to the event’s occurrence time for every event that affects this read model — product registration, items added, or items removed.

public record AuditableEntity(
[Key] Guid Id,
[FromAll(contextProperty: nameof(EventContext.Occurred))]
DateTimeOffset LastModified,
[FromAll(contextProperty: nameof(EventContext.SequenceNumber))]
ulong LastEventSequence,
[FromAll(contextProperty: nameof(EventContext.CorrelationId))]
string LastCorrelationId);

When you specify a property name via the property parameter, the attribute reads that property from each event. If an event does not have the specified property, the mapping is silently skipped.

public record OrderStatus(
[Key] Guid Id,
[FromAll(property: "Status")]
string CurrentStatus);

This assumes all events in the projection have a Status property.

When neither property nor contextProperty is specified, the attribute matches the read model property name against each event’s properties by convention:

public record Product(
[Key] Guid Id,
[FromAll] // Looks for 'Version' property on all events
int Version);

[FromAll] works alongside event-specific attributes. When an event occurs, all applicable attributes are evaluated:

public record UserProfile(
[Key] Guid Id,
[SetFrom<UserCreated>(nameof(UserCreated.Name))]
[SetFrom<UserNameChanged>(nameof(UserNameChanged.NewName))]
string Name,
[SetFrom<UserCreated>(nameof(UserCreated.Email))]
[SetFrom<UserEmailChanged>(nameof(UserEmailChanged.NewEmail))]
string Email,
[FromAll(contextProperty: nameof(EventContext.Occurred))]
DateTimeOffset LastUpdated);

When a UserNameChanged event occurs:

  1. Name is updated by [SetFrom<UserNameChanged>].
  2. LastUpdated is updated by [FromAll].

[FromAll] is the attribute equivalent of FromAll() in fluent projections:

Fluent Projection:

public class InventoryStatusProjection : IProjectionFor<InventoryStatus>
{
public void Define(IProjectionBuilderFor<InventoryStatus> builder) => builder
.AutoMap()
.FromAll(_ => _
.Set(m => m.LastUpdated).ToEventContextProperty(c => c.Occurred))
.From<ProductRegisteredInInventory>()
.From<ItemsAddedToInventory>()
.From<ItemsRemovedFromInventory>();
}

Model-Bound Projection:

[FromEvent<ProductRegisteredInInventory>]
[FromEvent<ItemsAddedToInventory>]
[FromEvent<ItemsRemovedFromInventory>]
public record InventoryStatus(
[Key] Guid Id,
string ProductName,
int CurrentStock,
[FromAll(contextProperty: nameof(EventContext.Occurred))] DateTimeOffset LastUpdated);

Both produce identical results. The model-bound approach keeps the metadata definition on the read model type.

[FromAll(contextProperty: nameof(EventContext.Occurred))]
DateTimeOffset LastModified
[FromAll(contextProperty: nameof(EventContext.SequenceNumber))]
ulong LastEventSequence
[FromAll(contextProperty: nameof(EventContext.CorrelationId))]
string LastOperationId
[FromAll(contextProperty: nameof(EventContext.CausedBy))]
string LastModifiedBy
  1. Use for metadata: [FromAll] is ideal for tracking timestamps, sequence numbers, and correlation IDs.
  2. Avoid business logic: Do not use [FromAll] for properties that should only change under specific conditions.
  3. Prefer context properties: Event context properties (contextProperty) are more robust than event data properties because all events share the same context shape.
  4. Clear naming: Use property names that clearly indicate they are updated by all events — for example, LastUpdated, LastModified.
  • Only one [FromAll] attribute can be applied per property.
  • When mapping from event properties (property parameter), missing properties are silently skipped.