I don’t even know what a Repository Pattern is!
I’ve been super lucky in that writing code has never been hard for me. Learning languages, picking up concepts, all that algorithm nonsense… when it comes to code, things just come pretty easily to me. However, that has made me a lazy programmer which comes back to bite me every now and then. One example of this is me and the Repository Pattern. I first heard about the Repository Pattern right about when asp.net MVC first came out (2009-ish?). A buddy of mine mentioned the repository pattern and how it made testing easier and bam, a lightbulb (apparently the wrong lightbulb) went off and I immediately thought I got it and my brain started thinking about how I would implement something like that. He kept on talking but my brain was already onto other things and for the next 8 years, I just assumed I knew what I was doing. Make my code testable, so cram all my database access into a “repository”. Wrap it up in an interface, use DI to inject the repository into my controller class and voila, done!
Fast forward to today. I was writing some code for LoEDA.com. This is an asp.net core web app running inside of a container using EFCore to access a sql server database. On my pull request, Donovan Brown (@DonovanBrown) was like, dude, you’re doing it wrong. Whaaaaaaat? Really???? Me???? LOL! Yeah, I was totally doing it wrong.
What is it then?
First, let’s start with what a Repository should be. According to Martin Fowler (https://martinfowler.com/eaaCatalog/repository.html), “a repository mediates between the domain and data mapping layers, acting like an in-memory domain object collection.”
Eureka! The key phrase that stuck out to me is that it needs to act like an in memory collection of the domain objects! And why do I need this? Is this to make my code testable? Well… not really. I mean, it does make your code much easier to test but that’s not really the main goal of a repo. The goal of using a repo is to
- Minimize duplicate query logic
- Decouple your application from your persistence layer
This will create much cleaner code, allows us the option to easily swap out persistence layers if we need to and as a side affect, business logic code becomes very testable (although if you use EF as your ORM, everything is already testable since EF uses interfaces that can be mocked).
Ok, so what does all this mean from a code perspective? If we want our repo to act like an in memory list, then we need the following methods
Add(obj)
Remove(obj)
Get(id)
GetAll()
Find(predicate)
Notice I don’t have any methods for updating or saving. That’s because if a repo is like an in memory list, you don’t ever update or save lists, you just update the value and move on. So repo’s shouldn’t have any concept of updating or saving either.
So how do we update or save to the database? That’s where the Unit of Work comes in. Once again, quoting Martin Fowler, a unit of work “Maintains a list of objects affected by a business transaction and coordinates the writing out of changes”.
Wait, if I’m using Entity Framework (EF), isn’t that already a repository pattern?
While actually reading about Repository Patterns and entity framework, I ran across a lot of articles claiming there is no need to use a Repository Pattern with EF as EF already implements the Repository Pattern. People said the repository was implemented by a DbSet and the DbContext acted like the unit of work. At first glance, this actually seemed to work out. But looking at it a little more carefully, I found that I wasn’t totally comfortable with how EF implemented the repository pattern.
First, a repository should minimize duplicate query logic. EF and the DbSet don’t minimize duplicating query logic. In fact, DbSets totally expose querying by returning an IQueryable which means EF as a repository leaks the ability to query out of the repo and into the business logic.
For a concrete example, in our site, there are a couple of places I need to return a list of all the developer advocates, with a list of all their current events, ordered by the event start times. That means if I just use EF, I have this code strewn all over the place in my controller:
1 2 3 4 5 6 7 8 9 |
this.ExtraordinaryContext .Advocates .Include(x => x.PhysicalPresence) .Select(x => new Advocate{ AdvocateId = x.AdvocateId, Name = x.Name, ImagePath = x.ImagePath, PhysicalPresence = x.PhysicalPresence.Where(ev => ev.EndDate >= DateTime.Today) .OrderBy(ev => ev.StartDate).ToList()}) |
Ugghhh, that just smells wrong. Also, wow, I’m doing an awful lot of DB querying in my business layer now. This can’t be right.
So what’s the right way to implement the Repository Pattern/Unit of Work with Entity Framework?
You want to know the right way to implement a Repo/Unit of Work pattern? Check out this fantastic video by Mosh. He walks through step by step exactly how to implement this pattern. https://www.youtube.com/watch?v=rtXpYpZdOzM
Besides walking through clearly showing how to implement the repo/unit of work pattern, Mosh also made a great point about over architecting your app. I’m going to paraphrase him, but he said something like, “don’t use patterns as a deodorant to make smelly code smell good. Only use patterns when you need them.”