Building Microservices Through Event-Driven Architecture, Part 4: Repositories
A developer and architect gives a tutorial on how to apply the principles of event-driven design to building out a microservices architecture.
Join the DZone community and get the full member experience.Join For Free
you may also like: building microservices with event-driven architecture, part 1: application-specific business rules
during this journey, i will implement the command side of repositories. repositories belong to interface adapters of uncle bob clean architecture.
in this step, i will start implementing the command side of the infrastructure, i will focus on how to persist data.
i will use entityframeworkcore and sql server.
logcorner.edusync.speech.application.usecases use an ispeechrepository as a dependency, i think that the most obvious way is to start by implementing ispeechrepository, and to continue by implementing its dependencies, etc. since i know where i am going, i will proceed as follows:
- unitofwork: i will use the unitofwork pattern, it will help me to treat aggregateroot as a unit for data changes.
- repository: i will use a repository pattern, aggregateroots are the only objects my code loads from the repository.
let us create a generic repository irepository and apply aggregateroot constraints.
my irepository will look like this :
t is an aggregateroot and identifier is the type of aggregateroot identifier: int, guid, etc.
ispeechrepository implements irepository<speech, guid> where speech is an aggregateroot and guid is the type of speech.id.
it is not possible to create a repository for a non-aggregateroot entity: mediafile for example.
iunitofwork.commit persist (save or update) the entire aggregate (aggregateroot and related entities).
let's start by testing iunitofwork, it will result in the implementation of unitofwork. the latter will need a class that inherits from dbcontext. ( databasecontext in my case).
when saving iunitofwork.commit should save aggregate root and dbcontext.savechanges called only once
implementation of unitofwork.
let us create a databasecontext class that inherits from dbcontext.
the final implementation of unitofwork first test.
when disposing of unitofwork. dispose of should be called only once.
let us implement unitofwork.dispose().
at this stage, the solution compiles, all the tests pass and the code coverage of logcorner.edusync.speech.infrastructure is 100%.
verify that createasync can be called on repository and should trigger dbset.addasync.
the repository can only be instantiated with an aggregateroot, so let us create a class that inherits from aggregateroot<guid> for testing purposes.
the final implementation of the repository will look like this.
verify that createasync can be called on speechrepository and fire repository.createasync only once.
the goal of this test is to implement speechrepository, so i verify that when speechrepository.createasync is called then repository.createasync is called only once.
here is the final implementation of the speechrepository.
the implementation of this section differs according to the orm used (ef, nhibernate, or others). for example, we can create classes specific to the repository (speechdao) and apply a mapping between speechdao and speech.
speechdao can be seen as a duplicate class (properties ) of the speech class of the domain.
knowing that ef allows me to do more simple, without creating repository-specific classes and then apply to map between duplicate classes, by providing an ientitytypeconfiguration interface.
i can use it to point domain objects to database tables without applying additional mapping between speechdao and speech like this:
we can note here, how valueobjects are managed.
the last thing you need to know is that efcore needs a parameterless constructor because it uses reflection to do its thing.
if you do not want to update domain classes and introduces private parameterless contractors, you should create repository-specific classes and then apply them to the map between duplicate classes. this repository-specific classes should have parameterless contractors.
i design the sql server database using ssdt, it will help on my devops pipeline
configure logcorner.edusync.speech.presentation to target the sql database.
finally, finish the configuration of the dependency injection.
the entire application can now be tested using postman ( use the registerspeech or develop branch ).
the source code is available here: registerspeechrepository
Published at DZone with permission of Gora LEYE, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.