Get the source code for this video for FREE → the-dotnet-weekly.ck.page/cqrs-v2 Want to master Clean Architecture? Go here: bit.ly/3PupkOJ Want to unlock Modular Monoliths? Go here: bit.ly/3SXlzSt
Thanks for the great content! I have a suggestion. Could you please make a video about deciding aggregate root. The way you think and the logic you apply in such a scenario. Simply how do you decide? I saw your previous video regarding this. But it would be great if you can explain the decision making part more than coding part in this case. Thanks Milan 😊
thanks for the video, and I think that mentioning db read and write(db recaplication) in this topic is redundant, because CQRS is not related to it, and your example also did not mention anything about db recaplication, in fact you have no cqrs between your application and db (most of time we don't need it because efcore support unit of work), you only have it between your api and application. CQRS is about using different models for read and write, not about db recaplication, even you have db recaplication in your project, you don't need CQRS becausse thoses read and write db are still using the same model (entity)
@@MilanJovanovicTech yes, I listened to it, but it still redundant, when you mention it first, people will probally misunderstand that what you said is the primary definition, but it is not, you are influential person, what you said will probally lead people to misunderstanding
How do I understand what should be a domain level service (FollowerService), and what should be an Application Layer Service or Use Case Command Handler? Both have business logic, both use Repositories etc...??? As far as I understood from your previous videos - the main difference between onion architecture and clean architecture is that onion architecture uses services, while clean architecture is about use cases. Anyway. Lets imaging I use onion architecture. I have FollowerService. Should FollowerService be Domain level or Application Layer Service? Or I should have 2 FollowerServices at both places? What kind of logic then should be inside each one?
@@MilanJovanovicTech Hmmm, probably my I don't even know how to ask a question correctly due to lack of experience. I should've probably asked - What kind of logic belongs to domain layer (so domain services) and what kind of logic should be placed to application service layer
"You want queries to be fast". The idea of cqrs is to separate reads from writes because reads are often overload database and don't mutating state of record. It is useless to implement cqrs in application that are not using read database replicas. If you mutate record all you do is propagating changes to read replicas and you can put load away from write db. Another thing is queries can go through business logic because some processes require validation through process. For e.g. if attendee does not have appointment in certain timeframe he cant get info about other attendee. Does this use case mutate data? No. But it must pass validation business rules. But even in this case you can use cqrs and it will be viable if only you have heavy read load and you have read db replica. So in the end cqrs is not needed with single database and query can pass domain layer.
@@MilanJovanovicTech Even Martin Fowler who heavily promotes it says that cqrs is "must be deep down in your toolbag" from goto talk from 2017. And it is like that. cqrs is bringing complexity, produces more garbage to collect, brings needs of separation between what query needs to pass domain layer and what is not, don't give you real benefit in small-medium size apps, because it depends on db and infrastructure. For e.g. cassandra has slower reads than writes. It is tool and it better to use it when its needed. So this is about "You want queries to be fast" and not implementation. Your implementation like many other is good as always 😁.
@milan is there anywhere I can see the full implementation of your result class. I think it's such a clean way of writing and resulting results. I'd like to do the same in both personal and professional projects.
Thanks for the video (the guy who asked about domain services…). So is it “ok”/valid to inject the domain service class directly in a handler? Why can’t you create an interface for the domain service (follower service)? Just curious about best practices in ddd using domain services.
Why is IUserRepository defined at the Application Services level? How do you make a choice where should be the Repository interface - inside domain level, like IFollowerRepository, or inside Application Level like IUserRepository?
Isn't the repository at domain level? (That's where I usually place it). I use repositories only for domain entities, so I place them in domain. I don't use them for ad-hoc queries or returning DTOs.
@@MilanJovanovicTech I can see that you define IUserRepository at the same file with StartFollowingCommandHandler. Do I miss something in the video? Isn't StartFollowingCommandHandler - application service layer?
I am just learning CQRS using your videos, and I have a few doubts. Could you please help me to solve, I have a request for calculating some operations in a database. It involves a few insertions and updates. After the operation, I get List of some data. In CQRS, how should I handle this scenario? Should I put this logic on the command side or the query side? and one more thing Can we use a common DTO in the CQRS pattern?
Is it an anti-pattern to call queries inside command handlers ? For example, you want to fetch some entity from the db to update it inside a command handler. It seems like we can avoid duplicating querying logic by using a query inside a command handler instead of injecting repository or raw sql. The query handler will already have an implementation where it calls repository or raw sql.
Thank you Milan for high quality content. I have two questions, need your help to understand Mediator and CQRS pattern. 1. About CQRS - It is good idea to use this pattern if you want to use 2 databases, one for write and another one for read operations. My questions are : 1. There is high chance of delay in data sync bwt write to read database, how to deal with it? 2. If I want to use single database for both read and write, Is it worth using this pattern? 3. If I want to fetch data based on multiple filters rather getbyId or getbyemail. Is this fine? and how to achieve it? 4. How to handle if I have to fetch data from multiple tables in one go..
1. a) Wait until the sync completes - b) Accept that you'll be eventually consistent and work around it 2. Yes 3. As you would with any complex query 4. Multiple split queries, or joins
I have a minor problem. I setup messaging layer (Command, CommandHandler, Query, QueryHandler) like you, but in what way can I register my handlers within web API? MediatR needs implements IRequest and IRequestHandler, but you didn't implement that
Thank you for the great content, Milan. Have you a git for your examples? Often, while watching the video, linked questions appear. And, imho, it is more useful to look at the code to understand where it is located, referenced, and implemented related things rather than search for them on the video. Thanks
The problem with this implementation is that you would have to manually maintain those sql query strings when the domain properties change, l think EF is still a great option for huge projects.
Hello, thanks for your video, always i have had this question, the business logic in clean architecture go in domain layer? or in application layer, i have seen others videos where the business logic is in the application layer and not in the domain. thanks.
You can do both! What I showed here is placing logic in application use cases. Here's a domain service example: ru-vid.com/video/%D0%B2%D0%B8%D0%B4%D0%B5%D0%BE-HVaGeqe9TPA.html
Nice video! I have two questions for you. In the video, you mentioned using Dapper for queries. Now, with EF8 SqlQuery, which one do you think is best to use: SqlQuery or Dapper? Another question is, how do you set up the 'Add => New From Template' option?
Hi Milan, appreciate your video and insights! Wondering if implementing CQRS is beneficial for optimizing response times in a rating system, especially when dealing with large amounts of data, to prevent incorrect reads or potential deadlocks? Thanks!
Great video! I have a question. Suppose I am using Dapper for the write side as well as the read side while implementing DDD and clean architecture, including the CQRS pattern. I can easily replace a DbContext implementation with my standard class library using Dapper that contains methods for saving and loading data from the database, then call those methods from the repository implementations in the infrastructure layer. It seems like nearly everything else (DDD, CQRS, repositories, etc.) all would remain just as you have it, but does UnitOfWork become extraneous in that scenario as an EF Core-specific item? Or would I still use the UOW even with Dapper on the write side?
@@MilanJovanovicTech Thanks so much for responding so quickly! Typically, I push transactions into stored procedures written in SQL that I can trigger through a custom 'SaveData' method using Dapper (with generic arguments for the stored procedure and parameters). After thinking very carefully about your setup, I think I'm not going to need UoW with Dapper, given my approach of pushing transactions to the database level and requiring the database either to accept or reject all changes in a single transaction. I just put a method in my repository, say 'UpdateLineItem', which uses the SaveData method using Dapper calling, say, 'UpdateLineItem.sql' and whatever parameters, and then performs all transactions internally inside of the database. The only scenario I can foresee possibly needing a UoW pattern given my setup would be if, for some reason, I ever need to write a transaction that affects multiple databases where I must roll back everything if anything fails. Am I missing another reason to use the UoW pattern if I handle transactions entirely at the SQL level? Thanks again for your help!!
I tried using the SQL server transactional replication technique to replicate from my write database to read database, but I found a critical problem, the replicate is not realtime, it delay about 2 seconds. Imagine user submit/update a form and back to grid listing but the new data is not appears. Just wonder what technology that you use for the projection ?
@@MilanJovanovicTech I found many articles and videos about the theory of Eventual consistency, but didn't find any articles on how to implement it. It will be good if you can show me/us how to implement Eventual consistency for the CQRS pattern.
Hi again! Another question: If u call on another entity in the domain service; does that become an application service? Or can you still call another domain in another domain service?
Great video as always. What benefit do repository gives us? Just the ability to switch to different ORM without changing logic inside of our handlers? Is it worth it extra time and complexity? I dont imagine for now to implement repositories inside of my full time job project. I just staight code ef core on dbcontext inside of handler, which I guess saves me a lot of time and effort. Is there any extra benefit of using repository? Also, Im really surprised by holding all the business logic inside of Domain project. Is there something wrong with doing everything inside of handler? I also sometimes do some "ApplicationLayerService" class just to share same logic between two handlers. I need to learn more of domain Services from Your videos, because I think that might be more elegant way of code than my current way of writing it. Thanks Milan!
- Encapsulation (of queries) - Code reuse (no duplication) - Cross-cutting concerns (transactions, caching, logging) - Most importantly (for me): TESTABILITY I only use repositories on write (command side) because I want to test this. If you see value in this, then great.
@@MilanJovanovicTech I find myself asking the same questions as @arteqppp6223. The principles you enumerated should be a priority for every developer. 1. With the shift to minimal apis, CQRS, we are now more focused on the features, rather than technical layers. I like it more and it makes more sense. Don't you think we could extend this to repositories too? Why not have commands and queries at the repository level? 2. It's not very clear for me when we should introduce a domain service. Should it only when we have a shared logic between handlers? Also, it's very uncommon to see a call to the repository in a domain model. Do you have some references to better explain the domain services ? Thanks!
Thank you for sharing your knowledge. After watching this video I have 2 questions: 1)In my project generally we follow this: Create generic repo, if needed extend repo for specific class. And then use those repo withing Services layer and call them on controller. But here I see you used commands and queries which are relying on Services. Instead can't we have simply 2 set of services for read and write? (My question might not be the best but I am just trying to understand what is with to add another layer of calls) 2)Let say once I get clarity on my 1st question then is it good practice to call repository and services both on handler or is better only use services on command and no direct access to repository? TIA @MillanJovanovicTech
1) Commands/Queries are what you do in the Services, pretty much. Your service method becomes a Command/Query class. 2) Yes, it's fine to use repositories/services from handlers
Could u give me an example for using HttpContext in Handler? Recently, I research for this problem but I can not find out the expected result. Some of them I think I will pass it from Controller or DI HttpContextAccesstor into Handler, it's right for this design patern?
I personally like to separate the external implementations from the use cases. So, rather than getting or using the context in the handler, add the items you need from the HTTP context into the command. Since the API/Presentation layer creates the command, it has access to the context. Although, yes it is possible to inject ContextAccessor into your handler.
You would end up using IHttpContextAccessor. A better approach would be to abstract this behind a service that will use the HttpContext. That implementation can be in Infra.
It can. It's about where you want the logic to be - domain or application layers. Which further impacts testability and how you want to test the logic.
Because in this pattern, you're trying to segregate domain and data logic. This is opinionated, and as such, isn't strictly required. But, if you wanted to change the database implementation, directly applying dbcontext into a handler would mean that its tightly coupled with the database implementation which isn't always ideal.