Releases: eventflow/EventFlow
v0.12.891
- Breaking: Aggregate root no longer have
Aggregate
removed from their
when name, i.e., the metadata property with keyaggregate_name
(or
MetadataKeys.AggregateName
). If you are dependent on the previous naming,
use the newAggregateName
attribute and apply it to your aggregates - Breaking: Moved
Identity<>
andIIdentity
from theEventFlow.Aggregates
namespace toEventFlow.Core
as the identities are not specific for aggregates - Breaking:
ICommand.Id
is renamed toICommand.AggregateId
to make "room"
for the newICommand.SourceId
property. If commands are serialized, then
it might be important verify that the serialization still works. EventFlow
does not serialize commands, so no mitigation is provided. If the
Command<,>
is used, make sure to use the correct protected constructor - Breaking:
IEventStore.StoreAsync(...)
now requires an additional
ISourceId
argument. To create a random one, useSourceId.New
, but it
should be e.g. the command ID that resulted in the events. Note, this method
isn't typically used by developers - New: Added
ICommand.SourceId
, which contains the ID of the source. The
default (if your commands inherit fromCommand<,>
) will be a new
CommandId
each time the aCommand<,>
instance is created. You can pass
specific value, merely use the newly added constructor taking the ID.
Alternatively you commands could inherit from the new
DistinctCommand
, enabling commands with the same state to have the
sameSourceId
- New: Duplicate commands can be detected using the new
ISourceId
. Read the
EventFlow article regarding commands for more details - New: Aggregate names can now be configured using the attribute
AggregateName
. The name can be accessed using the newIAggregateRoot.Name
property - New: Added
Identity<>.NewDeterministic(Guid, string)
enabling creation of
deterministic GUIDs - New: Added new metadata key
source_id
(MetadataKeys.SourceId
) containing
the source ID, typically the ID of the command from which the event
originated - New: Added new metadata key
event_id
(MetadataKeys.EventId
) containing a
deterministic ID for the event. Events with the same aggregate sequence
number and from aggregates with the same identity, will have the same event
identity - Fixed:
Identity<>.With(string)
now throws anArgumentException
instead of
aTargetInvocationException
when passed an invalid identity - Fixed: Aggregate roots now build the cache of
Apply
methods once, instead
of when the method is requested the first time
v0.11.751
- Breaking:
EventFlowOptions.AddDefaults(...)
now also adds event
definitions - New: RabbitMQ is now supported through the new
NuGet package calledEventFlow.RabbitMQ
which enables domain events to be
published to the bus - New: If you want to subscribe to all domain events, you can implement
and register a service that implementsISubscribeSynchronousToAll
. Services
that implement this will automatically be added using the
AddSubscribers(...)
orAddDefaults(...)
extension toEventFlowOptions
- New: Use
EventFlowOptions.UseAutofacAggregateRootFactory(...)
to use an
Autofac aggregate root factory, enabling you to use services in your
aggregate root constructor - New: Use
EventFlowOptions.UseResolverAggregateRootFactory()
to use the
resolver to create aggregate roots. Same as
UseAutofacAggregateRootFactory(...)
but for when using the internal IoC
container - New: Use
EventFlowOptions.AddAggregateRoots(...)
to register aggregate root
types - New: Use
IServiceRegistration.RegisterType(...)
to register services by
type
v0.10.642
- Breaking: Updated NuGet reference
Newtonsoft.Json
to v7.0.1
(up from v6.0.8) - Breaking: Remove the empty constructor from
SingleValueObject<>
- New: Added
SingleValueObjectConverter
to help create clean JSON when
e.g. domain events are serialized - New: Added a protected method
Register(IEventApplier)
to
AggregateRoot<,>
that enables developers to override how events are
applied. Use this to e.g. implement state objects - New: Create
AggregateState<,,>
that developers can use to create aggregate
state objects. CallRegister(...)
with the state object as argument
to redirect events to it - New: Allow
AggregateRoot<,>.Apply(...)
, i.e., methods for applying events,
to beprivate
andprotected
- New: Made
AggregateRoot<,>.Emit(...)
protected and virtual to allow
overrides that e.g. add a standard set of metadata from the aggregate state. - New: Made
AggregateRoot<,>.ApplyEvent(...)
protected and virtual to
allow more custom implementations of applying events to the aggregate root. - Fixed: Updated internal NuGet reference
Dapper
to v1.42 (up from v1.38)
v0.9.580
- Braking:
IEventStore.LoadAllEventsAsync
andIEventStore.LoadAllEvents
now take aGlobalPosition
as an argument instead of along
for the
starting position. TheGlobalPosition
is basically a wrapper around a
string that hides the inner workings of each event store. - New: NuGet package
EventFlow.EventStores.EventStore
that provides
integration to Event Store. Its an initial
version and shouldn't be used in production.
v0.8.560
-
Breaking: Remove all functionality related to global sequence
numbers as it proved problematic to maintain. It also matches this
quote:Order is only assured per a handler within an aggregate root
boundary. There is no assurance of order between handlers or
between aggregates. Trying to provide those things leads to
the dark side.Greg Young
- If you use a MSSQL read store, be sure to delete the
LastGlobalSequenceNumber
column during update, or set it to
defaultNULL
IDomainEvent.GlobalSequenceNumber
removedIEventStore.LoadEventsAsync
andIEventStore.LoadEvents
taking
aGlobalSequenceNumberRange
removed
- If you use a MSSQL read store, be sure to delete the
-
Breaking: Remove the concept of event caches. If you really need this
then implement it by registering a decorator forIEventStore
-
Breaking: Moved
IDomainEvent.BatchId
to metadata and created
MetadataKeys.BatchId
to help access it -
New:
IEventStore.DeleteAggregateAsync
to delete an entire aggregate
stream. Please consider carefully if you really want to use it. Storage
might be cheaper than the historic knowledge within your events -
New:
IReadModelPopulator
is new and enables you to both purge and
populate read models by going though the entire event store. Currently
its only basic functionality, but more will be added -
New:
IEventStore
now hasLoadAllEventsAsync
andLoadAllEvents
that
enables you to load all events in the event store a few at a time. -
New:
IMetadata.TimestampEpoch
contains the Unix timestamp version
ofIMetadata.Timestamp
. Also, an additional metadata key
timestamp_epoch
is added to events containing the same data. Note,
theTimestampEpoch
onIMetadata
handles cases in which the
timestamp_epoch
is not present by using the existing timestamp -
Fixed:
AggregateRoot<>
now reads the aggregate version from
domain events applied during aggregate load. This resolves an issue
for when anIEventUpgrader
removed events from the event stream -
Fixed:
InMemoryReadModelStore<,>
is now thread safe
v0.7.481
- New: EventFlow now includes a
IQueryProcessor
that enables you to implement
queries and query handlers in a structure manner. EventFlow ships with two
ready-to-use queries and related handlersReadModelByIdQuery<TReadModel>
: Supported by in-memory and MSSQL read
model storesInMemoryQuery<TReadModel>
: Only supported by in-memory read model store,
but lets you search for any read model based on aPredicate<TReadModel>
v0.6.456
- Breaking: Read models have been significantly improved as they can now
subscribe to events from multiple aggregates. Use a custom
IReadModelLocator
to define how read models are located. The supplied
ILocateByAggregateId
simply uses the aggregate ID. To subscribe
to other events, simply implementIAmReadModelFor<,,>
and make sure
you have supplied a proper read model locator.UseMssqlReadModel
signature changed, change to
.UseMssqlReadModel<MyReadModel, ILocateByAggregateId>()
in
order to have the previous functionalityUseInMemoryReadStoreFor
signature changed, change to
.UseInMemoryReadStoreFor<MyReadModel, ILocateByAggregateId>()
in
order to have the previous functionality
- Breaking: A warning is no longer logged if you forgot to subscribe to
a aggregate event in your read model as read models are no longer
strongly coupled to a specific aggregate and its events - Breaking:
ITransientFaultHandler
now takes the strategy as a generic
argument instead of theUse<>
method. If you want to configure the
retry strategy, useConfigureRetryStrategy(...)
instead - New: You can now have multiple
IReadStoreManager
if you would like to
implement your own read model handling - New:
IEventStore
now has aLoadEventsAsync
andLoadEvents
that loadsIDomainEvent
s based on global sequence number range - New: Its now possible to register generic services without them being
constructed generic types, i.e., registertypeof(IMyService<>)
as
typeof(MyService<>)
- New: Table names for MSSQL read models can be assigned using the
TableAttribute
fromSystem.ComponentModel.DataAnnotations
- Fixed: Subscribers are invoked after read stores have been updated,
which ensures that subscribers can use any read models that were
updated
v0.5.390
- POTENTIAL DATA LOSS for files event store: Files event store now
stores its log as JSON instead of anint
in the form
{"GlobalSequenceNumber":2}
. So rename the current file and put in the
global sequence number before startup - Breaking: Major changes has been made regarding how the aggregate
identity is implemented and referenced through interfaces. These changes makes
it possible to access the identity type directly though all interface. Some
notable examples are listed here. Note that this has NO impact on how data
is stored!IAggregateRoot
changed toIAggregateRoot<TIdentity>
ICommand<TAggregate>
changed toICommand<TAggregate,TIdentity>
ICommandHandler<TAggregate,TCommand>
changed to
ICommandHandler<TAggregate,TIdentity, TCommand>
IAmReadModelFor<TEvent>
changed to
IAmReadModelFor<TAggregate,TIdentity,TEvent>
IDomainEvent<TEvent>
changed toIDomainEvent<TAggregate,TIdentity>
- New:
ICommandBus.Publish
now takes aCancellationToken
argument - Fixed: MSSQL should list columns to SELECT when fetching events
v0.4.353
- Breaking:
ValueObject
now uses public properties instead of both
private and public fields - Breaking: Aggregate IDs are no longer
string
but objects implementing
IIdentity
- Breaking: MSSQL transient exceptions are now retried
- Breaking: All methods on
IMsSqlConnection
has an extraLabel
argument - New:
ITransientFaultHandler
added along with default retry strategies
for optimistic concurrency and MSSQL transient exceptions - New: Release notes added to NuGet packages
- New: Better logging and more descriptive exceptions
- Fixed: Unchecked missing in
ValueObject
when claculating hash - Fixed:
NullReferenceException
thrown ifnull
was stored
inSingleValueObject
andToString()
was called