Should repository have a method for every specific database operation

design-patternspatterns-and-practicesrepository

When following the standard service and repository patterns, should your repository contain a specific method for every database operation or should you just use the general methods, e.g. update? Take for example the following service method:

DisableUser(User user) {
    user.enabled = false;
    userRepo.update(user); // General user update method
}

This performs its changes on the user record, then requests the repo update the database by calling the general user update method.

Or should it be more specific, like:

DisableUser(User user) {
    userRepo.disable(user); // Specific operation, matching the service
}

Obviously this is a very simple example but I feel the conclusion affects the way I move forward with repository's in general and this same logic applies to many scenarios.

What further confuses me is that in the first case using the standard update method may be seen as inefficient, because it may update every column on the record, but I happen to be using Entity Framework so it will take care of checking what fields have changed and only updating the changed field for me. But should I be making that assumption from my service?

If I were to write an alternate plain sql implementation of the repository id have to update all fields there, or implement field change detection myself. So that part leans me towards the specific implementation, but with that I'm adding a lot more methods and perhaps it feels a bit unnecessary.

So in a nutshell, should your repo just have the standard methods, update, insert, findById, findAll, delete. Or should it have a method for every specific database operation, like stored procedures.

There's probably several other considerations that I'm not grasping. Any advice would be appreciated.

Best Answer

To provide a different perspective than the already existing answer I would say that it depends.

The generic one is more reusable, but the domain-specific one signals intent and better separates your domain model from the choice of persistance. If you do

var user = repo.GetUser(id); user.Enabled = false; repo.Update(user);

Then the repo has no real idea what it is doing (which can be a good thing from the reusability perspective). But you have also lost the possibility of remembering the intent of the operation.

If you do the domain-specific one:

repo.DisableUser(id);

First of all, maybe you can implement your repository more efficiently. You might not need to get the user to disable him - maybe you can just do an UPDATE and be done with it. Also, you know what you are doing, so you could choose to also add a good log message in an audit log or something similiar at the repository level. While you could still do audit logging with the more generic version you would get a generic "customer updated" entry instead of a domain specific "customer disabled" entry. This can in many cases be very nice and valuable.

This is more work though, which is why in general people will go with the generic solution because it is more generic and easier to implement. But dont disregard the domain-specific repository as unusable or bad, the answer is always it depends.

Related Topic