ardalis / CleanArchitecture

Clean Architecture Solution Template: A starting point for Clean Architecture with ASP.NET Core
MIT License
16.34k stars 2.82k forks source link

Clean architecture + cqrs & mediatr pattern #138

Closed melikpehlivanov closed 4 years ago

melikpehlivanov commented 4 years ago

Hey. I'm wondering whether service and repository layer are necessary when creating applications using clean architecture + CQRS and mediatR patterns. @ardalis

Thanks in advance.

ruMoonGuard commented 4 years ago

Hi, recently I also asked this question. The first thing you need to do is keep your teams testable. If you can mock your data access for test(efkor allows it), then you probably don't need the repository layer.I use linq2db, there is no way to lock the context. This is why I use repositories for CUD operations. There remains a very good question about reading, because a read operation is most often a complex selection that is unique to a particular query, and therefore repositories make little sense for it, and read operations usually do not contain business logic. Given all this, read-only repositories are not necessary, but then the question is, but then there is the question of how to solve the context dependency in the core layer.Read requests may need to be moved to another layer, which may have links to the infrastructure layer. Sorry for my bad English.

DaveShopCtrl commented 4 years ago

If you can mock your data access for test(efkor allows it), then you probably don't need the repository layer.

CleanArchitecture comes with a (non-generic) IRepository interface that hide the DB implemention from your code. Queries are done using specifications, but the IRepository interface also provides Add, Update and Delete methods. These are generic versions (ie call them using repository.UpdateAsync(product)).

I have no knowledge about linq2sql (except that it was a 'precursor' to its bigger brother Entity Framework). But I was able to implement the LLBLGen Pro (self servicing (aka ActiveRecord pattern - entities communicate with DB) ).

I have a repository per domain and each support a subset of all entities. where I use a pattern matching if else structure (if T is ProductEntity product {} else T is ProductLineEntity productLine {}.

When testing you mock IRepository with Setup() calls for retrieval queries and Verify calls to check if the correct Add, Update or Delete methods are called. I use Strict mock behavior, so if an method or property is called that is configured, I will throw an exception.

Mediatr is just a framework to use the CQRS pattern. for query requests, you can use IRepository.ListAsync() with the correct specification to answer the request. Ccommand requests should be processed by your domain services (which contains validation and processing logic). The domain service will in turn use IRepository to query items, make modifications, save changes to the database and in most cases return a Result object..

In short: In most cases you still want to use domain services and repository to handle CQRS requests. For example, it is possible that you have similar (overloaded) CQRS events and you want processing in one location. domain services (or actually the entities) also guard against data corruption.

Technically you could replace the domain services with pure CQRS requests, but then only CQRS handlers should be allowed to use the repository layer. If two code locations need to access the same data, you got yourself a code smell (duplicate logic / queries).

Hope this makes sense..