During a job interview, I was asked to explain why the repository pattern isn't a good pattern to work with ORMs like Entity Framework. Why is this the case?
-
72it was a trick question– OmuCommented Dec 12, 2012 at 21:34
-
3I would probably have answered to the interviewer that Microsoft use the repository pattern very often while they demonstrate the entity framework :| .– Laurent Bourgault-RoyCommented Dec 28, 2012 at 17:12
-
2So what was the interviewer's reason for it not being a good idea?– Bob HornCommented Dec 30, 2012 at 15:42
-
4The funny fact is that searching for "repository pattern" in Google gives the results which are mostly related to Entity Framework and how to use the pattern with EF.– Arseni MourzenkoCommented Dec 31, 2012 at 18:43
-
2check ayende's blog ayende.com/blog. Base on what I know, he used to use Repository Pattern but eventually gave it up in favor of the Query Object Pattern– Jaime SangcapCommented Feb 2, 2014 at 8:30
9 Answers
I don't see any reason for the Repository pattern to not work with Entity Framework. Repository pattern is an abstraction layer you put on your data access layer. Your data access layer can be anything from pure ADO.NET stored procedures to Entity Framework or an XML file.
In large systems, where you have data coming from different sources (database/XML/web service), it is good to have an abstraction layer. The Repository pattern works well in this scenario. I do not believe that Entity Framework is enough abstraction to hide what goes on behind the scenes.
I have used the Repository pattern with Entity Framework as my data access layer method and am yet to face a problem.
Another advantage of abstracting the DbContext
with a Repository is unit-testability. You can have your IRepository
interface to which has 2 implementations, one (the real Repository) which uses DbContext
to talk to the database and the second, FakeRepository
which can return in-memory objects/mocked data. This makes your IRepository
unit-testable, thus other parts of code which uses IRepository
.
public interface IRepository
{
IEnumerable<CustomerDto> GetCustomers();
}
public EFRepository : IRepository
{
private YourDbContext db;
private EFRepository()
{
db = new YourDbContext();
}
public IEnumerable<CustomerDto> GetCustomers()
{
return db.Customers.Select(f=>new CustomerDto { Id=f.Id, Name =f.Name}).ToList();
}
}
public MockRepository : IRepository
{
public IEnumerable<CustomerDto> GetCustomers()
{
// to do : return a mock list of Customers
// Or you may even use a mocking framework like Moq
}
}
Now using DI, you get the implementation
public class SomeService
{
IRepository repo;
public SomeService(IRepository repo)
{
this.repo = repo;
}
public void SomeMethod()
{
//use this.repo as needed
}
}
-
3I didn't said it will not work , I am also worked with repository pattern with EF , but today I was asked why IT IS NOT GOOD to use the pattern with DataBase , application that using Database– StringBuilderCommented Dec 12, 2012 at 21:08
-
2Ok , since this is the most popular answer I'll chose it as Correct Answer– StringBuilderCommented Dec 15, 2012 at 12:21
-
87
-
20DbContext is already a repository, the repository is meant to be a low level abstraction. If you want to abstract different data sources create objects to represent those. Commented Dec 3, 2013 at 4:34
-
11ColacX. We tried just that--DBcontext right in the controller layer--and we are reverting to the repo pattern. With the Repo pattern, the Unit Tests went from massive DbContext mocking that constantly failed. EF was was difficult to use and brittle and cost hours of research for EF nuances. We now have small simple mocks of the repo. The code is cleaner. The separation of work is clearer. I no longer agree with the crowd that EF is already a repo pattern and already unit testable.– RhyousCommented Jul 11, 2016 at 22:57
The single best reason to not use the repository pattern with Entity Framework? Entity Framework already implements a repository pattern. DbContext
is your UoW (Unit of Work) and each DbSet
is the repository. Implementing another layer on top of this is not only redundant, but makes maintenance harder.
People follow patterns without realizing the purpose of the pattern. In the case of the repository pattern, the purpose is to abstract away the low-level database querying logic. In the old days of actually writing SQL statements in your code, the repository pattern was a way to move that SQL out of individual methods scattered throughout your code base and localize it in one place. Having an ORM like Entity Framework, NHibernate, etc. is a replacement for this code abstraction, and as such, negates the need for the pattern.
However, it's not a bad idea to create an abstraction on top of your ORM, just not anything as complex as UoW/repostitory. I'd go with a service pattern, where you construct an API that your application can use without knowing or caring whether the data is coming from Entity Framework, NHibernate, or a Web API. This is much simpler, as you merely add methods to your service class to return the data your application needs. If you were writing a To-do app, for example, you might have a service call to return items that are due this week and have not been completed yet. All your app knows is that if it wants this information, it calls that method. Inside that method and in your service in general, you interact with Entity Framework or whatever else you're using. Then, if you later decide to switch ORMs or pull the info from a Web API, you only have to change the service and the rest of your code goes along happily, none the wiser.
It may sound like that's a potential argument for using the repository pattern, but the key difference here is that a service is a thinner layer and is geared towards returning fully-baked data, rather than something that you continue to query into, like with a repository.
-
95
-
14You can mock
DbContext
in EF6+ (see: msdn.microsoft.com/en-us/data/dn314429.aspx). Even in lesser versions, you can use a fakeDbContext
-like class with mockedDbSet
s, sinceDbSet
implements an iterface,IDbSet
. Commented Mar 6, 2014 at 0:23 -
16@TheZenker, you may not have been exactly following the repository pattern. The strictest difference is the return value. Repositories return queryables, whereas services should return enumerables. Even that's not really that black and white, as there's some overlap there. It's more in how you use it. A repository should just return the set of all objects, which you then further query into, while the service should return the final dataset, and should not support further querying. Commented Mar 27, 2014 at 14:31
-
15At the risk of sounding egotistical: they're wrong. Now, as far as the official tutorials go, Microsoft has backed off using repositories from what I've seen since EF6. Regarding the book, i can't speak to why the author chose to use repositories. What i can speak to, as someone in the trenches building large scale applications, is that using the repository pattern with Entity Framework is a maintenance nightmare. Once you move into anything more complex than a handful of repositories, you end up spending exhorbitant amounts of time managing your repositories/unit of work. Commented Oct 29, 2014 at 17:42
-
7I usually have just one service per database or access method. I use generic methods to query multiple entity types from the same set of methods. I use Ninject to inject my context into my service and then my service into my controllers so everything is neat and tidy. Commented Jul 13, 2015 at 14:42
Here's one take from Ayende Rahien: Architecting in the pit of doom: The evils of the repository abstraction layer
I'm not sure yet whether I agree with his conclusion. It's a catch-22 - on the one hand, if I wrap my EF Context in type-specific repositories with query-specific data retrieval methods, I am actually able to unit test my code (sort of), which is almost impossible with Entity Framework alone. On the other hand, I lose the ability to do rich querying and semantic maintenance of relationships (but even when I have full access to those features I always feel like I'm walking on egg shells around EF or any other other ORM I might choose, since I never know what methods its IQueryable implementation might or might not support, whether it will interpret my adding to a navigation property collection as a creation or merely an association, whether it is going to lazy or eager load or not load at all by default, etc., so maybe this is for the better. Zero-impedance object-relational "mapping" is something of mythological creature - maybe that is why the latest release of Entity Framework was codenamed "Magic Unicorn").
However, retrieving your entities through query-specific data retrieval methods means that your unit tests are now essentially white-box tests and you have no choice in this matter, since you must know in advance exactly which repository method the unit under test is going to call in order to mock it. And you're still not actually testing the queries themselves, unless you also write integration tests.
These are complex problems that need a complex solution. You can't fix it by just pretending that all your entities are separate types with no relationships between them and atomize them each into their own repository. Well you can, but it sucks.
Update: I have had some success using the Effort provider for Entity Framework. Effort is an in-memory provider (open source) that allows you to use EF in tests exactly the way you would use it against a real database. I am consider switching all the tests in this project I'm working to use this provider, since it seems to make things so much easier. It is the only solution I've found so far that addresses all of the issues that I was ranting about earlier. Only thing is there is a slight delay when starting my tests as it's creating the in-memory database (it uses another package called NMemory to do this), but I don't see this as a real problem. There's a Code Project article that talks about using Effort (versus SQL CE) for testing.
-
4Any architecture article without mentioning unit test are automatically sent to the trash bin for me. One of the point of repository pattern is to gain some test-ability. Commented Feb 19, 2013 at 6:06
-
3You can still have unit tests without wrapping the EF Context (which is already a repository). You should be unit testing your domain / services not database queries (they're integration tests). Commented Dec 3, 2013 at 4:36
-
2EF's testability has improved greatly in version 6. You may now fully mock
DbContext
. Regardless, you could always mockDbSet
, and that's the meat of Entity Framework, anyways.DbContext
is little more than a class to house yourDbSet
properties (repositories) in one location (unit of work), especially in a unit testing context, where all the database initialization and connection stuff is not wanted or needed anyways. Commented Mar 6, 2014 at 0:29 -
Loosing related entity navigation is bad and is counter OOP, but you'll have more control on what's being queried.– AlirezaCommented May 30, 2015 at 6:58
-
To the point of testing, EF Core has come a long way with out of the box In-Memory and In-Memory with Sqlite providers to enable unit testing. Bring in docker when you need integration testing to run tests on a containerised database. Commented Jun 27, 2019 at 0:20
The reason why you probably would do that is because it's a little redundant. Entity Framework gives you a wealth of coding and functional advantages, that's why you use it, if you then take that and wrap it in a repository pattern you are throwing those advantages away, you might as well be using any other data access layer.
-
could you please tell some of the advantages for "Entity Framework gives you a wealth of coding and functional advantages"? Commented Oct 29, 2015 at 15:44
-
3this is what he meant. var id = Entity.Where(i => i.Id == 1337).Single() encapsulated and wrap this in a repository you basically cannot do query logic like this from the outside, which either forces you to A add more code to the repository and the interface for fetching id. B return the entity context from the repository so that you can write the query logic (which is just nonsense)– ColacXCommented Jan 21, 2016 at 10:24
In theory I think it makes sense to encapsulate the database connection logic to make it more easily reusable, but as the link below argues, our modern frameworks essentially take care of this now.
-
I liked the article , but IMHO for enterprise apps , the abstraction layer between DAL and Bl MUST Have feature , since you couldn't know what exactly will be used tomorrow. But thanks for sharing the link– StringBuilderCommented Dec 12, 2012 at 21:15
-
1While personally I think it's true for e.g. NHibernate (
ISessionFactory
andISession
are easily mockable), it's not that easy withDbContext
, unfortunately... Commented Dec 28, 2012 at 23:02
A very good reason to use the repository pattern is to allow the separation of your business logic and/or your UI from System.Data.Entity. There are numerous advantages to this, including real benefits in unit testing by allowing he use of Fakes or Mocks.
-
I agree with this answer. My repositories are basically just extension methods, which do nothing but build expression trees. Over a VERY simple abstraction that simply provides generic functionality directly over the top of dbcontext. The only real purpose of the abstraction is to make IoC a little easier. I think people try to do things in their repositories that they shouldn't do. They make on repo per entity, or put business logic in there that should be in the services layer. You only ever actually need one simple generic repo. Its not necessary, just provides a consistent interface.– BrandonCommented Mar 24, 2016 at 4:39
-
One more thing I just wanted to add. Yes CQRS is a vastly superior methodology in MOST cases. For some clients I have worked at when the database guys dont work well with developers (which happens more often than one would think especially at banks), EF over SQL is the best option. In that specific scenario, when you have absolutely no control over your database, repository pattern makes sense. Because closely resembles the data structure and is easy to translate whats going on to the database and vise versa. Its really a political and logistical decision in my opinion. To appease the DB gods.– BrandonCommented Mar 24, 2016 at 4:56
-
3I'm actually beginning to question my earlier opinions on this. EF is a combined Unit-of-Work and Repository pattern. As Chris Pratt mentioned above with EF6 you can easily mock the Context and DbSet objects. I still believe that the data access should be wrapped in classes to shield the business logic classes from the actual data access mechanism, but to go the whole hog and wrap EF with another repository and Unit of Work abstraction seems to be overkill. Commented Mar 26, 2016 at 19:33
-
I don't think this is a good answer because your supporting statement is just that there are numerous advantages while only listing one.The one you do list isn't a good reason because you can use an in-memory database for entity to do unit testing. Commented Mar 14, 2017 at 23:18
-
@jcmcbeth if you look at my comment directly above your you will see that I have changed my original opinion with regards repository pattern and EF. Commented Mar 15, 2017 at 16:12
After trying out repository pattern on small project I strongly advise not to use it; not because it complicates your system, and not because mocking data is nightmare, but because your testing becomes useless!!
Mocking data allows you add details without headers, add records that violate database constraints, and remove entities that the database would refuse to remove. In the real world a single update may affect multiple tables, logs, history, summaries, etc., as well as columns such as the last-modified-date field, auto generated keys, computed fields.
In short running your test on real database gives you real results and you can test not only your services and interfaces but also database behavior. You can check if your stored procedures do the right thing with data, return the expected result, or that the record you sent to delete really deleted! Such tests can also expose issues such as forgetting to raise errors from stored procedure, and thousands of such scenarios.
I think entity framework implements repository pattern better than any of the articles I have read so far and it goes far beyond what they are trying to accomplish.
Repository was best practice on those days where we were using XBase, AdoX and Ado.Net, but with entity!! (Repository over repository)
Lastly I think too many people invest lots of time on learning and implementing repository pattern and they refuse to let it go. Mostly to prove to themselves that they did not waste their time.
-
1Except that you do NOT want to test your database behaviour in unit tests, as it's completely not that level of testing. Commented Mar 6, 2016 at 13:12
-
Yes, what you're talking about here is integration testing, and it is indeed valuable, but unit tests are totally different. Your unit tests should never hit a real database, but you are encouraged to add integration testing that does. Commented Jun 15, 2017 at 18:52
We have had problems with duplicate but different Entity Framework DbContext instances when a IoC container that new() up repositories per type (for example a UserRepository and a GroupRepository instance that each call their own IDbSet from DBContext), can sometimes cause multiple contexts per request (in an MVC/web context).
Most of the time it still works, but when you add a service layer on top of that and those services assume objects created with one context will correctly be attached as child collections to a new object in another context, it sometimes fails and sometimes doesn't depending on the speed of the commits.
-
I have encountered this problem to in several different projects.– ColacXCommented Jan 21, 2016 at 10:26
Its due to Migrations:It is not possible to get migrations to work , as the connection string resides in the web.config. But, the DbContext resides in the Repository layer . IDbContextFactory needs to have configuration string to the database .But There is no way that migrations gets the connection string from web.config.
There are work around but I have not found a clean solution for this yet!
-
3