The Kladde's sales pipeline has been event-sourced since module 4.4. The Deal aggregate decides in pure functions which events a command
produces, and builds its state from events. The SqlEventStore appends the events to one stream per deal, with an expected version, and two
read models follow the stream. What is still missing is the same thing the quotes were missing before lesson 4.5.2: two concurrent commands to
the same deal run side by side, and only the event store notices the conflict.
Orleans has a base class of its own for event-sourced grains, JournaledGrain. In this lesson you put the deal into it, and in such a way
that your event store stays the source and the read models from 4.4.5 notice nothing. Along the way you meet the hardest failure case of this
module: a write that succeeds but comes back as an error.
JournaledGrain
JournaledGrain<TState, TEvent> from the package Microsoft.Orleans.EventSourcing is a grain base class with two type parameters:
TStateis the state, a class with a public parameterless constructor. Orleans copies it internally, so it needs[GenerateSerializer].TEventis the common base type of all events of this grain.
The base class brings along:
| Member | Meaning |
|---|---|
State |
the confirmed state: all stored events applied to the initial state; read-only |
Version |
the number of confirmed events |
RaiseEvents(events) |
queue events for writing, as one unit |
ConfirmEvents() |
wait until all queued events are written |
RaiseConditionalEvents(events) |
write events, but only if nobody else has written since the read; returns true or false |
TransitionState(state, event) |
the method that applies an event to the state; you override it |
How an event changes the state is something the grain says through TransitionState, and here the house rules apply as always: The grain
calculates nothing itself, it asks the model.