Posts tagged ‘NHibernate’

March 3rd, 2010

Unintended consequences – Transactions

What’s wrong with the following code?

using (var transaction = session.BeginTransaction())
{
    session.Save(something);
    transaction .Commit();
}

Nothing if you are using MySQL connector 6.0, which has the following Dispose method on its MySqlTransaction class.

protected override void Dispose(bool disposing)
{
    if ((((this.conn != null) && (this.conn.State == ConnectionState.Open)) || this.conn.SoftClosed) && this.open)
    {
        this.Rollback();
    }
    base.Dispose(disposing);
}

But if you are using 5.0.9, check out this code (which is actually from the underlying DbTransaction object).

public void Dispose()
{
    this.Dispose(true);
}
 
protected virtual void Dispose(bool disposing)
{
}

Where’s the rollback? Missing. Just wait till your next transaction block.

Looks like it was fixed in 5.1. Srijak and Dellanoce figured this out, but I sniped it from them before they could post. I was standing over their shoulder :)

Post to Twitter Post to Delicious Post to Digg Post to Facebook Post to Reddit

December 17th, 2009

NHibernate Connection Release Modes

Some team members and I spent the better part of a few hours today researching a really weird bug we were seeing with our data access code built on NHibernate.

The basic symptoms were a duplicate key violation on a unique column in a table. This only happened under decent load, so reproducing in dev was pretty hard. To make matters more interested, it only happened with NHibernate 2.0. We started looking at MySQL logs and saw the following.

INSERT (value, unique_value) some_table VALUES ('some_value', 'some_unique_value');
-- Auto-increment ID column gets set to 10
SELECT LAST_INSERT_ID()
-- Returns 9
UPDATE unique_value='some_unique_value' AND value='other_value' WHERE id=9
-- Duplicate key exception because unique constraint is violated

Yes, SELECT LAST_INSERT_ID() was returning the wrong value. After digging through the NHibernate source code, it became pretty apparent what was happening. We weren’t using transactions (because the DB is MyISAM) and we found the following code.

// (Some ConnectionManager code)
public void AfterTransaction()
{
	if (IsAfterTransactionRelease)
	{
		AggressiveRelease();
	}
	else if (IsAggressiveRelease && batcher.HasOpenResources)
	{
		log.Info("forcing batcher resource cleanup on transaction completion; forgot to close ScrollableResults/Enumerable?");
		batcher.CloseCommands();
		AggressiveRelease();
	}
	else if (IsOnCloseRelease)
	{
		// log a message about potential connection leaks
		log.Debug(
			"transaction completed on session with on_close connection release mode; be sure to close the session to release ADO.Net resources!");
	}
	transaction = null;
}
 
private bool IsAggressiveRelease
{
	get
	{
		if (connectionReleaseMode == ConnectionReleaseMode.AfterTransaction)
		{
			return !IsInActiveTransaction;
		}
		return false;
	}
}
 
//Some AbstractSessionImpl code
 
protected void AfterOperation(bool success)
{
	using (new SessionIdLoggingContext(SessionId))
	{
		if (!ConnectionManager.IsInActiveTransaction)
		{
			ConnectionManager.AfterNonTransactionalQuery(success);
		}
	}
}
 
//And finally the AdoTransaction code
public bool IsActive
{
	get { return begun && !rolledBack && !committed; }
}

Basically, NHibernate will quasi-create an implicit transaction if it isn’t explicitly created. What’s weird is the scope of the transaction is just a single query. As you can see in the above code, I never called BeginTransaction() so tx.IsActive returns false, which indirectly makes the AbstractSessionImpl class think the transaction is over, which in turn indirectly triggers the ConnectionManager code to release the connection if the ConnectionReleaseMode is set to after transaction (which it is by default).

Whew!

Some outstanding questions though are why did this start happening with 2.0 and not 1.2? My guess is some code was refactored with how the last insert ID is retrieved, and in 1.2 it was impossible for it to have different connections. With 2.0, it is pretty easy to have different connection objects if concurrent operations are occurring.

Read more on ConnectionReleaseMode‘s here.

(I hope this post made sense as I am super tired and have been learning NHibernate source code rapidly for the past few hours)

Post to Twitter Post to Delicious Post to Digg Post to Facebook Post to Reddit

October 14th, 2009

Thoughts on #RichCC

A couple weekends ago, I attended Richmond Code Camp and had a great time. This was different than the last code camp I went to, in the fact that I spent most of the day presenting, not watching others.

I have coded in front of co-workers before. I have given presentations to strangers before. But I had never coded in front of strangers before. There were a lot of things I learned. Here is a summary of just a few.

Know your audience

One of the two talks I gave was on Powershell. In this talk, I didn’t understand the audience that would be in attendance. I am a coder, not a system administrator. Powershell was designed for both, but a large percentage of attendees were sysadmins, not straight up developers. This assumption caused most of my examples to be irrelevant. Instead of showing how to create a Runspace and call Powershell from within C#, I should have focused more on things like interacting with a database, remoting, and common sysadmin type tasks.

Maybe next time my abstract should be a little more well-defined so that the audience and I are on the same page.

Code very little

In my NHibernate talk, I had about 25 test cases I worked through. Each of those tests started off failing, and required one or two additional lines to make them pass. I would go through each test case, explain what it was doing, why it was failing, and type a couple lines to make it pass. This strategy worked WONDERS!

In my Powershell talk, I tried to code a script from scratch that queried the Twitter API. Bomb. I got so flustered I just copy and pasted from my helper file and made it work. I had to code too much during this demo. Here is my new mantra:

The more critics, the exponentially higher chance of a typo.

(NOTE: Please don’t think I am saying use PowerPoint. Just make it hard for you to screw up the code you have to write)

Figure out how to get some interaction

If you haven’t guessed, I think my NHibernate talk went a lot better than the Powershell talk. One reason I think this is I had almost no audience interaction in Powershell. When I did, they were asking a question that I couldn’t easily answer during my talk. NHibernate had a ton more interaction, and I felt everyone left the room with more info than when they came in.

Wow factor

The wow factor is crucial. Something that is going to make the audience remember your talk.

For NHibernate, the last thing I did was switch my config from MySQL to MSSQL (just the config, no code) and all the tests still passed. Definitely caught peoples attention.

For Powershell, I data bound a WPF app with Powershell scripts. I don’t think it achieved the wow I wanted, but I think its pretty damn cool.

Post to Twitter Post to Delicious Post to Digg Post to Facebook Post to Reddit

October 4th, 2009

NHibernate CodeCamp Talk – Source Code

I have published the source of my Code Camp talk here. Check it out and post any questions.

Thanks to everyone who showed up for the NHibernate talk. It went really well and everyone had tons of great questions. Feel free to post feedback here, both positive and negative, so the next time I give this talk, it will be even better.

For those of you that just want a little more guidance on NHibernate, here are some good links:

Also, thanks to the coordinators of Richmond CC. I had a great time.

Post to Twitter Post to Delicious Post to Digg Post to Facebook Post to Reddit

September 28th, 2009

Why you should use NHibernate.Linq, not Criteria or HQL

What’s wrong with the following?

return s.CreateQuery("from CodeCamp c where c.Name = :name order by c.Name")
    .SetParameter("name", "test")
    .List<CodeCamp>();
return s.CreateCriteria<CodeCamp>()
    .Add(Expression.Eq("Name", "test"))
    .AddOrder(Order.Asc("Name"))
    .List<CodeCamp>();

There are string references to .NET properties. That is a no-no. If there is a typo, you get runtime errors and not compile time errors. Now, good tests would catch it, but if you want the absolute fastest way to catch typos, NHibernate.Linq is the way to go.

return (from camp in s.Linq<CodeCamp>()
          where camp.Name == "test"
          orderby camp.Name
          select camp).ToList();

With Linq, you get that compile time checking that is going to help you move a little bit faster and make your code more robust. Combine this with Fluent NHibernate and you have a solid solution. Your mappings still have to be correct of course, but these projects take two variables out of the equation and use the compiler as a safety blanket.

Post to Twitter Post to Delicious Post to Digg Post to Facebook Post to Reddit