In my previous articles when I was talking about Clean architecture and Domain Driven Design I mentioned one piece of domain layer – repository or more precisely repository pattern. The repository pattern is used to persist and retrieve domain models. Although repositories are mostly related to Domain Driven Design the other architectures might have the objects with the same functionality but are called different. In Fitradar application (front end and back end) the objects that are used to persist data in the database and fetch data from the database and map data to in-memory objects (aka POCO – Plain Old C# Object, POJO – Plain Old Java Object) and are not part of the Domain layer are called DAO (Data Access Objects). DAO usually are used in cases when no business logic is involved and the application needs to execute simple CRUD operation.
In Android application to work with database we use Room Persistence library but in our back-end solution we use Entity Framework Core. These two are know as Object-relational mappers or ORM. And today I wanted to explore the relationship between Domain Repositories, Data Access Objects and ORM and share some experience we had in our team working with these patterns and libraries.
If you look at the responsibilities of Repository, DAO and ORM they are very close to each other. Some years ago when ORM technology was in its inception the DAO and Repositories usually were working directly with the low level database access services. In case of .NET it was ADO.NET library and in case of Android it was SQLite library. And it was quite clear that DAO or Repository should use these libraries to persist or retrieve in-memory objects and map the data. But now-days when in application development main data access technology became ORM the border between ORM and DAO and Repository has become very blur, especially when one just switched to ORM. Working with ORM in different projects and languages our team came to conclusion that in same cases ORM can fully replace the DAO or Repository and can be used instead of it. Let’s look closer at the cases when it is appropriate to use just a ORM library and when the DAO or Repository should be used in combination with ORM:
- If you need to save, update or delete single flat plain old object then in most cases ORM library will do the job for you. Of course EF Core and Room are capable of doing more, but then we really should investigate each case separately
- If you need to fetch the data from single table by primary key then again in most cases you can fully relay on ORM
- In case Domain layer aggregate has complex entity cluster hierarchy, where different entities might have different persistence state you most likely will need to write such aggregate persistence logic by yourself either using ORM or low level database access library. In our application one such aggregate is Sport Event that has Place and Organizer and some other entities. And the problem we faced when tried to save Sport Event by using built in EF Core capabilities was the different Entity State and the calculated state before Save operation. For example we had cases when we needed to create a Sport Event in Place that was not yet saved in database, and since both entities have the same Entity State EF Core tackled that case well and was able to create both entity records in database. But the problem started to appear when we wanted to create Sport Event in the Place that already had other Sport Events, now before saving aggregate Sport Event we had to fetch Place entity to make sure EF Core sets the correct Entity State. And the more entities your aggregate root has the more fetch operations might be needed. So in this case for us seemed obvious putting Entity State synchronization logic in separate Repository.
- In case data query logic and following mapping logic is so complex that to make a code readable it is necessary to split logic in separate functions, you most likely will move those functions to separate class, Data Access Object, to persist the Single Responsibility principle.
As you can see the Repository and DAO still has their place in the modern software architecture. In case of queries in CQSR architecture query logic might be put in Application layer since anyway contrary to Commands, Queries only responsibility is data fetching, and that duplicates DAO responsibility. By choosing to put query logic in Application layer we make a direct dependency on EF Core. That is not a problem in classical three layer application, but it does not fit the Clean Architecture principle where Application layer should be aware only of Domain layer and with outer layers (EF Core belongs to the Infrastructure layer) communicates only through interfaces. In this case we should use DAO.
Please visit our website and join the mailing list. Our app is coming soon: