Search code examples
c#.netasp.netasp.net-mvcrepository-pattern

How can I use the repository pattern correctly?


I am wondering how should I be grouping my repositories? Like from the examples I seen on the ASP.NET MVC and in my books they basically use one repository per database table. But that seems like a lot of repositories leading you to have to call up many repositories later on for mocking and stuff.

So I am guessing I should group them. However I am not sure how to group them.

Right now I made a registration Repository to handle all my registration stuff. However, there are like four tables I need to update and before I had three repositories to do this.

For example, one of the tables is a license table. When they register I look at their key and check it to see if exists in the database. Now what happens if I need to check this license key or something else from that table at some other spot other then registration?

One spot could be login (check if the key is not expired).

So what would I do in this situation? Rewrite the code again (break DRY)? Try to merge these two repositories together and hope that none of the methods are needed in some other point of time(like maybe I might have a method that checks if userName is used - maybe I will need that somewhere else).

Also if I merge them together I would either need two service layers going to the same repository since I think having all the logic for two different parts of a site would be long, and I would have to have names like ValidateLogin(), ValdiateRegistrationForm(), ValdiateLoginRetrievePassword(), etc.

Or call the Repository anyway and just have a weird sounding name around?

It just seems hard to make a repository that has a general enough name so you can use it for many spots of your application and still make sense and I don't think calling another repository in a repository would be a good practice?


Solution

  • One thing that I did wrong when playing around with repository pattern—just like you, I thought that table relates to repository 1:1. When we apply some rules from domain-driven design, the grouping repositories problem often disappears.

    The repository should be per the Aggregate root and not table. It means, if entity shouldn't live alone (i.e., if you have a Registrant that participates in a particular Registration), it's just an entity, and it doesn't need a repository. It should be updated/created/retrieved through the repository of aggregate root it belongs to.

    Of course, in many cases, this technique of reducing the count of repositories (actually, it's more a technique to structure your domain model) can't be applied, because every entity is supposed to be an aggregate root (that highly depends on your domain, I can provide blind guesses only). In your example, License seems to be an aggregate root, because you need to be able to check them without any context of the Registration entity.

    But that does not restrict us to cascade repositories (the Registration repository is allowed to reference the License repository if needed). That does not restrict us to reference the License repository (preferable, through IoC) directly from the Registration object.

    Just try not to drive your design through complications provided by technologies or misunderstanding something. Grouping repositories in ServiceX just because you don't want to construct two repositories isn’t good idea.

    Much better would be to give it a proper, name, RegistrationService, for example.

    But services should be avoided in general. They often are cause that leads to an anemic domain model.

    Do start to use IoC. It truly eases the pain of injecting dependencies.

    Instead of writing:

    var registrationService = new RegistrationService(new RegistrationRepository(),
          new LicenseRepository(), new GodOnlyKnowsWhatElseThatServiceNeeds());
    

    you will be able to write:

    var registrationService = IoC.Resolve<IRegistrationService>();
    

    P.S.: It would be better to use so called common service locator, but that's just an example.