Repository Pattern With Entity Framework Core | Clean Architecture, .NET 6

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hi everyone my name is milan and today i have a potentially controversial topic prepared for you i want to talk about the repository pattern what are some of the pros and cons of using the repository pattern and why is it a topic of many discussions in the software engineering community let's jump straight into the code and see how we can define a very simple repository interface here i have the i gathering repository which represents the repository that manages the gathering entity as you can see i have two methods for fetching the gathering from the repository the first is the get by id with creator method the second is the get by id with invitations method and we have one method for adding a gathering to the repository and another method for removing a gathering from the repository in essence the repository pattern is supposed to represent an interface between your application and the underlying data storage as you can see with this repository interface definition we have a few methods for fetching the entity from the database and also a few methods for adding or removing the entity from the database let's see how we would actually use this repository interface i'm going to navigate to the accept invitation command handler inside of this command handler you can see that we are injecting two repositories the gathering and the attendee repository and also we are using the unit of work for persisting the changes at the end of the transaction let's take a look at the handle method of this command handler at the start of the handle method we are using the gathering repository to fetch our entity from the underlying data storage it's interesting to note here that because we are abstracting away our data storage behind the repository interface we don't actually know how we are fetching the data from the database and also where our data actually is it could be a relational database it could be a document database it could even be uh in memory cache and we wouldn't be able to tell the difference after we have fetched the gathering using the repository we can now use it in the rest of our method we are checking if it is null and if it is we are returning an appropriate error response if it is not null we can get the invitation that we are accepting we check the invitation status we use the gathering entity that we fetched from the repository to accept the invitation and if accepting the invitation was successful we have created a new attendee entity and we add it to the attendee repository at the very end of the handle method we persist all of our changes to our underlying data storage by calling the save changes method on the unit of work let me discuss what are the benefits of abstracting away your data storage behind the repository interface first off here we are following the clean architecture and by convention the application layer of the clean architecture should not have any external dependencies one of these external dependencies is the database so by using the repository interface we are abstracting away how we are accessing the data storage and in that regard we are following the clean architecture also you can consider your repositories as entity factories they have the responsibility of fetching the entity from the database and materializing that entity into the appropriate domain model that you can use inside of your command handlers the biggest pushback that i hear from other engineers against the repository pattern is that they consider it an unnecessary abstraction and why is that if you are using an orm for example any framework core it already abstracts away the access to the database the database context represents the unit of work and the actual db sets represent the individual repositories but this only applies if you actually use the repository pattern for all data access inside of your application how i like to use the repository pattern is only inside of my command handlers it makes it easier for me to fetch my domain entities from the database materialize them into actual object instances and manipulate them according to the commands that i am currently handling and at the end of the command handler i commit everything using the unit of work one other benefit of using the repository pattern is that you get a very high degree of testability since you are using interfaces here for example the eye gathering repository the i attendee repository and the i unit of work this makes it very easy for you to write tests because you can provide mocks using some mocking library like mock you for example let's see how the actual repository implementation would look like i already stopped out gathering repository inside of the persistence layer as you can see none of the methods are implemented and i'm going to implement it using any framework core so here i'm going to create a private read-only field that will hold my application dbcontext i'm going to inject this dbcontext using the constructor and i will quickly implement all of these methods for the get by id with creator method we first want to make it a synchronous get rid of this not implemented exception and here we want to fetch the gathering by id so i'm going to say return db context set gathering and this will give me the db set for talking with the gathering collection and i'm going to select the first or default gathering that has an id that is equal to the id that we have passed in from the arguments and additionally i'm going to specify the cancellation token notice that the name of the method says with creator by default any frame record does not implement lazy loading so you have to eagerly include any of the navigation properties that you want to be fetched inside of the same query so i'm going to say include the creator of the gathering so this is how our implementation would look like it's pretty straightforward i'm going to copy this over to implement the next method which does something similar i have to make it asynchronous and instead of including the creator i'm going to include the invitations collection all right the add method is also straightforward to implement i'm going to say db context set gathering and add the gathering to the repository and i will copy this over for the remove method and instead of calling the add on the db set i'm going to call remove you can see that we already have two similar get methods here one is including the creator and the other one is including the invitations this is the downside if you want to have very specific methods with your repositories there is a way to mitigate this using the specification pattern which i will discuss in some of my future videos but i'm going to leave this as is notice that all of these methods are loading the entities using any framework and they are being added to the change tracker this is because i mentioned that the way that i use the repository pattern is for my command handlers i want to fetch the entities from the database apply some changes and then save that to the database for the query side my preferred approach is not using the repository pattern but rather accessing the database directly either by injecting the db context and writing the specific query that you need or perhaps you can even write a sql query i want to show you one slight improvement that you can make inside of your repository interface definitions if you want to enforce a constraint that you can only define repository interfaces for your aggregate routes what you can do is define a marker interface that you will call i repository it has to be a generic interface so i'm going to say i repository of t and it won't have any methods inside and the only thing i'm going to add is add a generic constraint that the specified type has to be an aggregate root implementation and you would use it by making your actual repositories inherit from the generic eye repository and specifying the aggregate route now of course this doesn't prevent somebody from just creating a repository interface which does not inherit from the base high repository and you can't really force anyone to do this what you can do is write a unit test that uses reflection to get all of the repository interface definitions inside of your domain layer and this test should verify that all of the repository interfaces implement the generic irepository interface so that is one way that you can enforce this constraint all right so this was a discussion about the repository pattern i hope that you enjoyed the video and that you now have a better understanding of what are the pros and cons of using the repository pattern whether you end up using it in your own project is entirely up to you i personally use the repository pattern in my project specifically since i'm mostly working with clean architecture implemented using cqrs i use the repository pattern inside of my command handlers for interacting with my domain layer and on the query side i usually go with some custom implementation which is more performant if you like this video subscribe to my channel so that you don't miss any of my future videos and until next time stay awesome you
Info
Channel: Milan Jovanović
Views: 39,813
Rating: undefined out of 5
Keywords: repository pattern, repository pattern c#, repository pattern in asp.net core web api, repository pattern c# mvc, repository pattern in asp.net core, repository pattern in mvc, repository pattern c# web api, repository pattern and unit of work with asp.net core 5, repository, design pattern, design patterns, .net 6, dotnet, .net 5, .net 7, cqrs, entity framework, repository pattern with entity framework, repository pattern with entity framework core
Id: h4KIngWVpfU
Channel Id: undefined
Length: 9min 31sec (571 seconds)
Published: Tue Sep 20 2022
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.