❔ How can I better understand the concepts of unit of work and repository pattern in C# .NET 7?
I am seeking assistance in understanding the unit of work and repository pattern in C#.NET7. While I understand that these patterns can help avoid code duplication, create a flexible and modular access layer, and improve code maintainability and scalability, I am having difficulty comprehending the code transitions and how they relate to UoW, Repository, and Interfaces. Could you please provide a more detailed explanation or point me to any helpful resources that can guide me in better understanding these patterns? Thank you for your assistance.
17 Replies
If you use Entity Framework Core, you will get a practical demonstration of these patterns because it implements both of them.
Thank you for your reply
To understand unit of work, you'll need to first understand what a "database transaction" is, and why its important
Repository is easier, its just a class that is responsible for accessing data of a given type. So a
PatientRepository
is responsible for accessing Patient data, whatever that might be or what technology is used to access it.
it could be from another API, a database, a file.. doesnt matter. The point is to abstract away the actual access code, and just expose methods that do the things you want
GetPatient(int patientId)
, RemovePatient(int patientId)
, AdmitPatientToWard(int patientId, int wardId)
etcDo I need to manually define methods like All(), GetById() inside a new repository every time I create a repository for a new model?
First, you should be aware that
ApiDbContext
is a unit of work, and contains DbSet<T>
s, which are generic repositories. There is little to gain by implementing a generic repository over an already generic repository.
If you are going to wrap EF in a repository, which I again suggest you don't, you should be aware of the very important difference between IQueryable<T>
and IEnumerable<T>
Anything you get from the DbSet<T>
will be of type IQueryable<T>
and can conceptually be thought of as an SQL query being built
If you do .Where
on it, that gets added to the SQL query
when you then cast it to an IEnumerable or do ToListAsync
or whatever on it, thats when the query actually gets executed
after that, all .Where
or similar is in-memory
As such, a method like your All()
here will realize the entire table in memory
if your goal is to return every single Driver, thats fine
but if you have code that looks like...
you are fetching a lot of extra dataI appreciate your response and the helpful tips you provided. I took note of all the information you shared as a reference for my future studies. However, I am still a bit confused about some aspects, so I decided to seek further clarification here.
On what aspects do you need further clarification?
I mean if what I'm doing is right or if the approach I'm taking is right, it's just things like that. I've just started learning this C#.NET, maybe I've only been in 2 weeks, and most of the tutorials I see have different implementations, so I'm even more confused.
First, you should be aware that ApiDbContext is a unit of work, and contains DbSet<T>s, which are generic repositories. There is little to gain by implementing a generic repository over an already generic repository.Yes, writing repositories over EF Core is sadly very common Some people to this day still think its a good idea. It is not, with few exceptions. This is mostly for historical reasons, as UoW and encapsulating your database queries made a lot of sense when you were hardcoding your SQL queries or using stored procedures but best practice has changed over the years, and with EF Core already implementing these two important patterns it doesnt make much sense implementing them again However, if we ignore the conceptual "is this a good idea?" question and focus on your code at hand... Your
All
method should probably be implemented once in the GenericRepository<T>
class
its logic doesnt change based on types, and you can access the generic set via dbContext.Set<T>()
https://github.com/MarchTala/dotnet7-crud-webapi/tree/3-of-3-uow-repository-pattern
I created a CRUD project and separated it into three branches. The first branch is focused on In-Memory implementation, the second on DbContext, and the third on UoW and Repository Pattern.
I created that project with the aim of gaining an understanding of the implementation of In-Memory Database, DbContext, as well as UoW and Repository Pattern. While I have some grasp on In-Memory and DbContext, I am facing confusion with UoW and Repository Pattern.
Could you please confirm if the implementation of UoW and Repository Pattern that I am using is correct? I am having difficulty articulating the issue in detail, but I am seeking guidance on the soundness of my approach.
GitHub
GitHub - MarchTala/dotnet7-crud-webapi at 3-of-3-uow-repository-pat...
Contribute to MarchTala/dotnet7-crud-webapi development by creating an account on GitHub.
Why is your third branch using EF?
You say that branch 2 uses dbcontext, but you do that in the third branch too
If you want to learn and understand repositories and Unit of Work, I would suggest implementing it without EF
What I did there was I continued the process in the 3rd branch and included the uow and repository pattern.
Is it still necessary to incorporate the repository and unit of work patterns when building a system?
?
I'm getting the feeling you are not actually reading what I'm writing here
What i mean is, is the use of repository and UoW mandatory in all cases?
Some individuals argue that you should only utilize it if you're building a very large system or application.
I have said several times that EF Core already implements both UoW and repository. If you are not using EF, its a good idea to implement them, as they solve very real problems
you dont NEED to do anything
for a web app in particular I think UoW is near mandatory thou
transactional security is incredibly important
if you are writing a tiny console app to run a single cleanup query every 24 hours, you do not need EF, repos or UoW.
Alright, Thank you very much for all the helpful tips you provided, sir.
I appreciate your guidance, and I look forward to applying these tips to my learning journey. I have been aspiring to learn C# for a long time, and I am finally starting this year. Thanks again sir. 🫡
Was this issue resolved? If so, run
/close
- otherwise I will mark this as stale and this post will be archived until there is new activity.