Sony Arouje

a programmer's log

Posts Tagged ‘Hibernate Configuration

Persist Domain Model using NHibernate

with 2 comments

Last couple of days I was spending time with NHibernate. I went through several articles and books related to NHibernate. I learned bits and pieces about hibernate, next step for me is to implement what ever I learned so far. I choose a small Sales Tax problem for learning NH.

Object Relational Mappers are best suited in Object oriented development (OOD). In OOD process the designer first implement the domain model based on the business requirement. Then use any ORM to persist. In this approach we are giving importance to domain model then comes the db modelling. Domain model and NHibernate will go hand in hand. A designer can design the domain model without thinking much about persistence. Anyway I am not going much in detail of Domain models, you all can read more from Patterns of Enterprise Application Architecture and Domain-Driven Design: Tackling Complexity in the Heart of Software

Below is the rough diagram of domain model I created

image

Let’s go through Order Entity

namespace DDD.DomainModel
{
    public class Order
    {
        private IList<OrderLine> _lineItems;
        private Customer _customer;
        private ISalesTaxCalculator _salesCalculator;
        private int _orderId;

        private Order() 
        {

        } 
        public Order(Customer customer, ISalesTaxCalculator salesCalculator)
        {
            this._customer = customer;
            this._lineItems = new List<OrderLine>();
            this._salesCalculator = salesCalculator;
        }

        public int OrderId
        {
            get { return _orderId; }
        }
        public Order With(OrderLine orderLine)
        {
            Money tax = _salesCalculator.CalculateTax(orderLine);
            orderLine.SetTaxAmount(tax);
            orderLine.SetOrder(this);
            _lineItems.Add(orderLine);
            return this;
        }
        public Money GetTotalTax()
        {
            Money totalTax = Money.Empty();
            for (int i = 0; i < _lineItems.Count; i++)
                totalTax += _lineItems[i].GetTaxAmount();
            return totalTax;
        }
        public Money GetGrandTotal()
        {
            Money total = Money.Empty();
            for (int i = 0; i < _lineItems.Count; i++)
                total += _lineItems[i].GetSubTotal();
            return total;
        }
        
        public int GetNumberOfItems()
        {
            return this._lineItems.Count();
        }
        public virtual IList<OrderLine> LineItems
        {
            get { return _lineItems; }
        }
        public Customer Customer
        {
            get
            {
                return _customer;
            }
        }

    }
}

 

As you could see in the order class there is no Getter/Setter properties for setting the data from db. One of the good feature of NHibernate is, it can set or get data from private fields via reflection. It helps us to maintain Immutability in entities.

Mapping File

Hibernate uses xml configuration files to map Entities to database tables. Let’s see the configuration file for Order entity.

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping default-access="field"
    xmlns="urn:nhibernate-mapping-2.2"
    auto-import="true">
  <class name="DDD.DomainModel.Order,DDD.DomainModel"  lazy="false" table="[Order]">
    <id name="OrderId" column="order_id" access="nosetter.camelcase-underscore">
      <generator class="native"></generator>
    </id>
    <bag
      name="LineItems"
      cascade="all-delete-orphan" access="nosetter.camelcase-underscore" lazy="true">
      <key column ="order_id"/>
      <one-to-many class ="DDD.DomainModel.OrderLine,DDD.DomainModel"/>
    </bag>
    <many-to-one name="Customer" column="customer_id" not-null="false" cascade="none" 
       access="nosetter.camelcase-underscore" update="false" 
       class="DDD.DomainModel.Customer,DDD.DomainModel"/>
  </class>
</hibernate-mapping>

Let’s go through the config file

In the class tag, I mapped the Order class with the database table Order. Inside the class tag provide the mappings for the fields to the table row.

id tag tells hibernate that the field is an Identity field, here I mapped _orderId to column order_id. So what is this access property. It will directs the hibernate from where to get/set the value. Here I set as nosetter.camelcase-underscore. I explain that part later.

Bag tag tells hibernate that LineItems is a collection. Inside bag we define the relationship with orderline.

Access Attribute

Hibernate can set value to private fields or to property. Hibernate uses ‘access’ attribute to determine this.

field: Set access to field (access=’field’) directs hibernate to read values from private field during persisting and while fetching it sets the private field with the value from database. I feel it’s a very important feature, this makes objects hides the data and exposed through predefined interfaces.

property: Set access to property (access=’property’) directs hibernate to get and set values to the properties.

nosetter.*: Set access to property (access=’nosetter’) directs hibernate to get values from property of the field mentioned but set value to private field. Let’s explain with an e.g.

private Customer _customer;
public Customer Customer { get { return _customer; } }
In xml we configure like
<many-to-one name="Customer" column="customer_id" not-null="false" cascade="none" access="nosetter.camelcase-underscore" …./>

 

This tells hibernate while persisting get the value from the Customer property but while setting the value from db uses the variable field (with same name as property) in camelcase-underscore format, here it will set the value to _customer.

You all can see the rest of the configuration in the source code.

Hibernate Repository

I created a generic repository for Hibernate just like the one I created for Entity Framework. Let’s go through the hibernate repository.

public class HibernateRepo:IRepository
{
    IList _itemsAdded = new System.Collections.ArrayList();
    ISession _session;

    private static ISessionFactory CreateSessionFactory()
    {
        Configuration cfg = new Configuration().Configure();
        return cfg.BuildSessionFactory();
    }

    private ISession Session
    {
        get 
        {
            if (_session!=null && _session.Connection.State != System.Data.ConnectionState.Open)
            {
                _session.Connection.Close();
                _session.Connection.Open();
            }
            if (_session == null || _session.IsOpen == false)
                _session = CreateSessionFactory().OpenSession();
            
            return _session;
        }
    }

    ITransaction _currentTransaction = null;
    public void BeginTransaction()
    {
        _currentTransaction= this.Session.BeginTransaction();
    }
    public void CommitTransaction()
    {
        if (_currentTransaction != null)
            _currentTransaction.Commit();
    }
    public void Rollback()
    {
        if(_currentTransaction!=null)
            _currentTransaction.Rollback();
    }

   
    public IQueryable<TEntity> GetQuery<TEntity>() where TEntity : class
    {
        return this.Session.Query<TEntity>();
    }

    public IList<TEntity> GetAll<TEntity>() where TEntity : class
    {
        return this.GetQuery<TEntity>().AsEnumerable<TEntity>().ToList();
    }

    public IList<TEntity> Find<TEntity>(System.Linq.Expressions.Expression<Func<TEntity, bool>> criteria) where TEntity : class
    {
        IList<TEntity> entities= this.GetQuery<TEntity>().Where(criteria).ToList();
        NHibernateUtil.Initialize(entities);
        return entities;
    }

    public TEntity Single<TEntity>(System.Linq.Expressions.Expression<Func<TEntity, bool>> criteria) where TEntity : class
    {
        TEntity entity= this.GetQuery<TEntity>().SingleOrDefault<TEntity>(criteria);
        return entity;
    }

    public TEntity First<TEntity>(System.Linq.Expressions.Expression<Func<TEntity, bool>> criteria) where TEntity : class
    {
        TEntity entity = this.GetQuery<TEntity>().FirstOrDefault<TEntity>(criteria);
        return entity;
    }

    public void Add<TEntity>(TEntity entity) where TEntity : class
    {
        _itemsAdded.Add(entity);
    }

    public void Delete<TEntity>(TEntity entity) where TEntity : class
    {
        this.Session.Delete(entity);
    }

    public void Delete<TEntity>(IEnumerable<TEntity> entites) where TEntity : class
    {
        throw new NotImplementedException();
    }

    public void SaveChanges()
    {
        for (int i = 0; i < _itemsAdded.Count; i++)
        {
            this.Session.SaveOrUpdate(_itemsAdded[i]);
        }
    }

    public void Dispose()
    {
        if (this.Session != null)
        {
            _session.Close();
            _session.Dispose();
        }
        if (this._currentTransaction != null)
            _currentTransaction.Dispose();
    }
}

 

Most of the functions are same as the one I created for EF. Let’s go through some function I added for hibernate.

You might wonder why there is no connection string mentioned in this class, also there is no reference about the mapping xml files. How hibernate get all these information? Hibernate uses a configuration file called ‘hibernate.cfg.xml’. This file should exist in the bin folder. This file is not mandatory, you can directly give all the information to hibernation while creating session. Let’s see the configuration file

<?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="connection.driver_class">
      NHibernate.Driver.SqlClientDriver
    </property>
    <property name="connection.connection_string">
      Data Source=PROLAPE00700\SQLSERVER;Initial Catalog=SASales;
      Persist Security Info=True;User ID=sony;pwd=sony
    </property>
    <property name="proxyfactory.factory_class">
       NHibernate.ByteCode.Castle.ProxyFactoryFactory, NHibernate.ByteCode.Castle
    </property>
    <property name="dialect">
      NHibernate.Dialect.MsSql2008Dialect
    </property>
    <mapping assembly="DDD.Infrastructure.Persistance"/>
  </session-factory>
</hibernate-configuration>

 

I configured connection string and mapping assembly here. Hibernate uses mapping assembly tag to find out here the mapping files located and it fetches from the assembly using reflection. One thing to remember is the mapping files Build Action should be Embedded Resource.

How this configuration file get passed to hibernate? Have a look at the static function in the repository called CreateSesstionFactory().

private static ISessionFactory CreateSessionFactory()
{
    Configuration cfg = new Configuration().Configure();
    return cfg.BuildSessionFactory();
}

When we call Configuration().Configure() hibernate search for the above configuration file and uses the settings in the file to configure the session.

Once you go through the source you might understand how easy we can persist out domain models with less effort.

Download Source Code

Written by Sony Arouje

June 24, 2011 at 8:35 pm

%d bloggers like this: