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.
Overview
Section titled “Overview”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.
Basic Usage
Section titled “Basic Usage”Mapping from Event Context Properties
Section titled “Mapping from Event Context Properties”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.
Available Event Context Properties
Section titled “Available Event Context Properties”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);Mapping from Event Properties
Section titled “Mapping from Event Properties”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.
Convention-Based Mapping
Section titled “Convention-Based Mapping”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);Combining with Other Attributes
Section titled “Combining with Other Attributes”[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:
Nameis updated by[SetFrom<UserNameChanged>].LastUpdatedis updated by[FromAll].
Comparison with Fluent API
Section titled “Comparison with Fluent API”[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.
Use Cases
Section titled “Use Cases”Audit Timestamps
Section titled “Audit Timestamps”[FromAll(contextProperty: nameof(EventContext.Occurred))]DateTimeOffset LastModifiedEvent Sequencing
Section titled “Event Sequencing”[FromAll(contextProperty: nameof(EventContext.SequenceNumber))]ulong LastEventSequenceCorrelation Tracking
Section titled “Correlation Tracking”[FromAll(contextProperty: nameof(EventContext.CorrelationId))]string LastOperationIdCausation Tracking
Section titled “Causation Tracking”[FromAll(contextProperty: nameof(EventContext.CausedBy))]string LastModifiedByBest Practices
Section titled “Best Practices”- Use for metadata:
[FromAll]is ideal for tracking timestamps, sequence numbers, and correlation IDs. - Avoid business logic: Do not use
[FromAll]for properties that should only change under specific conditions. - Prefer context properties: Event context properties (
contextProperty) are more robust than event data properties because all events share the same context shape. - Clear naming: Use property names that clearly indicate they are updated by all events — for example,
LastUpdated,LastModified.
Limitations
Section titled “Limitations”- Only one
[FromAll]attribute can be applied per property. - When mapping from event properties (
propertyparameter), missing properties are silently skipped.