243

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?

ChW
  • 103

9 Answers9

544

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.

Chris Pratt
  • 6,402
120

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
  }    
}
Shyju
  • 1,548
47

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.

luksan
  • 633
17

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.

15

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.

Reconsidering the Repository Pattern

Pang
  • 335
Splendor
  • 251
7

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.

3

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.

Matthew Flynn
  • 13,495
  • 2
  • 39
  • 58
0

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.

Mufasa
  • 144
-6

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!

Thunder
  • 89
  • 2