NHQS Part 4: Multiple Database Connectivity and Transaction Management
Most of the previous posts have alluded to the multiple-database goal of NHQS and some of the code has demonstrated the beginnings of a demonstration of the feature. This post will take a longer look at how NHQS can provide multiple-database support and will wrap up by demonstrating transaction management within NHQS.
Multiple Database Connectivity
As has been demonstrated in the previous posts’ unit test setup methods the provision within NHQS for multiple database support relies on the idea that multiple session factories are contained automatically by NHQS, and during that containment associations are made between the session factories and the domain entities they service. Take another look at the test fixture setup, which has been modified in this post to provide the initial persistence of testing data.
In this example, recall from the first post, we’ll be working with two different domain entity projects, each of which is serviced by its own session factory. Since both session factories are being contained by NHQS, the domain language specifies where the objects are sent, and the respective session factories do the rest.
To further understand how awesome this idea is take a peek at the test project’s configuration file. Note how the first of the connection strings points to a SQLCE database, and the second connection string points to a SQL Server 2008 database. So long as NHibernate supports the RDBMS you’re targeting, NHQS can target it.
The test below completes this section of the multiple-database examination by demonstrating how data from one of the databases tied to the application – the Person SQL CE table – can be pulled and inserted into a table in another database – the Customer SQL Server table.
This unit test demonstrates how you could potentially use domain language and NHQS to perform data migrations – even when the database platform is completely different.
Fans of the Unit of Workpattern/concept will appreciate this section of the post. Those with extensive NHibernate experience understand the idea of managing transactions explicitly rather than just expecting implicit transactions. If you’ve ever used NHProf to profile and trace your NHibernate queries you’ll know explicit transaction usage is an area it warns about repeatedly.
Basically the rule of thumb with NHibernate is that, one should always perform the work of saving, updating, and deleting related entities to an underlying persistence mechanism, in the context of an explicit transaction. Most problems or misunderstandings about when does my data truly get saved when I use NHibernatecan be mitigated by using explicit transactions. Most generic approaches yield problems when dealing with transactions, so NHQS had a goal of doing its best to allow the developer the right to manage their transactions separate to the internal workings of NHQS.
Take a look at the RealWorkWrappermethod within NHQS to demonstrate the way it works. The method peeks at the NHibernate session to see if it is involved in a transaction. If not, it starts its own and does the work. If so, the method just remains within that transaction as it does its own work.
One of the NHQS CRUD methods, Save<T>, is pictured below. These two code snippets are not to dive deep into howNHQS works (that would defeat the black-box idea in the first place, right?), but rather to demonstrate how NHQS will either use the existing transaction when it exists and if not, how it will create its own. The idea being, to keep inline with an NHibernate best practice recommendation (or to keep inline with my interpretation of it, which is open to review).
Here’s the point to that shallow dive. When a developer wants to do something in NHibernate specifically and maybe use NHQS here and there, they have the freedom of doing what they want to do in their own way and to combine NHQS by simply re-using an existing NHibernate session. This way, NHQS can be added or removed in-line with your current NHibernate implementation, without having to change a whole lot. Unit-of-work aficionados will appreciate the ability of re-using the transaction for multiple database procedures, so that CRUD operations can be grouped together to ensure validity.
Examine this unit test and how it would work (and why it would be valid).
- Verify there are no records in the table
- Add one person
- Add a second person
- Verify that two records are in the table
- Throw an exception. Since the steps are being performed in a transaction – via the DoWithTransaction call wrapping the unit of work being performed – firing the exception will cause avoidance of the transaction’s commit method being called, so…
- Verify that no records exist in the database
I hope you’ve enjoyed this brief encounter with NHQS. As was stated in the original post, it had a few clear goals. I hope NHQS makes your life easier and, if you’ve recently embarked into using NHibernate, that it makes that process a little less painful. If you have any suggestions, or have extensive experience with NHibernate and find yourself strongly objecting to how NHQS does things, please leave a comment. I’m always trying to improve not only NHQS, but my understanding of how NHibernate works.