Building microservices through Event Driven Architecture part4: repositories

This tutorial is the  4th part of a series : Building microservices through Event Driven Architecture

During this journey, I will implement the command side of  Repositories. Repositories belong to Interface Adapters of Uncle Bob Clean Architecture

  • LogCorner.EduSync.Speech.Infrastructure

In this step, I will start implementing  the command side of the Infrastructure, I will focus on how to persist data.

And I will use EntityFrameworkCore and SQL Server.

Because LogCorner.EduSync.Speech.Application.UseCases  use a ISpeechRepository as dependency, I think that the most obvious way is to start by implementing ISpeechRepository , and to continue by implementing its dependencies, etc… But since I know where I am going, I will proceed as follows:

  • UnitOfWork : I will use UnitOfWork pattern, it will help me to treat AggregateRoot as a unit for the purpose of data changes.
  • Repository : I will use repository pattern, AggregateRoots are the only objects my code loads from the repository

Let us create a Generic Repository IRepository and apply an AggregateRoot contraints.

My IRepository  will look like this :

Repository

T is an AggregateRoot and TIdentifier 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 an non AggregateRoot  Entity : MediaFile for example

MediaFile

IUnitOfWork.Commit persist (save or update)  the entire Aggregate (AggregateRoot  and related Entities)

UnitOfWork

UNITOFWORK

let us 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)

TEST 1  : When saving IUnitOfWork.Commit Should Save Aggregate Root and DbContext.SaveChanges called only once

UnitOfWorkSpecs

Implementation of UnitOfWork

UnitOfWork

Let us create a DataBaseContext class that inherits from DbContext

DataBaseContext

The final implementation of UnitOfWork first test

UnitOfWorkSpecs

Implement UnitOfWork.Dispose

TEST 2 : When disposing unitOfWork.Dispose should be called only once

Dispose

Let us implement UnitOfWork.Dispose()

Dispose

At this stage, the solution compiles, all the tests pass and the code coverage of LogCorner.EduSync.Speech.Infrastructure is 100%

coverage

REPOSITORY

TEST 3 : Verify that CreateAsync can be called on Repository and should trigger dbset.AddAsync

Repository can only be instanciated with an AggregateRoot, so let us create an class that inherits from AggregateRoot<Guid> for testing purpose.

EntityAsAR

The final implementation of Repository will look like this

Repository

SPEECHREPOSITORY

TEST 4 : 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

Verify_that_CreateAsync_can_be_called_on_SpeechRepository_and_fire_RepositoryCreateAsync_only_once

Here is the final implementation of SpeechRepository

SpeechRepository

MAPPING

The implementation of this section differ 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.

But knowing that EF allows me to do more simple, without creating repository specific classes and then apply mapping 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 :

SpeechEntityTypeConfiguration

MediaFileEntityTypeConfiguration

we can note here, how ValueObjects are managed

OwnsOne

The last thing you need to know is that EFCore needs a parameterless constructor because it uses reflection to do its thing.

SpeechParameteless

MediaFileParameteless

If you do not want to update domain classes and introdues private parameterless contructors, you should  create repository specific classes and then apply mapping between duplicate classes.  And this repository specific classes should have parameterless contructors.

DATABASE 

I design the sql server database using SSDT, it will help on my devops pipeline

sqlserver

Import db

 

Import db 2

 

CONFIGURE

Configure LogCorner.EduSync.Speech.Presentation to target the sql database

AppSettings

And finally, finish the configuration of the dependency injection

Startup

coverage

API TESTING

The entire application can now be tested using postman  (use the RegisterSpeech or develop branch)

 

Postman

Code source is available here : RegisterSpeechRepository

Best regards

3,293 total views, 19 views today

Gora LEYE

I'm a microsoft most valuable professional (MVP) .NET Architect and Technical Expert skills located in Paris (FRANCE). The purpose of this blog is mainly to post general .NET tips and tricks, www.masterconduite.com Gora LEYE