NHibernate & Null Object Pattern: The Options

Don’t bother using Null Object Pattern

The first option is to just not bother using Null Object Pattern, this is the easiest solution however has the side-effect that you end up with null checks everywhere which is the reason for moving to the Null Object Pattern in the first place.

Place a Null Object in the database

Next option is to have an object in the database that represents the null object so it will probably have an Id of zero and a value of << Unassigned >> or along those lines. This then has its own problems because if it’s a user editable object you don’t really want them to be able to change/delete this data so it becomes a special case that will need to be locked for editing/deleting.

Use Field Access and have the Property Handle the Mismatch

This is my preferred method whereby NHibernate is configured to use field access to the object, and the property handles the mismatch internally for example:

// inside class definition
protected User assignedTo;

public virtual User AssignedTo
{
    get
    {
        return assignedTo ?? User.NotAssigned;
    }
    set
    {
        if (value == User.NotAssigned)
            assignedTo = null;
        else
            assignedTo = value;
    }
}

This gives NHibernate a different view of the assigned to value than outside objects, for NHibernate which uses the internal field assignedTo it can be set to a null however for outside objects that have to use the AssignedTo property it will never be a null and instead will be set to the Null Object in this case User.NotAssigned.

Any other options please add a comment below 🙂

Advertisements

Getting to grips with NHibernate: Stored Procedures Redux

Update: Due to popular demand I have included using stored procedures for insert/update/delete

I hope this post saves someone the amount of time it took me to try and run a stored procedure using NHibernate.

Selecting from a Stored Procedure

Create Stored Procedure

The first step is to create your stored procedure, if we take a basic example:

CREATE PROCEDURE SearchStaff
	(
	@LastName VARCHAR(255) = NULL,
	@FirstName VARCHAR(255) = NULL
	)
AS
	SET NOCOUNT ON

	SELECT s.*
	FROM Staff s
	WHERE (s.LastName LIKE @LastName OR @LastName IS NULL)
	AND (s.FirstName LIKE @FirstName OR @FirstName IS NULL)
	ORDER BY FirstName, LastName

	SET NOCOUNT OFF

Note the SET NOCOUNT ON/SET NOCOUNT OFF

Create a named query

In order for NHibernate to be able to run the stored procedure, we need to create a named query, in our hbm file:


	
	  
	  
	  
	  
	
	exec SearchStaff :LastName, :FirstName

In this example because the stored procedure is actually returning a staff object I set the return to the Staff class, if I was only returning something like an integer value I could use the following:


    
    exec StaffCount :LastName, :FirstName

The name does not need to be the same name as the stored procedure.

Create the NHibernate code

// session set here

IQuery searchQuery = session.GetNamedQuery("StaffSearching")

if (!string.IsNullOrEmpty(LastName))
	searchQuery.SetString("LastName", LastName);
else
    searchQuery.SetString("LastName", null);

if (!string.IsNullOrEmpty(FirstName))
    searchQuery.SetString("FirstName", FirstName);
else
    searchQuery.SetString("FirstName", null);

IList foundStaff = searchQuery.List();

Notice that the stored procedure can deal with or without filtering, so if the fields have not been set we can simply set them to a null value and NHibernate will pass the parameters as a NULL which is what we want.It’s worth noting that the above is quite a simple example and that for the above I would not use a stored procedure and instead just use NHibernates own querying objects. The case were I used a stored procedure was for a paging routine for SQL server 2000.

Using Stored Procedure for Insert, Update & Delete

Create Stored Procedures

CREATE PROCEDURE InsertStaff
	(
	@LastName VARCHAR(255),
	@FirstName VARCHAR(255),
             @EmailAddress VARCHAR(512)
	)
AS
             INSERT INTO Staff
             (
              LastName,
              FirstName,
              EmailAddress
             )
             VALUES
             (
              @LastName,
              @FirstName,
              @Email
             )

Note: SET NOCOUNT is not set for these stored procedures

I’m not going to include the SQL for the update and delete stored procedures as I don’t think it adds any value, and is the easy part.

Update NHibernate XML Mapping

We need to tell NHibernate the SQL we want to execute for our insert/update/delete, we do this inside the class element:


    
      
    
    
    
    

    EXEC InsertStaff ?,?,?
    EXEC UpdateStaff ?,?,?,?
    EXEC DeleteStaff ?

Caveats

  • The last parameter will be the id for the update.
  • The ordering of the parameters is determined by NHibernate, so the best way to find out the ordering would be to view the generated SQL, bit pants but hay ho.

Your code will remain the same, so no changes needed there.

NHibernate code snippet

Here is a sample code snippet that you can use to generate a standard call to use an nHibernate ISession, you will need to make a small adjustment as to how you retrieve the ISession in your own projects.


      
    <Header>
        nHibernate block
        nhblock
        Code snippet for a standard NHibernate session call block
        Mike Cromwell
        
            Expansion
            SurroundsWith
        
     </Header>
    
        
             
        

        <Code>
            
        </Code>
      
    
 

Using Repositories with nHibernate

Intro

The point of this article is to demonstrate 2 ways that I have been using the Repository pattern in conjuction with nHibernate to provide my applications with rich domain objects, I wanted to also get feedback to the options shown and if there are any other ways to implement Repository with nHibernate.

Repository manages session

The first option and the one I used for the Staff Intranet and for older applications is wereby the repository manages the session object and decides where transactions should be used, here is an example of one the methods that we might typically see:

public int Save(User user)
{
    ISession session = NHibernateSessionManager.GetSession();
    ITransaction transaction = session.BeginTransaction();
    try
    {
        session.Save(user);
        session.Flush();
        transaction.Commit();
        return user.Id;
    }
    catch
    {
        transaction.RollBack();
        throw;
    }
    finally
    {
        NHibernateSessionManager.CloseSession();
    }
}

This has a number of the issues:

  • If you need to use a number of repositories in a single transaction this option will not work
  • Integration testing becomes more difficult as the repository handles the session and transactions

Caller manages session

The other way we can implement repositories is to let the calling code manage session and when transactions take place, here is an updated version of the above to accomodate the caller managing session & transactions:

public int Save(User user)
{
    ISession session = NHibernateSessionManager.GetSession();
    session.Save(user);
    session.Flush();
    return user.Id;
}

Our code has been reduced however the caller would now contain the code removed:

public int SaveUser(User user)
{
    ITransaction transaction = NHibernateSessionManager.GetSession().BeginTransaction();
    try
    {
        int userId = userRepository.Save(user);
        transaction.Commit();
        return userId;
    }
    catch (Exception thrownException)
    {
        transaction.RollBack();
        //... log exception, wrap up exception, rethrow, etc...
    }
    finally
    {
        NHibernateSessionManager.CloseSession();
    }
}

We could now quite happily make calls before or after the saving of the user to other repositories knowing that they would all be using the session & transaction.

I’m pretty convinced that this option of having the caller responsible for manageing session & transactions is a better way of implementing repositories, however if you of any other ways then please point me in the right direction 🙂

Helping Integration testing

One thing that I didn’t like having to do was performing integration tests against the database the reason being the extra care that needed to be taken to make sure that data was reverted back to the state it was to begin with, by using the caller in charge of session & transactions approach you can rollback any data changes made.

New Staff Intranet Release

I have found enough spare time to put up a new release of the staff intranet project, for those who are not aware of this project it is a demonstration of using best practices, principles & patterns in a real world web application so if your looking for pointers or some code to use for your own applications go give it a look on codeplex.

In this newest version I have added AOP support to cut down on cross cutting code and also the ability to delete staff members from the GridView, most of the time spent was fighting against the asp.net controls (suprise, surprise) such as the GridView and the ObjectDataSource, I’m not sure what the guy(s) who created the ObjectDataSource object was smoking at the time but it must have been stronger than just tobacco 🙂

My next release I want to demonstrate adding some service support showing how we can re-use existing code so they become little more than a remote facade (in theory!).

Staff Intranet on Codeplex

I have not posted here for a little the main reason being I have been putting the final touches to another project I have been working on in my spare time, it’s a staff intranet application what I have tried to do with this project as with the previous projects is try and use it as a learning exercise, so I have incorporated some best practices and design patterns and used them for a real world example, in there you will find:

  • Inversion of control – This has been decoupled from a particular IoC container but I have utilised Castle Windsor under the hood
  • TDD/BDD – Around 98% of the behaviour of the application was designed test first, the reason I have put BDD as well is because I like to think of my tests as defining the behaviour of the application rather than of just testing assertions in my code, this comes out through the naming of my test cases
  • NHibernate – This was my first use of NHibernate and overall I was very pleased with what this very powerful ORM gives you and also keeping the domain clean from database artifacts (persistence ignorance)
  • Model View Presenter – This is the first time I have emplyed model view presenter for web and it acts as a nice interim between moving logic from the codebehind and going the whole hog and using an MVC framework such as monorail or ASP.NET MVC, I’m completely sold on having tests against the UI logic
  • SQL Server 2005 – This was probably the most dissapointing aspect of developing this application, I was hoping that the new client tools would be great and easy to get stuff done with however I found it the opposite things that used to be easy using the SQL server 2000 enterprise manager were not intuituve at all with the Management Studio, examples:
    • Wanting to remove a database that already exists
    • Setting permissions from the users perspective

Anyway after that intro you can find more details over at my project homepage on codeplex.

My hope is that this project will help others who are learning about the above but would like to see them used in a real world context rather than just in hello worls context.

NHibernate exception: Unexpected row count: 0; expected: 1

While working on a project that uses NHibernate I was receiving the exception Unexpected row count: 0; expected: 1 after some investigation I found out that the problem was caused by me not setting an attribute in the mapping file.

I had a table in a sql server 2000 database that had an Id column this was set to an identity column, in my mapping file I had the following:


    

I kept getting the exception the moment I made a call to SaveOrUpdate using a new object that was associated with the table and then flushing the session, calls to already existing objects in the database were fine (Id property set) It turned out that because I was using -1 as the default for an object that was not saved NHibernate did not know that this was a new object to be inserted.

The fix was to change the mapping file to this: