Using NHibernate Interfaces

This article shows how to use NHibernate Interfaces.

Introduction to Basic Interfaces

Interfaces called by applications to perform basic CRUD and querying operations (that is: Create, Retrieve, Update and Delete). These interfaces are the main point of dependency of application business/control logic on NHibernate.

Five basic Interfaces used as shown in the figure 1.1; where IQuery and ICriteria performs the same operation.


Figure 1.1 Five Basic Interfaces in NHibernate


ISession interface

1.      The ISession interface is the primary interface used by NHibernate applications, it exposes NHibernates methods for finding, saving, updating and deleting objects.

2.      An instance of ISession is lightweight and is inexpensive to create and destroy. This is important because your application will need to create and destroy sessions all the time, perhaps on every ASP.NET page request. NHibernate sessions are not thread safe and should by design be used by only one thread at a time. The NHibernate notion of a session is something between connection and transaction.

3.      It may be easier to think of a session as a cache or collection of loaded objects relating to a single unit of work. NHibernate can detect changes to the objects in this unit of work.

4.      We sometimes call the ISession a persistence manager because it's also the interface for persistence-related operations such as storing and retrieving objects. Note that a NHibernate session has nothing to do with an ASP.NET session. When we use the word session in this book, we mean the NHibernate session.


ISessionFactory interface

1.      The application obtains ISession instances from an ISessionFactory. Compared to the  ISession interface, this object is much less exciting. 

2.      The ISessionFactory is certainly not lightweight! It's intended to be shared among many application threads. There is typically a single instance of ISessionFactory for the whole application-created during application initialization, for example. However, if your application accesses multiple databases using NHibernate, you'll need a SessionFactory for each database.

3.      The SessionFactory caches generated SQL statements and other mapping metadata that NHibernate uses at runtime.

4.      It can also hold cached data that has been read in one unit of work, and which may be reused in a future unit of work or session. This is possible if you configure class and collection mappings to use the second-level cache.


ITransaction interface

1.      The ITransaction interface, next to the ISession interface. The ITransaction interface is an optional API. NHibernate applications may choose not to use this interface, instead managing transactions in their own infrastructure code.

2.      A NHibernate ITransaction abstracts application code from the underlying transaction implementation-which might be an ADO.NET transaction or any kind of manual transaction-allowing the application to control transaction boundaries via a consistent API. This helps to keep NHibernate applications portable between different kinds of execution environments and containers.

IQuery and ICriteria interfaces

1.      The IQuery interface gives you powerful ways of performing queries against the database, whilst also controlling how the query is executed.

2.      It is the basic interface used for fetching data using NHibernate. Queries are written in HQL or in the native SQL dialect of your database. An IQuery instance is lightweight and can't be used outside the ISession that created it. It is used to bind query parameters, limit the number of results returned by the query, and finally to execute the query. 

A.      The ICriteria interface is very similar; it allows you to create and execute object-oriented criteria queries. 


Interfaces Used for Storing Values

Suppose that our sellers can attach images to Items. An image is accessible only via the containing item; it doesn't need to support associations to any other entity in our system. In this case, it's reasonable to model the image as a value type.  Item would have a collection of images that NHibernate would consider to be part of the Item, and therefore without their own persistence lifecycle.


In this particular example scenario, let's assume that images are stored as files on the file-system rather than BLOBs in the database, and we'll simply store filenames in the database to record what images each Item has. We'll now walk through various ways this can be implemented using NHibernate, starting with the simplest implementation - the set.

Figure 1.2 Interfaces used for storing values

Using a set

1.      The simplest implementation is an ISet of string filenames.

2.      As a reminder, ISet is a container that only disallows duplicate objects, and is available in the Iesi.Collections library.

Here is the corresponding XML mapping:

<set name="Images" lazy="true" table="ITEM_IMAGE">

    <key column="ITEM_ID"/> 

    <element type="String" column="FILENAME" not-null="true"/> 


3.      The <key> element declares the foreign key, ITEM_ID of the parent entity. The <element> tag declares this collection as a collection of value type instances: in this case, of strings. 

Using a bag 

1.      An unordered collection that permits duplicate elements is called a bag.

2.      The .NET framework doesn't define an IBag interface. NHibernate lets you use an IList in .NET to simulate bag behavior; this is consistent with common usage in the .NET community.

3.      To use a bag, change the type of Images in Item from ISet to IList, probably using ArrayList as an implementation. 

4.      Changing the table definition from the previous section to permit duplicate FILENAMEs requires a different primary key.

5.      We use an <idbag> mapping to attach a surrogate key column to the collection table, much like the synthetic identifiers we use for entity classes: 

The XML mapping looks like this:

<idbag name="Images" lazy="true" table="ITEM_IMAGE"> 

    <collection-id type="Int32" column="ITEM_IMAGE_ID"> 

        <generator class="sequence"/> 


    <key column="ITEM_ID"/> 

    <element type="String" column="FILENAME" not-null="true"/> 


Using a list

1.      A <list> mapping requires the addition of an index column to the database table.

2.      The index column defines the position of the element in the collection. Thus, NHibernate can preserve the ordering of the collection elements when retrieving the collection from the database if we map the collection as a <list>: 

<list name="Images" lazy="true" table="ITEM_IMAGE"> 

    <key column="ITEM_ID"/> 

    <index column="POSITION"/> 

    <element type="String" column="FILENAME" not-null="true"/> 


3.      Notice that duplicate elements (FILENAME) are allowed, which is consistent with the semantics of a list. (We don't have to change the Item class; the types we used earlier for the bag are the same.) 

4.      Note that, even though the IList contract doesn't specify that a list is an ordered collection; NHibernate's implementation preserves the ordering when persisting the collection.

Using a map 

1.      Mapping a <map> (pardon us) is similar to mapping a list: 

<map name="Images" lazy="true" table="ITEM_IMAGE"> 

    <key column="ITEM_ID"/> 

    <index column="IMAGE_NAME" type="string"/> 

    <element type="String" column="FILENAME" not-null="true"/> 


4.      Again, duplicate elements are allowed.