-
-
Notifications
You must be signed in to change notification settings - Fork 445
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
34 changed files
with
793 additions
and
48 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
# Event upgrade | ||
At some point you might find the need to replace a event with zero or more | ||
events. Some use cases might be | ||
|
||
* A previous application version introduced a domain error in the form of a | ||
wrong event being emitted from the aggregate | ||
* Domain has changed, either from a change in requirements or simply from a | ||
better understanding of the domain | ||
|
||
EventFlow event upgraders are invoked whenever the event stream is loaded from | ||
the event store. Each event upgrader receives the entire event stream one event | ||
at a time. | ||
|
||
Note that the _ordering_ of event upgraders is important as you might implement | ||
two upgraders, one upgrade a event from V1 to V2 and then another upgrading V2 | ||
to V3. EventFlow orders the event upgraders by name before starting the event | ||
upgrade. | ||
|
||
## Example - removing a damaged event | ||
|
||
To remove an event, simply check and only return the event if its no the event | ||
you want to remove. | ||
|
||
```csharp | ||
public class DamagedEventRemover : IEventUpgrader<MyAggregate, MyId> | ||
{ | ||
public IEnumerable<IDomainEvent<TestAggregate, TestId>> Upgrade( | ||
IDomainEvent<TestAggregate, TestId> domainEvent) | ||
{ | ||
var damagedEvent = domainEvent as IDomainEvent<MyAggregate, MyId, DamagedEvent>; | ||
if (damagedEvent == null) | ||
{ | ||
yield return domainEvent; | ||
} | ||
} | ||
} | ||
``` | ||
|
||
## Example - replace event | ||
|
||
To one event to another, you should use the `IDomainEventFactory.Upgrade` to | ||
help migrate meta data and create the new event. | ||
|
||
```csharp | ||
public class UpgradeMyEventV1ToMyEventV2 : IEventUpgrader<MyAggregate, MyId> | ||
{ | ||
private readonly IDomainEventFactory _domainEventFactory; | ||
|
||
public UpgradeTestEventV1ToTestEventV2(IDomainEventFactory domainEventFactory) | ||
{ | ||
_domainEventFactory = domainEventFactory; | ||
} | ||
|
||
public IEnumerable<IDomainEvent<TestAggregate, TestId>> Upgrade( | ||
IDomainEvent<TestAggregate, TestId> domainEvent) | ||
{ | ||
var myEventV1 = domainEvent as IDomainEvent<MyAggregate, MyId, MyEventV1>; | ||
yield return myEventV1 == null | ||
? domainEvent | ||
: _domainEventFactory.Upgrade<MyAggregate, MyId>( | ||
domainEvent, new MyEventV2()); | ||
} | ||
} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
# Queries | ||
|
||
Creating queries in EventFlow is simple. | ||
|
||
First create a value object that contains the data required for the query. In | ||
this example we want to search for users based on their username. | ||
|
||
```csharp | ||
public class GetUserByUsernameQuery : IQuery<User> | ||
{ | ||
public string Username { get; private set; } | ||
|
||
public GetUserByUsernameQuery(string username) | ||
{ | ||
Username = username; | ||
} | ||
} | ||
``` | ||
|
||
Next create a query handler that implements how the query is processed. | ||
|
||
```csharp | ||
public class GetUserByUsernameQueryHandler : | ||
IQueryHandler<GetUserByUsernameQuery, User> | ||
{ | ||
private IUserReadModelRepository _userReadModelRepository; | ||
|
||
public GetUserByUsernameQueryHandler( | ||
IUserReadModelRepository userReadModelRepository) | ||
{ | ||
_userReadModelRepository = userReadModelRepository; | ||
} | ||
|
||
Task<User> ExecuteQueryAsync( | ||
GetUserByUsernameQuery query, | ||
CancellationToken cancellationToken) | ||
{ | ||
return _userReadModelRepository.GetByUsernameAsync( | ||
query.Username, | ||
cancellationToken) | ||
} | ||
} | ||
``` | ||
|
||
Last step is to register the query handler in EventFlow. Here we show the | ||
simple, but cumbersome version, you should use one of the overloads that | ||
scans an entire assembly. | ||
|
||
```csharp | ||
... | ||
EventFlowOptions.New | ||
.AddQueryHandler<GetUserByUsernameQueryHandler, GetUserByUsernameQuery, User>() | ||
... | ||
``` | ||
|
||
Then in order to use the query in your application, you need a reference to | ||
the `IQueryProcessor`, which in our case is stored in the `_queryProcessor` | ||
field. | ||
|
||
```csharp | ||
... | ||
var user = await _queryProcessor.ProcessAsync( | ||
new GetUserByUsernameQuery("root") | ||
cancellationToken) | ||
.ConfigureAwait(false); | ||
... | ||
``` | ||
|
||
## Queries shipped with EventFlow | ||
|
||
* `ReadModelByIdQuery<TReadModel>`: Supported by both the in-memory and MSSQL | ||
read model stores automatically as soon as you define the read model use | ||
using the EventFlow options for that store | ||
* `InMemoryQuery<TReadModel>`: Takes a `Predicate<TReadModel>` and returns | ||
`IEnumerable<TReadModel>`, making it possible to search all your in-memory | ||
read models based on any predicate |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.