Table of Contents
Working with object-oriented software and a relational database can be cumbersome and time consuming in today's enterprise environments. NHibernate is an object/relational mapping tool for .NET environments. The term object/relational mapping (ORM) refers to the technique of mapping a data representation from an object model to a relational data model with a SQL-based schema.
NHibernate not only takes care of the mapping from .NET classes to database tables (and from .NET data types to SQL data types), but also provides data query and retrieval facilities and can significantly reduce development time otherwise spent with manual data handling in SQL and ADO.NET.
NHibernate's goal is to relieve the developer from 95 percent of common data persistence related programming tasks. NHibernate may not be the best solution for data-centric applications that only use stored-procedures to implement the business logic in the database, it is most useful with object-oriented domain models and business logic in the .NET-based middle-tier. However, NHibernate can certainly help you to remove or encapsulate vendor-specific SQL code and will help with the common task of result set translation from a tabular representation to a graph of objects.
If you are new to NHibernate and Object/Relational Mapping or even .NET Framework, please follow these steps:
Read Chapter 1, Quickstart with IIS and Microsoft SQL Server for a 30 minute tutorial, using Internet Information Services (IIS) web server.
Read Chapter 2, Architecture to understand the environments where NHibernate can be used.
Use this reference documentation as your primary source of information. Consider reading Hibernate in Action (http://www.manning.com/bauer/) or the work-in-progress NHibernate in Action (http://www.manning.com/kuate/) if you need more help with application design or if you prefer a step-by-step tutorial. Also visit http://nhibernate.sourceforge.net/NHibernateEg/ for NHibernate tutorial with examples.
FAQs are answered on the NHibernate website.
Third party demos, examples and tutorials are linked on the NHibernate Resources page.
The Community Area on the NHibernate website is a good source for design patterns and various integration solutions (ASP.NET, Windows Forms).
If you have questions, use the NHibernate user forum. We also provide a JIRA issue trackings system for bug reports and feature requests. If you are interested in the development of NHibernate, join the developer mailing list. If you are interested in translating this documentation into your language, contact us on the developer mailing list.
This tutorial explains a setup of NHibernate 1.0.2 within a Microsoft environment. The tools used in this tutorial are:
First, we have to create a new Web project. We use the name QuickStart, the project web virtual directory will http://localhost/QuickStart. In the project, add a reference to NHibernate.dll. Visual Studio will automatically copy the library and its dependencies to the project output directory. If you are using a database other than SQL Server, add a reference to the driver assembly to your project.
We now set up the database connection information for NHibernate. To do this, open the file Web.config automatically generated for your project and add configuration elements according to the listing below:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<!-- Add this element -->
<configSections>
<section
name="hibernate-configuration"
type="NHibernate.Cfg.ConfigurationSectionHandler, NHibernate"
/>
</configSections>
<!-- Add this element -->
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
<session-factory>
<property name="dialect">NHibernate.Dialect.MsSql2000Dialect</property>
<property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</property>
<property name="connection.connection_string">Server=(local);initial catalog=quickstart;Integrated Security=SSPI</property>
<mapping assembly="QuickStart" />
</session-factory>
</hibernate-configuration>
<!-- Leave the system.web section unchanged -->
<system.web>
...
</system.web>
</configuration>The <configSections> element contains definitions of sections that follow and handlers to use to process their content. We declare the handler for the configuration section here. The <hibernate-configuration> section contains the configuration itself, telling NHibernate that we will use a Microsoft SQL Server 2000 database and connect to it through the specified connection string. The dialect is a required setting, databases differ in their interpretation of the SQL "standard". NHibernate will take care of the differences and comes bundled with dialects for several major commercial and open source databases.
An ISessionFactory is NHibernate's concept of a single datastore, multiple databases can be used by creating multiple XML configuration files and creating multiple Configuration and ISessionFactory objects in your application.
The last element of the <hibernate-configuration> section declares QuickStart as the name of an assembly containing class declarations and mapping files. The mapping files contain the metadata for the mapping of the POCO class to a database table (or multiple tables). We'll come back to mapping files soon. Let's write the POCO class first and then declare the mapping metadata for it.
NHibernate works best with the Plain Old CLR Objects (POCOs, sometimes called Plain Ordinary CLR Objects) programming model for persistent classes. A POCO has its data accessible through the standard .NET property mechanisms, shielding the internal representation from the publicly visible interface:
namespace QuickStart
{
public class Cat
{
private string id;
private string name;
private char sex;
private float weight;
public Cat()
{
}
public virtual string Id
{
get { return id; }
set { id = value; }
}
public virtual string Name
{
get { return name; }
set { name = value; }
}
public virtual char Sex
{
get { return sex; }
set { sex = value; }
}
public virtual float Weight
{
get { return weight; }
set { weight = value; }
}
}
}NHibernate is not restricted in its usage of property types, all .NET types and primitives (like string, char and DateTime) can be mapped, including classes from the System.Collections namespace. You can map them as values, collections of values, or associations to other entities. The Id is a special property that represents the database identifier (primary key) of that class, it is highly recommended for entities like a Cat. NHibernate can use identifiers only internally, without having to declare them on the class, but we would lose some of the flexibility in our application architecture.
No special interface has to be implemented for persistent classes nor do we have to subclass from a special root persistent class. NHibernate also doesn't use any build time processing, such as IL manipulation, it relies solely on .NET reflection and runtime class enhancement (through Castle.DynamicProxy library). So, without any dependency in the POCO class on NHibernate, we can map it to a database table.
For the above mentioned runtime class enhancement to work, NHibernate requires that all public properties of an entity class are declared as virtual.
The Cat.hbm.xml mapping file contains the metadata required for the object/relational mapping. The metadata includes declaration of persistent classes and the mapping of properties (to columns and foreign key relationships to other entities) to database tables.
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
namespace="QuickStart" assembly="QuickStart">
<class name="Cat" table="Cat">
<!-- A 32 hex character is our surrogate key. It's automatically
generated by NHibernate with the UUID pattern. -->
<id name="Id">
<column name="CatId" sql-type="char(32)" not-null="true"/>
<generator class="uuid.hex" />
</id>
<!-- A cat has to have a name, but it shouldn' be too long. -->
<property name="Name">
<column name="Name" length="16" not-null="true" />
</property>
<property name="Sex" />
<property name="Weight" />
</class>
</hibernate-mapping>Every persistent class should have an identifer attribute (actually, only classes representing entities, not dependent value objects, which are mapped as components of an entity). This property is used to distinguish persistent objects: Two cats are equal if catA.Id.Equals(catB.Id) is true, this concept is called database identity. NHibernate comes bundled with various identifer generators for different scenarios (including native generators for database sequences, hi/lo identifier tables, and application assigned identifiers). We use the UUID generator (only recommended for testing, as integer surrogate keys generated by the database should be prefered) and also specify the column CatId of the table Cat for the NHibernate generated identifier value (as a primary key of the table).
All other properties of Cat are mapped to the same table. In the case of the Name property, we mapped it with an explicit database column declaration. This is especially useful when the database schema is automatically generated (as SQL DDL statements) from the mapping declaration with NHibernate's SchemaExport tool. All other properties are mapped using NHibernate's default settings, which is what you need most of the time. The table Cat in the database looks like this:
Column | Type | Modifiers --------+--------------+---------------------- CatId | char(32) | not null, primary key Name | nvarchar(16) | not null Sex | nchar(1) | Weight | real |
You should now create the database and this table manually, and later read Chapter 16, Toolset Guide if you want to automate this step with the SchemaExport tool. This tool can create a full SQL DDL, including table definition, custom column type constraints, unique constraints and indexes. If you are using SQL Server, you should also make sure the ASPNET user has permissions to use the database.
We're now ready to start NHibernate's ISession. It is the persistence manager interface, we use it to store and retrieve Cats to and from the database. But first, we've to get an ISession (NHibernate's unit-of-work) from the ISessionFactory:
ISessionFactory sessionFactory =
new Configuration().Configure().BuildSessionFactory();An ISessionFactory is responsible for one database and may only use one XML configuration file (Web.config or hibernate.cfg.xml). You can set other properties (and even change the mapping metadata) by accessing the Configuration before you build the ISessionFactory (it is immutable). Where do we create the ISessionFactory and how can we access it in our application?
An ISessionFactory is usually only built once, e.g. at startup inside Application_Start event handler. This also means you should not keep it in an instance variable in your ASP.NET pages, but in some other location. Furthermore, we need some kind of Singleton, so we can access the ISessionFactory easily in application code. The approach shown next solves both problems: configuration and easy access to a ISessionFactory.
We implement a NHibernateHelper helper class:
using System;
using System.Web;
using NHibernate;
using NHibernate.Cfg;
namespace QuickStart
{
public sealed class NHibernateHelper
{
private const string CurrentSessionKey = "nhibernate.current_session";
private static readonly ISessionFactory sessionFactory;
static NHibernateHelper()
{
sessionFactory = new Configuration().Configure().BuildSessionFactory();
}
public static ISession GetCurrentSession()
{
HttpContext context = HttpContext.Current;
ISession currentSession = context.Items[CurrentSessionKey] as ISession;
if (currentSession == null)
{
currentSession = sessionFactory.OpenSession();
context.Items[CurrentSessionKey] = currentSession;
}
return currentSession;
}
public static void CloseSession()
{
HttpContext context = HttpContext.Current;
ISession currentSession = context.Items[CurrentSessionKey] as ISession;
if (currentSession == null)
{
// No current session
return;
}
currentSession.Close();
context.Items.Remove(CurrentSessionKey);
}
public static void CloseSessionFactory()
{
if (sessionFactory != null)
{
sessionFactory.Close();
}
}
}
}This class does not only take care of the ISessionFactory with its static attribute, but also has code to remember the ISession for the current HTTP request.
An ISessionFactory is threadsafe, many threads can access it concurrently and request ISessions. An ISession is a non-threadsafe object that represents a single unit-of-work with the database. ISessions are opened by an ISessionFactory and are closed when all work is completed:
ISession session = NHibernateHelper.GetCurrentSession(); ITransaction tx = session.BeginTransaction(); Cat princess = new Cat(); princess.Name = "Princess"; princess.Sex = 'F'; princess.Weight = 7.4f; session.Save(princess); tx.Commit(); NHibernateHelper.CloseSession();
In an ISession, every database operation occurs inside a transaction that isolates the database operations (even read-only operations). We use NHibernate's ITransaction API to abstract from the underlying transaction strategy (in our case, ADO.NET transactions). Please note that the example above does not handle any exceptions.
Also note that you may call NHibernateHelper.GetCurrentSession(); as many times as you like, you will always get the current ISession of this HTTP request. You have to make sure the ISession is closed after your unit-of-work completes, either in Application_EndRequest event handler in your application class or in a HttpModule before the HTTP response is sent. The nice side effect of the latter is easy lazy initialization: the ISession is still open when the view is rendered, so NHibernate can load unitialized objects while you navigate the graph.
NHibernate has various methods that can be used to retrieve objects from the database. The most flexible way is using the Hibernate Query Language (HQL), which is an easy to learn and powerful object-oriented extension to SQL:
ITransaction tx = session.BeginTransaction();
IQuery query = session.CreateQuery("select c from Cat as c where c.Sex = :sex");
query.SetCharacter("sex", 'F');
foreach (Cat cat in query.Enumerable())
{
Console.Out.WriteLine("Female Cat: " + cat.Name);
}
tx.Commit();NHibernate also offers an object-oriented query by criteria API that can be used to formulate type-safe queries. NHibernate of course uses IDbCommands and parameter binding for all SQL communication with the database. You may also use NHibernate's direct SQL query feature or get a plain ADO.NET connection from an ISession in rare cases.
We only scratched the surface of NHibernate in this small tutorial. Please note that we don't include any ASP.NET specific code in our examples. You have to create an ASP.NET page yourself and insert the NHibernate code as you see fit.
Keep in mind that NHibernate, as a data access layer, is tightly integrated into your application. Usually, all other layers depend on the persistence mechanism. Make sure you understand the implications of this design.
A (very) high-level view of the NHibernate architecture:

This diagram shows NHibernate using the database and configuration data to provide persistence services (and persistent objects) to the application.
We would like to show a more detailed view of the runtime architecture. Unfortunately, NHibernate is flexible and supports several approaches. We will show the two extremes. The "lite" architecture has the application provide its own ADO.NET connections and manage its own transactions. This approach uses a minimal subset of NHibernate's APIs:

The "full cream" architecture abstracts the application away from the underlying ADO.NET APIs and lets NHibernate take care of the details.

Heres some definitions of the objects in the diagrams:
A threadsafe (immutable) cache of compiled mappings for a single database. A factory for ISession and a client of IConnectionProvider. Might hold an optional (second-level) cache of data that is reusable between transactions, at a process- or cluster-level.
A single-threaded, short-lived object representing a conversation between the application and the persistent store. Wraps an ADO.NET connection. Factory for ITransaction. Holds a mandatory (first-level) cache of persistent objects, used when navigating the object graph or looking up objects by identifier.
Short-lived, single threaded objects containing persistent state and business function. These might be ordinary POCOs, the only special thing about them is that they are currently associated with (exactly one) ISession. As soon as the Session is closed, they will be detached and free to use in any application layer (e.g. directly as data transfer objects to and from presentation).
Instances of persistent classes that are not currently associated with a ISession. They may have been instantiated by the application and not (yet) persisted or they may have been instantiated by a closed ISession.
(Optional) A single-threaded, short-lived object used by the application to specify atomic units of work. Abstracts application from underlying ADO.NET transaction. An ISession might span several ITransactions in some cases.
(Optional) A factory for ADO.NET connections and commands. Abstracts application from the concrete vendor-specific implementations of IDbConnection and IDbCommand. Not exposed to application, but can be extended/implemented by the developer.
(Optional) An interface encapsulating differences between ADO.NET providers, such as parameter naming conventions and supported ADO.NET features.
(Optional) A factory for ITransaction instances. Not exposed to the application, but can be extended/implemented by the developer.
Given a "lite" architecture, the application bypasses the ITransaction/ITransactionFactory and/or IConnectionProvider APIs to talk to ADO.NET directly.
An instance of a persistent classes may be in one of three different states, which are defined with respect to a persistence context. The NHibernate ISession object is the persistence context:
The instance is not, and has never been associated with any persistence context. It has no persistent identity (primary key value).
The instance is currently associated with a persistence context. It has a persistent identity (primary key value) and, perhaps, a corresponding row in the database. For a particular persistence context, NHibernate guarantees that persistent identity is equivalent to CLR identity (in-memory location of the object).
The instance was once associated with a persistence context, but that context was closed, or the instance was serialized to another process. It has a persistent identity and, perhaps, a corrsponding row in the database. For detached instances, NHibernate makes no guarantees about the relationship between persistent identity and CLR identity.
Most applications using NHibernate need some form of "contextual" sessions, where a given session is in effect throughout the scope of a given context. However, across applications the definition of what constitutes a context is typically different; and different contexts define different scopes to the notion of current.
Starting with version 1.2, NHibernate added the ISessionFactory.GetCurrentSession() method. The processing behind ISessionFactory.GetCurrentSession() is pluggable. An extension interface (NHibernate.Context.ICurrentSessionContext) and a new configuration parameter (hibernate.current_session_context_class) have been added to allow pluggability of the scope and context of defining current sessions.
See the API documentation for the NHibernate.Context.ICurrentSessionContext interface for a detailed discussion of its contract. It defines a single method, CurrentSession(), by which the implementation is responsible for tracking the current contextual session. Out-of-the-box, NHibernate comes with one implementation of this interface:
NHibernate.Context.ManagedWebSessionContext - current sessions are tracked by HttpContext. However, you are responsible to bind and unbind an ISession instance with static methods on this class, it never opens, flushes, or closes an ISession itself.
The hibernate.current_session_context_class configuration parameter defines which NHibernate.Context.ICurrentSessionContext implementation should be used. Typically, the value of this parameter would just name the implementation class to use (including the assembly name); for the out-of-the-box implementation, however, there is a corresponding short name, "managed_web".
Because NHibernate is designed to operate in many different environments, there are a large number of configuration parameters. Fortunately, most have sensible default values and NHibernate is distributed with an example App.config file (found in src\NHibernate.Test) that shows the various options. You usually only have to put that file in your project and customize it.
An instance of NHibernate.Cfg.Configuration represents an entire set of mappings of an application's .NET types to a SQL database. The Configuration is used to build an (immutable) ISessionFactory. The mappings are compiled from various XML mapping files.
You may obtain a Configuration instance by instantiating it directly. Heres an example of setting up a datastore from mappings defined in two XML configuration files:
Configuration cfg = new Configuration()
.AddFile("Item.hbm.xml")
.AddFile("Bid.hbm.xml");An alternative (sometimes better) way is to let NHibernate load a mapping file from an embedded resource:
Configuration cfg = new Configuration()
.AddClass(typeof(NHibernate.Auction.Item))
.AddClass(typeof(NHibernate.Auction.Bid));Then NHibernate will look for mapping files named NHibernate.Auction.Item.hbm.xml and NHibernate.Auction.Bid.hbm.xml embedded as resources in the assembly that the types are contained in. This approach eliminates any hardcoded filenames.
Another alternative (probably the best) way is to let NHibernate load all of the mapping files contained in an Assembly:
Configuration cfg = new Configuration()
.AddAssembly( "NHibernate.Auction" );Then NHibernate will look through the assembly for any resources that end with .hbm.xml. This approach eliminates any hardcoded filenames and ensures the mapping files in the assembly get added.
If a tool like Visual Studio .NET or NAnt is used to build the assembly, then make sure that the .hbm.xml files are compiled into the assembly as Embedded Resources.
A Configuration also specifies various optional properties:
IDictionary props = new Hashtable();
...
Configuration cfg = new Configuration()
.AddClass(typeof(NHibernate.Auction.Item))
.AddClass(typeof(NHibernate.Auction.Bind))
.SetProperties(props);A Configuration is intended as a configuration-time object, to be discarded once an ISessionFactory is built.
When all mappings have been parsed by the Configuration, the application must obtain a factory for ISession instances. This factory is intended to be shared by all application threads:
ISessionFactory sessions = cfg.BuildSessionFactory();
However, NHibernate does allow your application to instantiate more than one ISessionFactory. This is useful if you are using more than one database.
An ISessionFactory may open an ISession on a user-provided ADO.NET connection. This design choice frees the application to obtain ADO.NET connections wherever it pleases:
IDbConnection conn = myApp.GetOpenConnection(); ISession session = sessions.OpenSession(conn); // do some data access work
The application must be careful not to open two concurrent ISessions on the same ADO.NET connection!
Alternatively, you can have the ISessionFactory open connections for you. The ISessionFactory must be provided with ADO.NET connection properties in one of the following ways:
Pass an instance of IDictionary mapping property names to property values to Configuration.SetProperties().
Add the properties to a configuration section in the application configuration file. The section should be named nhibernate and its handler set to System.Configuration.NameValueSectionHandler.
Include <property> elements in a configuration section in the application configuration file. The section should be named hibernate-configuration and its handler set to NHibernate.Cfg.ConfigurationSectionHandler. The XML namespace of the section should be set to urn:nhibernate-configuration-2.2.
Include <property> elements in hibernate.cfg.xml (discussed later).
If you take this approach, opening an ISession is as simple as:
ISession session = sessions.OpenSession(); // open a new Session // do some data access work, an ADO.NET connection will be used on demand
All NHibernate property names and semantics are defined on the class NHibernate.Cfg.Environment. We will now describe the most important settings for ADO.NET connection configuration.
NHibernate will obtain (and pool) connections using an ADO.NET data provider if you set the following properties:
Table 3.1. NHibernate ADO.NET Properties
| Property name | Purpose |
|---|---|
| hibernate.connection.provider_class |
The type of a custom IConnectionProvider.
eg. full.classname.of.ConnectionProvider if the Provider is built into NHibernate, or full.classname.of.ConnectionProvider, assembly if using an implementation of IConnectionProvider not included in NHibernate. |
| hibernate.connection.driver_class |
The type of a custom IDriver, if using DriverConnectionProvider.
full.classname.of.Driver if the Driver is built into NHibernate, or full.classname.of.Driver, assembly if using an implementation of IDriver not included in NHibernate. This is usually not needed, most of the time the hibernate.dialect will take care of setting the IDriver using a sensible default. See the API documentation of the specific dialect for the defaults. |
| hibernate.connection.connection_string | Connection string to use to obtain the connection. |
| hibernate.connection.connection_string_name | The name of the connection string (defined in <connectionStrings> configuration file element) to use to obtain the connection. |
| hibernate.connection.isolation |
Set the ADO.NET transaction isolation level. Check
System.Data.IsolationLevel for meaningful values
and the database's documentation to ensure that level is supported.
eg. Chaos, ReadCommitted, ReadUncommitted, RepeatableRead, Serializable, Unspecified |
| hibernate.connection.release_mode |
Specify when NHibernate should release ADO.NET connections.
See Section 10.7, “Connection Release Modes”.
eg. auto (default) | on_close | after_transaction Note that this setting only affects ISessions returned from ISessionFactory.OpenSession. For ISessions obtained through ISessionFactory.GetCurrentSession, the ICurrentSessionContext implementation configured for use controls the connection release mode for those ISessions. See Section 2.3, “Contextual Sessions”. |
| hibernate.adonet.batch_size | Specify the batch size to use when batching update statements. Setting this to 0 (the default) disables the functionality. See Section 15.6, “Batch updates”. |
This is an example of how to specify the database connection properties inside a web.config:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="nhibernate" type="System.Configuration.NameValueSectionHandler, System,
Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
</configSections>
<nhibernate>
<add
key="hibernate.connection.provider"
value="NHibernate.Connection.DriverConnectionProvider"
/>
<add
key="hibernate.dialect"
value="NHibernate.Dialect.MsSql2000Dialect"
/>
<add
key="hibernate.connection.driver_class"
value="NHibernate.Driver.SqlClientDriver"
/>
<add
key="hibernate.connection.connection_string"
value="Server=127.0.0.1; Initial Catalog=thedatabase; Integrated Security=SSPI"
/>
<add
key="hibernate.connection.isolation"
value="ReadCommitted"
/>
</nhibernate>
<!-- other app specific config follows -->
</configuration>NHibernate relies on the ADO.NET data provider implementation of connection pooling.
You may define your own plugin strategy for obtaining ADO.NET connections by implementing the interface NHibernate.Connection.IConnectionProvider. You may select a custom implementation by setting hibernate.connection.provider_class.
There are a number of other properties that control the behaviour of NHibernate at runtime. All are optional and have reasonable default values.
System-level properties can only be set manually by setting static properties of NHibernate.Cfg.Environment class or be defined in the <nhibernate> section of the application configuration file. These properties cannot be set using Configuration.SetProperties or be defined in the <hibernate-configuration> section of the application configuration file.
Table 3.2. NHibernate Configuration Properties
| Property name | Purpose |
|---|---|
| hibernate.dialect |
The classname of a NHibernate Dialect - enables
certain platform dependent features.
eg. full.classname.of.Dialect, assembly |
| hibernate.default_schema |
Qualify unqualified tablenames with the given schema/tablespace
in generated SQL.
eg. SCHEMA_NAME |
| hibernate.use_outer_join |
Enables outer join fetching. Deprecated, use max_fetch_depth.
eg. true | false |
| hibernate.max_fetch_depth |
Set a maximum "depth" for the outer join fetch tree
for single-ended associations (one-to-one, many-to-one).
A 0 disables default outer join fetching.
eg. recommended values between 0 and 3 |
| hibernate.use_reflection_optimizer |
Enables use of a runtime-generated class to set or get properties of an entity
or component instead of using runtime reflection (System-level property).
The use of the reflection optimizer inflicts a certain startup cost on the
application but should lead to better performance in the long run.
You can not set this property in hibernate.cfg.xml
or <hibernate-configuration> section of the application
configuration file.
eg. true | false |
| hibernate.bytecode.provider |
Specifies the bytecode provider to use to optimize the use of reflection in NHibernate.
Use null to disable the optimization completely, lcg
to use lightweight code generation (supported on .NET 2.0 only), and
codedom to use CodeDOM-based code generation (supported on .NET 1.1, has problems
with generic types on .NET 2.0).
eg. null | lcg | codedom |
| hibernate.cache.provider_class |
The classname of a custom ICacheProvider.
eg. classname.of.CacheProvider, assembly |
| hibernate.cache.use_minimal_puts |
Optimize second-level cache operation to minimize writes, at the
cost of more frequent reads (useful for clustered caches).
eg. true | false |
| hibernate.cache.use_query_cache |
Enable the query cache, individual queries still have to be set cacheable.
eg. true | false |
| hibernate.cache.query_cache_factory |
The classname of a custom IQueryCacheFactory interface,
defaults to the built-in StandardQueryCacheFactory.
eg. classname.of.QueryCacheFactory, assembly |
| hibernate.cache.region_prefix |
A prefix to use for second-level cache region names.
eg. prefix |
| hibernate.query.substitutions |
Mapping from tokens in NHibernate queries to SQL tokens
(tokens might be function or literal names, for example).
eg. hqlLiteral=SQL_LITERAL, hqlFunction=SQLFUNC |
| hibernate.show_sql |
Write all SQL statements to console.
eg. true | false |
| hibernate.hbm2ddl.auto |
Automatically export schema DDL to the database when the
ISessionFactory is created. With
create-drop, the database schema
will be dropped when the ISessionFactory
is closed explicitly.
eg. create | create-drop |
| hibernate.use_proxy_validator |
Enables or disables validation of interfaces or classes specified
as proxies. Enabled by default.
eg. true | false |
You should always set the hibernate.dialect property to the correct NHibernate.Dialect.Dialect subclass for your database. This is not strictly essential unless you wish to use native or sequence primary key generation or pessimistic locking (with, eg. ISession.Lock() or IQuery.SetLockMode()). However, if you specify a dialect, NHibernate will use sensible defaults for some of the other properties listed above, saving you the effort of specifying them manually.
Table 3.3. NHibernate SQL Dialects (hibernate.dialect)
| RDBMS | Dialect | Remarks |
|---|---|---|
| DB2 | NHibernate.Dialect.DB2Dialect | |
| DB2 for iSeries (OS/400) | NHibernate.Dialect.DB2400Dialect | |
| Ingres | NHibernate.Dialect.IngresDialect | |
| PostgreSQL | NHibernate.Dialect.PostgreSQLDialect | |
| PostgreSQL 8.1 | NHibernate.Dialect.PostgreSQL81Dialect | This dialect supports FOR UPDATE NOWAIT available in PostgreSQL 8.1. |
| PostgreSQL 8.2 | NHibernate.Dialect.PostgreSQL82Dialect | This dialect supports IF EXISTS keyword in DROP TABLE and DROP SEQUENCE available in PostgreSQL 8.2. |
| MySQL 3 or 4 | NHibernate.Dialect.MySQLDialect | |
| MySQL 5 | NHibernate.Dialect.MySQL5Dialect | |
| Oracle (any version) | NHibernate.Dialect.OracleDialect | |
| Oracle 9/10g | NHibernate.Dialect.Oracle9Dialect | |
| Sybase Adaptive Server Enterprise | NHibernate.Dialect.SybaseDialect | |
| Sybase Adaptive Server Anywhere | NHibernate.Dialect.SybaseAnywhereDialect | |
| Microsoft SQL Server 2000 | NHibernate.Dialect.MsSql2000Dialect | |
| Microsoft SQL Server 2005 | NHibernate.Dialect.MsSql2005Dialect | |
| Microsoft SQL Server 2005 Everywhere Edition | NHibernate.Dialect.MsSqlCeDialect | |
| Microsoft SQL Server 7 | NHibernate.Dialect.MsSql7Dialect | |
| Firebird | NHibernate.Dialect.FirebirdDialect | Set hibernate.driver_class to NHibernate.Driver.FirebirdClientDriver for Firebird ADO.NET provider 2.0. |
| SQLite | NHibernate.Dialect.SQLiteDialect | Set hibernate.driver_class to NHibernate.Driver.SQLite20Driver for System.Data.SQLite provider for .NET 2.0. |
| Ingres 3.0 | NHibernate.Dialect.IngresDialect |
Additional dialects may be available in the NHibernateContrib package (see Part I, “NHibernateContrib Documentation”). At the time of writing this package contains support for Microsoft Access (Jet) database engine.
If your database supports ANSI or Oracle style outer joins, outer join fetching might increase performance by limiting the number of round trips to and from the database (at the cost of possibly more work performed by the database itself). Outer join fetching allows a graph of objects connected by many-to-one, one-to-many or one-to-one associations to be retrieved in a single SQL SELECT.
By default, the fetched graph when loading an objects ends at leaf objects, collections, objects with proxies, or where circularities occur.
For a particular association, fetching may be configured (and the default behaviour overridden) by setting the fetch attribute in the XML mapping.
Outer join fetching may be disabled globally by setting the property hibernate.max_fetch_depth to 0. A setting of 1 or higher enables outer join fetching for one-to-one and many-to-one associations which have been mapped with fetch="join".
See Section 15.1, “Fetching strategies” for more information.
In NHibernate 1.0, outer-join attribute could be used to achieve a similar effect. This attribute is now deprecated in favor of fetch.
You may integrate a process-level (or clustered) second-level cache system by implementing the interface NHibernate.Cache.ICacheProvider. You may select the custom implementation by setting hibernate.cache.provider_class. See the Section 15.2, “The Second Level Cache” for more details.
You may define new NHibernate query tokens using hibernate.query.substitutions. For example:
hibernate.query.substitutions true=1, false=0
would cause the tokens true and false to be translated to integer literals in the generated SQL.
hibernate.query.substitutions toLowercase=LOWER
would allow you to rename the SQL LOWER function.
NHibernate logs various events using Apache log4net.
You may download log4net from http://logging.apache.org/log4net/. To use log4net you will need a log4net configuration section in the application configuration file. An example of the configuration section is distributed with NHibernate in the src/NHibernate.Test project.
We strongly recommend that you familiarize yourself with NHibernate's log messages. A lot of work has been put into making the NHibernate log as detailed as possible, without making it unreadable. It is an essential troubleshooting device. Also don't forget to enable SQL logging as described above (hibernate.show_sql), it is your first step when looking for performance problems.
The interface NHibernate.Cfg.INamingStrategy allows you to specify a "naming standard" for database objects and schema elements.
You may provide rules for automatically generating database identifiers from .NET identifiers or for processing "logical" column and table names given in the mapping file into "physical" table and column names. This feature helps reduce the verbosity of the mapping document, eliminating repetitive noise (TBL_ prefixes, for example). The default strategy used by NHibernate is quite minimal.
You may specify a different strategy by calling Configuration.SetNamingStrategy() before adding mappings:
ISessionFactory sf = new Configuration()
.SetNamingStrategy(ImprovedNamingStrategy.Instance)
.AddFile("Item.hbm.xml")
.AddFile("Bid.hbm.xml")
.BuildSessionFactory();NHibernate.Cfg.ImprovedNamingStrategy is a built-in strategy that might be a useful starting point for some applications.
An alternative approach is to specify a full configuration in a file named hibernate.cfg.xml. This file can be used as a replacement for the <nhibernate;> or <hibernate-configuration> sections of the application configuration file.
The XML configuration file is by default expected to be in your application directory. Here is an example:
<?xml version='1.0' encoding='utf-8'?>
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
<!-- an ISessionFactory instance -->
<session-factory>
<!-- properties -->
<property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</property>
<property name="connection.driver_class">NHibernate.Driver.SqlClientDriver</property>
<property name="connection.connection_string">Server=localhost;initial catalog=nhibernate;User Id=;Password=</property>
<property name="show_sql">false</property>
<property name="dialect">NHibernate.Dialect.MsSql2000Dialect</property>
<property name="use_outer_join">true</property>
<!-- mapping files -->
<mapping resource="NHibernate.Auction.Item.hbm.xml" assembly="NHibernate.Auction" />
<mapping resource="NHibernate.Auction.Bid.hbm.xml" assembly="NHibernate.Auction" />
</session-factory>
</hibernate-configuration>Configuring NHibernate is then as simple as
ISessionFactory sf = new Configuration().Configure().BuildSessionFactory();
You can pick a different XML configuration file using
ISessionFactory sf = new Configuration()
.Configure("/path/to/config.cfg.xml")
.BuildSessionFactory();Persistent classes are classes in an application that implement the entities of the business problem (e.g. Customer and Order in an E-commerce application). Persistent classes have, as the name implies, transient and also persistent instance stored in the database.
NHibernate works best if these classes follow some simple rules, also known as the Plain Old CLR Object (POCO) programming model.
Most .NET applications require a persistent class representing felines.
using System;
using Iesi.Collections;
namespace Eg
{
public class Cat
{
private long id; // identifier
private string name;
private DateTime birthdate;
private Cat mate;
private ISet kittens
private Color color;
private char sex;
private float weight;
public virtual long Id
{
get { return id; }
set { id = value; }
}
public virtual string Name
{
get { return name; }
set { name = value; }
}
public virtual Cat Mate
{
get { return mate; }
set { mate = value; }
}
public virtual DateTime Birthdate
{
get { return birthdate; }
set { birthdate = value; }
}
public virtual float Weight
{
get { return weight; }
set { weight = value; }
}
public virtual Color Color
{
get { return color; }
set { color = value; }
}
public virtual ISet Kittens
{
get { return kittens; }
set { kittens = value; }
}
// AddKitten not needed by NHibernate
public virtual void AddKitten(Cat kitten)
{
kittens.Add(kitten);
}
public virtual char Sex
{
get { return sex; }
set { sex = value; }
}
}
}There are four main rules to follow here:
Cat declares accessor methods for all its persistent fields. Many other ORM tools directly persist instance variables. We believe it is far better to decouple this implementation detail from the persistence mechanism. NHibernate persists properties, using their getter and setter methods.
Properties need not be declared public - NHibernate can persist a property with an internal, protected, protected internal or private visibility.
Cat has an implicit default (no-argument) constructor. All persistent classes must have a default constructor (which may be non-public) so NHibernate can instantiate them using Activator.CreateInstance().
Cat has a property called Id. This property holds the primary key column of a database table. The property might have been called anything, and its type might have been any primitive type, string or System.DateTime. (If your legacy database table has composite keys, you can even use a user-defined class with properties of these types - see the section on composite identifiers below.)
The identifier property is optional. You can leave it off and let NHibernate keep track of object identifiers internally. However, for many applications it is still a good (and very popular) design decision.
What's more, some functionality is available only to classes which declare an identifier property:
Cascaded updates (see "Lifecycle Objects")
ISession.SaveOrUpdate()
We recommend you declare consistently-named identifier properties on persistent classes.
A central feature of NHibernate, proxies, depends upon the persistent class being non-sealed and all its public methods, properties and events declared as virtual. Another possibility is for the class to implement an interface that declares all public members.
You can persist sealed classes that do not implement an interface and don't have virtual members with NHibernate, but you won't be able to use proxies - which will limit your options for performance tuning.
A subclass must also observe the first and second rules. It inherits its identifier property from Cat.
using System;
namespace Eg
{
public class DomesticCat : Cat
{
private string name;
public virtual string Name
{
get { return name; }
set { name = value; }
}
}
}You have to override the Equals() and GetHashCode() methods if you intend to mix objects of persistent classes (e.g. in an ISet).
This only applies if these objects are loaded in two different ISessions, as NHibernate only guarantees identity ( a == b , the default implementation of Equals()) inside a single ISession!
Even if both objecs a and b are the same database row (they have the same primary key value as their identifier), we can't guarantee that they are the same object instance outside of a particular ISession context.
The most obvious way is to implement Equals()/GetHashCode() by comparing the identifier value of both objects. If the value is the same, both must be the same database row, they are therefore equal (if both are added to an ISet, we will only have one element in the ISet). Unfortunately, we can't use that approach. NHibernate will only assign identifier values to objects that are persistent, a newly created instance will not have any identifier value! We recommend implementing Equals() and GetHashCode() using Business key equality.
Business key equality means that the Equals() method compares only the properties that form the business key, a key that would identify our instance in the real world (a natural candidate key):
public class Cat
{
...
public override bool Equals(object other)
{
if (this == other) return true;
Cat cat = other as Cat;
if (cat == null) return false; // null or not a cat
if (Name != cat.Name) return false;
if (!Birthday.Equals(cat.Birthday)) return false;
return true;
}
public override int GetHashCode()
{
unchecked
{
int result;
result = Name.GetHashCode();
result = 29 * result + Birthday.GetHashCode();
return result;
}
}
}Keep in mind that our candidate key (in this case a composite of name and birthday) has to be only valid for a particular comparison operation (maybe even only in a single use case). We don't need the stability criteria we usually apply to a real primary key!
Optionally, a persistent class might implement the interface ILifecycle which provides some callbacks that allow the persistent object to perform necessary initialization/cleanup after save or load and before deletion or update.
The NHibernate IInterceptor offers a less intrusive alternative, however.
public interface ILifecycle
{ (1)
LifecycleVeto OnSave(ISession s); (2)
LifecycleVeto OnUpdate(ISession s); (3)
LifecycleVeto OnDelete(ISession s); (4)
void OnLoad(ISession s, object id);
}| (1) | OnSave - called just before the object is saved or inserted |
| (2) | OnUpdate - called just before an object is updated (when the object is passed to ISession.Update()) |
| (3) | OnDelete - called just before an object is deleted |
| (4) | OnLoad - called just after an object is loaded |
OnSave(), OnDelete() and OnUpdate() may be used to cascade saves and deletions of dependent objects. This is an alternative to declaring cascaded operations in the mapping file. OnLoad() may be used to initialize transient properties of the object from its persistent state. It may not be used to load dependent objects since the ISession interface may not be invoked from inside this method. A further intended usage of OnLoad(), OnSave() and OnUpdate() is to store a reference to the current ISession for later use.
Note that OnUpdate() is not called every time the object's persistent state is updated. It is called only when a transient object is passed to ISession.Update().
If OnSave(), OnUpdate() or OnDelete() return LifecycleVeto.Veto, the operation is silently vetoed. If a CallbackException is thrown, the operation is vetoed and the exception is passed back to the application.
Note that OnSave() is called after an identifier is assigned to the object, except when native key generation is used.
If the persistent class needs to check invariants before its state is persisted, it may implement the following interface:
public interface IValidatable
{
void Validate();
}The object should throw a ValidationFailure if an invariant was violated. An instance of Validatable should not change its state from inside Validate().
Unlike the callback methods of the ILifecycle interface, Validate() might be called at unpredictable times. The application should not rely upon calls to Validate() for business functionality.
Object/relational mappings are defined in an XML document. The mapping document is designed to be readable and hand-editable. The mapping language is object-centric, meaning that mappings are constructed around persistent class declarations, not table declarations.
Note that, even though many NHibernate users choose to define XML mappings by hand, a number of tools exist to generate the mapping document, including NHibernate.Mapping.Attributes library and various template-based code generators (CodeSmith, MyGeneration).
Let's kick off with an example mapping:
<?xml version="1.0"?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="Eg"
namespace="Eg">
<class name="Cat" table="CATS" discriminator-value="C">
<id name="Id" column="uid" type="Int64">
<generator class="hilo"/>
</id>
<discriminator column="subclass" type="Char"/>
<property name="BirthDate" type="Date"/>
<property name="Color" not-null="true"/>
<property name="Sex" not-null="true" update="false"/>
<property name="Weight"/>
<many-to-one name="Mate" column="mate_id"/>
<set name="Kittens">
<key column="mother_id"/>
<one-to-many class="Cat"/>
</set>
<subclass name="DomesticCat" discriminator-value="D">
<property name="Name" type="String"/>
</subclass>
</class>
<class name="Dog">
<!-- mapping for Dog could go here -->
</class>
</hibernate-mapping>We will now discuss the content of the mapping document. We will only describe the document elements and attributes that are used by NHibernate at runtime. The mapping document also contains some extra optional attributes and elements that affect the database schemas exported by the schema export tool. (For example the not-null attribute.)
All XML mappings should declare the XML namespace shown. The actual schema definition may be found in the src\nhibernate-mapping.xsd file in the NHibernate distribution.
Tip: to enable IntelliSense for mapping and configuration files, copy the appropriate .xsd files to <VS.NET installation directory>\Common7\Packages\schemas\xml if you are using Visual Studio .NET 2003, or to <VS 2005 installation directory>\Xml\Schemas for Visual Studio 2005.
This element has several optional attributes. The schema attribute specifies that tables referred to by this mapping belong to the named schema. If specified, tablenames will be qualified by the given schema name. If missing, tablenames will be unqualified. The default-cascade attribute specifies what cascade style should be assumed for properties and collections which do not specify a cascade attribute. The auto-import attribute lets us use unqualified class names in the query language, by default. The assembly and namespace attributes specify the assembly where persistent classes are located and the namespace they are declared in.
<hibernate-mapping
schema="schemaName" (1)
default-cascade="none|save-update" (2)
auto-import="true|false" (3)
assembly="Eg" (4)
namespace="Eg" (5)
/>| (1) | schema (optional): The name of a database schema. |
| (2) | default-cascade (optional - defaults to none): A default cascade style. |
| (3) | auto-import (optional - defaults to true): Specifies whether we can use unqualified class names (of classes in this mapping) in the query language. |
| (4)(5) | assembly and namespace(optional): Specify assembly and namespace to assume for unqualified class names in the mapping document. |
If you are not using assembly and namespace attributes, you have to specify fully-qualified class names, including the name of the assembly that classes are declared in.
If you have two persistent classes with the same (unqualified) name, you should set auto-import="false". NHibernate will throw an exception if you attempt to assign two classes to the same "imported" name.
You may declare a persistent class using the class element:
<class
name="ClassName" (1)
table="tableName" (2)
discriminator-value="discriminator_value" (3)
mutable="true|false" (4)
schema="owner" (5)
proxy="ProxyInterface" (6)
dynamic-update="true|false" (7)
dynamic-insert="true|false" (8)
select-before-update="true|false" (9)
polymorphism="implicit|explicit" (10)
where="arbitrary sql where condition" (11)
persister="PersisterClass" (12)
batch-size="N" (13)
optimistic-lock="none|version|dirty|all" (14)
lazy="true|false" (15)
/>| (1) | name: The fully qualified .NET class name of the persistent class (or interface), including its assembly name. |
| (2) | table: The name of its database table. |
| (3) | discriminator-value (optional - defaults to the class name): A value that distiguishes individual subclasses, used for polymorphic behaviour. Acceptable values include null and not null. |
| (4) | mutable (optional, defaults to true): Specifies that instances of the class are (not) mutable. |
| (5) | schema (optional): Override the schema name specified by the root <hibernate-mapping> element. |
| (6) | proxy (optional): Specifies an interface to use for lazy initializing proxies. You may specify the name of the class itself. |
| (7) | dynamic-update (optional, defaults to false): Specifies that UPDATE SQL should be generated at runtime and contain only those columns whose values have changed. |
| (8) | dynamic-insert (optional, defaults to false): Specifies that INSERT SQL should be generated at runtime and contain only the columns whose values are not null. |
| (9) | select-before-update (optional, defaults to false): Specifies that NHibernate should never perform an SQL UPDATE unless it is certain that an object is actually modified. In certain cases (actually, only when a transient object has been associated with a new session using update()), this means that NHibernate will perform an extra SQL SELECT to determine if an UPDATE is actually required. |
| (10) | polymorphism (optional, defaults to implicit): Determines whether implicit or explicit query polymorphism is used. |
| (11) | where (optional) specify an arbitrary SQL WHERE condition to be used when retrieving objects of this class |
| (12) | persister (optional): Specifies a custom IClassPersister. |
| (13) | batch-size (optional, defaults to 1) specify a "batch size" for fetching instances of this class by identifier. |
| (14) | optimistic-lock (optional, defaults to version): Determines the optimistic locking strategy. |
| (15) | lazy (optional): Lazy fetching may be completely disabled by setting lazy="false". |
It is perfectly acceptable for the named persistent class to be an interface. You would then declare implementing classes of that interface using the <subclass> element. You may persist any inner class. You should specify the class name using the standard form ie. Eg.Foo+Bar, Eg. Due to an HQL parser limitation inner classes can not be used in queries in NHibernate 1.0.
Immutable classes, mutable="false", may not be updated or deleted by the application. This allows NHibernate to make some minor performance optimizations.
The optional proxy attribute enables lazy initialization of persistent instances of the class. NHibernate will initially return proxies which implement the named interface. The actual persistent object will be loaded when a method of the proxy is invoked. See "Proxies for Lazy Initialization" below.
Implicit polymorphism means that instances of the class will be returned by a query that names any superclass or implemented interface or the class and that instances of any subclass of the class will be returned by a query that names the class itself. Explicit polymorphism means that class instances will be returned only be queries that explicitly name that class and that queries that name the class will return only instances of subclasses mapped inside this <class> declaration as a <subclass> or <joined-subclass>. For most purposes the default, polymorphism="implicit", is appropriate. Explicit polymorphism is useful when two different classes are mapped to the same table (this allows a "lightweight" class that contains a subset of the table columns).