No video

How I Use The Generic Repository Pattern In Clean Architecture

  Рет қаралды 35,881

Milan Jovanović

Milan Jovanović

Күн бұрын

☄️ Master the Modular Monolith Architecture: bit.ly/3SXlzSt
📌 Accelerate your Clean Architecture skills: bit.ly/3PupkOJ
🚀 Support me on Patreon to access the source code: / milanjovanovic
The generic repository pattern is precisely that - a repository pattern implementation that is generic. You won't benefit much from implementing it on top of EF Core.
Specific repositories are a different story, and they're common in DDD. I'll explain in the video how I use the specific repository pattern and use the generic repository pattern to reduce code duplication.
Join my weekly .NET newsletter:
www.milanjovan...
Read my Blog here:
www.milanjovan...
Subscribe for more:
/ @milanjovanovictech
Chapters
0:00 Specific repository in the Domain layer
1:26 Using the repositories in use cases
3:25 Why I like Specific repositories with Clean Architecture
5:13 Specific repository downsides
6:06 Creating a generic repository with EF Core
8:40 Refactoring to use the generic repository
11:04 Strongly typed IDs with generic repository
15:45 Solving breaking changes with Extract Interface refactoring

Пікірлер: 196
@MilanJovanovicTech
@MilanJovanovicTech 11 ай бұрын
Want to master Clean Architecture? Go here: bit.ly/3PupkOJ Want to unlock Modular Monoliths? Go here: bit.ly/3SXlzSt
@lahao1
@lahao1 11 ай бұрын
sir, you just got my voice ! 🫡
@dansmif
@dansmif 11 ай бұрын
Adding a repository layer on top of EF is just wrapping one repository pattern with another. The DbSets in your context are already your repositories, and the DbContext itself implements the unit of work pattern. It's worth bearing in mind that patterns are often derived from other languages (especially Java) that lack nice things like extension methods in C# so there's sometimes better ways to approach things. For example you can extend the DbSet collections in your EF context with extension methods to add methods like GetProductById to DbSet. You can even add generic GetById methods to all your DbSets using a single extension method. It's much cleaner this way, with less code and less complexity.
@MilanJovanovicTech
@MilanJovanovicTech 11 ай бұрын
I'm focusing on my Domain design, and dictating what the Application layer can do with those repositories. You're missing the point, because "EF is a repository already" doesn't matter. You can use just EF, and you'll be fine. But that has other implications for your application.
@user-em8rt4eq2s
@user-em8rt4eq2s 11 ай бұрын
i had thousand problems with tis method, dont use in large scale projects
@123sampletext5
@123sampletext5 11 ай бұрын
This is a very unintuitive solution. No one expects to use the logic coded only in extension methods + by adding extension methods to DbSet which is a strictly EfCore class you tie your project to use EntityFramework only and you are not able to switch it to different project/database connector.
@PauloWirth
@PauloWirth 11 ай бұрын
Seriously, this is like repeating the same argument over and over. Specific repository or generic are not silver bullets. Also, there will be projects you will come across multiple database providers, and the generic repository might be useful. Also, combining it with the specification pattern helps reduce the number of overloads for read commands.
@Ryan-mg2uv
@Ryan-mg2uv 7 ай бұрын
How would this work if you wanted to mock out the db for testing and use in memory data instead of data in a db? In this case that you mention, you are stuck with using EF and a db
@danilonotsys
@danilonotsys 10 ай бұрын
I like to use generic repositories these days, since many database providers - relational or not - support queryable linq and it's relatively easy to implement an in-memory cache or change tracking system for any of them that don't support EFCore. When I need a custom operation on the repository, lets say it due to a need of a very optimized query or bulk update or insert, then I create a specific method in the domain repository interface. This has worked very well for many projects I've worked on.
@MilanJovanovicTech
@MilanJovanovicTech 10 ай бұрын
Very nice approach!
@victorgarcia3526
@victorgarcia3526 11 ай бұрын
This is an approach I used in a project where you had to connect to multiple providers via API and keep their information in our db, this helped a lot to reduce the code generated via the integration of every provider, and we could have a lot of providers almost seamlessly
@MilanJovanovicTech
@MilanJovanovicTech 11 ай бұрын
That's awesome. Which providers were you working with?
@victorgarcia3526
@victorgarcia3526 11 ай бұрын
@@MilanJovanovicTech it was a tourism related company so they were APIs like booking, Expedia... We used that pattern to keep all the different information for all these providers in different tables
@jonclark25
@jonclark25 9 ай бұрын
When using generic repository pattern with EF I always liked to make the methods simple and return an Iqueryable so the inheriting class can modify the "Base query" and add to it. E. G the repository class has a getById but the inheriting class can call this, get the Iqueryable and add a where clause to it to filter further more but only actually executing once.
@MilanJovanovicTech
@MilanJovanovicTech 9 ай бұрын
At that point - why not use EF Core directly?
@hkoueke
@hkoueke 2 ай бұрын
Hey there. Long time sub from Cameroon. Keep up with videos, i learn a lot from them.
@MilanJovanovicTech
@MilanJovanovicTech 2 ай бұрын
Thanks a lot, glad you're getting value from the videos :)
@frankhalbach2591
@frankhalbach2591 11 ай бұрын
Nice video, i’d love to see a version of this with Dapper instead of efCore.
@MilanJovanovicTech
@MilanJovanovicTech 11 ай бұрын
Dapper one would be much more verbose on the implementation side - and we don't have a UoW 😁
@frankhalbach2591
@frankhalbach2591 11 ай бұрын
Right, i use dapper in my project and have some repetition with the scenarios you solve in the video.
@Greenthum6
@Greenthum6 11 ай бұрын
Dapper benefits from repository pattern much more than EF
@xustis
@xustis 7 ай бұрын
i love that too, i am using dapper and i dont know how call the base repository method from my service, calling the specific repository interface with DI :S
@alessandrohudson5221
@alessandrohudson5221 11 ай бұрын
Valious tips Milan!! Depending of project, can be useful
@MilanJovanovicTech
@MilanJovanovicTech 11 ай бұрын
Everything has a use case
@i.paradox
@i.paradox 11 ай бұрын
Thanks for sharing your valuable knowledge.
@MilanJovanovicTech
@MilanJovanovicTech 11 ай бұрын
My pleasure
@sadkcoban625
@sadkcoban625 7 ай бұрын
Thank you for your answers. I will approach things like this in my future applications I don't know is it true or not. I will use repository pattern in basic crud operations becauase it is good especially when you want implement something like soft delete mechanism. But in complex queries no matter I use cqrs or not I will do in bussiness/application layer because it really gives complexity. I really see a lot solution people does not use select query and directly map into objects. What is the reason to get all the data from database and map to them. Because if you get 8 columns of data maybe you need 4 columns of it..Map after get all the data. Select after ToListAsync.All columns queired allready!. This is performance issue.If it is wrong to use dtos in repositories object or dynmaic i should do this operation in bussiness layer. So I should abstract away dbcontext because my application shouldn't reference persistence layer.I am really tired to search how to solve this. Thanks for the answer again.
@MilanJovanovicTech
@MilanJovanovicTech 7 ай бұрын
Nice 👌
@xenofenus
@xenofenus 11 ай бұрын
Patreon email coming in clutch to quickly absorb Milan's new content
@MilanJovanovicTech
@MilanJovanovicTech 11 ай бұрын
Haha! You're fast 😁
@Flanno91
@Flanno91 11 ай бұрын
Great video Milan. Would love to see how something like this would work with the MongoDB driver. First thought is that each collection is it's own property in the MongoDB context and can't just use the generic Set property. As far as I'm aware?
@MilanJovanovicTech
@MilanJovanovicTech 11 ай бұрын
Will check to see how this works with MongoDb. Could possibly require some re-design. 🤔
@KristofGalNix
@KristofGalNix 11 ай бұрын
Awesome, love your explanation. Earned a subscriber. 💪
@MilanJovanovicTech
@MilanJovanovicTech 11 ай бұрын
Thanks a lot! Hope you found the other videos just as valuable 😊
@kp_xcess
@kp_xcess 6 ай бұрын
It is interesting that you decided to define the repository interfaces within the domain project. I myself usually define them within the application layer, because it is actually the application that determines what exact data it needs, based on what the application actually does. The domain layer should not be bothered with that. Of course it does still own its own entities, value objects and contains all related domain logic. One down side of my way however is that a lot of these repository interfaces end up in the Common area, since their usage often spans across multiple application microservices... And then also your reasoning does make sense and got me thinking about it once again. I've yet to decide if we will be switching back to defining 'em in the domain layer after all :)
@MilanJovanovicTech
@MilanJovanovicTech 6 ай бұрын
Maybe we can look at it as "domain repositories" and "application repositories"? The naming might be a bit strange, but I think it describe what you/me are doing
@kp_xcess
@kp_xcess 6 ай бұрын
@@MilanJovanovicTech Well that does indicate the difference.
@manueliriarte1535
@manueliriarte1535 5 ай бұрын
thought the same thing. interesting approach but I would not put them in the Domain, good to hear I wasn't the only one thinking of that.
@marcnacionales7786
@marcnacionales7786 11 ай бұрын
I'm learning a lot on your videos. 😁 I'm just wondering if, is it better to have a method GetAsync with a parameter of an expression (Expression predicate = null) rather than adding a method GetByIdAsync ?
@MilanJovanovicTech
@MilanJovanovicTech 11 ай бұрын
If you want that flexibility then yeah, go for it
@yiliang9702
@yiliang9702 11 ай бұрын
Great video. if the app logic is complex. we better make a abstract class between actual service class and their interfaces. it is more flexible.
@MilanJovanovicTech
@MilanJovanovicTech 11 ай бұрын
Thanks!
@svorskemattias
@svorskemattias 11 ай бұрын
The order and orderlines could be defined using the ownsmany-relationship, and efcore will handle the include for you, so you can skip the override.
@MilanJovanovicTech
@MilanJovanovicTech 11 ай бұрын
Do you always want to include them, though?
@svorskemattias
@svorskemattias 11 ай бұрын
@@MilanJovanovicTech when reading for modifying, yes! I've used another set of dbcontexts with plain hasmany-relations for readmodels. Not sure if it's a good idea in the long run, but it has been ok so far.
@Tof__
@Tof__ 11 ай бұрын
What exactly are the OrderId, ProductId classes?
@MilanJovanovicTech
@MilanJovanovicTech 11 ай бұрын
Strongly Typed IDs: kzfaq.info/get/bejne/gsqigMd6xsipYaM.html
@kodindoyannick5328
@kodindoyannick5328 5 ай бұрын
Great video! Thank Milan.
@MilanJovanovicTech
@MilanJovanovicTech 5 ай бұрын
Sure thing :)
@mocca9016
@mocca9016 6 ай бұрын
Really good and concise video explaining the pattern. I have one question that I couldn't find an answer on. What if we are working with a DbContextFactory? How would the Repository and UnitOfWork class use the context in this case?
@MilanJovanovicTech
@MilanJovanovicTech 6 ай бұрын
Configure them to resolve the DbContext form the factory? 🤔
@mocca9016
@mocca9016 6 ай бұрын
@@MilanJovanovicTech So we wouldn't inject the repository with DI but instantiate it in the calling method with a created context? Or is there another way to make the repository use the created context, preferably with DI? Sry for the stupid question 😅 Because what I think the problem is, when having DbContextFactory in repository class, it always creates a new context for each repository method, but I would like the repository and the unit of work to use the same context. Maybe I'm just missing something
@ardavaztterterian1211
@ardavaztterterian1211 9 ай бұрын
What are the domain events for in the Persistence layer? Shouldn't they be raised from the Domain/Application layer?
@MilanJovanovicTech
@MilanJovanovicTech 9 ай бұрын
How do you "raise" a domain event?
@hassenlazli6047
@hassenlazli6047 2 ай бұрын
Hi, what should we do when we find ourselves with a service like UserService that injects, for example, 10 repositories? How can we make it cleaner?
@MilanJovanovicTech
@MilanJovanovicTech 2 ай бұрын
Break it up into use cases? An idea
@pete9049
@pete9049 11 ай бұрын
holy this is clean af
@MilanJovanovicTech
@MilanJovanovicTech 11 ай бұрын
Overengineering at its finest 😁🔥
@MrNickP
@MrNickP 11 ай бұрын
I'm primarily a DB developer so forgive my ignorance but does entity retrieve full objects from the DB even if you only use a few columns?
@MilanJovanovicTech
@MilanJovanovicTech 11 ай бұрын
Yes, that's one of the drawback of ORMs. If you want to load an entity, it'll have all the columns. You could optimize it by manually fetching specific columns, but most of the times you wouldn't do this if your intent is to write back to the DB. If you are using an ORM for a query (read) than you will definitely only want to fetch the columns you need.
@svorskemattias
@svorskemattias 11 ай бұрын
This is not an ORM drawback! In ef core you can do it how you like it! Either you project your entities onto a dto, and EF CORE will only select the columns needed. This is good for readonly operations! In this case however, when trying to do DDD, you want your aggregates to be fully loaded into memory, because the aggregates define your consistency boundary. The aggregate can now use all the information in the aggregate to validate the operations your doing on it! If this means pulling too many unwanted columns from the database, maybe your aggregate is to big? Maybe it holds many unrelated fields, that don't have to be inside the same consistency boundary?
@olamidejames7968
@olamidejames7968 11 ай бұрын
HI @MilanJovanovicTech, I really enjoy watching your tutorials. Please do you have any video on unit testing ef core async methods like AnyAsync, FirstOrDefaultAsync, e.t.c as well as AsNoTracking method? Thanks
@MilanJovanovicTech
@MilanJovanovicTech 11 ай бұрын
Maybe this: kzfaq.info/get/bejne/qtBljaal2828e40.html
@ARESCOM_PA
@ARESCOM_PA 9 ай бұрын
Thanks for this helpful video Milan! Wouldn't it be great to use this generic repository pattern with CQRS and only the Command uses it and the Query part still uses EF directly? Should be a good content for another video?
@MilanJovanovicTech
@MilanJovanovicTech 8 ай бұрын
It's something I've done in future videos, more or less
@matthewrossee
@matthewrossee 11 ай бұрын
Hi Milan! How do you deal with models in domain driven design that don't have behavior? In my project great majority of domain models have rich business logic (like 95%), but sometimes I encounter something that should just be a dumb data container, and it doesn't make sense to make it an aggregate root. For example when I create some Order aggregate, the client needs to pass some OrderOptions, like product's color, product's material, etc.. These cannot be a value object, because these order options have concrete price assigned to them, and should be seeded into the database (probably not gonna change often). So the only option I see is that the order option is an aggregate root, and then in Order.Create() factory method I can pass List. The thing I don't like about this approach is that OrderOption doesn't really have any behavior, other than maybe changing a price, that could raise some domain event. But still it doesn't seem like a good fit for an aggregate. Do you think that I should create some directory in domain layer for something like DataModels and throw anemic models there? I'm really curious how you'd handle this.
@MilanJovanovicTech
@MilanJovanovicTech 11 ай бұрын
Just because it's anemic doesn't mean it's wrong. Some parts of the Domain simply won't have any behavior. Take a look at this for static data: kzfaq.info/get/bejne/rJyTjLeUqsy-aHU.html
@pagorbunov
@pagorbunov 11 ай бұрын
You said that the domain layer dictates how the repository interfaces should be implemented but isn't it vice versa? it looks like knowing that the reads and writes are separated and ef is an orm forces you to create such interfaces where the reads are async methods and writes are not.
@MilanJovanovicTech
@MilanJovanovicTech 11 ай бұрын
Repository doesn't do writes, just adds stuff to the repo. UoW takes care of write. I don't think async (Task) in domain is bad, anyhow. The repository dictates the usage (not the implementation).
@ibrahimoguzhanyilmaz3451
@ibrahimoguzhanyilmaz3451 11 ай бұрын
why would you implement UnitOfWork just to call SaveChanges?
@ibrahimoguzhanyilmaz3451
@ibrahimoguzhanyilmaz3451 11 ай бұрын
I asked this to GPT and this is the answer. But it is still not a good answer for me. When using the Entity Framework (EF) in .NET, the DbContext class already provides a SaveChanges() method, which might make it seem redundant to wrap this with a UnitOfWork. However, implementing the UnitOfWork pattern can still be beneficial, even if all you're doing is calling SaveChanges(). Here's why: Abstraction: UnitOfWork abstracts the underlying data access logic from the rest of the application. By doing so, it makes your application less dependent on a particular ORM or database technology. If you ever need to change your data access logic or even switch to another ORM, you'll have a single point of change. Testability: With the UnitOfWork pattern, you can mock your unit of work in unit tests. This makes testing easier, especially if you want to test services that have database interactions without actually hitting the database. Multiple Data Sources: In more complex applications, you might be dealing with multiple databases or data sources. A UnitOfWork can help manage transactions across these different sources. Decoupling: It allows services to be decoupled from the specific persistence mechanism being used, making the architecture cleaner and more maintainable. Flexibility: In the future, if you need to add more functionality around the commit (like logging, event raising, etc.), you can do it in the UnitOfWork without altering your service or repository classes. Transaction Management: The pattern can simplify transaction management, especially if there's a need to handle custom business transactions that span multiple operations or repositories. Clarity: By using the UnitOfWork pattern, you're signaling to other developers that you're aggregating operations for eventual transactional persistence. This can help in understanding the application's flow and logic.
@MilanJovanovicTech
@MilanJovanovicTech 11 ай бұрын
Would you make each repository method also go to the DB?
@Greenthum6
@Greenthum6 11 ай бұрын
​@MilanJovanovicTech Isn't that the main responsibility of a repository? Your get methods already access the DB. Excluding SaveChanges from the repository and renaming it to UnitOfWork outsources transaction handling to application logic.
@ibrahimoguzhanyilmaz3451
@ibrahimoguzhanyilmaz3451 11 ай бұрын
@@MilanJovanovicTech i feel you, i've never thought uow like that, thanks you :) love your content :)
@svorskemattias
@svorskemattias 11 ай бұрын
​@@Greenthum6I guess because you don't really know how many repositories you wanna touch before committing the transaction.Even though most often you'd only want a single aggregate to participate in your transaction.
@tasin5541
@tasin5541 11 ай бұрын
How would you handle tables that don't have Id? Or use composite keys?
@MilanJovanovicTech
@MilanJovanovicTech 11 ай бұрын
Will they need repositories at all? Composite keys are a bit complex, so probably a slightly different solution
@Cornet435
@Cornet435 11 ай бұрын
What do u think about second optional parameter in GetByIdAsnc where you have array of expresionss. If this array is not null we just applay all includes expresionss.
@MilanJovanovicTech
@MilanJovanovicTech 11 ай бұрын
I'd be careful with expanding the interface like that, but it should be fine
@sadkcoban625
@sadkcoban625 7 ай бұрын
Hello if I want to implement select can I use dto in repository is it good practice what is your suggestion? Some people says repository should return domaim entities repository should not use dtos
@MilanJovanovicTech
@MilanJovanovicTech 7 ай бұрын
I'm on the same side of the fence: repositories should only work with domain entities
@sergeu90
@sergeu90 4 ай бұрын
I see in your examples unit of work in command. But if need call multiply commands and after that call unit of work. It is need to do in controller if we speak about mediator ?
@MilanJovanovicTech
@MilanJovanovicTech 4 ай бұрын
I strive to send one command per request
@sergeu90
@sergeu90 4 ай бұрын
@@MilanJovanovicTech But then if i want to create specific command need to create a lot of diff commands. But better in conroller call multiply small comands and after that call commit
@patrykwikacz869
@patrykwikacz869 11 ай бұрын
Very nice and usefull video. What theme are you using for visual studio?
@MilanJovanovicTech
@MilanJovanovicTech 11 ай бұрын
R#
@dionismendanha4649
@dionismendanha4649 11 ай бұрын
I'm looking forward to seeing a video explaining about upgrading with multilevel. Is there a way to do this dynamically?
@MilanJovanovicTech
@MilanJovanovicTech 11 ай бұрын
Multilevel what?
@dionismendanha4649
@dionismendanha4649 11 ай бұрын
@@MilanJovanovicTech Multi children entities
@ravindranaths513
@ravindranaths513 6 ай бұрын
What if any repository class doen't want the functionality (method), which is defined in base repository class?
@MilanJovanovicTech
@MilanJovanovicTech 6 ай бұрын
Well, nothing really. You can't remove it from the base class.
@ravindranaths513
@ravindranaths513 6 ай бұрын
1) can we write : throw NotImlementedException in child repository classes, to suppress not required methds of base Generic repo class? 2) If not then, this Generic repository approach is not usefull where only writing method (POST) is there. Forex: in case of some business transations, having only adding new records into db table is enough. Plz give your comments
@kp_xcess
@kp_xcess 6 ай бұрын
@@ravindranaths513 Throwing NotImplementedExceptions is only for methods that are yet to be implemented (and _will_ be implemented). They should never be thrown purposely otherwise. In this case you'll simply get the methods for free within other repositories too, even if you don't (currently) need them 😉
@Benke01
@Benke01 8 ай бұрын
Regarding the Include: personally I think this is a requirement only the consumer of the repository knows about. And I think the repository shouldn't specify it because its related to the domain logic. One consumer of a repository method might need 2 types of .Include() while another might need 3 others or another .ThenInclude(). You then have two choices: either let all consumers of a method fetch the total set of Include() flavours or you let the consumer specify the include as a functional parameter to the repository method.
@MilanJovanovicTech
@MilanJovanovicTech 8 ай бұрын
So either go for everything - or use something like a specification pattern
@Benke01
@Benke01 8 ай бұрын
@@MilanJovanovicTech You could use the specification pattern but that doesn't necessarily address the issue. Depends on the implementation.🙂 In a real world example a repository method can and should be able to be used by multiple consumers. But rarely they have the exact same needs when it comes to includes.
@kp_xcess
@kp_xcess 6 ай бұрын
@@Benke01 Then just let the repository offer multiple variants of the method, either by adding an additional parameter or just create a few extra methods that include specific things.
@Benke01
@Benke01 5 ай бұрын
@@kp_xcess That would quickly escalate to multitudes of methods. And their naming... 😥
@salmanshafiq8151
@salmanshafiq8151 11 ай бұрын
Nice video, Milan. But here, inspite of need an add method for an entity, the entity has now four or more method by inheriting the generic repository. 1. Then What is purpose of using interface? 2. Why the repository expose the methods that doesn't need?
11 ай бұрын
Remember that you always use the repo interfaces defined at the domain layer. You don't have access to the members of the implementation so you won't see the generic repo methods.
@MilanJovanovicTech
@MilanJovanovicTech 11 ай бұрын
1 - I explained that in the video, in-depth with my reasoning 2 - The repository implementation is internal - you're working with the interface
@rouziuzi
@rouziuzi 6 ай бұрын
Very useful. Hvala :D
@MilanJovanovicTech
@MilanJovanovicTech 6 ай бұрын
Nema na čemu :)
@jadenrogers3133
@jadenrogers3133 11 ай бұрын
Great video, EF is a repository 😂 I think they missed the point. Would love to see a video on GUID vs X for id's that one also gets a lot of debate. I notice you use GUIDs, do you do this on large systems?
@MilanJovanovicTech
@MilanJovanovicTech 11 ай бұрын
There are sequential GUIDs and ULIDs without the drawbacks. But GUIDs are mostly fine (albeit random). And in a distributed system you have to use something like that.
@smeta72
@smeta72 11 ай бұрын
Thanks!
@MilanJovanovicTech
@MilanJovanovicTech 11 ай бұрын
Don't mention it :)
@feli4521
@feli4521 11 ай бұрын
I really like this approach when using ef core with the repository pattern
@MilanJovanovicTech
@MilanJovanovicTech 11 ай бұрын
Did you use it before?
@feli4521
@feli4521 11 ай бұрын
@@MilanJovanovicTech Yes, it avoids having to write repeated code in the repositories and it allows you only to write specific queries only for certain entities
@user-bx2er2zx5u
@user-bx2er2zx5u 11 ай бұрын
But you don't solve the problem with interface that your repository don't need - CustomerRepository needs only generic Add , but get also Remove and Update .
@TheFeljoy
@TheFeljoy 11 ай бұрын
Not quite. Because the interface isn’t exposing the methods, they cannot be accessed outside of the Infrastructure layer. The domain & application layer will only use the interfaced methods :)
@Forshen
@Forshen 11 ай бұрын
You can argue that you most likely always need CRUD actions on an entity. But I do get our point. There are definitely scenarios where you don't need the full CRUD actions.
@user-bx2er2zx5u
@user-bx2er2zx5u 11 ай бұрын
@@TheFeljoy I mentioned only interface methods . Dont get your point.
@user-bx2er2zx5u
@user-bx2er2zx5u 11 ай бұрын
@@Forshen So Milan said that he does not like it because all repo's get access to full crud , but we can dont need it . And than make same stuff.
@MilanJovanovicTech
@MilanJovanovicTech 11 ай бұрын
I'm not worried about having these methods in the implementation, since they aren't exposed to the consumer
@programmingskills3404
@programmingskills3404 11 ай бұрын
Nice video
@MilanJovanovicTech
@MilanJovanovicTech 11 ай бұрын
Thanks!
@krcarbo
@krcarbo 11 ай бұрын
Thanks for the video and the explanations. Is it possible to have access to the code please?
@MilanJovanovicTech
@MilanJovanovicTech 11 ай бұрын
In the description
@arivoarivo
@arivoarivo 7 ай бұрын
@MilanJovanovicTech I thought we should only create repositories for aggregate roots in DDD pattern? And 2nd question, if I want to implement a custom query for an entity which is not an aggregate root, where should I put that
@MilanJovanovicTech
@MilanJovanovicTech 7 ай бұрын
That rule is too constrictive for most applications
@sadkcoban625
@sadkcoban625 7 ай бұрын
Hello. How should I implememt select with this pattern. I implemented one but it is complex. Should i implement another overload for select functionality thanks for answer.
@MilanJovanovicTech
@MilanJovanovicTech 7 ай бұрын
Might be better off creating a concrete method for complex queries
@jorgellanque7704
@jorgellanque7704 8 ай бұрын
Where is the link of the code repo?
@MilanJovanovicTech
@MilanJovanovicTech 8 ай бұрын
Patreon
@SalmanTariq223
@SalmanTariq223 11 ай бұрын
You make the generic repository class in which all methods depend on the type of class. While I think there should be generic methods which are independent and called for any entity type.
@MilanJovanovicTech
@MilanJovanovicTech 11 ай бұрын
And how would you do that?
@SalmanTariq223
@SalmanTariq223 11 ай бұрын
@@MilanJovanovicTech don't make custom repositories like OrdersRepository or SalesRepository etc. Just make a generic Repository by using specification design pattern.
@michaelgrass
@michaelgrass 4 ай бұрын
Why do we use SingleOrDefault() instead of Find()?
@MilanJovanovicTech
@MilanJovanovicTech 4 ай бұрын
Same result, but I don't like using Find. Prefer writing my LINQ condition
@attilaguba856
@attilaguba856 11 ай бұрын
Nice one ! Could you make the same Generics Repository pattern /UnitOfWork/ with Stored Procedure and EF! That would be amazing! Thanks
@Code_Bits
@Code_Bits 11 ай бұрын
Honestly, you should try avoid using Stored Procedures if possible.
@attilaguba856
@attilaguba856 11 ай бұрын
@@Code_Bits can you explain why ? I have UnitOfWork with Generic Repository and I thought with Stored Procedure you can avoid sql injection?!? So what do you suggest?
@MilanJovanovicTech
@MilanJovanovicTech 11 ай бұрын
How will you run into SQL injection with EF?
@attilaguba856
@attilaguba856 11 ай бұрын
@@MilanJovanovicTech so what do you suggest? Leave just EF in my project without Stored Procedure? It's better ?
@Code_Bits
@Code_Bits 11 ай бұрын
@@attilaguba856 I think the first Google search would answer your question honestly.
@aah134-K
@aah134-K 11 ай бұрын
How did you wire the unit of work class
@MilanJovanovicTech
@MilanJovanovicTech 11 ай бұрын
As a scoped service -> services.AddScoped()
@aah134-K
@aah134-K 11 ай бұрын
@@MilanJovanovicTech i mean doest have to be the same dbcontext, used in the repository class or two scoped instances are ok, one to do the databas access one will do the save changes. What I had before a method within the abstract reposotory class, this method will do save changes.
@sunguhan
@sunguhan 7 ай бұрын
First of all, great video! I really enjoy your work so keep it up! I am currently working on a clean architecture solution and I'm are quite new in the concept and noticed that you refer the domain layer in infrastructure. Is it alright that infrastructure can reference to classes in the domain layer or is it only application who have access to this layer? I mean based on the clean architecture diagram, the domain layer is the inner most layer where the application layer is the adjacent layer to domain while presentation and infrastructure are the outer layers. So im just a bit confused on how outer layers can reference each inner layers without breaking best practices? 😅
@MilanJovanovicTech
@MilanJovanovicTech 7 ай бұрын
Yes, the outer layers can reference the inner layers.
@MilanJovanovicTech
@MilanJovanovicTech 7 ай бұрын
- www.milanjovanovic.tech/blog/clean-architecture-and-the-benefits-of-structured-software-design - www.milanjovanovic.tech/blog/why-clean-architecture-is-great-for-complex-projects
@piottrk
@piottrk 2 ай бұрын
Hi, is it possible to review your project somewhere (maybe git?)?
@MilanJovanovicTech
@MilanJovanovicTech 2 ай бұрын
I share the source code on Patreon
@jonny.rubber
@jonny.rubber 11 ай бұрын
Isn't Moq caught secretly gathering email addresses?
@MilanJovanovicTech
@MilanJovanovicTech 11 ай бұрын
Yes, in some versions. The versions before that (and after) are fine
@hrobertson4
@hrobertson4 10 ай бұрын
It also wasn't really secret, they weren't caught, they announced it
@anilkarasahh
@anilkarasahh 11 ай бұрын
How would this behave if an entity had a composite key?
@MilanJovanovicTech
@MilanJovanovicTech 11 ай бұрын
Now you're reaching... I think it's still doable, but the GetById method would need to be updated slightly on the key filtering part
@microtech2448
@microtech2448 9 ай бұрын
Should Domain project be allowed to reference in Persistence project? As per clean architecture diagram, domain should be referenced in Application project only?
@MilanJovanovicTech
@MilanJovanovicTech 9 ай бұрын
No - it's the other way around. Persistence can reference Application/Domain
@microtech2448
@microtech2448 9 ай бұрын
@@MilanJovanovicTech ok, but if one may want to keep both layers independent of each other then in which project domain and DB entities should be mapped to each other and what would be appropriate way of mapping them?
@MDM666666
@MDM666666 11 ай бұрын
Which keyboard are you using?
@MilanJovanovicTech
@MilanJovanovicTech 11 ай бұрын
LOGITECH G413 CARBON
@andtkach
@andtkach 11 ай бұрын
Great
@MilanJovanovicTech
@MilanJovanovicTech 11 ай бұрын
Thanks!
@svorskemattias
@svorskemattias 11 ай бұрын
What happens when mediator fails to handle your events? They just dissappear, and the initial transaction (your savechanges) is completed! This is not good is it? The change you made in the domain is probably not idempotent, so you can't just run it again and hope the events succeed next time. Shouldn't you save the events along with the entity in a transactional outbox!?
@MilanJovanovicTech
@MilanJovanovicTech 11 ай бұрын
I explained in the Domaim events video this specific problem, and how to solve it
@svorskemattias
@svorskemattias 11 ай бұрын
@@MilanJovanovicTech I'll take a look!
@svorskemattias
@svorskemattias 11 ай бұрын
@@MilanJovanovicTech This? kzfaq.info/get/bejne/eM-dmaeWqbyYqYk.html Because it only briefly touches the transactional outbox at the end. It seems like you have solution for this without transactional outbox hidden somewhere, but I can't find it, nor understand how it would work. :)
@svorskemattias
@svorskemattias 11 ай бұрын
Oh. This one? It is just as problematic as it was before introducing events, only now the chain of events can be basically infinite and crash anytime? Transactional outbox is the only way, as I see it. kzfaq.info/get/bejne/d66qiq2QuLPVfKM.html
@MilanJovanovicTech
@MilanJovanovicTech 11 ай бұрын
@@svorskemattias This one kzfaq.info/get/bejne/jqd8qdGJnLO0laM.html 😅😅
@RespectNaturalBeauty
@RespectNaturalBeauty 11 ай бұрын
Could you please project regarding this?
@MilanJovanovicTech
@MilanJovanovicTech 11 ай бұрын
I share the code on my Patreon
@jwbonnett
@jwbonnett 11 ай бұрын
Why use UOW pattern when you can just use the DB Set as it already does what the UOW does?
@MilanJovanovicTech
@MilanJovanovicTech 11 ай бұрын
Sigh... Didn't I explain it in the video?
@jwbonnett
@jwbonnett 11 ай бұрын
@@MilanJovanovicTech No, I'm talking context. You explain why you use it. I am asking why not use it in a specific way, as all you're doing is recreating functionality that is already available.
@charlesschneiderp
@charlesschneiderp 11 ай бұрын
Is this project code available on git? Thanks!
@MilanJovanovicTech
@MilanJovanovicTech 11 ай бұрын
No, I share the code on my Patreon
@lettuceturnipthebeets790
@lettuceturnipthebeets790 11 ай бұрын
awesome! it's quite similar to the approach we've used at my previous work. what do you think of accessing generic repository via a factory or builder of some sort? would it be bad to expose generic repo building based on specified entity type, even if the entity doesn't have an concrete repo?
@Code_Bits
@Code_Bits 11 ай бұрын
You can directly use Entities without an concrete repository for them. So you'll only be able to use the Add(), Update() etc... methods for that specific entity. If you implement the repositories the way Milan implemented them you could also make these methods virtual and override them in your specific repositories if needed. At work we also used this implementation of the generic repository pattern and it's a very good way imho. We also used a IUnitOfWorkFactory to create the Unit of Work and retrieving from the dependency injection container the repositories we needed.
@MilanJovanovicTech
@MilanJovanovicTech 11 ай бұрын
How that builder work? Got an example?
@lettuceturnipthebeets790
@lettuceturnipthebeets790 11 ай бұрын
​@@MilanJovanovicTechI think there were some ideas with exposing Set() DbContext method (where TEntity is IEntity, of course) and some scoped caching of the built repositories in a concurrent collection (if the repo is needed again in the same request)
@lettuceturnipthebeets790
@lettuceturnipthebeets790 11 ай бұрын
I personally root against it, since there could be more Entities than DbSets, which could lead to some runtime exceptions
@Code_Bits
@Code_Bits 11 ай бұрын
@@MilanJovanovicTech I don't have an example unfortunately, however the Factory created an UnitOfWork instance with the right DbContext. This UnitOfWork instance was used to get repositories (like the Product repository) which only accepted domain entities and automatically mapped them to the DbEntity (in case of an Add()). In case of an any other operation like Update() etc we also passed in a domain entity which would update the DbEntity. The repository took care of mapping them and you only needed to have the mapping configured and the repositories registered in your DI container. This worked very well in our case since as you can guess you only needed to inject the factory within your classes and not the UnitOfWork and repositories.
@techpc5453
@techpc5453 11 ай бұрын
@MilanJovanovicTech
@MilanJovanovicTech 11 ай бұрын
👋👋👋
@rishiraj1616
@rishiraj1616 4 ай бұрын
hmm so if I am not using EF then how to have a generic repository pattern?
@MilanJovanovicTech
@MilanJovanovicTech 4 ай бұрын
Tough
@krccmsitp2884
@krccmsitp2884 11 ай бұрын
CRUD repositorys: 👎🏼 / Domain repositorys: 👍🏼
@MilanJovanovicTech
@MilanJovanovicTech 11 ай бұрын
Fully agree!
@iamorhanmir
@iamorhanmir 11 ай бұрын
First Viewer ❤
@MilanJovanovicTech
@MilanJovanovicTech 11 ай бұрын
Blazing fast, congrats! 🔥
@jessegador
@jessegador 11 ай бұрын
You are just reinventing the wheel. EF is already a repository.
@MilanJovanovicTech
@MilanJovanovicTech 11 ай бұрын
What about code duplication?
@svorskemattias
@svorskemattias 11 ай бұрын
@@MilanJovanovicTech Its nice to put an interface around things for many reasons! The repository is not reinvented by doing this. Its just getting a nicer packaging, communicating through specific interfaces what operations are allowed. Also, you gain mockability.
@microtech2448
@microtech2448 11 ай бұрын
Nice video
@MilanJovanovicTech
@MilanJovanovicTech 11 ай бұрын
Thanks!
Fix Your Controllers By Refactoring To Minimal APIs
14:56
Milan Jovanović
Рет қаралды 38 М.
Vertical Slice Architecture Project Setup From Scratch
22:43
Milan Jovanović
Рет қаралды 55 М.
EVOLUTION OF ICE CREAM 😱 #shorts
00:11
Savage Vlogs
Рет қаралды 14 МЛН
Kind Waiter's Gesture to Homeless Boy #shorts
00:32
I migliori trucchetti di Fabiosa
Рет қаралды 4,7 МЛН
Generic Repository Pattern With EF Core - Why It Sucks
9:33
Milan Jovanović
Рет қаралды 40 М.
Deep Dive Into the Repository Design Pattern in Python
11:56
ArjanCodes
Рет қаралды 75 М.
Unit of Work in ASP.NET Core
14:57
Raw Coding
Рет қаралды 18 М.
Repository Pattern
11:08
Coding Concepts
Рет қаралды 67 М.
Repository Pattern with C# and Entity Framework, Done Right | Mosh
26:24
Programming with Mosh
Рет қаралды 869 М.
How to use the Repository Design Pattern in C# and ASP.NET
18:35
tutorialsEU - C#
Рет қаралды 11 М.