Analysis
Your business intelligence department asks you to provide a more analysis-friendly representation of the leads data. For their current research, they want to get the num‐ ber of follow-up calls scheduled for different leads. Later they will filter the converted and closed leads data and use the model to optimize the sales process. Let’s project the data they are asking for:
public class AnalysisModelProjection
{
public long LeadId { get; private set; } public int Followups { get; private set; } public LeadStatus Status { get; private set; } public int Version { get; private set; }
public void Apply(LeadInitialized @event)
{
LeadId = @event.LeadId; Followups = 0;
Status = LeadStatus.NEW_LEAD; Version = 0;
}
public void Apply(Contacted @event)
{
Version += 1;
}
public void Apply(FollowupSet @event)
{
Status = LeadStatus.FOLLOWUP_SET; Followups += 1;
Version += 1;
}
public void Apply(ContactDetailsChanged @event)
{
Version += 1;
}
public void Apply(OrderSubmitted @event)
{
Status = LeadStatus.PENDING_PAYMENT; Version += 1;
}
public void Apply(PaymentConfirmed @event)
{
Status = LeadStatus.CONVERTED; Version += 1;
}
}
The preceding logic maintains a counter of the number of times follow-up events appeared in the lead’s events. If we were to apply this projection to the example of the aggregate’s events, it would generate the following state:
LeadId: 12
Followups: 1 Status: Converted Version: 6
The logic implemented in the preceding examples projects the search-optimized and analysis-optimized models in-memory. However, to actually implement the required functionality, we have to persist the projected models in a database. In Chapter 8, you will learn about a pattern that allows us to do that: command-query responsibility segregation (CQRS).