Introduction
Hibernate is an open source object/relational persistence framework that is widely use in Enterprise Java applications. NHibernate is a .Net port of Hibernate for Java (more specifically the Hibernate Core), and can be used to persist plain .Net objects.
Downloads
NHibernateSampleApplication.zip [VS2005]
About the Sample Project
The sample project includes a SQL script for creating the DB. The extra tables and data are included for use in further articles. Also, you may wish to visit http://www.hibernate.org/343.html for more information and downloads. The sample does include the libraries needs.
Mapping Files
The key to NHibernate understanding how to persist your objects to a data store is mapping files. These files are XML structures with information on how to get your class properties persisted, and which columns the data relates to. This is an extract of the Contact.hbm.xml file in the sample, demonstrating the mapping of the Domain.Contact class to the Contact table in SQL. Take note of the ContactID column definition; the column node is notated as <id>, which in turn has a <generator> node, indicating to NHibernate that this field needs to be auto-generated.
<class name="TelephoneBook.Library.Domain.Contact" table="Contact" lazy="false">
<id name="ContactId" column="ContactId" type="Guid" >
<generator class="guid" />
</id>
<property name="Title" column="Title" type="String" length="10" />
<property name="FirstName" column="FirstName" type="String" length="50"/>
<property name="LastName" column="LastName" type="String" length="50" />
<property name="Age" column="Age" type="Int32" />
<property name="DateOfBirth" column="DateOfBirth" type="DateTime" />
<property name="IsDeleted" column="IsDeleted" type="Boolean" />
<bag name="TelephoneNumbers" cascade="all">
<key column="ContactId"/>
<one-to-many class="TelephoneBook.Library.Domain.TelephoneNumber"/>
</bag>
</class>
The rest of the fields are properties of the class/table, and the final section starting with the <bag> node is actually a one-to-many notation. A look at the TelephoneLibrary mapping show an example of a many-to-one mapping. NHibernate also support one-to-one and many-to-many mappings.
There are templates available for many popular code generators that allow automatic generation of mapping files.
Getting ready to use NHibernate
For simplicities sake in the sample project, I constructed a NHibernate factory class which correctly sets up a static session object that I use throughout the application. The configuration of the object can take place programmatically, but my first choice is always to do this from a configuration file.
<nhibernate>
<add key="hibernate.connection.provider" value="NHibernate.Connection.DriverConnectionProvider" />
<add key="hibernate.dialect" value="NHibernate.Dialect.MsSql2005Dialect" />
<add key="hibernate.connection.driver_class" value="NHibernate.Driver.SqlClientDriver" />
<add key="hibernate.connection.connection_string" value="Server=(local);initial catalog=TelephoneBook;Integrated Security=SSPI" />
<add key="hibernate.show_sql" value="true" />
</nhibernate>
As you can see in the snippet above taken from the App.Config file, setting up NHibernate involves no rocket science and is self explanatory.
Getting back to the factory class, you’ll notice that the constructor of the class instantiates a configuration class, which in turn has assemblies added to it.
_cfg = new NHibernate.Cfg.Configuration();
_cfg.AddAssembly(Assembly.GetExecutingAssembly());
_sessionFactory = _cfg.BuildSessionFactory();
_session = _sessionFactory.OpenSession();
NHibernate performs validation on the mapping files which are included in the assembly, and then a single instance of a session is open.
The Code
I’ve separated the domain objects (Contact and TelephoneNumber) from the persistence-related functionality (which I’ve thrown into the factory classes) for clearly demonstrating the CRUD functionality.
When designing your domain classes, remeber to make the properties and methods virtual, as NHibernate actually overrides these when persisting and populating objects.
A look at the ContactFactory class demonstrates a single record load as well as 2 methods retrieving a list of data. The criteria and expressions classes a discussion on their own, but very good documentation is available from the link above.
NHibernate 1.2 includes very comprehensive caching, and you can also make use of SQL 2005 specific functionality that invalidates caches when a set of retrieved data changes.
The TelephoneNumberFactory class demonstrates save functionality for an object.
public static bool Save(TelephoneNumber telephoneNumber)
{
ISession session = NHibernateSessionFactory.GetSession();
try
{
session.Save(telephoneNumber);
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
return (false);
}
session.Flush();
return (true);
}
Notice that a session.Flush() is called at the end. This commits data to the data store. To restrict chatter on a function that does multiple saves/updates, a Flush can be called and the operations can be batched. This causes all the SQL statements to be sent at once, rather than one at a time.
Other Stuff
There is a multitude of functionality in NHibernate that I haven’t even begun to mention, and that could turn this article into a book rather than an intro. There is support for transactions, and SQL stored procedures, and support for GUIDs and GUID generation, and identity columns, and…
Next
I’ll be looking at an ActiveRecord example, which makes use of NHibernate.