EF Core: Repository Pattern and IMemoryCache Tutorial
March 10, 2025
• 908 views
In a previous video, we managed to add caching to our repository pattern. But... we had to essentially duplicate all of the code. Can we do better than that?
Yes! Let's see the decorator pattern in action.
View Transcript
in this video we're going to look at using The Decorator pattern with the repository pattern with Entity framework core and IM memory cache if that's not enough I don't know what to tell you my name is Nick centino and I'm a principal software engineering manager at Microsoft like I said in this video we're going to be combining all of these different pieces to try and build upon the previous video which if you haven't watched you can find it right up here and in that video we were starting to transform a repository pattern wrapped around nty framework core to start leveraging caching as I've mentioned in the other videos that are part of the series and if you haven't started looking at that playlist you can check that out up here Entity framework core does not necessarily need a repository around it and a lot of
people don't like doing it because it's just more levels of abstraction but what we're going to look at in this video is building upon this pattern we're going to look at using The Decorator pattern and that's because we encountered something sort of interesting in the last video when it came to putting caching in place if that sounds interesting and maybe a little bit wordy just a remind to subscribe to the channel and check out that pin comment for my courses on dome train now let's jump over to visual studio and we're going to start by reflecting on the previous repository pattern okay in the previous video we were putting together caching around this Entity framework core repository right so if we were to just take a look at the get method here what I was mentioning is that we end up having this block of
code from line 31 to 34 that's really the core code that we had in the original Repository that's the part that's going to be using Entity framework core to try and get the record back from the database everything else around that is really just for the caching and I was even saying we don't need this to set the expiration it's really just an enhancement or something that you can tailor in tune with your repository but now we're kind of left with the code that wraps this call and that's essentially giving us the caching part and again just a reminder this is with an IM memory cache just the one that's built in to net for us at this point and if we start scrolling through the other methods we start to see something pretty common we basically have the exact same code copy pasted from
the other repository and then a bit of caching logic and then we have the exact same code copied from the other repository with a little bit of caching logic this is a pattern that is something that we can pick up on and what we're going to look at is not necessarily A solution that solves this problem all of the time but I think it's a really good fit here and that's going to be called The Decorator The Decorator pattern is a design pattern it's part of the big list of all the design patterns from the gang of four so it's a pretty popular one the repository pattern is itself included in there but what The Decorator allows us to do is essentially wrap things around another implementation which sounds kind of interesting cuz it's wrapping kind of like a present we're decorating this thing right
so it looks different because we're wrapping stuff around it but what we're going to do is create a decor operator that performs the caching for us and the benefit of doing that is that if we wanted a non-caching implementation we could leave our original repository in its current format so for example if I jump back to the Entity framework core repository this is the one that did not have caching right if we look at this method for get right I said it's just a few lines of code and we were wrapping caching around this stuff if we wanted to preserve this for a non-caching implementation instead of copy pasting all of that code over because this part right here is literally just duplicated what we can do instead is have a class that wraps the other one so from the outside it still just looks
like an eye repository so just to call it out right up here this is where we have our interface so callers that are working with our repository are really just dealing with this interface I'll jump over to it very briefly so you can see they have these methods to work with right so they don't know that just from the interface that it's a caching one or a non-caching one but you could go configure your application to say you know what all of the repositories or some subset of repositories that you're working with I want these ones to be caching so instead of copy paste and code around you just wrap a caching repository around it we're going to go look at what that wrapper looks like or we'll call it the decorator class what that looks like and I'm just calling it a caching repository
we're going to look at this this and then we're going to see how we can set that up with dependency injection which is yet another buzzword that I could have added into the intro of this video oops too late but let's go see how this works right so when we're dealing with a decorator like this this caching repository what we're going to do is take in the thing that we want to decorate or to wrap and then we're going to in this case take in the cache that we want to work with now like I said in this video we're just dealing with the memory cache in subsequent videos that are part of this overall playlist I'll be looking at different types of caches as well but for now just the memory cache so here we have these things passed in and set as fields
for us to work with now let's go see what these other methods look like right so if we go look at the get method it's still going to have the caching part right but instead of copy pasting the lines of code inside of this Factory method right here it's just calling get a sync right this line of code that I have highlighted is essentially calling this but on the other implementation let's skip over get all a sync I've covered this in the previous video where I talked about you don't just want to blindly copy paste someone's implementation of get all a sync if you don't understand what it's going to be doing make sure you go back and watch that video to understand my point if we go look here we have the repository create a sync now the exercise we talked about in the
previous video was how we wanted to work with our cash and I talked about different things right so technically having a remove here on a create call doesn't make a whole lot of sense because you're creating something new there shouldn't be something in the cash so that's not going to be super helpful we might take that out if you want you could leave it in and there was something in the cache with the same ID you could make sure that it's being removed so maybe you want to leave that in but the other thing that we could consider and this is really up to you depending on your caching needs is when we create we could also set into the cash if you have some type of system where when you create things it's very very likely that you'll have subsequent calls that go read
these things back right away then maybe adding it to the cash right away is helpful but these are design decisions that you have to think about and if you're thinking about how your decorator works this is an option that you have I'm going to go ahead and remove it because we're not going to be adding things to the cache when we're creating or updating or deleting them we're just going to be adding things to the cach when we're getting stuff back from the database these are different options that you have to consider though I'm not saying it's right or wrong you have to decide for your setup before we move on this is just a quick reminder that I do have a course on C refactoring available on dome train refactoring is one of the most critical skills that you can learn as a software
engineer and this helps you continue to build upon applications that already exist making sure that they can scale and have extensibility I walk you through a bunch of various techniques and give you some examples that we walk through together to see see how we can apply these techniques to refactor the code check out the pin comment and the links in the description to get this course now back to the video now when we have update async same idea here right so we can go ahead and say hey look we're about to go update something in our database let's go make sure that it's removed from the cache first right you could do that if you would like instead of copying and pasting the lines of code for update async into here we're just wrapping around another repository right so we just call the same method
it's like this part is the pass through from one repository to another but we get to decide before or after how we want to work with the cash something else you could do is instead of having the remove up front you could say instead once I have updated the record I would like to go update the cach so you could go do that but like I said above I'm not going to go add setting things to the cach when we're doing rights I'm just going to have things get cleaned up or invalidated from the cash as writing getting things will add to the cache in the implementation that I'd like to use finally deleting is very very similar we're not going to be adding anything to the cach because we're literally deleting things so we're just going to make sure that it's removed from the
cache just like with all the other examples it's just a pass through after that right so we're calling delete we're going to call delete on line 60 on the repository that we're wrapping instead of duplicating a whole bunch of code this becomes a very very thin wrapper class CL that we can use and if we think about the responsibility that this has the responsibility is just cashing right just being able to cash it's not other logic that's added in and I think that that's one way that we can clean this stuff up but you do have to consider right like do you actually need this does it make more sense that in your situation all of your repositories are cashing so you might as well have just built the other one that we just looked at for you to decide this is just a tool
tool that you can add to your toolbox but how do we go configure this we've built it so we've built this wrapper that can go around another repository which by the way is very generic right this has nothing specifically to do with Entity framework core and if you think about that the other videos in this playlist also talked about a Dapper repository so this one could go ahead and wrap the Dapper repository as well because it doesn't care at all about the implementation of the Repository that it's taking in right it's just an ey repository not any framework core not Dapper specific and not any other implementation specific so pretty cool again how do we go set this up how do we make it active in our application so dependency injection is where this thing is going to come into play if we go look
up at the top here when we're dealing with our builder at the top of our application this is where we're setting up dependency injection for different services so we've added the memory cache on line five line four is where before we were setting up our Entity framework core crud repository with caching but we're going to go into here and instead of using this method which was setting up the dependency injection rate here on line 27 we're going to do something a little bit different we're going to expand this one because we're going to use this for the dependency injection instead so set up Entity framework crud with cach decorator the important part so let me start with the non-important part this part right here is the exact same as up here so we don't have to pay special attention to setting up the database context
Factory in this case it's the same as before in the other videos and if you're not familiar with that like I said you're already in part of the playlist you can go ahead and check out the other videos they cover this stuff way more in depth at least enough to get you started in leveraging them so this part is the same let's go ahead and collapse that part now if we look at these lines here this part is going to be different than this line right here they have a similar responsibility but this is where the difference comes in on line 27 we were saying I want to use a caching Entity framework core repository this is the first implementation with caching that we saw that basically duplicated the repository code and added caching in and then we're saying so use this when someone asks
for this we're no longer going to be calling this though so if we look down below what we're doing is we're saying we want to add a Singleton and we want it to be the Entity framework core repository notice that I am not mapping this to this type here if someone wants this they have to ask for it by this type hopefully that makes sense so far because you're going to see if you pay close attention on line 37 where the Highlight is right here you'll notice that on line 40 the Highlight is the same so I'm just going to highlight with my cursor this part's the same and what we're doing is we're asking the provider which is where all of our services are registered we're saying we want specifically this Entity framework core repository of type entity that means just to make it
a little bit more clear that having this line here on line 37 allows us to specifically ask for this implementation but why are we even asking for this one well that's because we are basically Al saying if anyone wants this interface so if anyone's asking for the generic I repository we're going to say you're going to use a caching repository implementation the caching repository is our decorator it's just the thing that's going to wrap around the other repository so we'll make a new one we will wrap it around this one and we also need the memory cache just to make that a little bit more succinct I'll iterate the last part one more time this part down here allow ows us to go add a decorator and that decorator will wrap around this particular repository implementation and that means that we need to have that
specific repository implementation available to us on the dependency container if we go back into program.cs and I say set up with the cache decorator now right if I have this in place if we look at our crud methods and I add this disclaimer into every video this is not how you would go write your cred methods these are all get methods in a minimal API this is just so I could be showing people in the videos through the browser but what we're able to do here is we ask for an i repository right see the Highlight on all of these methods now if you were to guess at what implementation of the repository is coming back I'll give you a moment to think about this and I think you're right it's going to be the caching one right that's the one that will get resolved
and inside of the caching one we are w in or decorating the Entity framework core one that we started with but if you don't believe me let's go ahead and run this I'm not going to go exercise all of the cred methods because if you've watched the other videos you've probably seen this about 400 times now let me put a breako on the get method we're going to run this and then we're just going to go inspect what repository is when we run this okay with the application running if I go ahead and press enter now we should hit this break point and if we hover over over this repository which might be a little bit hard to see so we'll check it out in the locals part down below you can see the type of this repository when the editor Zooms in is going
to be a caching repository if we expand that caching repository we can see that it took in the memory cache and it also took in this EF core repository right this type that you see right here is this type over here if I jump into it this is the non-caching implement mentation so we have the caching one wrapping around the non-caching one and this allows us to have a decorator you might be asking yourself at this point what's the whole reason for doing this well one of the main reasons is that we could go ahead and essentially reduce code duplication so that's one nice part but we also decoupled these things right because the first one that I showed you that had the caching in place we had to go duplicate ND framework core and combine it with caching logic but I did drop a
little bit of a hint that from the previous videos we looked at a Dapper repository so if I wanted to go follow that first pattern and add caching to the Dapper repository I'd basically have to copy and paste the Dapper repository add the caching in and it's really now like a handful of classes but really I could have just had the same caching logic and not cared about which other repository I'm working with your situation may call for something very different so just as an example you might say I have some other implementation of a repository and I definitely need to deal with my caching in a different way then using The Decorator is probably not a good approach for you and that's because the way that you are caching or the way that you are decorating things is going to be consistent if you
need different Behavior across those things then either your decorator needs to be figured differently or you need to have a different decorator or you just go change that other class so this is one type of approach that you can use if you have this Challenge and I think that it's an interesting one especially if you have the need for reusability and separate these things in a way that gives you some more simplified classes instead of some bunched up logic that's a quick look at how you can use a decorator for caching stuff with a repository with entity framework core but now that you've seen it if you watched the other videos you know that you can just swap out the repository with the Dapper one and if you've already built your own you could swap it out for that too so if that was interesting
and you want to see more about caching this video next will start talking about hybrid cache I'll see you in the next video [Music]
Frequently Asked Questions
What is the purpose of using the Decorator pattern with the Repository pattern in this tutorial?
The purpose of using the Decorator pattern with the Repository pattern is to enhance the functionality of the repository without duplicating code. By wrapping the original repository with a caching decorator, I can add caching logic while keeping the core repository implementation intact. This allows for a cleaner design and reduces code duplication.
How does the caching mechanism work in the context of the Repository pattern?
In this tutorial, the caching mechanism works by creating a caching repository that wraps around the original repository. When a data retrieval method is called, the caching repository first checks if the data is available in the cache. If it is, it returns the cached data; if not, it retrieves the data from the database using the original repository and then stores it in the cache for future requests.
Can I use the caching decorator with other types of repositories besides Entity Framework Core?
Yes, you can use the caching decorator with other types of repositories, such as Dapper or any custom repository implementation. The caching decorator is designed to be generic and works with any repository that implements the same interface, allowing you to add caching functionality without being tied to a specific data access technology.
These FAQs were generated by AI from the video transcript.