This question is actually to wide. I will try to add an images to reduce lengthy code. I am considering only UniqueConstraintException
in this example and will use C# instead of vb.net. Have to change my lot of code otherwise.
In my scenario, I created a BaseException
class which is inherited from Exception
class.
public class BaseException : Exception
{
public BaseException()
: base()
{ }
public BaseException(string _exceptionMessage)
: base(_exceptionMessage)
{
}
public BaseException(string _exceptionMessage, Exception _innerException)
: base(_exceptionMessage, _innerException)
{
}
}
Since I am interested SQL exceptions so I will create few more classes.
See my class diagram below, SqlHelperException
is derived from BaseException class. SqlHelperException class object will be thrown by your CRUD operations in DAL
hitting database, should be handled by BAL
layer.
public class SqlHelperException : BaseException
{
public string ErrorMessage { get; set; }
public SqlHelperException()
: base()
{
}
public SqlHelperException(string message)
: base(message)
{
}
public SqlHelperException(string message, System.Exception innerException)
: base(message, innerException)
{
}
}
public class SqlHelperUniqueConstraintException : SqlHelperException
{
public SqlHelperUniqueConstraintException()
: base()
{
}
public SqlHelperUniqueConstraintException(string message)
: base(message)
{
}
public SqlHelperUniqueConstraintException(string message, Exception innerException)
: base(message, innerException)
{
}
}
Once my ground work is done, I wrote a translator which accepts SqlException
and wraps it into SqlHelperException object
public static SqlHelperException TranslateException(System.Data.SqlClient.SqlException ex)
{
SqlHelperException dalException = null;
// Return the first Custom exception thrown by a RAISERROR
foreach (System.Data.SqlClient.SqlError error in ex.Errors)
{
if (error.Number >= 50000)
{
dalException = new SqlHelperException(error.Message, ex);
}
}
if (dalException == null)
{
// uses SQLServer 2005 ErrorCodes
switch (ex.Number)
{
case 2601:
// Unique Index/Constriant Violation
dalException = new SqlHelperUniqueConstraintException(ex.Message, ex);
//Overwrite Error message with your custom error message, we can use Resource file
dalException.ErrorMessage = ErrorMessages.SqlHelperUniqueConstraintException;
break;
case 18456:
// Login Failed
dalException = new SqlHelperLoginException(ex.Message, ex);
break;
default:
// throw a general DAL Exception
dalException = new SqlHelperException(ex.Message, ex);
break;
}
}
// return the error
return dalException;
}
Here in this translator, I used ErrorMessages.SqlHelperUniqueConstraintException
static property which holds actual error message.
public class ErrorMessages
{
public static readonly string SqlHelperUniqueConstraintException;
static ErrorMessages()
{
SqlHelperUniqueConstraintException = "{0} failed, duplicate {1} already exists.";
}
}
Now in my DAL layer where I wrote my CRUD operations, I simply consumed these exceptions
public class Person
{
public void Create()
{
SqlHelper sql = new SqlHelper();
try
{
sql.ExecuteNonQuery()
}
catch (SqlEception ex)
{
var e =TranslateException(ex);
e.ErrorMessage = string.Format(e.ErrorMessage, "Creation", "Person");
throw e;
}
}
}
By doing so, at BAL I will get error message saying : "Creation failed! duplicate person already exist."