Skip to content

Projection With FromAll

FromAll subscribes to every event type in the event sequence, not just event types declared by the projection. It can create or update a read-model instance for any event source, keyed by the event source id unless you configure another key. Use FromEvery instead when mappings should apply only to event types the projection already handles.

A declared Join event type is excluded from the separate all-events subscription to avoid processing a matched event twice. Its FromAll mapping runs through the join instead. Known limitation: if that join finds no read-model instance, the mapping does not fall back to creating one under the event source id. An event type that is also declared in From runs the mapping through From instead, once, and can construct its own keyed instance.

Use FromAll in .NET for sequence-wide mappings such as per-source event counts. The root all block in the declaration language has the same subscription scope: it observes child-projection event types as well as unrelated event types. FromAll sends child inclusion as true and has no child-exclusion switch. Child-only events apply the mappings once to their containing parent, using the child’s resolved parent key. Unrelated event types still use the configured all-events key. Use FromEvery with ExcludeChildProjections() (or every with exclude children) for mappings limited to one projection level.

Declarative FromAll
using Cratis.Chronicle.Events;
using Cratis.Chronicle.Projections;
[EventType]
public record UserCreatedDeclarativeAll(string Name, string Email);
[EventType]
public record UserEmailChangedDeclarativeAll(string Email);
public record UserProfileDeclarativeAll(
string Name,
string Email,
DateTimeOffset LastUpdated);
public class UserProfileDeclarativeAllProjection : IProjectionFor<UserProfileDeclarativeAll>
{
public void Define(IProjectionBuilderFor<UserProfileDeclarativeAll> builder) => builder
.From<UserCreatedDeclarativeAll>()
.From<UserEmailChangedDeclarativeAll>()
.FromAll(_ => _
.Set(m => m.LastUpdated)
.ToEventContextProperty(c => c.Occurred));
}

View C# snippet source on GitHub

Map context fields with FromAll
using Cratis.Chronicle.Events;
using Cratis.Chronicle.Projections;
[EventType]
public record AccountTouchedDeclarativeAll(string Reason);
public record AccountAuditDeclarativeAll(
DateTimeOffset LastUpdated,
EventSequenceNumber LastEventSequence,
string LastCorrelationId);
public class AccountAuditDeclarativeAllProjection : IProjectionFor<AccountAuditDeclarativeAll>
{
public void Define(IProjectionBuilderFor<AccountAuditDeclarativeAll> builder) => builder
.From<AccountTouchedDeclarativeAll>()
.FromAll(_ => _
.Set(m => m.LastUpdated).ToEventContextProperty(c => c.Occurred)
.Set(m => m.LastEventSequence).ToEventContextProperty(c => c.SequenceNumber)
.Set(m => m.LastCorrelationId).ToEventContextProperty(c => c.CorrelationId));
}

View C# snippet source on GitHub

Map event source id with FromAll
using Cratis.Chronicle.Events;
using Cratis.Chronicle.Projections;
[EventType]
public record AccountOpenedDeclarativeAll(string OwnerName);
public record AccountSummaryDeclarativeAll(
string AccountId,
string OwnerName);
public class AccountSummaryDeclarativeAllProjection : IProjectionFor<AccountSummaryDeclarativeAll>
{
public void Define(IProjectionBuilderFor<AccountSummaryDeclarativeAll> builder) => builder
.From<AccountOpenedDeclarativeAll>()
.FromAll(_ => _
.Set(m => m.AccountId)
.ToEventSourceId());
}

View C# snippet source on GitHub

FromAll can sit beside event-specific From mappings, but the FromAll mapping also processes event types not shown in this example. Those events can create instances without the event-specific business fields. If metadata should update only for the events listed in From, use FromEvery instead.

Combine FromAll with event-specific mappings
using Cratis.Chronicle.Events;
using Cratis.Chronicle.Projections;
[EventType]
public record OrderCreatedDeclarativeAll(string OrderNumber);
[EventType]
public record OrderShippedDeclarativeAll(string TrackingNumber);
public record OrderDeclarativeAll(
string OrderNumber,
string Status,
DateTimeOffset LastModified);
public class OrderDeclarativeAllProjection : IProjectionFor<OrderDeclarativeAll>
{
public void Define(IProjectionBuilderFor<OrderDeclarativeAll> builder) => builder
.FromAll(_ => _
.Set(m => m.LastModified)
.ToEventContextProperty(c => c.Occurred))
.From<OrderCreatedDeclarativeAll>(_ => _
.Set(m => m.OrderNumber).To(e => e.OrderNumber)
.Set(m => m.Status)
.ToValue("Placed"))
.From<OrderShippedDeclarativeAll>(_ => _
.Set(m => m.Status)
.ToValue("Shipped"));
}

View C# snippet source on GitHub

Counting Into A Dictionary With A Dynamic Key

Section titled “Counting Into A Dictionary With A Dynamic Key”

FromAll also supports Count, Increment, and Decrement against a dictionary-typed property, where the key is resolved per event from a value on the EventContext — for example, one counter per event type, keyed by the event type identifier. The dictionary’s value type is always int64 for these operations; the key is always string.

Declarative FromAll with a dynamic dictionary key
using Cratis.Chronicle.Events;
using Cratis.Chronicle.Projections;
[EventType]
public record UserRegisteredForEventCounts(string Name);
[EventType]
public record OrderPlacedForEventCounts(string OrderId);
public record EventTypeCountsReadModel(
Guid Id,
Dictionary<string, int> EventCountByType,
DateTimeOffset LastEventOccurred);
public class EventTypeCountsProjection : IProjectionFor<EventTypeCountsReadModel>
{
public void Define(IProjectionBuilderFor<EventTypeCountsReadModel> builder) => builder
.FromAll(_ => _
.Count(m => m.EventCountByType, c => c.EventType.Id)
.Set(m => m.LastEventOccurred).ToEventContextProperty(c => c.Occurred));
}

View C# snippet source on GitHub

The model-bound [FromAll] attribute does not yet support this dictionary form — use the fluent API above until it does.

APIUse it when
FromAllYou are using the .NET declarative projection API and want to express an all-events mapping.
FromEveryYou want mappings applied to the projection’s own handled event types, without subscribing to unrelated event types.

Prefer event context sources for audit fields because every event has the same context shape. Use event payload properties only when the event contracts intentionally share the same property.