Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why do Examples of the Repository Pattern never deal with Database Connection Exceptions?

I've read a lot of tutorials and seen a lot of code samples regarding implementations of the Repository pattern. In pretty much every case, exceptions that would result from attempting to hit the database when the database is unavailable is not addressed. This seems strange considering that this is a very realistic scenario if the DB is somewhere on a network.

So what is the best practice for handling these exceptions?

  • Wrap each of those hundred calls in a try/catch, where each one might have the same n catch blocks? That's a lot of duplication, messy, error-prone, etc.

  • Let the exceptions bubble up to the app level an catch them as unhandled exceptions? This makes sense if the exception is thrown on the UI thread, but otherwise, the handling of an unhandled AppDomain exception results in the app shutting down.

  • Use a framework such as Enterprise Library's Exception Handling Application Block?

like image 774
BCA Avatar asked May 07 '15 21:05

BCA


2 Answers

I honestly think that it isn't addressed because of the ongoing (and emotional) debate about what to do with exceptions. There is a constant back and forth over whether exceptions should be handled locally (where there is a greater chance of understanding them and doing something intelligent, like retrying) or handled at the UI layer (where 99.9% of exceptions eventually bubble up to).

Personally, I find it most elegant to do the try/catch inside the Repository layer, to catch the database-specific exceptions, and throw a new exception of my own making. That gives me a place to put retry logic. I can also then make the decision about whether that DAOException is a checked or a runtime exception.

This allows the user interface to deal with a known exception, and it helps me to isolate my higher-level layers from any provider-specific errors. For example, if I was migrating my data store to a No-SQL database like Mongo or Cassandra, I could still throw the same exceptions, and maintain their semantic meaning, without changing all the calling code.

like image 68
Rob Conklin Avatar answered Sep 30 '22 23:09

Rob Conklin


First, because SRP. A class only handle one and only one responsibility. At least in a method it is.

Second, it depends on what you need to do with the failure. Will you only show the error message to user? Handle it at application-level since data-level and business-level do not know what UI is there.

If you have a logic, for example: if the database cannot be accessed, use the offline cache, handle it using Decorator pattern or similar, ex:

public class OnlineUserRepository : IUserRepository{
    public User Get(){ /* get the user from online source */ }
}

public class OfflineUserRepository : IUserRepository{
    public User Get(){ /* get the user from offline source */ }
}

public class UserRepository : IUserRepository{
    public UserRepository(IUserRepository onlineRepo, IUserRepository offlineRepo){
        //parameter assignment
    }
    IUserRepository onlineRepo;
    IUserRepository offlineRepo;
    public User Get(){
        try{
            onlineRepo.Get();
        }
        catch{
            return offlineRepo.Get();
        }
    }
}

Why we need to handle it that way? Again, because SRP.

like image 33
Fendy Avatar answered Oct 01 '22 01:10

Fendy