|
| 1 | +.. _aggregates: |
| 2 | + |
| 3 | +Aggregates |
| 4 | +========== |
| 5 | + |
| 6 | +Initially before you can create a aggregate, you need to create its |
| 7 | +identity. You can create your own implementation by implementing the |
| 8 | +``IIdentity`` interface or you can use a base class ``Identity<>`` that |
| 9 | +EventFlow provides, like this. |
| 10 | + |
| 11 | +.. code-block:: c# |
| 12 | +
|
| 13 | + public class TestId : Identity<TestId> |
| 14 | + { |
| 15 | + public TestId(string value) : base(value) |
| 16 | + { |
| 17 | + } |
| 18 | + } |
| 19 | +
|
| 20 | +The :ref:`Identity\<\> <identity>` value object |
| 21 | +provides generic functionality to create and validate aggregate root |
| 22 | +IDs. Please read the documentation regarding the bundled ``Identity<>`` |
| 23 | +type as it provides several useful features, e.g. several different |
| 24 | +schemes for ID generation, one that minimizes MSSQL database |
| 25 | +fragmentation. |
| 26 | + |
| 27 | +Next, to create a new aggregate, simply inherit from |
| 28 | +``AggregateRoot<,>`` like this, making sure to pass test aggregate own |
| 29 | +type as the first generic argument and the identity as the second. |
| 30 | + |
| 31 | +.. code-block:: c# |
| 32 | +
|
| 33 | + public class TestAggregate : AggregateRoot<TestAggregate, TestId> |
| 34 | + { |
| 35 | + public TestAggregate(TestId id) |
| 36 | + : base(id) |
| 37 | + { |
| 38 | + } |
| 39 | + } |
| 40 | +
|
| 41 | +Events |
| 42 | +------ |
| 43 | + |
| 44 | +In an event source system like EventFlow, aggregate root data are stored |
| 45 | +on events. |
| 46 | + |
| 47 | +.. code-block:: c# |
| 48 | +
|
| 49 | + public class PingEvent : AggregateEvent<TestAggregate, TestId> |
| 50 | + { |
| 51 | + public string Data { get; } |
| 52 | + public PingEvent(string data) |
| 53 | + { |
| 54 | + Data = data; |
| 55 | + } |
| 56 | + } |
| 57 | +
|
| 58 | +Please make sure to read the section on :ref:`value objects and |
| 59 | +events <value-objects>` for some important notes on creating |
| 60 | +events. |
| 61 | + |
| 62 | +Emitting events |
| 63 | +--------------- |
| 64 | + |
| 65 | +In order to emit an event from an aggregate, call the ``protected`` |
| 66 | +``Emit(...)`` method which applies the event and adds it to the list of |
| 67 | +uncommitted events. |
| 68 | + |
| 69 | +.. code-block:: c# |
| 70 | +
|
| 71 | + public void Ping(string data) |
| 72 | + { |
| 73 | + // Fancy domain logic here that validates aggregate state... |
| 74 | +
|
| 75 | + if (string.IsNullOrEmpty(data)) |
| 76 | + { |
| 77 | + throw DomainError.With("Ping data empty") |
| 78 | + } |
| 79 | +
|
| 80 | + Emit(new PingEvent(data)) |
| 81 | + } |
| 82 | +
|
| 83 | +Remember not to do any changes to the aggregate with the these methods, |
| 84 | +as as state are only stored through events and how they are applied to |
| 85 | +the aggregate root. |
| 86 | + |
| 87 | +Applying events |
| 88 | +--------------- |
| 89 | + |
| 90 | +Currently EventFlow has three methods of applying events to the |
| 91 | +aggregate when emitted or loaded from the event store. Which you choose |
| 92 | +is up to you, implementing ``IEmit<SomeEvent>`` is the most convenient, |
| 93 | +but will expose public ``Apply`` methods. |
| 94 | + |
| 95 | +- Create a method called ``Apply`` that takes the event as argument. To |
| 96 | + get the method signature right, implement the ``IEmit<SomeEvent>`` on |
| 97 | + your aggregate. This is the default fallback and you will get an |
| 98 | + exception if no other strategies are configured. Although you *can* |
| 99 | + implement ``IEmit<SomeEvent>``, its optional, the ``Apply`` methods |
| 100 | + can be ``protected`` or ``private`` |
| 101 | +- Create a state object by inheriting from ``AggregateState<,,>`` and |
| 102 | + registering using the protected ``Register(...)`` in the aggregate |
| 103 | + root constructor |
| 104 | +- Register a specific handler for a event using the protected |
| 105 | + ``Register<SomeEvent>(e => Handler(e))`` from within the constructor |
| 106 | +- Register an event applier using |
| 107 | + ``Register(IEventApplier eventApplier)``, which could be a e.g state |
| 108 | + object |
0 commit comments