The Repository Pattern is Dead If You Use Entity Framework

That is, it’s dead if you are using Entity Framework Core. If you’re still using straight ADO.NET, or even just dapper, then the repository pattern still probably makes sense for you. If you’re using Entity Framework, then you really aren’t gaining much from doing so anymore. Five years ago, you could reasonably argue that it was beneficial to use the repository pattern, or some form of abstraction, over entity framework for the following reasons:

  • Entity Framework had a history of poor performance and issues, and there were still some reasonable contenders at the time that you could successfully argue you may want to switch ORMs later on.
  • Mocking the database context was difficult, which made unit testing painful.
  • Support for anything other than SQL Server was either not provided out of box, or was unreliable at best. At the very least, it was nothing like the support that is now available for other persistence implementations. If you decided to move away from SQL Server, you were probably going to move away from Entity Framework as well.
  • Directly injecting the context was not as easy back then as it is today. .NET Core assumes that if you are using entity framework, you will be doing dependency injection, and now has built in configuration in start up for it.

There Is No Gain To The Repository Pattern

Given the above points, we have to ask what we are gaining by continuing with it. I don’t care what pattern, architecture, or technology you choose, you should always ask “What do I have to gain from this decision?” Does it make the code more maintainable? Does it reduce development time? Can I refactor more easily? If you aren’t asking these questions and dispassionately making decisions based on the answers you arrive at, then you are doing a disservice to your clients and to the software developers that have to work in your code. Lets look at the following code, which is actual code from a client I am currently working with.

public abstract class ╥RepositoryBaseß<♣Tß, ♣TRepoß> : «IRepositoryBaseß where ♣Tß : ╥ModelBaseß where ♣TRepoß : ╥RepositoryBaseß<♣Tß, ♣TRepoß>
        protected ╥DbContextß _dbContext { get; }
        protected «ILoggerß _logger { get; }

        protected RepositoryBase(╥DbContextß dbContext, «ILoggerß logger)

            _dbContext = dbContext;
            _logger = logger;

        public virtual async ╥Taskß<╥Listß<♣Tß>> GetAllAsync()
            ╥DbSetß dbSet = _dbContext.Set();
            return await dbSet.ToListAsync();

        public virtual async ╥Taskß<╥Listß<♣Tß>> GetManyAsync(Listß<☼Guidß>> ids)
            return await _dbContext.Set().Where(m => ids.Contains(m.Id)).ToListAsync();

        public virtual async ╥Taskß GetOneAsync(☼Guidß id)
            ╥DbSetß dbSet = _dbContext.Set();
            ♣Tß item = await dbSet.FirstOrDefaultAsync(x => x.Id == id);
            return item;

        public virtual async ╥Taskß AddAsync(♣Tß data)
            await _dbContext.SaveChangesAsync();
            return data.Id;
        public virtual async ╥Taskß UpdateAsync(♣Tß item)
            ╥DbSetß dbSet = _dbContext.Set();
            await _dbContext.SaveChangesAsync();

Now, there is a lot I can argue that is wrong with this code such as calling SaveChanges after every command. There are also a lot of things that are questionable such as the use of Guids for all PKs and the existence of this base class in the first place. What I want to focus on instead though is the overall uselessness of this approach. What are we gaining from wrapping up simple LINQ queries in a repository? They aren’t more readable for the most part, unless you aren’t very familiar with LINQ, but that would be a problem in itself. They don’t save code or reduce refactor effort since these are too simplistic to be changed to something different with the same intent. All you’ve accomplished is to abstract away Entity Framework, which isn’t much at all.

Entity Framework is already a generic repository pattern with a UOW pattern built in. I would argue that it has already given you persistence ignorance since you can safely change the underlying database implementation without touching Entity Framework for the most part. If you’ve built the whole system on Entity Framework, then the probability is low that you will abandon an ORM, and almost non-existent that you will choose another ORM. By going with a repository pattern, and especially one with a set up like this, you are introducing complexity where it isn’t warranted. To make matters worse, if you need to compose a larger call that works with more than one repository, you will be working with more than one context. This will prevent you from composing all your commands and then committing them as one transaction.

Reusability Is Still a Principle

That being said, that doesn’t mean that we can write all our queries as one offs. I have seen this done before and the duplication of non-trivial queries became a real problem. If you’re doing something more than just doing a FirstOrDefaultAsync or a ToListAsync, then you should add them to a query class. My personal approach is to store all queries for a given aggregate root in their own class and then inject the queries where necessary. Likewise for commands, although my own experience has seen a far larger reusability issue with queries than commands. You could inject the database context directly into your query class, but I prefer to pass it to the query method itself. This allows me to keep one context for everything in a given request. If you’re just doing simple .Include() queries, then it’s a matter of personal preference if you want to add it to a query class. I tend to use Select statements with hand crafted queries due to their increased performance and control. Since I use Request Injection and I don’t use DTOs in my APIs, I often times utilize the added performance of returning an anonymous type from the query. Regardless of what approach you take, don’t just run around writing non-trivial queries with reckless abandon. You’re still going to want to reuse them in an injected class, but don’t worry about abstracting away entity framework.

Sean Leitzinger
Latest posts by Sean Leitzinger (see all)

12 Replies to “The Repository Pattern is Dead If You Use Entity Framework”

    1. Hi. By query class I just mean a class that contains only queries. So instead of creating a repository that houses both commands and queries you would separate it into two classes. This falls more in line with CQS (Command Query Separation) which, to me, is easier to maintain. You could then take it a step further and do CQRS like what I wrote about here: In this case I’m using extension methods but you could also do it by injecting the context into a regular class as well like you would with a repository pattern.

  1. A good reason to use to wrap Entity framework in repositories would be if your datastore may change from a supported database type (relational db) to non-supported type (schema-less db i.e mongodb). I personally prefer wrapping away entity framework

  2. Hi Hubert, thanks for reading. The probability that your persistence implementation is going to completely change so radically is slim. It’s not by any means a common case, and the vast majority of applications are adding in overhead for something that is 99.9% certain not to happen. Even in the event that you did end up switching to a schema-less database from a relational one, the chance that you can just simply swap out the underlying implementation without any rework to the interface is also slim. I used to wrap entity framework in an abstraction too, but I feel confident saying at this point that it’s just not worth it.

  3. I prefer this pattern because I modularize my repository/data access layer and pattern into a .NET Standard library that many other departments within my company utilize.

    I agree there is overhead, but I like to think it helps me stay organized and in control of all data access.

    1. If you’re in a distributed environment and you need to control data access then I agree that injecting the context directly is not appropriate. That being said, I would still favor a CQS or CQRS pattern over the repository pattern. Repositories end up just becoming giant dumping grounds.

  4. I have a few comments on this:

    1) 99% of the time when people call their classes “Repositories” they have made a mistake. What they actually have created is a “Dao” (Data Access Object). The Repository pattern is slightly different from Dao and focuses on caching data that has been loaded from the data access layer. I guess the confusion originally arose because frameworks like Hibernate and EF do some caching within their contexts. This doesn’t really relate to anything you have said in your blog post but I just thought I’d mention it, and from this moment on I’ll say “Dao” instead of “Repository” 🙂

    2) I agree with you that calling “SaveChanges()” from inside a Dao is very bad practice. However, this doesn’t mean that Dao is a bad design pattern, it just means that this is an incorrect implementation of it.

    3) The two main benefits of a Dao are (i) Encapsulating data access logic, ie queries and (ii) Hiding your data access implementation, which in this case is Entity Framework.
    You said “My personal approach is to store all queries for a given aggregate root in their own class and then inject the queries where necessary”… so you are still keeping the second benefit, so this is basically a Dao. There is no extra harm in keeping EF implementation details hidden within the data access code of your application.

    Personally I still use Daos, the main benefit being the encapsulation of data access logic. Although I might never switch from EF to NHIbernate or visa versa, to me it seems much cleaner to keep any EF code out of the higher layers of the application. Injecting a DbContext into a Service or Controller seems very bad practice to me.

    1. Sorry when I said “so you are still keeping the second benefit” I should have said “so you are still keeping the first benefit”

  5. Hey Jordan, sorry for the late reply. I agree with everything you said about the DAO and what repositories these days usually are in reality. The point I would disagree with you on is that injecting the context directly is a bad practice.

    1. The .NET Core source code uses the context directly in numerous places. The UserStore in ASP.NET Identity for example directly injects the context, and I don’t think we can make the argument that the UserStore is a DAO given everything it does. By your reasoning, this would be considered bad practice. In my view though, this decision makes perfect sense.

    2. The heart of the argument is that I personally feel the DbContext is enough of an abstraction to not warrant wrapping it in a DAO. My current approach is described here where I write extension methods on the context.

    3. I think often times we make our lives far more difficult than they have to be due to always reaching for abstraction and separation. As long as you write your EF code in a reusable manner, I think forcing the context into its own separate layer hidden behind DAOs is just adding in extra work and complexity in most cases.

  6. Hey Sean,

    Sorry about the even later reply!

    Funnily enough I have just reaped the benefit of keeping the DbContext encapsulated in my data access layer, because we have just switched our project from EF Core to NHibernate after finding some bugs and missing features in EF Core (and then realising that EF Core really isn’t a high priority for Microsoft). But I concede that it is rare to switch ORM during the course of the project.

    I think the most important thing is to keep your data acess logic encapsulated somewhere,, so thankyou for the link to your cqrs blog. I’ve definitely got to the point where I’m interested in other approaches to doing things, so I’ll have a proper read of it when I’ve got the time.


  7. Hello, Thank you very much for this blog post. Is the repository patter good to use if I want to use EF instead of EF core. Also can you please do a blog post on migrations in EF(better way to do if) when using code first approach. Thank you.

Leave a Reply

Your email address will not be published. Required fields are marked *