views:

153

answers:

2

I have an asp .net MVC application and recently started implementing the repository pattern with a service validation layer, much like this.

I've been creating one repository/service for each model that I create. Is this overkill? Instead, should I create one repository/service for each logical business area that provides CRUD for many different models?

To me, it seems like I'm either cluttering the project tree with many files or cluttering a class with many methods. 6 one way half dozen the other. Can you think of any good arguments either way?

A: 

This is a question I recently asked, and despite getting several good answers I eventually came to my own conclusion - there is no right answer. That doesn't mean there isn't a wrong answer, infact there are lots of wrong answers, but the right answer will always depend on your own individual case.

I ended up with four repositories, and a partial class extension of my EF4 Entity Model for the standard CRUD actions for the child entities (addresses, phone numbers, status codes et al) so they were implemented once and available across all repositories. However, I am still refining it as I go, so perhaps I haven't yet come across the best solution.

My advice would be to try it and see if it fits, and see if it feels right. Usually, if it doesnt feel right, its wrong anyway.

If you are really afraid of cluttering up your source code tree, you can always break the model part out into its own library, and include it as a dependency.

Moo
+2  A: 

Generally, if you're using a "true" Repository Pattern, as opposed to other persistence layers (e.g. ActiveRecord or DAO's), you should aim to identify your domain aggregates, and create one repository per aggregate.

What does that mean? Well, it depends a lot on your app, but generally there are objects which are naturally 'parents' of other objects, or which are part of a related transaction.

I think the canonical example is an ecommerce system in which you have a concept of an order, and in an order you have orderlines each orderline is some product and a quantity, and so on.

In that case, the Order object is one of the system's aggregate roots and an OrderRepository is created.

The thing to remember in that case is that there's some relationship (implied or otherwise) between a order and its orderlines and so on. So the C-UD parts of "CRUD" on the Repository should generally just be one method each, and should generally just take in an instance of that aggregate root object and operate on it (.e.g. repo.Save(order)). Other possible params might be there, but that depends on your impl.

IN fact, you can often solve most of the C-UD part w/ inheritance (i.e. make a RepositoryBase that implements them using some known logic about what shoudl happen for your particular persistence scheme).

So that leaves us the R part of CRUD. In this case is where you might get a ton of query methods (GetById; GetByName; GetByCustomerName, etc) if you choose to go the query method route. Some folks prefer, espeically for simple apps, exposing a linq-based interface (e.g. an IQueryable GetAll()) that can then have Where clauses applied. YMMV depending on your underlying persistence on that one, but it's a solid shot for simple apps, esp. if you expect your persistence provider to support linq directly.

Lastly, many folks actually separate out the query part via one implentation or another of the Command Query Responsibility Separation pattern, which says the interfaces for persisting and querying should be different. IN that case, you'd have a Repo that just has basic CRUD (GetById, GetAll, Save, Delete) ops and another class of some sort which queries things based on your app's intentions.

Hope that helps.

Paul

Paul
Paul thanks for that detailed answer. After much thought and reading, I feel you're spot on with one repository/service per aggregate root. You are also correct about the CRUD, 1 method each for C_UD and lots of methods of R. In your Order example, would the OrderRepository also be the place to put R methods for OrderLines and OrderSubLines?
bradjive
That's a good question, and it depends. Do the orderlines and sublines actually mean anything useful w/o their associated order? If so, then yes, if not, then all your queries have to do w/ Orders and you can filter the child collection(s) using regular LINQ expressions over the IEnumerables.
Paul