28

I am bit curious as to what experience other developers have of applying the Repository pattern when programming in ASP.NET MVC with Entity Framework or NHibernate. It seems to me that this pattern is already implemented in the ORM themselves. DbContext and DbSet<T> in the Entity Framework and by the ISession in NHibernate. Most of the concerns mentioned in the Repository pattern - as catalogued in POEE and DDD - are pretty adequately implemented by these ORMs. Namely these concerns are,

  • Persistence
  • OO View of the data
  • Data Access Logic Abstraction
  • Query Access Logic

In addition, most of the implemententations of the repository pattern that I have seen follow this implementation pattern - assuming that we are developing a blog application.

NHibernate implementation:

public class PostRepository : IPostRepository
{
    private ISession _session;

    public PostRepository(ISession session)
    {
        _session = session;
    }

    public void Add(Post post)
    {
        _session.Save(post);
    }

    // other crud methods. 
}

Entity Framework:

public class PostRepository : IPostRepository
{
    private DbContext _session;

    public PostRepository(DbContext session)
    {
        _session = session;
    }

    public void Add(Post post)
    {
        _session.Posts.Add(post);
        -session.SaveChanges();
    }

    // other crud methods. 
}

It seems to me that when we are using ORMs - such as Nhibernate or Entity Framework - creating these repository implementation are redundant. Furthermore since these pattern implementations does no more than what is already there in the ORMS, these act more as noise than helpful OO abstractions. It seems using the repository pattern in the situation mentioned above is nothing more than developer self aggrandizement and more pomp and ceremony without any realizable techical benefits. What are your thoughts ??

Bikal Lem
  • 2,403
  • 18
  • 19
  • I agree with the sentiment here (and [I'm not the only one](http://ayende.com/Blog/archive/2009/04/17/repository-is-the-new-singleton.aspx)), but "What are your thoughts" is the very definition of a subjective and argumentative question. – Jeff Sternal Jan 18 '11 at 20:17
  • 3
    "creating these repository implementation are redundant" That is because they are doing it wrong. The repository *should* represent **domain** concepts, not generic CRUD. – quentin-starin Jan 18 '11 at 20:28
  • @Jeff - By its very nature 'Software Patterns' are very context sensitive and not as universal across programming languages and platforms. Read this http://blog.plover.com/2006/09/11/ . So when discussing software patterns, some level of subjective rationale in inevitable. – Bikal Lem Jan 24 '11 at 10:50
  • 1
    @qstarin - The software pattern spec for Repository states `Mediates between the domain and data mapping layers using a collection-like interface for accessing domain objects.` Clearly the Repository pattern was conceived to abstract out the data access concerns, which ORMs like nHibernate and Entity Framework does extremely well. In DDD **Domain objects abstract the domain logic not the repository**. Which makes the repository pattern redundant. – Bikal Lem Jan 24 '11 at 11:07
  • @Bikal: No, repositories are not redundant. They are *complementary*. They are part of the picture of a domain, just like entities and value types and events and many other pieces. Their purpose is **not** to abstract out the data access (that's the data mapping layer's job), but to be an abstraction of the *collection of entities*. An account repository is not a place for CRUD, it should serve as a representation of Accounts in your world. The operation valid on a Repository are dependent upon the type of entity the repository serves. It is clearly a part of the domain. – quentin-starin Jan 24 '11 at 16:29
  • @qstrain Indeed. Abstracting data access and collection like interfaces is the job of a Repository pattern, which is done already for you by **DbSet** in Entity Framework and **ISession.Linq** in nHibernate and thus is not necessary for the developer to implement this in the code. Therefore, if you use either of the aforementioned ORMs, implementing IRepository via interfaces is redundant and doesn't provide for any helpful abstraction. – Bikal Lem Jan 25 '11 at 00:52
  • @qstrain With regards to where to abstract the domain logic. This again very much depends on the context. One popular approach - I believe - in ASP.NET MVC is to abstract this out in a Service pattern if reusability is required. The other approach is to implement this logic in the Controller action methods. Another approach favoured in the Ruby on Rails camp is to abstract this out in the Domain model themselves - in a fat model, thin controller pattern/scheme. Using the repository provided by the ORMs makes our abstractions much succint. – Bikal Lem Jan 25 '11 at 00:58
  • 1
    From what I can tell, the main tangible benefits of the repository pattern that are missing from an ORM is that ability to abstract the dependency (testing), and to keep reusable queries in one place. In my opinion, these shortcomings can and should be addressed by the ORM designers. In fact, between partial classes from code gen and extension methods, I think the query reuse issue has been some what solved by the Entity Framework. – grimus Mar 15 '11 at 21:22
  • @grimus - query reuse or business logic reuse should mostly be on the domain objects/classes if you are doing DDD. Repository for the most part abstracts the low-level cross-cutting concerns of accessing data from the data storage. In asp.net mvc apps you might also consider controller action methods to hold business logic if you want to keep your model objects dumb. – Bikal Lem Mar 28 '11 at 10:13

3 Answers3

12

The answer is no if you do not need to be able to switch ORM or be able to test any class that has a dependency to your ORM/database.

If you want to be able to switch ORM or be able to easily test your classes which uses the database layer: Yes you need a repository (with an interface specification).

You can also switch to a memory repository (which I do in my unit tests), a XML file or whatever if you use repository pattern.

Update

The problem with most repository pattern implementations which you can find by Googling is that they don't work very well in production. They lack options to limit the result (paging) and ordering the result which is kind of amazing.

Repository pattern comes to it's glory when it's combined with a UnitOfWork implementation and has support for the Specification pattern.

If you find one having all of that, let me know :) (I do have my own, exception for a well working specification part)

Update 2

Repository is so much more than just accessing the database in a abstracted way such as can be done by ORM's. A normal Repository implementation should handle all aggregate entities (for instance Order and OrderLine). Bu handling them in the same repository class you can always make sure that those are built correctly.

But hey you say: That's done automatically for me by the ORM. Well, yes and no. If you create a website, you most likely want to edit only one order line. Do you fetch the complete order, loop through it to find the order, and then add it to the view?

By doing so you introduce logic to your controller that do not belong there. How do you do it when a webservice want's the same thing? Duplicate your code?

By using a ORM it's quite easy to fetch any entity from anywhere myOrm.Fetch<User>(user => user.Id == 1) modify it and then save it. This can be quite handy, but also add code smells since you duplicate code and have no control over how the objects are created, if they got a valid state or correct associations.

The next thing that comes to mind is that you might want to be able to subscribe on events like Created, Updated and Deleted in a centralized way. That's easy if you have a repository.

For me an ORM provides a way to map classes to tables and nothing more. I still like to wrap them in repositories to have control over them and get a single point of modification.

jgauffin
  • 99,844
  • 45
  • 235
  • 372
  • @Bikal Gurung: or in other more drastic words: The Repository is not necessary but it allows you to easyly replace one orm with an other. – k3b Jan 18 '11 at 13:19
  • 1
    Actually, I would put the emphasis on that Repository pattern makes it **easier** to test your code. It's more important than replacing a ORM implementation. Also, check my updated answer. – jgauffin Jan 18 '11 at 13:21
  • 3
    @k3b - Thats a bad reason. Switching ORMs on the fly is rare. @jgauffin - I don't understand your update. If a repo is built without paging or ordering than it won't have it. It has nothing to do with the pattern itself. – John Farrell Jan 18 '11 at 13:28
  • I did say *implementation* in my update, not that it was a problem with the pattern itself. – jgauffin Jan 18 '11 at 14:14
  • @kb3 Is having the requirement of being able to change ORM a realistic, practical and viable use case of the Repository pattern? Let's assume it was, what business and technical benefit does having such flexibility provide? – Bikal Lem Jan 18 '11 at 16:58
  • @kb3 Even for test puposes, these days you do not really need a interface backed repository. You can pretty much mock with MS Moles/Pex or other Moq libraries and tools. – Bikal Lem Jan 18 '11 at 17:02
  • 3
    @Bikal The benefit isn't actually being able to change the ORM, it's more subtle than that. The fact that you **can** change it shows that you have successfully separated your domain layer from data access concerns, giving you a loosely coupled, cohesive design. This means the domain layer is only responsible for modeling the domain. This is easier to test, easier to refactor, and all the other benefits of DDD that are well established. – James Morcom Jan 20 '11 at 10:05
  • @James Please read my assertion again. By using an ORM you have already abstracted out the data access logic. Further abstraction via Repository pattern in not necessary and thus adds to the noise & code bloat of the software design. Usage of ORMs pretty much makes the pattern redundant and doesn't provide for any significant and useful abstraction to the system. How does Repository pattern help with refactoring? Refactoring is a software developement process - maybe you IDE can help you better. – Bikal Lem Jan 24 '11 at 11:20
  • @BikalGurung: Want me to elaborate on anything else? – jgauffin Mar 12 '14 at 16:00
2

I think it make sense only if you want to decrease level of dependency. In the abstract you can have IPostRepository in your infrastructure package and several independent implementations of this interface built on top of EF or NH, or something else. It useful for TDD.

In practice NH session (and EF context) implements something like the "Unit of Work" pattern. Furthermore with NH and the Repository pattern you can get a lot of bugs and architectural issues.

For example, NH entity can be saved bypassing your Repository implementation. You can get it from session (Repository.Load), change one of its properties, and call session.Flush (at the end of request for example, because Repository pattern doesn't suppose flushing) - and your changes will be successfully processed in db.

mefcorvi
  • 139
  • 1
  • 4
1

You've only mentioned basic CRUD actions. Doing these directly does mean you have to be aware of transactions, flushing and other things that a repository can wrap up, but I guess the value of repositories becomes more apparent when you think about complex retrieval queries.

Imagine then that you do decide to use the NHibernate session directly in your application layer.

You will need to do the equivalent of WHERE clauses and ORDER BYs etc, using either HQL or NHibernate criteria. This means your code has to reference NHibernate, and contains ideas specific to NHibernate. This makes your application hard to test and harder for others unfamiliar with NH to follow. A call to repository.GetCompletedOrders is much more descriptive and reusable than one that includes something like "where IsComplete = true and IsDeleted = false..." etc.

You could use Linq to NHibernate instead, but now you have the situation where you can easily forget that you're working on an IQueryable. You could end up chaining Linq expressions which generate enormous queries when they execute, without realising it (I speak from experience)! Mike Hadlow sparked a conversation on essentially this topic in his post Should my repository expose IQueryable.

N.b. If you don't like having lots of methods on custom repositories for different queries (like GetCompletedOrders), you can use specification parameters (like Get(specification)), which allow you to specify filters, orderings etc. without using data access language.

Going back to the list of benefits of repository that you gave:

  • Persistence
  • OO View of the data
  • Data Access Logic Abstraction
  • Query Access Logic

You can see that points 3 and 4 are not provided for by using the persistence framework classes directly, especially in real world retrieval scenarios.

James Morcom
  • 1,749
  • 14
  • 17