IRepository
(defined in Revo.Infrastructure module) is the high-level repository that would be used in the command handlers for the write side of the application working with the domain model.IRepository
interface is not bound to any specific database system backend (or an ORM library) and instead delegates most of the actual data-persistence related responsibilities to different aggregate stores - i.e. event sourced aggregate store or CRUD aggregate store. The repository itself is then just a thin wrapper over those aggregate stores, making it easier to work with aggregate stored in different persistence backends by providing a single unified API for them while also handing some of the concepts related to domain repositories – like the unit-of-work pattern and event publishing.IAggregateRoot
descendant). This prevents breaking the encapsulation of aggregates by querying and manually modifying single aggregate entities separately.
IRepository
interface definition shows some of the basic functionality it offers for working with aggregates.
IQueryableEntity
interface (this interface is empty and serves just to signify what entities can be used in those queries). For example, this means while these methods will be available for aggregate roots stored in a RDBMS and accessed via Entity Framework (generally any BasicAggregateRoot
-derived aggregate roots), they will not be available for event sourced aggregate roots because event store usually do not possess these kinds of querying features.
ICrudRepository
which is contained in Revo.DataAccess module) represent a way of a more direct way of accessing database. Unlike the aggregate repository (IRepository
), it is not burdened with domain concepts like aggregate consistency boundaries and encapsulation and provides more flexibility when working with data. Where IRepository offered only basic functionality for working with entities to abstract from the underlying technology, ICrudRepository
strives to do the opposite and offer maximum of the features that the used database (or an ORM) has while still maintaining some minimum level of abstraction in order to enable easy testing. Having said that, it is important to emphasize that they serve a completely different purpose – while the aggregate IRepository would usually be used on the write side of the application in command handlers to update the domain, the CRUD repository will mostly be used just for efficient access to read models in projectors and query handlers and in other places that are not encumbered by the complex business rules handled by the domain model.
ICrudRepository
interfaces relies heavily on the use of IQueryable<T>
support of the .NET platform. This enables to perform arbitrary queries on the database without bloating the interface definition with a huge number of different query methods or a need for custom repositories for every specific, saving a lot of developer’s time, while still also providing type safety and the safety of compile-time checks to a certain degree.
ICrudRepository
is actually defined in a base type named IReadRepository
. This base type does not allow any modifications to the entities (i.e. it has no save or add/remove methods), which means it is very suitable in situations when we want to limit the operations an object can do with entities in the repository – for example in a query handler that should always only performs reads of the database. It also potentially makes testing those entities easier.
ICrudRepository
in order to facilitate the use of the features specific to its technology (for example, IEFCoreCrudRepository
making it possible to directly work with some of the EF Core ORM features).