4

I'm using the Entity Framework as my ORM and I'm using a Repository of repositories (?) to abstract the EF so I can mock out etc and test etc.

A single repo.

public interface IRepository<T> : IView<T>
{
    IQueryable<T> GetAll();
    void Update( T entity );
    void Delete( T entity );
    void Add(T entity);
    T Default();
}

the repo of repo's ;)

   public interface IRepoOfRepos
    {
        IRepository<Table_a> Table_as { get; }

        IRepository<Table_b> Table_bs { get; }

        IRepository<Table_c> Table_cs { get; }

etc etc

In our application we have a series of 'modules' that perform discrete chunks of business logic and I was planning on 'injecting' the 'IRepoOfRepos' into each.

However, another team member has suggested that we should really be creating an additional layer (interface) with only the data access methods needed by each module (aka the 'I' in SOLID).

We have quite a large number of modules (30+) and this seems like quite a lot of extra work for a principle that I feel may not apply to the Data Access Layer and is really aimed at the Business Layer?

Your thoughts are much appreciated and thanks in advance!

  • You never abstract the ORM, you're always abstracting the Persistence. Also you need to understand the Repository pattern first (see [this less technical explanation](http://www.sapiensworks.com/blog/post/2014/06/02/The-Repository-Pattern-For-Dummies.aspx) ), your code is the repository anti-pattern – MikeSW Jun 05 '14 at 15:25

2 Answers2

1

There's a bunch of questions that cover this already:

How to use the repository pattern correctly? (best)

One repository per table or one per functional section?
What is best practise for repository pattern - repo per table?
Are you supposed to have one repository per table in JPA?

From my experience: Be ruthlessly pragmatic in your repository design. Only implement the queries you actually need RIGHT NOW, like Customer.CreateOrder() which may have required several different IRepository.Add() calls.

You won't end up using all of the CRUD methods on every table, anyway. (YAGNI)

If your Data Access Layer just provides implementations of IRepository<T>, then it doesn't fulfill its purpose. Have a look at the first question I linked - it's very instructive.

Community
  • 1
  • 1
Zachary Yates
  • 11,664
  • 7
  • 50
  • 84
  • Thankyou, I'm looking at the first link now ;) – user3710407 Jun 05 '14 at 10:03
  • ok, I've looked at the first link and I take your point (maybe) but I'm still not sure if I should add a further layer to the repository that would limit a Modules access to the repo? – user3710407 Jun 05 '14 at 12:56
  • Ask yourself: Why am I even creating the IRepository interface? Will I switch the EF implementation out with something else later? (That almost never happens). It just depends on your design preference. Go for whatever is less code, and have a good reason for everything you do. – Zachary Yates Jun 05 '14 at 13:10
  • sounds kewl, but my main reason for doing it was to allow me to mock out the EF and use dummy data in unit tests...it may not be the ideal repository pattern but it's consistent and gives me what I need to write unit/integration tests around my code....it took a couple of hours to implement also so it wasn't expensive... – user3710407 Jun 05 '14 at 13:14
  • That's a good reason. The mocking/unit testing gets harder with more complex operations where there are keys/dependencies between tables though. – Zachary Yates Jun 05 '14 at 13:19
  • maybe a bit of background may explain why I did this. I'm a contractor working on a project were most of the team is an offshore outsourced software house. The only testing they have is full end to end testing using a real db. They are currently taking over a week per story to create the test data needed to test each module - that's not including the time to code or test the module. I can code up a module and do all the unit tests in a couple of days.. – user3710407 Jun 05 '14 at 13:19
1

The 'composite' repository pattern doesn't exist. A repository doesn't know about other repositories. If you need to use more than one, have all the relevant interfaces injected as arguments for the service using them.

A repository interface is defined only for the specific bounded context needs. You have 30 modules,that's ok, some of their needs are common so you can have a common interface definition (because it's an abstraction there's no tight coupling). You define then other interface specific for the module's needs. Each module service (regardless of the module) will use only the needed abstractions.

When testing you'll be testing business service behaviour, using repository fakes/mocks. ORM is irrelevant, because your repo interface knows only about business objects and you never tell the repository how to do its work.

In conclusion, yes, Interface Segregation is valid to use, but no repository of repositories.

MikeSW
  • 15,292
  • 3
  • 33
  • 50