Why I Use The Unit of Work Pattern With EF Core | Clean Architecture

  Рет қаралды 61,147

Milan Jovanović

Milan Jovanović

Күн бұрын

Get the source code for this video for FREE → the-dotnet-weekly.ck.page/uni...
☄️ 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
In this video, I talk about how to implement the Unit of Work pattern with EF Core. I discuss what I think are the benefits of using the Unit of Work pattern and what could be some of the drawbacks. Do you consider the Unit of Work an anti-pattern with EF Core? I don't, but I have a good reason why.
Join my weekly .NET newsletter:
www.milanjovanovic.tech
Read my Blog here:
www.milanjovanovic.tech/blog
Subscribe for more:
kzfaq.info...
Chapters
0:00 Benefits of the Unit of Work
3:23 Adding behavior to Unit of Work
5:55 Unit of Work in action

Пікірлер: 185
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
Master the Clean Architecture: bit.ly/3PupkOJ
@AnotherFancyUser
@AnotherFancyUser Жыл бұрын
Hey Milan, how are you? Great content, please keep doing these videos!. I'm seeing a lot of questions that can be answered by going a little bit lower as to why we use patterns like these. Would you be interested in creating a video explaining SOLID with real examples? I know you make content for Ssr and up, but this can help a lot of people that maybe don't know about SOLID, and I think SOLID is the foundation to modern software, to have maintainable, testable, readable code. Also... which one do you like the most? a lot of people likes SRP, I do too but I love Dependency Inversion even more.
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
@@AnotherFancyUser That's a nice idea, I'll add that topic to my list. Gotta think of a clever way to present the topic
@efimov90
@efimov90 Жыл бұрын
kzfaq.info/get/bejne/rLSPnZRz2JalfIk.html but actually at this point when you go to 46 line - you have update sql log in console. So there are update call to database. And after at 48 we have new insert sql call. Should't we use transaction? And there are no locks at database, what if you have 2 requests in same time that will change diffent properties? And still i see a problem if you will use several UnitOfWorks at the same time. As example in desktop application. Shouldn't you nest repositories inside of Unit Of Work? And several scopes.
@YehorBachurinDev
@YehorBachurinDev 4 ай бұрын
Thank you for providing the code for free
@cleitonosti1756
@cleitonosti1756 Жыл бұрын
An excellent video, last week I ended up implementing it almost similar to what you show in the video. Although it is implicit that EF already has a Unit of Work behind it, many developers confuse the fact that the repository pattern is per entity, thinking that when giving savechanges only the entity itself will be saved. So the implementation of the pattern in this way is very clear and objective.
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
I like to have one way to things, and UoW achieves this easily
@vamvdotnet
@vamvdotnet Жыл бұрын
Excellent video, Milan! Thank you so much for sharing with us how your implementation of UoW + EF Core is!😀
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
Thanks! 😁
@majormartintibor
@majormartintibor Жыл бұрын
Thanks for this video Milan!
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
You're more than welcome 😁
@saidhalloun8640
@saidhalloun8640 2 ай бұрын
Great explication!, im new at Clean architecture and im learning a lot with your videos. Thanks Milan!
@MilanJovanovicTech
@MilanJovanovicTech 2 ай бұрын
Happy to help!
@stunna4498
@stunna4498 Жыл бұрын
I also enjoy using unit of work with the transaction pattern where you would tell if you want to use a transaction or not . In my case i used it by default so you could call multiple save changes and unless everything went well nothing would be commited ( it was a requirement to be like this)
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
That's a great use case and it makes a lot of sense
@takkerutube
@takkerutube 11 ай бұрын
Excellent video! Thank you!
@MilanJovanovicTech
@MilanJovanovicTech 11 ай бұрын
Glad you liked it!
@igeoorge3g
@igeoorge3g Жыл бұрын
to the sky milan 😜thanks for sharing
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
You're most welcome! Thanks for watching 😁
@stef2528
@stef2528 3 күн бұрын
Thank's for this very competent nice presented and insightful explanations! I will definitlely recommend you anyone I know who could be intrerested in your channel.
@MilanJovanovicTech
@MilanJovanovicTech 3 күн бұрын
Much appreciated!
@carmineos
@carmineos Жыл бұрын
It would be nice to see this in action without EF, with things like Dapper or simply with repositories and ITransaction
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
You would have to implement your own Identith Map, would be interesting surely
@kvloover
@kvloover Жыл бұрын
uow and repositories get alot of undeserved hate these days. If you think UoW and Repo's are going to make your life easier use them. If you think you can manage and do without, don't use them. People should stop forcing their opinions on others. Good intro into why you use them and how you do so.
@AnotherFancyUser
@AnotherFancyUser Жыл бұрын
"these days" since they existed, but some people don't understand why they hate it. For example IStudentRepository, "you are just creating an abstraction on top of an abstraction, dbContext is a Unit of Work and DbSet is a Repository! harrr harr harrr!" (they say). But the day you want to change data providers, you have the repository abstraction and is only a matter of creating a new class that satisfies implementation detail for that new Data provider. Not only that, whoever uses your repositories don't use concrete classes, it uses an abstraction and that high level module wont depend upon a concretion ( new StudentRepository() ) but the other way around, these complies D in SOLID (High-level modules should not import anything from low-level modules, both should depend on abstractions (e.g., interfaces). Abstractions should not depend on details, details (concrete implementations) should depend on abstractions), which a lot of people don't use them and at the same time they want testable, maintainable, readable code (Insert John Travolta pulp fiction meme). Of course, make the interface as generic as possible, I mean, don't marry to concretions or expressions that maybe a data provider cant use (LINQ to SQL). But in these days EF is so big, so good (that's what she said) that we have NuGet packages to work with a lot of data providers out there with EF. Anyways, is all fine and dandy to know different strategies and design patterns, but never forget why they exist, they exist because there is a common underlying issue that can be solved by a particular design pattern but also these design patterns usually follow SOLID.
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
I try to be careful when talking about these topics. I always talk from a personal perspective, _how_ and _why_ I use certain patterns even though a large portion of the dev community dislikes them. At the end of the day, I'm happy with the choices I make on my projects and I'm yet to run into problems because of it.
@pilotboba
@pilotboba Жыл бұрын
@@AnotherFancyUser How many times have you replaced the database provider? EF even lets you do this. Sure, if you wrap EF you can change to say NHibernate. But who does this? YGNI
@psyaviah
@psyaviah Жыл бұрын
​@@AnotherFancyUser for most projects, this never happens in their lifespan. Be pragmatic IU'd say - you can then just change the actual provider you connect to EFCore when setting it up. Yes, yes, I know you will have to change some command handler things if the db doesn't support some things. But you'd have to rewrite all implementations of the repos & unitofwork too. Which is a ton more work. (I)DbContext effectively is flexible enough now, to change the dbprovider. And with the Command/Query pattern, well, change the query/db specifics. You have integration tests in place as well (I hope) to an actual db so you then can verify the outcome and see if it's still the same. So, personally, I see no benefit here. I used to see a benefit when this was all locked away and not open to change - but we moved on a long time ago. DbContext is flexible enough in 99% of the situations and I recommend people learning the intricate nature of it instead of using old patterns that add no value. So I don't like UoW or Repo-patterns. If you need more complicated setup, then you probably would write your own kind of ORM & db-setup even when you have to deal with very complex and specific stuff. Yeah, no repo-patterns, the logic belongs in the command. Even if it's kind of duplicate at first. You never know how your business logic may change. Sometimes code looks the same and you abstract it away in a repo or service, but is it actually the same business use case? No. So when something changes, you then have to split that. I like it when I have to change one thing only in the command-handler, and I know that affects then only one command handler.
@mohammad_mr
@mohammad_mr Жыл бұрын
Excellent
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
Thanks!
@PaulSebastianM
@PaulSebastianM Жыл бұрын
Now this is useful!
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
I appreciate your unbiased comments. 😁
@PaulSebastianM
@PaulSebastianM Жыл бұрын
@@MilanJovanovicTech Hahaha! Will try to do my best! 😉
@fernandocalmet
@fernandocalmet Жыл бұрын
This is how we could add an optional parameter in the UnitOfWork to capture the Creator Guid to be able to set it in the audit columns. Excellent video Milan, Thanks! 😃
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
Or you can inject a service and resolve the userId
@stevehiggin
@stevehiggin Жыл бұрын
In IUnitOfWork the SaveChangesAsync() method would this not be marked as async and then you would await _dbContext.SaveChangesAsync() as well?
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
You can make it async, and await _dbContext.SaveChangesAsync It's awaited in any case in the end
@graylee9567
@graylee9567 Жыл бұрын
Sometimes its required to perform several save points/SaveChanges() calls and wrap it into transaction, EF is already implemented as Unit Of Work but because there is no control over commands order (DELETE/UPDATE/INSERT) in that case UnitOfWork pattern should have some Begin/Commit/Rollback transaction inside.
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
What do you mean there is no order? I'd say there's a very logical order in how EF executes DELETE/UPDATE/INSERT commands
@graylee9567
@graylee9567 Жыл бұрын
@@MilanJovanovicTech I mean in case you need that Add/Remove/Update to be executed in the same order they were called from code you need several SaveChanges and wrap it into transaction
@taleslopes9421
@taleslopes9421 Жыл бұрын
Thanks for sharing knowledge, my problem if UOW and Repository wrapping EF is to make queries with eager loading (Include), specific filters and group by, I have to make a method that will be used just 1 time, turning my repositories into a giant bloatware, there is any way to solve this and still detach the EF dependencies in the application layer?
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
From what you're writing, you are probably using filtering/group by on the read side. I would suggest not using repositories to wrap Read queries. If you still want to abstract away EF for those use cases, you can create some simple abstraction like IDataRequest which has a generic request/response
@sorteslyngel2k
@sorteslyngel2k Жыл бұрын
Hi Milan, thanks for the content. Really appreciate it. Do you know if using saveChangesAsync like this actually acts as a transaction against the db? That is, if one of the inserts fails, they are all rolled back?
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
Yes learn.microsoft.com/en-us/ef/core/saving/transactions#default-transaction-behavior
@psyaviah
@psyaviah Жыл бұрын
@@MilanJovanovicTech Indeed, but your db needs to support this. So talk to your db admin first to make sure this scenario is supported.
@adrielairaldo
@adrielairaldo 10 ай бұрын
Hello Milan! First of all thanks for the material you share. I am interested in decoupling the Unit of Work with the Repositories, in terms of having to have the reference of each repository in the unit of work (it is tedious to have to update the UoW for each new repository), and I see that in your example you are doing it. The idea I'm implementing now is through Dependency Injection in Scoped mode, so that repositories can consume the UoW just like higher order services (like Handlers, for example). I would like to know your thoughts on this :) Thanks!
@MilanJovanovicTech
@MilanJovanovicTech 10 ай бұрын
I think it's justified, as long as you accept that all repository methods will now have to complete the UoW
@alexkovanev1425
@alexkovanev1425 Жыл бұрын
If your ApplicationDBContext class starts implementing IUnitOfWork, you don't need to have an extra UnitOfWork class.
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
Agreed, but then you'll start putting a lot of logic inside of the DbContext. And I like to keep it clean. That being said, I've used the approach you're describing and it works great.
@InfinityFnatic
@InfinityFnatic Жыл бұрын
DbContext already implements a heavily abstracted Unit of Work, Repository and Transaction pattern, no need to abstract it even further and throw a leaky API at your team. It is beyond me why people are sticking to the custom repository and unit of work dogma.
@DoctorMatt6
@DoctorMatt6 Жыл бұрын
@@InfinityFnatic I think it is much easier to unit test your business logic with repository/uow pattern, but I don't see any more benefits from using it
@juankasem4911
@juankasem4911 Жыл бұрын
@@DoctorMatt6 And what if you need a shared dbcontext among multiple repositories that is needed to perform a single transaction(ex: case to update multiple database entities: update bank accounts for sender and recipient nd update the cash transfers tables, etc... )
@krccmsitp2884
@krccmsitp2884 Жыл бұрын
Milan applied the composition over inheritance pattern here for better decoupling.
@dejansavanovic4476
@dejansavanovic4476 Жыл бұрын
For web API-s do you prefer to use EntityFramework with connected change tracking or with disconnected change tracking?
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
When I want to insert/update/delete, then I want change tracking enabled
@juankasem4911
@juankasem4911 Жыл бұрын
We would like to make you a video about the Error response class & the FluentValidation implementation
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
Check this out: kzfaq.info/get/bejne/bpuUq9qVna7edZ8.html
@waleed-alshinawi
@waleed-alshinawi Жыл бұрын
Thank you Milan for the great videos that you making, am always learning new things from you :). I wanted to ask for your opinion for the approach that you've presented in this video, where you Set the Modified_Date in the UnitOfWork, isn't the responsibility of the Domain to set the modified_date / creation_date, because i've seen the same approach used for soft delete, where they change the entries with state = deleted to updated and set the deletion_date instead im just carious to know what you think about this point of view Thanks again for the amazing efforts you're putting
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
When I place the logic in UoW it saves me from writing a lot of code in the Domain entities. Don't you think so?
@waleed-alshinawi
@waleed-alshinawi Жыл бұрын
@@MilanJovanovicTech Totally agree with you
@samehkeshta89
@samehkeshta89 Жыл бұрын
Great
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
Thanks!
@ismaelperezmesa524
@ismaelperezmesa524 Жыл бұрын
@Milan Jovanović Thank you so much for all your effort by sharing your knowledge with us, every lesson is greater. I would like to ask you something that is really urgent to me: How can I dockerize a project like this(ddd clean arch) we are studying with you, for deploying as a container on a cloud? Please, Can you or another people here, share the way or an example to achieve it? Thanks a lot, you're amazing!
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
Releasing a CICD video on Friday. If that's too late, I can find some resources for you
@ismaelperezmesa524
@ismaelperezmesa524 Жыл бұрын
@@MilanJovanovicTech Thanks a lot! I really appreciate you for answering. I could wait until Friday, but really any advance before would be useful and saving for me. Thank you again!
@sky3913
@sky3913 2 ай бұрын
Hi Milan, thanks for sharing. I have some questions 1. Should we also implement IDisposable in IUnitOfWork? 2. I see you defined IUnitOfWork in Domain.Repositories, but in other video, you defined in Application.Data, which one is appropriate and why? 3. I see in some resources, the repositories are defined in UnitOfWork, where do you define them? 4. I also saw in other video you're using TransactionScope, what's the difference with IDbContextTransaction for handling Transaction?
@MilanJovanovicTech
@MilanJovanovicTech 2 ай бұрын
1. If you're creating resources manually 2. That's for you to decide. Which one makes more sense, and why? 3. Separately 4. learn.microsoft.com/en-us/dotnet/framework/data/transactions/implementing-an-implicit-transaction-using-transaction-scope
@MarcusKaseder
@MarcusKaseder Жыл бұрын
I'm a bit confused about your overall approach. You said one reason to use UoW is that you don't want do pollute your Application layer with entity framework. IoC magic. In another video, you've mentioned that you use the repository pattern only for edit purposes. Repositories read only data that are required for editing. For queries, you tend to use the dbcontext directly. Is that correct? Am I missing something? If so, you have to "pollute" your application layer with entity framework to do your queries, right?
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
| For queries, you tend to use the dbcontext directly. Yes! I just abstract it behind an interface. I'll make a video explaining the idea here.
@vAmp1que
@vAmp1que Жыл бұрын
Milan, great job again. Am I wrong that we could move our common logic of IRepositories to the generic IUnitOfWork? It looks like we incapsulate the dbContext data inside one place. What do you think about this point?
@AnotherFancyUser
@AnotherFancyUser Жыл бұрын
You want different classes to do what they suppose they have to do (depending on you of course), SRP (Single Responsibility Principle) states "A class should have a single responsibility and this responsibility should be entirely encapsulated by the class, a class should have one reason to change", so your UoW will save the changes, and the repositories will create the transactions.
@vAmp1que
@vAmp1que Жыл бұрын
@@AnotherFancyUser yeah sure you're right that my described case actually have large troubles, but it's interesting how our mate will answer the question:) Just conversation at tech topic, you know:) Huge respect to him and yours opinions, much love!
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
Hey Alexey, how's it going? 😁 So how would this generic UoW behave? We would end up with one UoW per entity type? This kind of defeats the purpose of having the UoW in the first place. 🤔 Curious to hear more.
@vAmp1que
@vAmp1que Жыл бұрын
@@MilanJovanovicTech kinda well, and you? About subject: exactly. One UoW per entity type. It could prevent creation of repositories at some scenarios. But, as our friend above wrote, this usecase destroys single responsibility principle. But in my experience I prefer to use generic baseRepository, where I have all the logic and if I need something uncommon, I could extend my baseRepository using inheritance. Imho it's the best approach for me)
@bitukr.nirala3377
@bitukr.nirala3377 Жыл бұрын
With Entity Framework 4.x tried updating automapper and it crashesh due to multiple reason and finally again had to stay with same version. Please suggest the approach
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
No idea what's going on there
@amantinband
@amantinband Жыл бұрын
I keep going back and forth about both the repository and UoW patterns. It adds a cognitive load for engineers onboarding the project. Especially since these patterns usually come on top of CQRS, Clean Architecture, and DDD. Is it worth it? Do these patterns add enough value to justify their usage?
@amantinband
@amantinband Жыл бұрын
Great video non the less. Thank you, Milan!
@pilotboba
@pilotboba Жыл бұрын
I don't think it is. Also, you can mock dbcontext just as well as your customer unit of work if you provide an IDbcontext in your application layer. Yes, before interceptors were a thing the unit of work was a nice way to provide those types of features. But, even without that, you can add those types of things to your DbContext SaveChanges override too. Of course, YMMV.
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
I don't get where these complexity/cognitive-load arguments come from. It's one interface. With one method. How hard can it be? You want to persist changes at the end of your business operation, and there's only one way to do it with this design. I think that's as simple as we can get. Curious to hear what you think Amichai.
@alexkovanev1425
@alexkovanev1425 Жыл бұрын
@Amichai Mantinband Short answer: if you don't wish to tie your application layer to the specific data access implementation, then repositories + UoW is an option. Real life example: you work for an organization which has a lot of different microservices leveraging both relational and nosql databases. For each microservice you have the same standards, like Clean Architecture, CQRS and so on. You expect the similar common code base, in particular for infrastructure both SQL Server + EF Core and MongoDB + MongoDB Driver respectively. (I'm not discussing + and - of that 'common code' approach here). Besides that, one day you may want to change the db. How would you achieve this w/o repositories and UoW?
@psyaviah
@psyaviah Жыл бұрын
@@alexkovanev1425 for most projects, this never happens in their lifespan. Be pragmatic - you can then just change the actual provider you connect to EFCore when setting it up. Yes, yes, I know you will have to change some command handler things if the db doesn't support some things. But you'd have to rewrite all implementations of the repos & unitofwork too. Which is a ton more work. (I)DbContext effectively is flexible enough now, to change the dbprovider. And with the Command/Query pattern, well, change the query/db specifics. You have integration tests in place as well (I hope) to an actual db so you then can verify the outcome and see if it's still the same. I see no benefit here. I used to see a benefit, but it's totally gone for me now. DbContext is flexible enough in most situations and I recommend people learning the intricate nature of it instead of using old patterns that add no value. So I don't like UoW or Repo-patterns. Yeah, no repo-patterns, the logic belongs in the command. Even if it's kind of duplicate at first. You never know how your business logic may change. Sometimes code looks the same and you abstract it away in a repo or service, but is it actually the same business use case? No. So when something changes, you then have to split that. I like it when I have to change one thing only in the command-handler, and I know that affects then only one command handler.
@christopherfox6914
@christopherfox6914 11 күн бұрын
Do you think it is a bad idea to also create and set the Guid for created entities inside the UnitOfWork similarly to DateTimes of auditable entities?
@MilanJovanovicTech
@MilanJovanovicTech 10 күн бұрын
You'd typically do that while creating the entity (constructor/factory method).
@WayneMunro
@WayneMunro Жыл бұрын
EF core service this purpose on its own. If you take a dependency on EF you may as well use it.
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
I am using it, just not exposing is as a dependency to the Application layer
@empireofhearts
@empireofhearts Жыл бұрын
In case of dealing with dependent entities where you have to save mutiple entities & need to call save changes only once for some transactions and save single entities in some other transactions thats where Unit of work will start crumbling as domain layer is not where you started UOW to know which domain will call SaveChanges and which ones doesnt. also wouldnt this add one more item to the list of DI constructor args that need to be maintained?
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
Why would we mix multiple domains a single business operation (transaction)?
@empireofhearts
@empireofhearts Жыл бұрын
So let's think of scenario where we have investigation and dependent on that is investigators. A single investigation can have multiple investigators so they stored in diff tables with investigation ID as the foreign key. When investigation data is getting selected investigators are also selected and sent along with it. So now both need to saved at same time as investigators cannot be saved until investigation is saved. The same scenario is applicable in various situations in real world business applications.
@jbb4play
@jbb4play Жыл бұрын
Hey, I was wondering if you could do a video on this one issue. On entity framework, lets assume we have a person entity with the following properties. firstname, lastname, age, email If we do a PUT from postman, we do some validation on each property, and tell entity framework to update all properties, easy peasy. However, if we do a PATCH, and only patch firstname and age, then if you are not careful in what do you, entity framework might possibly set the other properties to null or 0. I always find this to be rather annoying to handle, not difficult just VERY annoying, so I am very curious as how other people handle it.
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
Would you not first load the entity to memory before applying the PATCH?
@mariuskoen1
@mariuskoen1 Жыл бұрын
Do you have a complete example of the source code as well, I have been looking for a complete example for a very long time now 😐
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
Yes, I share it on my Patreon
@hmsiegel79
@hmsiegel79 Жыл бұрын
Milan, I noticed after making these changes that I'm getting a circular dependency exception in regards to the MemberNameChangedDomainEvent. Any idea why?
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
How is that even possible? What's in there that could be causing a circular dependency injection?
@hmsiegel79
@hmsiegel79 Жыл бұрын
@@MilanJovanovicTech I'm not sure. It's weird because when I switched to another box that I'm running, I don't get the error.
@hmsiegel79
@hmsiegel79 Жыл бұрын
@@MilanJovanovicTech So, I initially still had the lines in the ProcessOutboxMessagesJob for Polly , to retry on failure. With those in there, the applicaiton will not run. If I remove them and go with the default implementation, I can run the application but there's still an error in the console. I am a Patron, so we can continue there if that would be easier.
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
@@hmsiegel79 Sent you a message
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
@@hmsiegel79 Seems I'm having issues sending you a message on Patreon. Can you try messaging me?
@mahfoudbouabdallah6286
@mahfoudbouabdallah6286 Жыл бұрын
You mentioned that postgreSql is smarter than SQL Server can you please explain the advantages about using postgreSql over SQL Server
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
I was talking the EF providers for SQL Server/PostgreSQL. The PostgreSQL provider handles change tracking better, from my experience.
@microtech2448
@microtech2448 Жыл бұрын
Can you please create video on working with ef core and parallel foreach? In parallel foreach method with some max degree of parallelism greater than 1, when you use dbcontext to get and save entities, it crashes. Which is due to multiple threads. Can you create video on right implementation of it? Thank you
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
That's how it is supposed to work. The DbContext is not thread safe. If you want to achieve what you're talking about, you need to create one DbContext per thread and then use that.
@microtech2448
@microtech2448 Жыл бұрын
@@MilanJovanovicTech I have read this at various places but I don't understand how it should be implemented? So, can you please create implementation video on same? So in nutshell, I have parallel foreach loop. Within it I am calling business layer method. This method calls data layer to fetch entity using dbcontext. I do some operations on fetched entity and calls another data layer method to save updated entity. And then after some iterations program crashes. I have configured dbcontext in startup as transient btw.
@microtech2448
@microtech2448 Жыл бұрын
@@meetingattender8132 I had tried this earlier with no luck, I will try again.
@seekmanish
@seekmanish 11 ай бұрын
​@@MilanJovanovicTech where can I download the source code that you used for this demo?
@janhendrych1076
@janhendrych1076 4 ай бұрын
Hi, does this mean that after I implemented the unit of work like this, then I can delete the ConvertDomainEventsToOutboxMessage Interceptor?
@MilanJovanovicTech
@MilanJovanovicTech 4 ай бұрын
Yes
@janhendrych1076
@janhendrych1076 4 ай бұрын
@@MilanJovanovicTech thanks man, your videos are golden + you reply to all comments. Legend💯
@MilanJovanovicTech
@MilanJovanovicTech 4 ай бұрын
@@janhendrych1076 I try to bring value. If this is how I can be different (better?) form other creators, so be it. 😁
@omarjamil5688
@omarjamil5688 Жыл бұрын
why you don't add await keyword for SaveChangeAsync method on UnitOfWork Class
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
Don't need to await it there
@02244
@02244 Жыл бұрын
EF Core already implements UnitOfWork and Repository patterns. You just created an abstraction on top of the abstraction and lose all the benefits of EF Core, such as working with IQueryable, lazy loading & etc.
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
How am I losing any benefits of EF Core if I'm using EF in the implementation? I would be careful calling lazy load an advantage, it introduces more problems than it solves.
@nanvlad
@nanvlad Жыл бұрын
It looks like an abstraction over abstraction. The only worthy case I see in using additional interface is when you don't want to expose dbContext for other assemblies and want to keep all db logic inside a single ef (persistence/dal) library. But in current implementation we just hide 2 additional methods behind IUnitOfWork interface and call them before SaveChanges(). As for me it makes logic more complicated but code become more clear. What if I need to make different method calls before SaveChanges(), e.g. in 1 scenario I want to call method1, in 2nd - method2 only, in 3rd - method2 and then method1? Should this be implemented via single IUnitOfWork interface, like UnitOfWorkMethod1 : IUnitOfWork, UnitOfWorkMethod2 : IUnitOfWork, and UnitOfWorkMethod2BeforeMethod1 : IUnitOfWork? It's just a mess, maybe I don't get the point of this pattern.
@Petrovich2049
@Petrovich2049 7 ай бұрын
@@nanvladI think it’s better to rename SaveChangesAsync to DoWork(), and call savechanges on dbcontext outside of unit of work, and/or add a flag to save changes with true/false as default value. This way you can compose units of work and save changes when needed.
@user-yx4po9tt8z
@user-yx4po9tt8z 5 ай бұрын
if i want to use transaction queries in my project .this pattern can be a right approach?
@MilanJovanovicTech
@MilanJovanovicTech 5 ай бұрын
Might be
@user-yx4po9tt8z
@user-yx4po9tt8z 4 ай бұрын
is there a better way?@@MilanJovanovicTech
@pavelromashuk237
@pavelromashuk237 Жыл бұрын
What are the benefits when you take your logic out of interceptors and put it in savechanges method?
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
You'd have access to DI in the DbContext which can take in Scoped services Other than that, no difference
@pavelromashuk237
@pavelromashuk237 Жыл бұрын
@@MilanJovanovicTech Did you mean services from DI?
@DJohn001
@DJohn001 Жыл бұрын
Sorry, probably I missed the answer about the question you give yourself. Why do you use Unit of Work? You have shown that is can be used to sent the outboxmessage enz. but that's not needed anymore. My personal opinion is that it is a nice pattern to know in a few specific cases but I think it's usage is most of the time something of the past. As you did before, you could add this example functionality better/also in a different way by using EF middleware (I don't know if that's the right name). To me it looks like EF itself is already a Unit of Work pattern. So, why duplicate that?
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
I'm sure you listened to what I said in the video, but let me reiterate: - UoW represents a transaction boundary - Exposes only one way to persist changes to the database - Allows for flexible design, where I can add logic before/after saving changes
@psyaviah
@psyaviah Жыл бұрын
@@MilanJovanovicTech but, - multiple DbContexts are possible with multiple DbSets if need be to seperate it if you'd want to have that boundary; or via an interface if you'd like - DbContext does indeed expose more ways to persist to the db, but that's the power of it. If you want to take that away, and you'll need it someday, you'll have to duplicate it again in the UoW class. Then others can use it as well and you'll be introducing exactly the same kind of "multiple ways to persist to the database" - EF Core 6 & 7 are enormously flexible in their design, I'd say more flexible even. In this example you only moved code from EF Core interceptors to your own baked UoW that worked before. I don't see tha argument that UoW is more flexible than EF Core's DbContext then ;).
@yondaimefourth
@yondaimefourth 3 ай бұрын
Is it necessary to use UoW for read operations?
@MilanJovanovicTech
@MilanJovanovicTech 3 ай бұрын
No
@yondaimefourth
@yondaimefourth 3 ай бұрын
@@MilanJovanovicTech if I have uow and generic repo, is it correct just use the gerenic repo for read operations?
@goolom
@goolom Жыл бұрын
Perhaps it would be better to tie those “update auditable entities” and the other method at 5:00 to the DbContext - OnSaveChangesEvent? Is there a reason why you didn’t do this? That seems like a global event, and it seems intuitive to tie global events to the dbcontext itself, rather than a wrapper that abstracts logic further away - what do you think? - I can see the case that perhaps you have multiple UnitOfWorks and you don’t want to tightly couple the logic to the DbContext itself
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
I explored placing that logic inside of SaveChangesInterceptor in a separate video. I'm not aware of an _OnSaveChangesEvent_ on the DbContext? In any case, I wouldn't advise using events because it's more difficult to test..
@elpe21
@elpe21 Жыл бұрын
@@MilanJovanovicTech What he means is to override SaveChangesAsync
@alessandrovangeli8395
@alessandrovangeli8395 9 ай бұрын
Can I see the implementation of a repository? I dont understand how it works. A unitofwork class is coupled to some repositories? It cannot reference to any repository class? Thanks
@MilanJovanovicTech
@MilanJovanovicTech 9 ай бұрын
It's using EF Core under the hood
@alessandrovangeli8395
@alessandrovangeli8395 9 ай бұрын
@@MilanJovanovicTech you mean some configuration inside the program.cs?
@i.t.9015
@i.t.9015 Жыл бұрын
In my opinion UnitOfWork pattern adds more complexity to project if it is not necessary. So, lets talk about situations when it becomes necessary and how often this situation can occur.
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
Where do you think the complexity lies? It's a relatively simple wrapper. It has one only responsibility. It's behind an interface, so it's easy to consume.
@kabal911
@kabal911 Жыл бұрын
I think if you use repositories then unit of work is a no brainer. It makes transactions simple. If your are a heathen like me, that let’s his features/business logic use dbContext directly, as needed, on a case by case basis, then it doesn’t make much sense.
@user-fe8mu4zj5g
@user-fe8mu4zj5g 5 ай бұрын
Hi @MilanJovanovicTech Everything looks nice but it will only work if AddDbContext has Scoped lifetime. If not, repositories and UoW can have different DB context so I suppose your solution would not work. What about getting repositories via unit of work to be sure they share the same db context? How to solve this problem?
@MilanJovanovicTech
@MilanJovanovicTech 5 ай бұрын
I always use Scoped. When did you need to do it differently?
@user-fe8mu4zj5g
@user-fe8mu4zj5g 5 ай бұрын
​ @MilanJovanovicTech To be honest it does not matter when (I also used Scoped) but the problem is that there is such a possibility, so better to point this out at the beginning. Besides this I have few questions: 1. Why does your db Context implement IUnitOfWork? What's the point? 2. I am not convinced to have separately UnitOfWork and repositories. What about a custom AppUnitOfWork with db context and respositories in constructor (I assumed also here scoped "version") which provides repositories by Properties so then query/command handler or just a service has IAppUnitOfWork injected in constructor (not repositories)? What do you think? There is other advantage - if somehow you decide to use other than scoped db context, than you can just change AppUnitOfWork: Repositories would be created (new (...) with the same db context when they are called first time (unfortunately there is no possibbility I think to do it using DI) 3. When do you use IApplicationDbContext interface? I usually create db context without interface. In which situation do you use it?
@user-xn5do6xc1u
@user-xn5do6xc1u Жыл бұрын
Shouldn't the repositories be inside unit of work? Otherwise, they will work on different dbcontext and Unit of work save will not save repositories.
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
I dislike that approach
@OrientAryan
@OrientAryan Жыл бұрын
Please share github link for this complete example code.
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
I share the code with my Patreon supporters only
@rickyrick6901
@rickyrick6901 9 ай бұрын
Hi Milan, thank you for this super video ! I still have 2 unresolved points in my head, could you help ? 1. If this time, we had a CreateMemberCommand (instead of Update), and wanted to use this member created ID to update an other Repository (say XRepository) in the same handler method, so just before commiting with the Unit of Work (in order to keep consistency between the 2 corresponding tables (MemberRepositories and XRepositories)). Wouldn't it be mandatory to call twice the UoW commit method : i mean a first call to it, in order to get the member ID available provided by EF ? 2. In a DDD approach, they say : 1 Repository by Aggrgeate, where an Aggregate is responsible for ensuring consistency between the entities that it owns and controls. So does it mean (with EF) that the MyDbContext encapsulated into this MyRepository, will contain as many DbSet as necessary to handle the entities of the corresponding Aggregate, and so that this MyDbContext only makes sense for this particluar MyRepository ? While, there would be only 1 MyUnitOfWork for this MyDbContext , so related to only 1 Repository : MyRepository ? Finally meaning in most cases : 1 UoW by DbContext, and 1 DbContext by Repository, so 1 UoW by Repository (Aggregate) as indeed the UoW is also Responsible for consistency o f the persisted DbContext data ?
@MilanJovanovicTech
@MilanJovanovicTech 9 ай бұрын
1. Call it twice, yeah. Or generate ID on client side (Guid) 2. I think you're overthinking it 😁 DbContext = UoW, DbSet = Repository
@rickyrick6901
@rickyrick6901 9 ай бұрын
@@MilanJovanovicTech Thanks Milan for sharing your advices.
@AdCodicemFR
@AdCodicemFR 6 ай бұрын
I'm not sure to understand why placing in the unitofwork the methods that were in the interceptors is better? Aren't the responsibilities of each interceptors merged into one big unitofwork ?
@MilanJovanovicTech
@MilanJovanovicTech 6 ай бұрын
Yes, they are
@AdCodicemFR
@AdCodicemFR 6 ай бұрын
@@MilanJovanovicTech So, to separate concerns it could be interesting to keep the interceptor. As you showed in your video on using the DbContext as the repository, I think that I'll use the same approach for the UnitOfWork pattern. Anyway, you make great videos, keep going!
@gauravsingh-qt2zo
@gauravsingh-qt2zo Жыл бұрын
What is the advantage of using razor pages, aspx when we have frontend frameworks like angular,react?????
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
What does that have to do with the video? 😂
@gauravsingh-qt2zo
@gauravsingh-qt2zo Жыл бұрын
@@MilanJovanovicTech sir i want your help. I am stuck at one issue from last 2 days. We are using proxy server. My task is to get the client ip address. Instead I am always getting the same ip address from different client machine and that ip address is 99 percent the ip of the proxy server. I have used useforwardheaders middleware with all the combination of parameters and also included the ip address of the proxy server in the knownnetwork option. Still i am not getting the client ip address. Please help me. Your help would save my job.
@helen6400
@helen6400 Жыл бұрын
Hi, Have you ever tried to create a middleware with this unitofwork class? Instead of injection to the services it will work at every request. Maybe we have to check if the request is not a get request. I am not suggesting. I am only asking if you know smt about using this pattern in a middleware
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
I did. And it sounds like a good idea on the surface. But you could run into problems if at any point you _need_ to call SaveChanges more than once in a single request.
@Andy01010
@Andy01010 Жыл бұрын
Unit of work with repositories inside via Lazy in my case…
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
I tend to avoid that approach, as I think it becomes complicated quickly
@psyaviah
@psyaviah Жыл бұрын
@Milan Jovanović I don't understand the reasoning here. What is the actual benefit of using it - you did not explain it? Testing with DbContext is possible as well, and I always do that in an integration way aka testing against an actual db (localdb) as well as on my build server a localdb is setup, and then I can see if everything works on that end. As EF sometimes lets you write code that doesn't translate well to SQL, and you need to test that of course. Either way, I really don't see a benefit to use this. It might even complicate things further for newcomers. Yes, you expose a whole DbContext to newcomers, but isn't that the path to learn the developers and let them grow & know immediately. I feel this only adds complexity and code duplication - which I try to avoid. You mentioned you do use the DbContext on the "read"-side (aka queries) directly - even set changetracking off there for example with AsNoTracking(). Again, this might be me, but without more compelling arguments that would help junior developers, this is exactly the same and adds extra complexity. So it doesn't convince me. I would argue even; it would be more beneficial to abstract those things away for a READ-side, so you'd be able to mix both Dapper or EFCore behind a readonlyrepo for example + implement specifics on your reads/queries that you want optimized etc..?
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
You just argued for using the DbContext in the first half of the comment, only to do a 180 and propose a repository for reading in the second half. 🤔
@psyaviah
@psyaviah Жыл бұрын
@@MilanJovanovicTech no, to clarify, I said I think IF you'd be using repos maybe you could optimize for codereuse & AsNoTracking better in the read-side already and abstract that away. But to be clear, not very happy with that either. I only said it would make more sense to me then.
@psyaviah
@psyaviah Жыл бұрын
Also, to be clear, I wouldn't do all of this and I advice against it. But I value other opinions, hence why I am still subscribed and I value other reasoning. We're all here to learn and exchange ideas in this (very young) software industry. And what works for someone, or some teams, might not for others. So thanks for making the videos & spreading your ideas and being open in the comment section! That is actually very helpful. Sorry if I'm brash/harsh - but mind that it is written/typed, it's not meant to be hateful!
@iliashterev38
@iliashterev38 Жыл бұрын
Well, first of all, my thinking is that those are hancy fancy games and philosophies that just complicate the code. But if I go and play the game I would say that what you explained was not a unit of work. It would say that this is an extension of a repository. Unit of work should not contain DbContext within it. It only gets multiple repositories injected in it and then it gets injected into say Controllers. In the controller it uses the injected repositories as properties and through them it just calls their methods, etc. Kind of another level of abstraction between the controller and the repositories. Ex: public class UnitOfWork : IUnitOfWork { public IProductRepository Products { get; } public UnitOfWork(IProductRepository productRepository) { Products = productRepository; } } ------------ public class ProductController : Controller { private readonly IUnitOfWork _unitOfWork; public ProductController(IUnitOfWork unitOfWork) { _unitOfWork = unitOfWork; } ---------- [HttpGet] public async Task GetAll() { var data = await _unitOfWork.Products.GetAllAsync(); return Ok(data); } public IProductRepository Products { get; } Now, to me the best of my knowledges injecting means instantiating an object and then injecting it. So here comes the big sh_t - if I have 50 entities in my project and respectively 50 repositories then each time I use that Unit of work then I have 50 object instantiated only to use 1 or 2.
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
What about explicit dependencies principle? With this UnitOfWork, it's not really clear which repository you need along with the UnitOfWork.
@iliashterev38
@iliashterev38 Жыл бұрын
@@MilanJovanovicTech " it's not really clear which repository you need along". That was exactly what I was trying to say. If a projects has 50 entities then the unit of work will have 50 repositories instantiated each time and injected. And only one or two will be used.
@sauravbhatta5303
@sauravbhatta5303 Жыл бұрын
Nice pattern.
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
Many many thanks
@antwanwimberly1729
@antwanwimberly1729 8 ай бұрын
Wouldn’t it be easier to use rails
@MilanJovanovicTech
@MilanJovanovicTech 8 ай бұрын
Rails?
@metehanmutlu9187
@metehanmutlu9187 11 ай бұрын
Using repository and uow pattern on top of ef core only makes sense if you want to make your application layer orm/database agnostic and it does not worth the effort in my opinion.
@MilanJovanovicTech
@MilanJovanovicTech 11 ай бұрын
Oh, it's worth it in the long run as the project grows in complexity
@marna_li
@marna_li Жыл бұрын
So now you mean that I should revert my changes from when moving to interceptors.... ??? Haha
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
I don't mean that! haha I just like to explore and present the many possible options we have. It's on you to choose what you like. This approach supports supports Scoped DI, so take that as a consideration.
@marna_li
@marna_li Жыл бұрын
@@MilanJovanovicTech Yes. It is about requirements and preference. I do get that it might be more logical to put logic in Unit of Work. Discoverable. I register my Interceptors and scoped in the DI. A bit of wiring in AddSqlServer/AddDbContext but it works.
@techpc5453
@techpc5453 Жыл бұрын
@MilanJovanovicTech
@MilanJovanovicTech Жыл бұрын
👋
@antwanwimberly1729
@antwanwimberly1729 8 ай бұрын
It doesn’t have to be with entity framework We did it with as user transaction at #lanetix If any code failed within the promise block which composes then guess what We j ew to rollback the request level transaction as you should only call that function once per request within the context of your request handler Wouldn’t it lead to nested transactions Remember the distributed transaction coordinator ?? Yiani was xxX Hmmmm Big Design Up Front
@MilanJovanovicTech
@MilanJovanovicTech 8 ай бұрын
Interesting approach 🤔
@microtech2448
@microtech2448 5 ай бұрын
Hello, in case of IAuditable, if we would want to save CreatedBy and UodatedBy as well, how would you plan to send existing logged in user identity into persistence layer within IUnitOfWork implementation?
@MilanJovanovicTech
@MilanJovanovicTech 5 ай бұрын
I'd inject it using the HttpContext.User.Identity.Name
@microtech2448
@microtech2448 5 ай бұрын
Hmm, I thought so but I was hesitant to go this route but your comment makes me comfortable to go through it. Thanks
Using Domain Events To Build A Decoupled System The Scales
14:02
Milan Jovanović
Рет қаралды 22 М.
EF Core Performance Optimization Challenge | 233x FASTER
14:42
Milan Jovanović
Рет қаралды 63 М.
I CAN’T BELIEVE I LOST 😱
00:46
Topper Guild
Рет қаралды 114 МЛН
- А что в креме? - Это кАкАооо! #КондитерДети
00:24
Телеканал ПЯТНИЦА
Рет қаралды 5 МЛН
Can You Draw A PERFECTLY Dotted Line?
00:55
Stokes Twins
Рет қаралды 111 МЛН
I Can't Believe We Did This...
00:38
Stokes Twins
Рет қаралды 101 МЛН
The Unit of Work Design Pattern Explained
12:37
ArjanCodes
Рет қаралды 21 М.
"I Hate Agile!" | Allen Holub On Why He Thinks Agile And Scrum Are Broken
8:33
My Favorite Code "Anti-Patterns" (Break These)
16:52
Conner Ardman
Рет қаралды 53 М.
Intel's CPUs Are Failing, ft. Wendell of Level1 Techs
23:59
Gamers Nexus
Рет қаралды 357 М.
How To Create Smart Enums in C# With Rich Behavior
17:31
Milan Jovanović
Рет қаралды 52 М.
Unit of Work in ASP.NET Core
14:57
Raw Coding
Рет қаралды 18 М.
iPhone 16 с инновационным аккумулятором
0:45
ÉЖИ АКСЁНОВ
Рет қаралды 8 МЛН
Klavye İle Trafik Işığını Yönetmek #shorts
0:18
Osman Kabadayı
Рет қаралды 2,2 МЛН
Зачем ЭТО электрику? #секрет #прибор #энерголикбез
0:56
Александр Мальков
Рет қаралды 219 М.