NHibernate offers several methods for configuration and a number of configuration settings.
In this recipe, I'll show you how to configure NHibernate using your application's configuration file with a minimal number of settings to get your application up and running quickly. This recipe also forms the base for several other recipes in this chapter.
Eg.Core
model and mapping recipes from Chapter 1, Models and Mappings.ConfigByAppConfig
.ConfigByAppconfig
project, add references to NHibernate.dll
and NHibernate.ByteCode.Castle.dll
from the Lib
folder.ConfigByAppconfig
, add a reference to the Eg.Core
project.App.config
file to your console project.App.config
file.<configSections> <section name="hibernate-configuration" type="NHibernate.Cfg.ConfigurationSectionHandler, NHibernate"/> </configSections>
connectionStrings
section with a connection string:<connectionStrings> <add name="db" connectionString="Server=.SQLExpress; Database=NHCookbook; Trusted_Connection=SSPI"/> </connectionStrings>
hibernate-configuration
section:<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2"> <session-factory> <property name="proxyfactory.factory_class"> NHibernate.ByteCode.Castle.ProxyFactoryFactory, NHibernate.ByteCode.Castle </property> <property name="dialect"> NHibernate.Dialect.MsSql2008Dialect, NHibernate </property> <property name="connection.connection_string_name"> db </property> <property name="adonet.batch_size"> 100 </property> <mapping assembly="Eg.Core"/> </session-factory> </hibernate-configuration>>
App.config
file should look like this:<?xml version="1.0" encoding="utf-8" ?> <configuration> <configSections> <section name="hibernate-configuration" type="NHibernate.Cfg.ConfigurationSectionHandler, NHibernate"/> </configSections> <connectionStrings> <add name="db" connectionString="Server=.SQLExpress; Database=NHCookbook; Trusted_Connection=SSPI"/> </connectionStrings> <hibernate-configuration xmlns="urn:nhibernate-configuration-2.2"> <session-factory> <property name="proxyfactory.factory_class"> NHibernate.ByteCode.Castle.ProxyFactoryFactory, NHibernate.ByteCode.Castle </property> <property name="dialect"> NHibernate.Dialect.MsSql2008Dialect, NHibernate </property> <property name="connection.connection_string_name"> db </property> <property name="adonet.batch_size"> 100 </property> <mapping assembly="Eg.Core"/> </session-factory> </hibernate-configuration> </configuration>
Program.cs
and add using NHibernate.Cfg;
to the beginning of the file.Main
function, add the following code to configure NHibernate:var nhConfig = new Configuration().Configure(); var sessionFactory = nhConfig.BuildSessionFactory(); Console.WriteLine("NHibernate Configured!"); Console.ReadKey();
The connection string we've defined points to the NHCookbook database running under the local Microsoft SQL Server Express 2008.
Next, we define a few properties that tell NHibernate how to behave. proxyfactory.factory_class
specifies the proxy framework we'll use. In this case, we're using Castle's DynamicProxy2. Out of the box, NHibernate also supports the LinFu and Spring frameworks.
The
dialect
property specifies a dialect
class that NHibernate uses to build SQL syntax specific to a
Relational Database Management System (RDBMS). We're using the Microsoft SQL 2008 dialect. Additionally, most dialects set intelligent defaults for other NHibernate properties, such as connection.driver_class
.
The connection.connection_string_name
property references our connection string named db
. We can name the connection string anything we like, as long as this property matches the connection string's name.
By default, NHibernate will send a single SQL statement and wait for a response from the database. When we set the
adonet.batch_size
property to 100, NHibernate will group up to 100 SQL INSERT, UPDATE, and DELETE statements in a single ADO.NET command and send the whole batch at once. In effect, the work of 100 round trips to the database is combined in one. Because a roundtrip to the database is, at best, an out-of-process call, and at worst, a trip through the network or even the Internet, this improves performance significantly. Batching is currently supported when using the SqlClientDriver
for Microsoft SQL Server or the OracleDataClientDriver
for Oracle.
The mappings
element defines where NHibernate will search for our mappings. In this case, it will search the Eg.Core
assembly for embedded resources ending in .hbm.xml
.
There are several key components to an NHibernate application, as shown in this diagram:
On startup, an NHibernate application builds a Configuration
object. In this recipe, we build the configuration from settings in the App.config
file. The Configuration
object is responsible for loading mappings, reflecting the model for additional information, building the mapping metadata, and finally building a session factory. Building the session factory is an expensive operation, and should be done only once in the life of an application.
The session factory is responsible for building sessions. Unlike a session factory, building a session is very cheap.
A session represents a unit of work in the application. Martin Fowler defines a unit of work as an object that maintains a list of objects affected by a business transaction and coordinates the writing out of changes and the resolution of concurrency problems. An NHibernate session tracks changes to entities and writes those changes back to the database all at once. In NHibernate, this process of waiting to write to the database all at once is called transactional write-behind. In addition, the session is the entry point to much of the NHibernate API. More information about the unit of work pattern is available at http://martinfowler.com/eaaCatalog/unitOfWork.html and in Fowler's book, Patterns of Enterprise Application Architecture.
The session acts as an intermediary between our application and several key NHibernate components. A typical application will not interact with these components directly, but understanding them is critical to understanding NHibernate.
A dialect is used to build SQL syntax for a specific RDBMS. For example, in Microsoft SQL Server, we begin a select statement with SELECT TOP 20
to specify a maximum result set size. Only 20 rows will be returned. To do the same in SQLite, we append LIMIT 20
to the end of the select statement. Each dialect provides the necessary SQL syntax string fragments and other information to build correct SQL strings for the chosen RDBMS.
The driver is responsible for building the batcher, creating IDbConnection
and IDbCommand
objects, and preparing those commands.
The connection provider is simply responsible for opening and closing database connections.
The batcher manages the batch of commands to be sent to the database and the resulting data readers. Currently, only the SqlClientDriver
and OracleDataDriver
support batching. Those drivers that don't support batching provide a NonBatchingBatcher
to manage IDbCommands
and IDataReaders
and simulate the existence of a single logical batch of commands.
Here are some of the commonly used NHibernate properties:
Property name |
Description |
---|---|
Provider class to open and close database connections. | |
This is specific to the RDBMS used, and is typically set by the dialect. | |
Database connection string. | |
Name of connection string in | |
Transaction isolation level. | |
Required. A class to build RDBMS-specific SQL strings. Typically, this is one of the many dialects from the | |
Boolean value. Set to true to log all SQL statements to | |
Class to manage contextual sessions. This is covered in depth in Chapter 3. | |
Comma-separated list of translations to perform on query strings. For example, True=1, Yes=1, False=0, No=0. | |
Class to convert RDBMS-specific ADO.NET Exceptions to custom exceptions. | |
Boolean value. Prepares SQL statements and caches the execution plan for the duration of the database connection. | |
Number of seconds to wait for a SQL command to complete before timing out. | |
Number of SQL commands to send at once before waiting for a response from the database. | |
Enables tracking of some statistical information, such as the number of queries executed and entities loaded. | |
Required. Specifies a factory class for our chosen proxy framework, in this case Castle DynamicProxy2. | |
Adds line endings for easier-to-read SQL statements. |
Additional information about each of these settings is available in the reference documentation at http://www.nhforge.org/doc/nh/en/index.html.
Many dialects set other NHibernate properties to sensible default values, including, in most cases, the connection.driver_class
. NHibernate includes the following dialects in the NHibernate.Dialect
namespace and drivers in the NHibernate.Driver
namespace:
RDBMS |
Dialect(s) |
Driver(s) |
---|---|---|
Microsoft SQL Server |
|
|
Oracle |
|
|
MySql |
|
|
PostgreSQL |
|
|
DB2 |
|
|
Informix |
|
|
Sybase |
|
|
Firebird |
|
|
SQLite |
|
|
|