Logo

NHibernate

The object-relational mapper for .NET

A fluent interface to NHibernate - Part 4 - Configuration

Blog Signature Gabriel

This is the fourth post in a series of articles where I want to analyze and describe the new upcoming mapping interface providing a fluent interface to NHibernate for the mapping of a domain model to the underlying database. Other post will follow

  • A fluent interface to NHibernate
  • A fluent interface to NHibernate - Part 2 - Value Objects
  • A fluent interface to NHibernate - Part 3 - Mapping Relations
  • A fluent interface to NHibernate - Part 4 - Configuration
  • </ul>

    Configuration

    In NHibernate we traditionally had several methods how we could configure the database relevant parameters. These are

    • defining all requested configuration parameters in code
    • include a special section in the app.config or web.config file
    • define a hibernate.cfg.xml file
    • define a custom XML file
    • </ul>

      With the new mapping framework we have one more possibility by using a fluent interface to configure NHibernate. We can define all parameters in our code using a fluent interface. Let's review the various methods to configure our ORM framework.

      Defining requested configuration parameters in code

      When initializing the NHibernate framework I can configure all necessary parameters in code. I just instantiate a Configuration object and pass it all requested parameters via the SetProperty method. Having set all necessary connection parameters I can now define where my domain model is. In the sample below I take the AddAssembly method to tell NHibernate that all my model classes are to be found in the assembly where the class Blog is defined. NHibernate will then parse the whole assembly for embedded mapping files (e.g. Blog.hbm.xml etc.). In the last line of code I create the session factory. This factory instance I'll then use each time I need a connection to the database.

      var cfg = new Configuration();
       
      cfg.SetProperty("connection.provider", "NHibernate.Connection.DriverConnectionProvider");
      cfg.SetProperty("connection.driver_class", "NHibernate.Driver.SQLite20Driver");
      cfg.SetProperty("dialect", "NHibernate.Dialect.SQLiteDialect");
      cfg.SetProperty("connection.connection_string", "Data Source=:memory:;Version=3;New=True;");
      cfg.SetProperty("connection.release_mode", "on_close");
      cfg.SetProperty("show_sql", "true");
       
      cfg.AddAssembly(typeof (Blog).Assembly);
       
      ISessionFactory factory = cfg.BuildSessionFactory();

      In the above sample I'm using SqLite as my database and the connection string is configured such as that the database is in in-memory mode, that is the schema and the data is not written to disk but always kept in memory. I also have told NHibernate to output all SQL sent to the database to the console (for debugging purposes). This is the typical configuration I tend to use in my unit tests.

      The app.config or web.config

      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="hibernate-configuration"         
                   type="NHibernate.Cfg.ConfigurationSectionHandler, NHibernate" />
        </configSections>
        
        <hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
          <session-factory>
            <property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</property>
            <property name="connection.driver_class">NHibernate.Driver.SqlClientDriver</property>
            <property name="connection.connection_string">Server=(local);database=thedatabase;Integrated Security=SSPI;</property>
            <property name="dialect">NHibernate.Dialect.MsSql2005Dialect</property>
            <property name="show_sql">true</property>
          </session-factory>
        </hibernate-configuration>
        
        <!-- other app specific config follows... -->
        
      </configuration>
       

      You first have to define a section for NHibernate in the configSections part of the config file. The content of the NHibernate section is then the same as when you use the hibernate.cfg.xml file (see below). In this sample I'm using an SQL Server 2005 database which is installed on the local machine. The connection to the SQL Server uses integrated security. I also have told NHibernate to output all SQL sent to the database to the console.

      Now I can initialize NHibernate with the following code

      var cfg = new Configuration();
      cfg.AddAssembly(typeof (Product).Assembly);
      ISessionFactory factory = cfg.BuildSessionFactory();

      Note that the necessary configuration parameters are automatically picked up by NHibernate from the app.config or web.config file.

      The hibernate.cfg.xml file

      Below I present a typical configuration file. Again this sample assumes SqLite as my database.

      <?xml version="1.0" encoding="utf-8" ?>
      <hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
        <session-factory>
          <property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</property>
          <property name="dialect">NHibernate.Dialect.SQLiteDialect</property>
          <property name="connection.driver_class">NHibernate.Driver.SQLite20Driver</property>
          <property name="connection.connection_string">Data Source=:memory:;Version=3;New=True;</property>
          <property name="connection.release_mode">on_close</property>
       
          <property name="show_sql">true</property>
        </session-factory>
      </hibernate-configuration>

      This file must be present in the same directory as the application that uses it. Then NHibernate can automatically pick it up when you initialize the framework.

      var cfg = new Configuration();
      cfg.Configure();
       
      cfg.AddAssembly(typeof (Blog).Assembly);
       
      ISessionFactory factory = cfg.BuildSessionFactory();

      We have to instantiate a NHibernate Configuration object and call the method Configure. When doing this the default behavior is that NHibernate looks for a file called hibernate.cfg.xml in the application directory an opens it if available.

      A custom XML file

      The content of the file must be structured the same way as in the hibernate.cfg.xml presented above. But you can name the file however you want and you are also free to choose it's location. When you initialize NHibernate you have to provide the respective information about your configuration file.

      You can pick a different XML configuration file using the following syntax

      var cfg = new Configuration();
      cfg.Configure(Path.Combine(AppDomain.CurrentDomain.BaseDirectory,"my_config_file.xml"));
       
      cfg.AddAssembly(typeof(Product).Assembly);
       
      ISessionFactory factory = cfg.BuildSessionFactory();

      The method Configure accepts a parameter indicating the full path to my custom XML file.

      Use a fluent interface to configure NHibernate

      All the above samples are not really complicated but have the disadvantage that we have to deal with strings (configuration in code) or with XML. XML is not really nice to read and certainly not wrist friendly. Also there is no compile time error checking. Any typos introduced will only be detected during runtime.

      Comes the fluent interface to the rescue. I can now configure NHibernate in a strongly typed fashion. Have a look at the following code

      var cfg = new MyConfiguration()
          .ShowSql()
          .Driver<SQLite20Driver>()
          .Dialect<SQLiteDialect>()
          .ConnectionString.Is("Data Source=:memory:;Version=3;New=True;")
          .Raw("connection.release_mode", "on_close");

      A few remarks to this code

      • no need to define a connection provider (it's always and has always bee NHibernate.Connection.DriverConnectionProvider and thus this is configured implicitly by the framework)
      • all commonly used parameters can be configured using strong typing
      • generic methods are used wherever flexibility is needed (e.g. the method .Driver<T>() where T represents the concrete driver you want to choose)
      • the method Raw can be used whenever we need to configure non-standard (that is database specific) parameters. In the sample above I define the connection release mode for the SqLite database.
      • The connection string can either be defined in place (as in the above sample) or
        • be retrieved from the appSection in the web.config or app.config file
          .ConnectionString.FromAppSetting("MyConnectionString")
        • be retrieved from the connectionStrings section in the web.config or app.config file
          .ConnectionString.FromConnectionStringWithKey("MyConnectionString")
        • </ul>

        There are other methods we can use to further configure NHibernate (e.g. UseOuterJoin, MaxFetchDepth and UseReflectionOptimizer)

        Now I have to say some words to the MyConfiguration class used in the sample above... This class inherits from the PersistenceConfiguration class of the fluent interface framework and contains no code.

        public class MyConfiguration : PersistenceConfiguration<MyConfiguration>
        {
        }

        For some databases there are even pre-defined configuration classes that facilitate the job even further. For SqLite I can then write

        var cfg = new SQLiteConfiguration()
            .InMemory()
            .DoNot.ShowSql();

        Really nice! Please note also the DoNot... syntax to revert some boolean settings like ShowSql or UseOuterJoin, etc.

        Now a complete sample how to configure and use NHibernate

        var nhibernateConfig = new Configuration();
        var cfg = new SQLiteConfiguration()
            .InMemory()
            .ConfigureProperties(nhibernateConfig);
         
        var sessionSource = new SessionSource(cfg.Properties, new MyPersistenceModel());
         
        using (var session = sessionSource.CreateSession())
        {
            var product = new Product { Name = "Product 1", UnitPrice = 10.55m, Discontinued = false };
            session.Save(product);
        }

        First I instantiate an object of type NHibernate.Cfg.Configuration. I then instantiate an object of type SQLiteConfiguration which is defined in the mapping framework. With the ConfigureProperties method I tell this object to configure the NHibernate configuration object which I pass as a parameter. Then I instantiate a SessionSource object an pass it the properties of my SqLite configuration object as well as my persistence model. Last I use this session source to create a new session and insert a new product into the database. (Please refer to the previous articles of this series for a description of the persistence model).

        Summary

        Various methods exists how one can configure NHibernate. None of them is really complicated. But the new mapping framework facilitates the configuration even more and has the following advantages over the other methods

        • type safety (and thus also re-factor friendly)
        • good readability
        • intellisense support
        • </ul>

          Enjoy

          Blog Signature Gabriel .


Posted Sat, 06 September 2008 11:45:31 AM by gabriel.schenker
Filed under: mapping, configuration

comments powered by Disqus
© NHibernate Community 2024