Skip to content

Projection with FromEventSequence

The FromEventSequence() method allows you to specify which event sequence a projection should source events from. This is useful when you have multiple event sequences in your system and want to create projections that only process events from specific sequences.

Defining a projection with specific event sequence

Section titled “Defining a projection with specific event sequence”

Use FromEventSequence() to specify the event sequence to source events from:

using Cratis.Chronicle.Projections;
public class DecFromEventSequenceOrderProjection : IProjectionFor<DecFromEventSequenceOrder>
{
public void Define(IProjectionBuilderFor<DecFromEventSequenceOrder> builder) => builder
.FromEventSequence("order-management")
.AutoMap()
.From<DecFromEventSequenceOrderCreated>()
.From<DecFromEventSequenceOrderUpdated>()
.From<DecFromEventSequenceOrderShipped>();
}

This projection:

  • Only processes events from the “order-management” event sequence
  • Ignores events from other sequences like “user-management” or “inventory-management”
  • Uses the specified sequence for all event handling

Event sequences can be identified using string names or EventSequenceId:

public static class DecFromEventSequenceEventSequences
{
public const string OrderManagement = "order-management";
}
public class DecFromEventSequenceOrderProjectionWithConstant : IProjectionFor<DecFromEventSequenceOrder>
{
public void Define(IProjectionBuilderFor<DecFromEventSequenceOrder> builder) => builder
// Using a constant instead of a raw string keeps the sequence identifier consistent
// wherever it is referenced.
.FromEventSequence(DecFromEventSequenceEventSequences.OrderManagement)
.AutoMap()
.From<DecFromEventSequenceOrderCreated>();
}

The read model remains the same regardless of the event sequence:

public record DecFromEventSequenceOrder(
string OrderNumber,
string CustomerId,
decimal TotalAmount,
DecFromEventSequenceOrderStatus Status,
DateTimeOffset CreatedAt,
DateTimeOffset? ShippedAt);
public enum DecFromEventSequenceOrderStatus
{
Created,
Processing,
Shipped,
Delivered,
Cancelled
}

Events should be designed to work within the specific sequence context:

using Cratis.Chronicle.Events;
[EventType]
public record DecFromEventSequenceOrderCreated(
string OrderNumber,
string CustomerId,
decimal TotalAmount);
[EventType]
public record DecFromEventSequenceOrderUpdated(
string OrderNumber,
decimal NewTotalAmount);
[EventType]
public record DecFromEventSequenceOrderShipped(
string OrderNumber,
DateTimeOffset ShippedAt);

When using FromEventSequence():

  1. The projection subscribes only to the specified event sequence
  2. Events from other sequences are ignored, even if they match the event types
  3. The projection processes events in the order they appear in the specified sequence
  4. Event sequence numbers and ordering are maintained within that specific sequence

You can create different projections for different event sequences:

using Cratis.Chronicle.Events;
using Cratis.Chronicle.Projections;
[EventType]
public record DecFromEventSequencePackageCreated(string PackageId);
[EventType]
public record DecFromEventSequencePackageShipped(string PackageId, DateTimeOffset ShippedAt);
[EventType]
public record DecFromEventSequencePackageDelivered(string PackageId, DateTimeOffset DeliveredAt);
public record DecFromEventSequenceShipping(
string PackageId,
DateTimeOffset? ShippedAt,
DateTimeOffset? DeliveredAt);
// Projection for order management events
public class DecFromEventSequenceMultiOrderProjection : IProjectionFor<DecFromEventSequenceOrder>
{
public void Define(IProjectionBuilderFor<DecFromEventSequenceOrder> builder) => builder
.FromEventSequence("order-management")
.AutoMap()
.From<DecFromEventSequenceOrderCreated>(_ => _
.Set(m => m.Status).ToValue(DecFromEventSequenceOrderStatus.Created));
}
// Projection for shipping events from a different sequence
public class DecFromEventSequenceShippingProjection : IProjectionFor<DecFromEventSequenceShipping>
{
public void Define(IProjectionBuilderFor<DecFromEventSequenceShipping> builder) => builder
.FromEventSequence("shipping-management")
.AutoMap()
.From<DecFromEventSequencePackageCreated>()
.From<DecFromEventSequencePackageShipped>()
.From<DecFromEventSequencePackageDelivered>();
}

Use FromEventSequence() when:

  • Bounded contexts: You have separate domains with their own event sequences
  • Data partitioning: Events are logically separated by business area or tenant
  • Security boundaries: Different sequences have different access requirements
  • Performance optimization: You want to reduce the number of events a projection processes
  • Legacy integration: You need to process events from specific legacy systems
  • Multi-tenant scenarios: Each tenant has their own event sequence

If you don’t specify FromEventSequence():

  • The projection uses the default event-log event sequence.
  • All events matching the specified types are processed regardless of sequence
  • This is suitable for most single-sequence scenarios
  • Specifying an event sequence can improve performance by reducing the number of events processed
  • Each sequence maintains its own ordering and sequence numbers
  • Consider the volume and frequency of events in each sequence when designing projections
  • Event sequence isolation can help with parallel processing and scaling