
NHibernate Profiler’s Named Sessions
January 27th, 2010A typical DBA concern in larger shops is that once stored procedures no longer figure (or at least, are used where they are genuinely needed rather than as a mandate), they have no way of knowing what kind of NH-generated SQL might cause problems in production. A while ago I bought Ayende’s NHibernate Profiler (hereafter NHProf) as part of a way to try to alleviate these concerns.
As I’m sure everyone knows by now, NHProf is a nice tool which helps you spot when you’re doing something boneheaded when using NHibernate and gives you handy suggestions on what to do to fix it. It’ll also show you a every SQL statement you’re throwing at your database, nicely formatted for your convenience. It groups these statements into individual ISessions. So if I have three integration tests based on Northwind that look like this (InTransactionalSession is just shorthand for using(ISession) ... using(ITransaction)):
[Test]
public void CanLoadCustomer()
{
InTransactionalSession(session =>
{
var v = session.Load<Customer>("ALFKI");
Assert.That(v.CompanyName, Is.Not.Null & Is.Not.Empty);
});
}
[Test]
public void CanGetCustomersByRegion()
{
InTransactionalSession(session =>
{
IList<Customer> customers = session.CreateQuery("from Customer c where c.Region = 'OR'")
.List<Customer>();
Assert.That(customers.Count, Is.GreaterThan(0));
});
}
private const string TestCustomerId = "FLURB";
[Test]
public void CanDoRoundTripPersistenceTest()
{
InTransactionalSession(session =>
session.Delete(
string.Format("from Customer c where c.CustomerId = '{0}'",
TestCustomerId)));
InTransactionalSession(session =>
new PersistenceSpecification<Customer>(session)
.CheckProperty(c => c.CustomerId, TestCustomerId)
.CheckProperty(c => c.CompanyName, "Flurb's Jelly")
.CheckProperty(c => c.ContactName, "Mr. Flurby")
.CheckProperty(c => c.Region, "OR")
.VerifyTheMappings());
}
I can see four InTransactionalSession calls in those three tests, and the output from NHProf gives us what we might expect:

NHProf Numbered Sessions
Perfectly accurate, but if I had a hundred tests I’d struggle to notice which test had caused a problem and I’d lose time tying a session back to a test (ok, not too much time – NHProf has a stack trace tab which lets you double-click jump back to your code, after all, but I like “at-a-glance”). Post-NHProf v1.0, Ayende asked for feedback on what should go into future releases. Since he’d already covered showing DB plans, I thought I’d take a punt on named sessions.
A week or two back Ayende mailed me to say he’d added support (great customer service!). Now all you’ve got to do is call
NHibernateProfiler.RenameSessionInProfiler(session, sessionName);
and the next session that NHProf hears about will take that name. Combining this with a stack trace gives me exactly what I wanted in just a couple of overloads:
private string lastTestMethodName;
private int sameMethodCount;
protected void InTransactionalSession(Action<ISession> action)
{
string currentTestMethodName = new StackTrace().GetFrames()[1].GetMethod().Name;
sameMethodCount = currentTestMethodName == lastTestMethodName ? sameMethodCount + 1 : 1;
string methodName = string.Format("{0} #{1}", currentTestMethodName, sameMethodCount);
InTransactionalSession(methodName, action);
lastTestMethodName = currentTestMethodName;
}
protected void InTransactionalSession(string sessionName, Action<ISession> doDataAccess)
{
using(ISession session = SessionFactory.OpenSession())
using(ITransaction tx = session.BeginTransaction())
{
NHibernateProfiler.RenameSessionInProfiler(session, sessionName);
doDataAccess(session);
if(session.Transaction.IsActive)
tx.Commit();
}
}
This results in something that lets me tie sessions to methods at a glance:

At the moment, this is great for people new to NH who want a quick way of demonstrating concepts, but it’s also great as a quick way of running a few tests at once and getting an idea of where your problem areas are. Cheers Ayende.
