Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MVC: What's better, one large repository per db or one per business entity?

This time I have a more philosopical question.

Most MVC tutorials/books seem to suggest to restrict the scope of one repository to one aspect of the model and set up multiple repositories to cover all model classes. (E.g.: ProjectRep, UserRep, ImageRep, all mapping onto the same db eventually.)

I can see how that would make unittesting simpler but I can't imagine how this would work in the real world, where most entities have relationships between each other. In the end I always find myself with one gigantic repository class per DB connection and an equally arkward FakeRepository for unittesting.

So, what's your opinion? Should I try harder to seperate out repositories? Does it even matter if the ProductRep refers to data in the UserRep and vice versa via PurchaseHistory? How would the different reps make sure they don't lock each other up when accessing the single db?

Thanks, Duffy

like image 912
duffy Avatar asked Jul 16 '10 16:07

duffy


2 Answers

This works in the real world because there's single engine under the hood of the repositories. This can be ORM like NHibernate or your own solution. This engine knows how to relate objects, lock database, cache requests, etc. But the business code shouldn't know these infrastructure details.

What you effectively do when you end up with one giantic repository is exposing this single engine to the real world instead. Thus you mess your domain code with engine-specific details that are otherwise hidden behind repository interfaces.

S#arp Architecture is a very good illustration of how repositories that Josh talk about are implemented and work. Also read the NHibernate best practices article that explains much of S#arp background.

And frankly, I can't imagine how your giantic repository works in the real world. Because the very idea looks bad and unmaintainable.

like image 190
queen3 Avatar answered Sep 17 '22 15:09

queen3


I've found that by using generics and an interface, you can avoid having to code many separate repositories. If your domain model is well-factored, you can often navigate object graphs using the domain objects rather than another repository.

public class MyDomainObject : IEntity //IEntity is an arbitrary interface for base ents
{
     public int Id { get; set;}
     public List<DiffObj> NavigationProp { get; set;}
     //... and so on...
}

public interface IRepository<T> where T : IEntity, class, new()
{
     void Inert(T entity);
     T FindById(int id);
     //... and so on
}

The usage is pretty simple, and by using IoC you can completely decouple implementation from the rest of your application:

public class MyBusinessClass
{
     private IRepository<SomeDomainObject> _aRepo;
     public MyBusinessClass(IREpository<SomeDomainObject> aRepo)
     {
          _aRepo = aRepo;
     }
     //...and so on
}

This makes writing unit tests a real snap.

like image 43
Josh E Avatar answered Sep 17 '22 15:09

Josh E