BasicEntity
and EventSourcedEntity
(see below for more information). Entities are always a member of an aggregate.
IAggregateRoot
(which itself is also an entity) that provide a public interface for working with the aggregate.
BasicAggregateRoot
and BasicEntity
define base classes for aggregate roots and entities which will be persisted using their visible state (typically perstisting their public properties) to an RDBMS using an ORM or to a document-oriented database. Alone deriving from these base classes will be enough to be picked-up be Revo's selected persistence implentation (e.g. EF Core).DatabaseEntityAttribute
(just like these basic aggregate base classes) will be automatically be mapped to database using their public state (e.g. using EF Core if you are using Revo.EFCore as your primary data repository). For more see Data persistence.IQueryableEntity
which means it will be possible to query them as IQueryable
with repositories. By default, they will be automatically row-versioned to implement optimistic concurrency when saving them to a database (increasing their version number with each save).
protected
; this means it should not limit your from exposing another proper public constructor taking parameters and ensuring entity invariants).
EventSourcedAggregateRoot
and EventSourcedEntity
will use events to progress their state. Unlike the basic entities, they should only modify their state upon emitting a new event. Aggregates can internally publish new events using the Publish<TEvent>
method. This pushes the event to the internal queue of uncommitted events that will get persisted once the repository is saved and invokes an event handler for the specific event type that actually produces the effect of modifying the internal state of the aggregate (e.g. changes the values of its fields). The same event handlers get also invoked when the aggregate gets loaded from a repository.
Guid id
parameter. However, similarly to (non-event-sourced) basic aggregates, this constructor can be kept protected or private (being used only for the needs of deserialization) and the aggregate can define other public constructor(s) that will normally enforce its invariants by requiring more parameters. See also the example below.EventSourcedAggregateRoot
and EventSourcedEntity
use a convention-based event handling by default and will invoke any methods with the following signature:TEvent
is the type of the event handled).
DomainAggregateEvent
. This domain type includes the aggregate ID which gets automatically injected when publishing the event within an aggregate.
EventSourcedEntity
or directly EventSourcedComponent
, passing in the event router from the aggregate root (its EventRouter
). The event router takes care of routing the events inside the aggregate, delivering them to all registered components. With that, the event sourced entities and components can use the same Apply
method convention for handling events as with aggregate root and use the event router for publishing new events.
EventSourcedComponent
instead of EventSourcedEntity
instead.
Publish
method:ValueObject<T>
abstract base class that implements basic value-like semantics. An example follows.ValueObject<T>
(with T
being a self-reference to the value object type implemented) overrides object.Equals
, IEquatable<T>.Equals
, GetHashCode
and ToString
methods making it possible to treat the instances of the object as a single value - e.g. they can be correctly used in HashSets, as Dictionary keys, compared between each other, etc. (with objects having the same values considered to be equal, very much unlike with the default behavior of C# classes which considered references only), e.g.:GetValueComponents
method as shown previously.CollectionAsValueExtensions
implements the following extension methods (abridged code snippet):GetValueComponents
method to wrap lists, arrays, sets and dictionaries with correct value-object-like semantics.