What's the best practice for handling exceptions in NHibernate?
I've got a SubjectRepository with the following:
public void Add(Subject subject)
{
using (ISession session = HibernateUtil.CurrentSession)
using (ITransaction transaction = session.BeginTransaction())
{
session.Save(subject);
transaction.Commit();
}
}
And a Unit Test as follows:
[Test]
public void TestSaveDuplicate()
{
var subject = new Subject
{
Code = "En",
Name = "English"
};
_subjectRepository.Add(subject);
var duplicateSubject = new Subject
{
Code = "En",
Name = "English1"
};
_subjectRepository.Add(duplicateSubject);
}
I got to the point of handling the error generated by the unit test and got a bit stuck. This fails as expected, though with a GenericADOException, I was expecting a ConstraintViolationException or something similar (there is a uniqueness constraint on the subject code at database level).
The ADOException wraps a MySQL Exception that has a sensible error message but I don't want to start breaking encapsulation by just throwing the inner exception. Particularly as MySQL isn't finalised as the back end for this project.
Ideally I'd like to be able to catch the exception and return a sensible error to the user at this point. Are there any documented best practice approaches to handling NHibernate Exceptions and reporting back up to the user what went wrong and why?
Thanks,
Matt
I would handle it in the Add method as such:
public void Add(Subject subject)
{
using (ISession session = HibernateUtil.CurrentSession)
using (ITransaction transaction = session.BeginTransaction())
{
try
{
session.Save(subject);
transaction.Commit();
}
catch (Exception ex)
{
transaction.Rollback();
// log exception
throw;
}
}
}
In the catch block, you should first rollback the transaction and log the exception. Then your options are:
Rethrow the same exception, which is what my version does
Wrap it in your own exception and throw that
Swallow the exception by doing nothing, which is very rarely a good idea
You don't have any real options for handling the exception in this method. Assuming that the UI calls this method, it should call it in its own try..catch and handle it by displaying a meaningful error message to the user. You can make your unit test pass by using the ExpectedException(type) attribute.
To answer your question directly, you should create your own "sensible error" by extending Exception and throw that with the original exception as its InnerException. That's the exception wrapping technique I listed in (2).
All the Nhibernate exceptions are non recoverable, you could revisit the design of the app/data layer if you are trying to recover from nhibernate exceptions .
You can also Take a look at spring.net 's exception translation implementaion
Also you manually handling transactions on exceptions is tedious and error prone, take a look at nhibernate's contextual sessions .
Spring.net also has some nice helpers around nhibernate .
The general question is going to be, what do you want to tell the user, and who is the user?
If the user will sometimes be another computer (i.e., this is a web service), then you would want to use the appropriate mechanism to return a SOAP Fault or HTTP error.
If the user will sometimes be a UI of some sort, then you may want to display a message to the user, but what would you tell the user so he can do something about it? For instance, most web sites will say, "sorry, we had an unexpected error", no matter what the reason. That's because there's usually nothing the user could do about the error.
But in either case, the choice of how to tell "the user" is a matter for the Presentation layer (UI tier), not for the DAL. You should possibly wrap exceptions from the DAL in another exception type, but only if you're going to change the message. You don't need your own exception class, unless your callers would do something different if it's a data access exception rather than some other kind.
I'd probably validate the input before saving the object; that way you can implement whatever validation you like (e.g. check the length of the Subject Code as well as the fact that there aren't any duplicates), and pass back meaningful validation errors back to the user.
The logic is as follows; exceptions are used to indicate exceptional circumstances that your program doesn't cater for. A user entering a duplicate Subject Code in your example above is something your program should be catering for; so, rather than handling an exception because a DB constraint gets violated (which is an exceptional event and shouldn't be occurring), you'd want to handle that scenario first and only attempt to save the data when you know that the data you're saving is correct.
The advantage with implementing all validation rules in your DAL is that you can then ensure that the data going into your DB is valid as per your business processes in a consistent manner, rather than relying on the constraints in your DB to catch those for you.
Related
I'm creating integration tests for my application using Spek. I have a set of Providers to test and each one makes a request and parses a response.
describe("Providers")
{
for(provider in providers)
{
on("Provider: $providerName")
{
try
{
//...
val responsePromise = when (provider)
{
is HtmlProvider -> connectionService.reactiveGetForHtml(connectionRequest)
is JsonProvider<*> -> connectionService.reactiveGetForJson(connectionRequest, provider.getJsonClass())
else -> throw IllegalStateException("Provider must be either Html or JSON")
}
val response = runBlocking { responsePromise.await() }
Both connectionService.reactiveGetForHtml() reactiveGetForJson() return a RxJava2's SingleSource.
The problem: one of Providers throws a bunch of exceptions (it has to parse a big JSON file and due to problems with data model Jackson throws huge number of exceptions). This is fine, test are designed to handle and report such errors. In this case, problematic Provider fails its own test with a Jackson exception. But, when runner executes remaining test cases, strange things happen. All next Providers' tests fail because of the same exceptions. runBlocking keeps throwing exceptions from faulty Provider on and on, no matter what responsePromise is. Don't know if this is a bug or some strange behaviour of .await(), but I don't hava any idea how to overcome this.
All test cases of Providers that don't throw multiple exceptions run well and report their own errors, but after executing that faulty Provider everything fails. It's not the case of this exact Provider, if I removed this particular test case, other Providers that thrown multiple exceptions caused simiar problem.
I'm writing a small, simple web app in go using the gorm ORM.
Since the database can fail independently of the web application, I'd like to be able to identify errors that correspond to this case so that I can reconnect to my database without restarting the web application.
Motivating example:
Consider the following code:
var mrs MyRowStruct
db := myDB.Model(MyRowStruct{}).Where("column_name = ?", value).First(&mrs)
return &mrs, db.Error
In the event that db.Error != nil, how can I programmatically determine if the error stems from a database connection problem?
From my reading, I understand that gorm.DB does not represent a connection, so do I even have to worry about reconnecting or re-issuing a call to gorm.Open if a database connection fails?
Are there any common patterns for handling database failures in Go?
Gorm appears to swallow database driver errors and emit only it's own classification of error types (see gorm/errors.go). Connection errors do not currently appear to be reported.
Consider submitting an issue or pull request to expose the database driver error directly.
[Original]
Try inspecting the runtime type of db.Error per the advice in the gorm readme "Error Handling" section.
Assuming it's an error type returned by your database driver you can likely get a specific code that indicates connection errors. For example, if you're using PostgreSQL via the pq library then you might try something like this:
import "github.com/lib/pq"
// ...
if db.Error != nil {
pqerr, ok := err.(*pq.Error)
if ok && pqerr.Code[0:2] == "08" {
// PostgreSQL "Connection Exceptions" are class "08"
// http://www.postgresql.org/docs/9.4/static/errcodes-appendix.html#ERRCODES-TABLE
// Do something for connection errors...
} else {
// Do something else with non-pg error or non-connection error...
}
}
I have a handful of pages where I want to look for an element, and if it is present, get the text. But I've run into a bit of a conundrum with respect to exception handling.
I can use WebDriverWait:
wait.until(EC.presence_of_element_located((By.XPATH, '//div[#class="className"]')))
But if this throws an exception, I technically have no way of knowing whether it occurred because the element is in fact not present on the page, or because of something else (e.g. I didn't wait long enough or there's some other error in the code).
In my particular case I've been able to deal with this so far by using the presence of some other elements on the page to infer whether the one I'm looking for will be present. However, I am bound to run into some pages where I can't use other elements as proxies.
Is there any way for me to distinguish between an exception caused by the element actually not being in the page source versus some other reason?
You should specify the Exception you want to catch and then do something in the catchblock, refer to the Java Doc here to give you more insight on exceptions
http://selenium.googlecode.com/git/docs/api/java/index.html
public void aMethod() {
try {
//do someting
} catch( Exception e ) {
textLog( "Element not present -------" );
detailedText( e );
}
}
I have a .NET web application that frequently executes queries to get data from a local database.
In situations where the query doesn't run (due to an exception) or the query returns an unexpected set of data (such as an empty set). I want to be able to rebuild the query (replacing it's #parameters with the values actually used) and store the complete query in the database along with the exception.
I'm aware that I can do this through standard code but I was wondering whether it would be safer to do via Elmah?
Also would doing this via Elmah give me the ability to be able to view the executed sql through elmah.axd (when access is enabled)?
Unless the thrown exception includes the query with the actual values, ELMAH doesn't help you there other than logging the exception. You can catch the exception yourself and do a custom logging to ELMAH using the ErrorSignal.Raise method as explained here: How to use ELMAH to manually log errors?
I log SQL exceptions by passing the exception and the actual command to a new Exception class. The class wraps the SqlException and the System.Data.Common.DbCommand objects. Using that information I can create a message to provide the sql command details:
public override string Message
{
get
{
StringBuilder message = new StringBuilder("");
StringBuilder sql = new StringBuilder("");
sql.AppendFormat(" {0} ", Command.CommandText);
foreach (SqlParameter param in Command.Parameters)
{
sql.AppendFormat(" {0} - {1}", param.ParameterName,
param.Value.ToString());
}
message.AppendFormat("Error: {0} SQL: {1} User: {2}", SqlEx.Message,
sql, Username);
return message.ToString();
}
}
Finally, I use the ErrorSignal Raise method to log the message in Elmah:
Elmah.ErrorSignal.FromCurrentContext().Raise(new DetailSqlException(e.Exception as SqlException, e.Command, user));
In regards to Error handling in PHP -- As far I know there are 3 styles:
die()or exit() style:
$con = mysql_connect("localhost","root","password");
if (!$con) {
die('Could not connect: ' . mysql_error());
}
throw Exception style:
if (!function_exists('curl_init')) {
throw new Exception('need the CURL PHP extension.
Recomplie PHP with curl');
}
trigger_error() style:
if(!is_array($config) && isset($config)) {
trigger_error('Error: config is not an array or is not set', E_USER_ERROR);
}
Now, in the PHP manual all three methods are used.
What I want to know is which style should I prefer & why?
Are these 3 drop in replacements of each other & therefore can be used interchangeably?
Slightly OT: Is it just me or everyone thinks PHP error handling options are just too many to the extent it confuses php developers?
The first one should never be used in production code, since it's transporting information irrelevant to end-users (a user can't do anything about "Cannot connect to database").
You throw Exceptions if you know that at a certain critical code point, your application can fail and you want your code to recover across multiple call-levels.
trigger_error() lets you fine-grain error reporting (by using different levels of error messages) and you can hide those errors from end-users (using set_error_handler()) but still have them be displayed to you during testing.
Also trigger_error() can produce non-fatal messages important during development that can be suppressed in production code using a custom error handler. You can produce fatal errors, too (E_USER_ERROR) but those aren't recoverable. If you trigger one of those, program execution stops at that point. This is why, for fatal errors, Exceptions should be used. This way, you'll have more control over your program's flow:
// Example (pseudo-code for db queries):
$db->query('START TRANSACTION');
try {
while ($row = gather_data()) {
$db->query('INSERT INTO `table` (`foo`,`bar`) VALUES(?,?)', ...);
}
$db->query('COMMIT');
} catch(Exception $e) {
$db->query('ROLLBACK');
}
Here, if gather_data() just plain croaked (using E_USER_ERROR or die()) there's a chance, previous INSERT statements would have made it into your database, even if not desired and you'd have no control over what's to happen next.
I usually use the first way for simple debugging in development code. It is not recommended for production. The best way is to throw an exception, which you can catch in other parts of the program and do some error handling on.
The three styles are not drop-in replacements for each other. The first one is not an error at all, but just a way to stop the script and output some debugging info for you to manually parse. The second one is not an error per se, but will be converted into an error if you don't catch it. The last one is triggering a real error in the PHP engine which will be handled according to the configuration of your PHP environment (in some cases shown to the user, in other cases just logged to a file or not saved at all).