I hoped you would discuss the pros and cons putting the interfaces into the domain vs application layer. Maybe in a separate video? Thanks for the content. I always learn something new from it ❤
Nothing changes significantly if you place them in the Application layer, from a technical standpoint. From a Domain standpoint, I feel like placing them there expresses better the intent of your Domain and what you are allowing the Application layer to do with it i.e. how to orchestrate it.
It also allows sharing the interfaces with other projects. Say you want to share your domain/intefaces with other projects, without sharing the implementation (only the contracts). Then you can put your interfaces in domain, create a package/nugget with that, and let the user choose the implementation details
I don't think it matters if the domain is isolated to the single application. But if the domain is shared across multiple applications I think defining the repositories at the application layer is a better choice. Since each application may need to persist the domain in a different way.
IMHO Repository Interface goes into application layer. Why? Domain is knowledge and data (Model and Domain Services). How that data gets there is completely irrelevant to the business. If you define repository interface in the Domain you make Domain dependant and expecting something from the outer layer. Outer layer depends on the inner layer and never vice versa.
Maybe methods in the repository should return Result? Then at the application leyer you can use the functional approach (described by you earlier) and combine calls to methods from different layers that return Result.
Hey Milan, nice video as always. I have two questions related to this. 1) Do you sometimes return a IQueryable from your repositories, or you always prefer returning concrete entities (or a list of them)? 2) How do you avoid method explosions in the repositories, as different Includes or Where clauses are often needed?
Considering that he is talking about a domain-centric architecture, then repositories should only return Aggregates and should return them with all their state loaded. So, answering your questions, you should never return IQueryable from your repositories, and you would only need a few methods to load an Aggregate, even maybe just one to find by the Aggregate id. But again, this is only considering he's talking about domain-centric architecture and using DDD, and you should also consider your specific business case and performance issues by loading some Aggregates whole state.
@@AuraMajonezu I'm not a fan of Spec pattern. Perhaps it's the lack of experiance.. @Miroslav -> no , you never expose Iqueryable. @ruekkart -> well, loading whole order to delete one line seems like an overkill that Milan was explaining recently.
1) Never! Repositories (in the Domain) only return aggregates (and sometimes entities) 2) It won't happen typically, as you only ever need a few methods to implement most of the business logic. In case it does get out of hand, you can always resort to the Specification pattern.
I know that DDD advocates having the repository interfaces defined in the domain layer but as a general rule interfaces should be defined in the layer where they are consumed, i. e. in this case the application layer. But what frustrates me a bit about all these best practices and patterns is that they sometimes seem a bit rigid. I guess pragmatism is a good thing when applying them
This is the Separated Interfaces Pattern and Unit of Work pattern in action. I have the same implementation as you. Repository Interfaces go in Domain Layer, UoW interfaces goes in Application Layer and the implementations go in the infrastructure layer.
What are your thoughts on Ardalis' implementation of Clean Architecture, Specifications, and the Repository pattern? Do you think its better to write your own or use one that works out of the box?
+1 I'm interested in his thoughts on this as well. Ardalis's package offers a generic, abstract repository, which I know is generally frowned upon. However, he combines it with the specification pattern so, in theory, the combination would avoid violating the open-closed principle because you wouldn't have to create a God-object repository that has to be altered every time a new requirement comes along.
Definitely no need to reinvent the wheel with the Specification pattern, and you can use his library. I think it's pretty good. I can't recall the Specification class itself exposes some hard dependencies on EF.
13:03 - I know that it works, but I cannot understand that one, You register IApplicationDbContext and IUnitOfWork as scoped. If we will assume that scoped is treated as one request , we are creating two instances of ApplicationDbContext Then we add some entities in repositories to one context and saveChanges on second context, which should not works... How it works here? where is only one instance of dbContext?
Thanks Milan. I'm a bit confused; last time you showed us the EF Core implementation instead of the repository pattern. Which approach do you recommend, the Repository Pattern or EF Core?
My personal preference is: - Commands (business logic) - Specific repository, like here - Queries - EF directly, SQL, services, whatever works (just keep it simple) For super-simple applications - use EF everywhere.
@@MilanJovanovicTech I also follow this same pattern. People like Alexey Zimarev also recommend to follow it for the query side. Then when putting this abstraction layer for the command side it allows to express the intent way much better as you just said (domain oriented), and it makes unit tests way more easier with test doubles instead of relying on any ORM specific feature (like InMemory() with EF core). For the read side, where you don't want any kind of logic, but just fetching data/formatting, the abstraction layer makes less sense, you won't use unit test here (so no need to mock any dependencies), but you'll prefer integration tests against a real database (see TestContainers or Ductus.FluentDocker)
Hello Milan, thanks for your awesome videos!! I have a question. I have a library that extends entity framework core. In this library there are all the entities and the repositories of the database, a test app project and unit test project. Could I use this library in clean architecture if yes, in which Iayer I could put it?
@@MilanJovanovicTech Do you think is better to define the interfaces and the entities in the domain layer and the implementation of them in the infastracture layer or to have it together in a seperate library which is referenced in the infastructure layer as I did? Thanks :)
for example if we create a method in the repo GetPaginatedProducts in which we have to return paginated data with sorting sent from the client for example (nameAsc, nameDesc). Do we have to do that logic in the implementation of the repo? i mean switch between the sort argument if we have to sort by name, price, etc. Or is it a bussines logic and we have to encapsulate it and send it to the repo method?
Great video! Quick question, why we introduce an abstraction IUnitOfWork for the SaveChanges and just do that SaveChanges on the method in the repository? After all you have the ApplicationDbContext inside the repository.
Hello Milan! In order to ensure that only the repository's methods can be called wouldn't you have to move the IApplicationDbContext somewhere else? What I mean is that any application layer class could just inject the IApplicationDbContext and query in any way and perform any operations on the entity set.
I usually put my repository interfaces in the application layer because I only add the dependency on the C# projects in the layer n to the layer n-1. For example Infra -> application -> domain. Infra knows about the application, but doesn't know about the domain. Application knows about the domain, but doesn't know about the infra. And the domain doesn't know about any other layer. It feels wrong (out of place) to put them in the application layer, as there belongs to the domain layer, but I didn't want to add the infra -> domain dependency. As a work around, we can use Interface inheritance, where the real interface is in the domain layer, the application layer has interfaces that inherits from those in the domain layer and they should be visible in the infra layer, but was really defined in the domain layer. Not an elegant solution, but keeps the layers isolated. What do you think about this approach?
I don't see any problem with Infrastructure referencing Domain. Moreover, if Application is referencing Domain, and Infrastructure is referencing Application, then you have a transitive reference from Infrastructure to Domain. 😁
Exposing what are the allowed operations on your Domain. The Aplication layer has to use only that conntract. In essence, moving more of the logic into Domain, which is always a good thing.
Hey Milan, doesn't the reference to the IUnitOfWork interface from the domain layer break clean architecture, since it is referencing the application layer from the domain layer?
Hey Milian, I am still a bit consused by the repository, looking at many examples, repositoy interface is in the domain layer, but it is implemented in the presistence layer, my question is, doesnt this expose the Entity data.
@@MilanJovanovicTech Considering that the repository is implemented in the persistence layer and interfaces are defined in the domain layer, it follows that the implementation accepts arguments of types defined in the interfaces. For instance, when saving a Schedule, the interface method is defined to take a Schedule entity as an argument, possibly returning something. Similarly, when retrieving a schedule, the interface expects data of Schedule type. This implies that we need to import the entity inside the repository implementation.
Nice video as usually! Can you, please, enable the Tools > Options -> Projects and Solutions -> Track Active Item option? In this case the file you're working on will be highlighted at the Solution explorer and it will be much easier to follow your project structure at your videos.
Great content Milan! One question, how would you hide the Active record and specifically EF core functionalities such as AsNoTracking(), AsSplitQuery() behind an abstraction that we introduce?
@@MilanJovanovicTech Fair, however let's say you have a repository function that retrieves aggregate FooBar by ID. You invoke this function in multiple command/query handlers. Of course, in command you may want this aggregate to be tracked, but in queries you just want to return data and run the query AsNoTracking. I am currently exposing asNoTracking bool in the repository interface but I find it very ugly as it's tightly coupled to EF core.
@@MilanJovanovicTech but if we use specification pattern with expressions we are depending on ef core, because sql query cant apply expressions. And using specifications with strings for example we wont have compiling errors
Thanks Milan for your Videos, they are much appreciated! I also wonder why the repo interfaces are in the domain layer, when the IUnitOfWork is not. It means that the persitence layer has a dependency on the application layer. Is that intended? Also I would really like to see how you would do an update. If the object beeing updated can only update a few propertys, how is it best practice in clean architecture to receive some parameters through web api and persist these to the database? Kind regards
For updates, just apply the changes (covering that in the next video though) and persist it. Let EF Core take care of the rest. For repo in Domain: - I consider it part of my Domain - I only ever return aggregates (no DTOs)
You may need to access to database from somewhere that is not dependent on application layer, in this case placing repository interfaces in the domain layer will allow you to use it from almost anywhere with DI.
Precisely because you only use them in the command handlers (which is app layer) and to avoid (mis)using them from domain methods, it makes more sense to place them in the application layer. They return aggregates that are the entry point to your domain methods.
i need ur opinion about make uow create repositories inside i always take this approach and i feel more comfortable in that first i don't need in handler inject every repository i just inject uow and call whatever repo i need second i just add to startup service uow and i don't need to interduce every repo and i repo might i violate some solid principles but i feel it worth what's ur opinion about this approach ?!
With multiple repositories you're being explicit about your dependencies (and what you need to mock for testing). With UoW + Repo inside approach it's all a bit implicit. Right?
Great content. You mentioned that there are good sides and bad sides to this approach. Only pros were here. Do you have a plan to discuss the cons in the future?
Hi Milan, I've been using repository pattern for a long time and now I'd like to switch to EF Core repository.. but how to test my handlers (for example) if I can't mock EF Core repository? A video regarding this approach would be nice! Thanks for you content.
Yup, integration testing EF dependent code works well. There are too many moving parts with mocking and/or in-memory db. Postgres containers start and run tests in seconds.
This is regarding Domain reference to Persistance. With respect to my knowledge, only application should have reference right. This is what Onion architecture. Please explain your view on this.
Thanks Milan for the very informative video. For the remove order line item method, should it be a good idea to add a method removeOrderLineItem in the Order AggregateRoot? I thought any state changes has to be managed within the Aggregate Root. Thanks a lot again 😀
Wouldn't it be more convenient to have your repositories as properties within the UnitOfWork? This way, you can access them by simply injecting the UnitOfWork.
That might be easier to accomplish, but has some drawbacks: First and foremost it defies the Explicit Dependencies Principle, but also looks similar to a Service Locator, which is mostly seen as an anti-pattern.
@@krccmsitp2884 You might be right, but in the end, those principles act as guidance, and sometimes they bring nothing but complexity, like the one we're discussing. Repositories should be part of the UnitOfWork instead of being scattered throughout the application. They only require an instance of the DbContext, which is injected in the constructor of the UnitOfWork. To me, that seems more pragmatic.
Again it depends on the approach you take. I personally don't buy the argument of implicit/explicit dependencies of the application services / command handles simply because in many cases I DO NOT TEST handlers! Yes! I use them for loading objects into memory and to invoke methods on domain objects or domain services. With this approach you don't have to mock anything for unit tests, you simply use your objects in test cases. But hey you should do whatever works for you 😉
In my humble opinion, repository over ef is unnecessary redundancy. But with dapper it's quite ok. As always be pragmatic, don't dogmatic 😉 Anyway, thanks for the content 👍
@@MilanJovanovicTech I don't think you should have domain logic in your repository since you implement it in your persistence layer. Your persistence layer isn't Core (clean architecture). Interfaces are not behavior either.
Repositories are nice if you avoid lazy loading and want to encapsulate query that builds your agregate (whole graph of objects) Ideally you want your agregates to be as small as possible to protect the business rules. It depends on the complexity of the system and approach you take rather than the case of using ORM or not. For simple projects with anemic entities and minimal logic, repositories, DDD, CQRS and other sexy words in most cases is just an overengineering. Saying that in the same time there are projects where you should use those paterns to reduce complexity of already complex by nature domains.
Hot take I guess, repositories are application layer concerns just as third party api clients. Placing repositories in Domain layer implicitly opens up the "pure" Domain types to start referencing repository interfaces , which according to some authors is an anti-pattern Besides, I am a totally EF for full application kind of guy. All repository pattern ends up leaking implementation details of underlying ORM tech, eg. implicit Entity Tracking in Entity Framework.
In this implementation - you make too much coupling on EF. Because your IUnitOfWork isn't provider of repositories and you can call SaveAsync, because you know - implementation can make this. But what if you use not EF? How will it work with Dapper or NHibernate or Redis or something else?
@@efimov90 That's a lot of what ifs that may never actually happen. You never want to have multiple unit of works, because that implies a distributed transaction.
@@MilanJovanovicTech actually, i work on a project, that have more than 1 unit of work at same time, much more. It's enterprice desktop application for inner usage with direct access to database.
It’s a serious bad idea breaking the integrity of the Aggregate by fetching just a part of it. This violate the sense of having DDD in place. Aggregates MUST BE manipulated only through the AggregateRoot.
@@MilanJovanovicTech That's not a matter of risk but integrity of your system. AggregateRoots are the place to manage the invariants of the aggregate. By putting some "logic" within the repository (when you say "low risk") you're violating the ragion d'étre of the AggregateRoot, therefore your solution is not DDD compliant. Suppose your requirements evolve in a direction where you have to validate a delete operation based on the other items… you'll be in very big troubles
I think you should add to each folder a README that explains in a few sentences the organizational purpose of that folder. Making a folder is making an opinion and you should share it.
@@MilanJovanovicTech Your material is great. I'm a fan, I'm a Patreon subscriber, and I've been programming since way before you were born. There's a wide gap between no documentation (what you have) and verbose. Adding a readme file to explain your reasoning is not crossing over to "verbose". I began my career in the nuclear industry. We measured our documentation in feet-width of binders. That was verbose.
@@MilanJovanovicTech Why not? Just because such a test wouldn't test the entire application stack? Wouldn't you agree to different testing levels? And if we want to focus on "acceptance level testing" (pure functionality) wouldn't we try to be independent from complexity of the infrastructure? What about the UI? Would u include this in your acceptance tests?
This approach has an entanglement problem. Wheb dealing with the database you should always preference an approach that results in you only dealing with a single entity type at this level and stack more complex business logic layers on top of this.
@@MilanJovanovicTech think of it like ICrud then you're injecting multiple implementations of that with different T's in to this "handler". You get cleaner code if you layer your higher orders of logic in my experience.
Want to master Clean Architecture? Go here: bit.ly/3PupkOJ
Want to unlock Modular Monoliths? Go here: bit.ly/3SXlzSt
I hoped you would discuss the pros and cons putting the interfaces into the domain vs application layer. Maybe in a separate video? Thanks for the content. I always learn something new from it ❤
Nothing changes significantly if you place them in the Application layer, from a technical standpoint.
From a Domain standpoint, I feel like placing them there expresses better the intent of your Domain and what you are allowing the Application layer to do with it i.e. how to orchestrate it.
It enables injecting the repositories into domain objects. This is can be good and bad
It also allows sharing the interfaces with other projects. Say you want to share your domain/intefaces with other projects, without sharing the implementation (only the contracts). Then you can put your interfaces in domain, create a package/nugget with that, and let the user choose the implementation details
I don't think it matters if the domain is isolated to the single application. But if the domain is shared across multiple applications I think defining the repositories at the application layer is a better choice. Since each application may need to persist the domain in a different way.
IMHO Repository Interface goes into application layer. Why? Domain is knowledge and data (Model and Domain Services). How that data gets there is completely irrelevant to the business. If you define repository interface in the Domain you make Domain dependant and expecting something from the outer layer. Outer layer depends on the inner layer and never vice versa.
I think some graphics with layers and what you are doing, placed in the start of each section, could really help to understand what is going on :)
Hmm, didn't think about that, but it's not too difficult to add 🤔
Maybe methods in the repository should return Result? Then at the application leyer you can use the functional approach (described by you earlier) and combine calls to methods from different layers that return Result.
It's an option, I've done something similar once
Hey Milan, nice video as always. I have two questions related to this.
1) Do you sometimes return a IQueryable from your repositories, or you always prefer returning concrete entities (or a list of them)?
2) How do you avoid method explosions in the repositories, as different Includes or Where clauses are often needed?
Considering that he is talking about a domain-centric architecture, then repositories should only return Aggregates and should return them with all their state loaded.
So, answering your questions, you should never return IQueryable from your repositories, and you would only need a few methods to load an Aggregate, even maybe just one to find by the Aggregate id.
But again, this is only considering he's talking about domain-centric architecture and using DDD, and you should also consider your specific business case and performance issues by loading some Aggregates whole state.
You could use Lazy loading
For the part about explosion of different methods in repositories - there is a specification pattern that can solve this problem
@@AuraMajonezu I'm not a fan of Spec pattern. Perhaps it's the lack of experiance.. @Miroslav -> no , you never expose Iqueryable. @ruekkart -> well, loading whole order to delete one line seems like an overkill that Milan was explaining recently.
1) Never! Repositories (in the Domain) only return aggregates (and sometimes entities)
2) It won't happen typically, as you only ever need a few methods to implement most of the business logic.
In case it does get out of hand, you can always resort to the Specification pattern.
I know that DDD advocates having the repository interfaces defined in the domain layer but as a general rule interfaces should be defined in the layer where they are consumed, i. e. in this case the application layer. But what frustrates me a bit about all these best practices and patterns is that they sometimes seem a bit rigid. I guess pragmatism is a good thing when applying them
I like discussing options, and letting people do what feels right for them
Great content as always and in my opinion this is my preferred approach. Looking forward to the follow up on the query side.
Also thinking about a UoW pipeline behavior
This is the Separated Interfaces Pattern and Unit of Work pattern in action. I have the same implementation as you. Repository Interfaces go in Domain Layer, UoW interfaces goes in Application Layer and the implementations go in the infrastructure layer.
Do Repos only return aggregates (or entities)?
@Milan Jovanović depends on the repo I guess and the query / command. What say you?
This one is sooo great! Thanks Milan!
Thanks a lot, Guillaume 😁
What are your thoughts on Ardalis' implementation of Clean Architecture, Specifications, and the Repository pattern?
Do you think its better to write your own or use one that works out of the box?
+1 I'm interested in his thoughts on this as well. Ardalis's package offers a generic, abstract repository, which I know is generally frowned upon. However, he combines it with the specification pattern so, in theory, the combination would avoid violating the open-closed principle because you wouldn't have to create a God-object repository that has to be altered every time a new requirement comes along.
Definitely no need to reinvent the wheel with the Specification pattern, and you can use his library. I think it's pretty good.
I can't recall the Specification class itself exposes some hard dependencies on EF.
13:03 - I know that it works, but I cannot understand that one, You register IApplicationDbContext and IUnitOfWork as scoped. If we will assume that scoped is treated as one request , we are creating two instances of ApplicationDbContext
Then we add some entities in repositories to one context and saveChanges on second context, which should not works...
How it works here? where is only one instance of dbContext?
No - scoped means that when you resolve IApplicationDbContext and IUnitOfWork you will get the same object instance back (for that scope)
Yes, I checked it and that's make sense, @@MilanJovanovicTech , anyway thank's a lot for response :) great material as always :)
Do you have an end-to-end tutorial in C# building this application?
No, but I'm working on an end-to-end course that will cover a lot of these concepts (and more)
Thanks Milan.
I'm a bit confused; last time you showed us the EF Core implementation instead of the repository pattern.
Which approach do you recommend, the Repository Pattern or EF Core?
Ff. Im confused as well.. what use cases do you use context directly or repositories?
My personal preference is:
- Commands (business logic) - Specific repository, like here
- Queries - EF directly, SQL, services, whatever works (just keep it simple)
For super-simple applications - use EF everywhere.
@@MilanJovanovicTech I also follow this same pattern. People like Alexey Zimarev also recommend to follow it for the query side.
Then when putting this abstraction layer for the command side it allows to express the intent way much better as you just said (domain oriented), and it makes unit tests way more easier with test doubles instead of relying on any ORM specific feature (like InMemory() with EF core).
For the read side, where you don't want any kind of logic, but just fetching data/formatting, the abstraction layer makes less sense, you won't use unit test here (so no need to mock any dependencies), but you'll prefer integration tests against a real database (see TestContainers or Ductus.FluentDocker)
Hello Milan, thanks for your awesome videos!!
I have a question.
I have a library that extends entity framework core. In this library there are all the entities and the repositories of the database, a test app project and unit test project. Could I use this library in clean architecture if yes, in which Iayer I could put it?
Most likely Infrastructure layer
@@MilanJovanovicTech Do you think is better to define the interfaces and the entities in the domain layer and the implementation of them in the infastracture layer or to have it together in a seperate library which is referenced in the infastructure layer as I did? Thanks :)
Perfect Milan Thank you
Sure thing :)
for example if we create a method in the repo GetPaginatedProducts in which we have to return paginated data with sorting sent from the client for example (nameAsc, nameDesc). Do we have to do that logic in the implementation of the repo? i mean switch between the sort argument if we have to sort by name, price, etc. Or is it a bussines logic and we have to encapsulate it and send it to the repo method?
That would be a Query, I handle those separately from my repository.
I use Repositories only on the command side.
Great video! Quick question, why we introduce an abstraction IUnitOfWork for the SaveChanges and just do that SaveChanges on the method in the repository? After all you have the ApplicationDbContext inside the repository.
I believe this is for transaction block so that operations from different repos are done in single transaction block
I like to do only 1 save changes call per request, also planning to cover a behavior that will wrap the UoW
Hello Milan! In order to ensure that only the repository's methods can be called wouldn't you have to move the IApplicationDbContext somewhere else? What I mean is that any application layer class could just inject the IApplicationDbContext and query in any way and perform any operations on the entity set.
I assume you now can safely remove that interface since it's no longer of use.
Yes, planning that for another video when I tackle the query side
Thanks for video!
You're welcome!
I usually put my repository interfaces in the application layer because I only add the dependency on the C# projects in the layer n to the layer n-1. For example Infra -> application -> domain. Infra knows about the application, but doesn't know about the domain. Application knows about the domain, but doesn't know about the infra. And the domain doesn't know about any other layer.
It feels wrong (out of place) to put them in the application layer, as there belongs to the domain layer, but I didn't want to add the infra -> domain dependency.
As a work around, we can use Interface inheritance, where the real interface is in the domain layer, the application layer has interfaces that inherits from those in the domain layer and they should be visible in the infra layer, but was really defined in the domain layer.
Not an elegant solution, but keeps the layers isolated.
What do you think about this approach?
I don't see any problem with Infrastructure referencing Domain. Moreover, if Application is referencing Domain, and Infrastructure is referencing Application, then you have a transitive reference from Infrastructure to Domain. 😁
Thanks for what your do! I was wondering we have over 100 Entities and Repositories interface, do we have to manually them inject Dependency Injection
How are you doing it right now?
@@MilanJovanovicTech Manually registering them all 🥲 is there a better way?
What is the benefit on defining repositories in the domain layer rather than in the application layer?
Exposing what are the allowed operations on your Domain. The Aplication layer has to use only that conntract. In essence, moving more of the logic into Domain, which is always a good thing.
If you have Domain Services in your Domain Layer that want or need to access "the DB" you need the repository interfaces right there.
Hey Milan, doesn't the reference to the IUnitOfWork interface from the domain layer break clean architecture, since it is referencing the application layer from the domain layer?
There's no reference to the UoW in Domain layer
Hey Milian, I am still a bit consused by the repository, looking at many examples, repositoy interface is in the domain layer, but it is implemented in the presistence layer, my question is, doesnt this expose the Entity data.
How does it expose entity data?
@@MilanJovanovicTech Considering that the repository is implemented in the persistence layer and interfaces are defined in the domain layer, it follows that the implementation accepts arguments of types defined in the interfaces. For instance, when saving a Schedule, the interface method is defined to take a Schedule entity as an argument, possibly returning something. Similarly, when retrieving a schedule, the interface expects data of Schedule type. This implies that we need to import the entity inside the repository implementation.
Nice video as usually!
Can you, please, enable the Tools > Options -> Projects and Solutions -> Track Active Item option?
In this case the file you're working on will be highlighted at the Solution explorer and it will be much easier to follow your project structure at your videos.
I'll think about it - since there's a chance the active item could overlap with my face on the screen 😅
I like that approach an do nearly the same for my current and new projects.
That's awesome!
Great content Milan! One question, how would you hide the Active record and specifically EF core functionalities such as AsNoTracking(), AsSplitQuery() behind an abstraction that we introduce?
Just place it in the repository implementation and forget about it
@@MilanJovanovicTech Fair, however let's say you have a repository function that retrieves aggregate FooBar by ID. You invoke this function in multiple command/query handlers. Of course, in command you may want this aggregate to be tracked, but in queries you just want to return data and run the query AsNoTracking. I am currently exposing asNoTracking bool in the repository interface but I find it very ugly as it's tightly coupled to EF core.
@@marinobjelopera4444 I don't use repositories on the query side
If I have a method in my repo interface which has a parameter typed as IIncludableQueryable, how can I break the EF Core dependency?
Get rid of the dependency on IIncludableQueryable, and wrap it inside a well named method. Or try using the specification pattern.
@@MilanJovanovicTech but if we use specification pattern with expressions we are depending on ef core, because sql query cant apply expressions. And using specifications with strings for example we wont have compiling errors
Thanks Milan for your Videos, they are much appreciated!
I also wonder why the repo interfaces are in the domain layer, when the IUnitOfWork is not. It means that the persitence layer has a dependency on the application layer. Is that intended?
Also I would really like to see how you would do an update. If the object beeing updated can only update a few propertys, how is it best practice in clean architecture to receive some parameters through web api and persist these to the database?
Kind regards
For updates, just apply the changes (covering that in the next video though) and persist it. Let EF Core take care of the rest.
For repo in Domain:
- I consider it part of my Domain
- I only ever return aggregates (no DTOs)
Why don’t put repo interfaces in the application layer?
You may need to access to database from somewhere that is not dependent on application layer, in this case placing repository interfaces in the domain layer will allow you to use it from almost anywhere with DI.
the same confusion, for my design, I would put IXXRespository and IUnitOfWork in application layer, and the implementation in the Infra layer.
A few reasons:
- I consider them part of my Domain logic
- I only use them in Command handlers (business logic)
- They always return aggregates
Precisely because you only use them in the command handlers (which is app layer) and to avoid (mis)using them from domain methods, it makes more sense to place them in the application layer. They return aggregates that are the entry point to your domain methods.
@@pablolopezponce agreed
i need ur opinion about make uow create repositories inside i always take this approach and i feel more comfortable in that first i don't need in handler inject every repository i just inject uow and call whatever repo i need second i just add to startup service uow and i don't need to interduce every repo and i repo might i violate some solid principles but i feel it worth what's ur opinion about this approach ?!
With multiple repositories you're being explicit about your dependencies (and what you need to mock for testing). With UoW + Repo inside approach it's all a bit implicit. Right?
Great content. You mentioned that there are good sides and bad sides to this approach. Only pros were here. Do you have a plan to discuss the cons in the future?
The "only" con is that people might misuse it and add some EF concerns, otherwise that's about it.
Damn, I had to SMASHED the like button.
This is the way
Hi Milan, I've been using repository pattern for a long time and now I'd like to switch to EF Core repository.. but how to test my handlers (for example) if I can't mock EF Core repository? A video regarding this approach would be nice! Thanks for you content.
Integration test with a db container.
You mean mocking a DbSet?
@@MilanJovanovicTech yeahh. I'll give a look at PelFox suggestion as well. Thanks a million
Yup, integration testing EF dependent code works well. There are too many moving parts with mocking and/or in-memory db. Postgres containers start and run tests in seconds.
Hi Milan, Which approach is best in real project ? We should go for repository or use EF.
You decide
This is regarding Domain reference to Persistance. With respect to my knowledge, only application should have reference right. This is what Onion architecture. Please explain your view on this.
Any outer layer is allowed to reference inner layers
Thanks Milan for the very informative video.
For the remove order line item method, should it be a good idea to add a method removeOrderLineItem in the Order AggregateRoot?
I thought any state changes has to be managed within the Aggregate Root.
Thanks a lot again 😀
Isn't there an order.RemoveLineItem method?
@@MilanJovanovicTech my bad :D
Wouldn't it be more convenient to have your repositories as properties within the UnitOfWork? This way, you can access them by simply injecting the UnitOfWork.
That might be easier to accomplish, but has some drawbacks: First and foremost it defies the Explicit Dependencies Principle, but also looks similar to a Service Locator, which is mostly seen as an anti-pattern.
@@krccmsitp2884 You might be right, but in the end, those principles act as guidance, and sometimes they bring nothing but complexity, like the one we're discussing. Repositories should be part of the UnitOfWork instead of being scattered throughout the application. They only require an instance of the DbContext, which is injected in the constructor of the UnitOfWork. To me, that seems more pragmatic.
I particularly dislike that approach because it makes the dependencies implicit
Again it depends on the approach you take. I personally don't buy the argument of implicit/explicit dependencies of the application services / command handles simply because in many cases I DO NOT TEST handlers! Yes! I use them for loading objects into memory and to invoke methods on domain objects or domain services. With this approach you don't have to mock anything for unit tests, you simply use your objects in test cases. But hey you should do whatever works for you 😉
In my humble opinion, repository over ef is unnecessary redundancy. But with dapper it's quite ok. As always be pragmatic, don't dogmatic 😉
Anyway, thanks for the content 👍
I like it as an additional way of expressing my Domain logic
@@MilanJovanovicTech I don't think you should have domain logic in your repository since you implement it in your persistence layer. Your persistence layer isn't Core (clean architecture). Interfaces are not behavior either.
Repositories are nice if you avoid lazy loading and want to encapsulate query that builds your agregate (whole graph of objects) Ideally you want your agregates to be as small as possible to protect the business rules. It depends on the complexity of the system and approach you take rather than the case of using ORM or not. For simple projects with anemic entities and minimal logic, repositories, DDD, CQRS and other sexy words in most cases is just an overengineering. Saying that in the same time there are projects where you should use those paterns to reduce complexity of already complex by nature domains.
Hi Milan, thank you for the video, can I please get the example code?
Will post it under the video next week
@@MilanJovanovicTech thank you so much.
Have you considered providing a git repository with the code that you're working on so that viewers can follow along?
I share the code on Patreon: www.patreon.com/milanjovanovic
is this not enough?
public interface IRepository
where T : BaseEntity
{
IQueryable Table { get; }
Task Insert(T entity, CancellationToken cancellationToken = default);
void Remove(T entity);
Task SaveAll(CancellationToken cancellationToken = default);
}
This might be OK for CRUD, but not for domain-driven apps.
You don't want to be coupled to IQueryable
Hot take I guess, repositories are application layer concerns just as third party api clients. Placing repositories in Domain layer implicitly opens up the "pure" Domain types to start referencing repository interfaces , which according to some authors is an anti-pattern
Besides, I am a totally EF for full application kind of guy. All repository pattern ends up leaking implementation details of underlying ORM tech, eg. implicit Entity Tracking in Entity Framework.
If you go all in on EF, I support you completely. I don't think there's a wrong choice in software, just tradeoffs.
How do you handle projection since the repository interface lives in the Domain layer?
I don't. These are repositories for domain entities.
Nice 🙏🙏
Thanks!
Yo Milan,
Great channel, do you by chance have a video on "Using Multiple DbContexts with Repository Pattern with IUnitOfWork" ?
I have this for the initial set up: th-cam.com/video/-_AKTzDrYVc/w-d-xo.html
In this implementation - you make too much coupling on EF. Because your IUnitOfWork isn't provider of repositories and you can call SaveAsync, because you know - implementation can make this. But what if you use not EF? How will it work with Dapper or NHibernate or Redis or something else?
I'm pretty sure NHibernate would be similar. Dapper (SQL) is a different thing, since there's no built-in UoW concept.
@@MilanJovanovicTech for sure NHibernate have it, but what if i need several unit of works? How it can be implemented?
@@efimov90 That's a lot of what ifs that may never actually happen. You never want to have multiple unit of works, because that implies a distributed transaction.
@@MilanJovanovicTech actually, i work on a project, that have more than 1 unit of work at same time, much more. It's enterprice desktop application for inner usage with direct access to database.
in DDD approach you should act on a single aggregate per transaction
Yes
How to register all repository automatically using reflection?
Try Scrutor: www.milanjovanovic.tech/blog/improving-aspnetcore-dependency-injection-with-scrutor
Sooooo where should i put it?
You have to decide 😁 I like placing them in the Domain, because I consider them part of my Domain logic
It’s a serious bad idea breaking the integrity of the Aggregate by fetching just a part of it. This violate the sense of having DDD in place. Aggregates MUST BE manipulated only through the AggregateRoot.
Even when the risk is low?
@@MilanJovanovicTech That's not a matter of risk but integrity of your system. AggregateRoots are the place to manage the invariants of the aggregate. By putting some "logic" within the repository (when you say "low risk") you're violating the ragion d'étre of the AggregateRoot, therefore your solution is not DDD compliant. Suppose your requirements evolve in a direction where you have to validate a delete operation based on the other items… you'll be in very big troubles
I think you should add to each folder a README that explains in a few sentences the organizational purpose of that folder. Making a folder is making an opinion and you should share it.
That seems overly verbose 🤔
@@MilanJovanovicTech Your material is great. I'm a fan, I'm a Patreon subscriber, and I've been programming since way before you were born. There's a wide gap between no documentation (what you have) and verbose. Adding a readme file to explain your reasoning is not crossing over to "verbose". I began my career in the nuclear industry. We measured our documentation in feet-width of binders. That was verbose.
Wouldn't we almost always mock the database for execution speed of our tests?
Not a proper test though
@@MilanJovanovicTech Why not? Just because such a test wouldn't test the entire application stack? Wouldn't you agree to different testing levels? And if we want to focus on "acceptance level testing" (pure functionality) wouldn't we try to be independent from complexity of the infrastructure? What about the UI? Would u include this in your acceptance tests?
I use CQRS and inject the dbContext interface directly into the handler. I don't like to use repositories if I use CQRS, it seems redundant to me.
but how yo can constraint the add, update, delete methods to be an aggregate root?
That's a perfectly fine approach. There's never "one" right answer
put them in the domain core, or domain interfaces 🙂
Agree!
This approach has an entanglement problem.
Wheb dealing with the database you should always preference an approach that results in you only dealing with a single entity type at this level and stack more complex business logic layers on top of this.
Care to point me where you see the issue? Couldn't figure out from your comment 🤔
@@MilanJovanovicTech think of it like ICrud then you're injecting multiple implementations of that with different T's in to this "handler".
You get cleaner code if you layer your higher orders of logic in my experience.
Referencing domain in Persistence will not break Clean Architecture
I agree
Trick question... You shouldn't use repositories at all
Not necessarily, but at least have a good reason for using them.