Sony Arouje

a programmer's log

Archive for the ‘NHibernate’ Category

KeyNotFoundException from NHibernate’s Session.Evict

leave a comment »

We started getting KeyNotFoundException when we evict an entity from session. The error is not consistent, some time it work and some time it wont. Searched a lot for the cause of this exception but not got any proper solution.

As per the stack trace, the error is because it couldn’t find the key in a collection. In a collection an entities identity is based on the hash code. In this case the entity has composite key. In the GetHashCode function, we append the values of composite properties and get the hash code of the resultant string.  When I start checking in more details I saw some properties we used in getting hash code is not exist as part composite key in the mapping file (some keys were removed from the composite mapping but not updated GetHasCode()). I need to do some more analysis to find why those extra fields screwing up the GetHashCode function. I will update the post later if I get the answer.

To avoid these kind of issues make sure to use only composite properties in the Equal and GetHashCode function and avoid using properties that are not part of composite.

 

Happy coding…

Written by Sony Arouje

November 13, 2013 at 6:12 pm

StaleStateException for Entity with Assigned Id and version in NHibernate

with 2 comments

I was trying to persist an entity using NHibernate that uses Assigned Id’s and Version concurrency mechanism. Every time I try to persist a new instance, I am getting a StaleStateException. As per my knowledge the concurrency check will happen when we try to do an update, in my scenario it’s throwing while doing an insert. Also in the nhibernate log, I could see nhiberate is firing update command instead of insert. 

After doing some googling I come across a stackoverflow post, that NHibernate will fire update or insert based on three parameters.

  1. Id
  2. Version
  3. Timestamp

In my case Id is assigned and it will exist even if it’s a new data and I can’t help it. I am not using Timestamp. So the issue narrowed down to Version. Entity do have a version and unfortunately it’s updated using Automapper, while converting DTO to Entity. I use unix timestamp as version and we added a custom mapping in automapper to fill current date in unix timestamp format if version field is coming as empty from the client and is useful in update scenario. So for NHibernate this is not a new data because it has Id and version, so it will try to do an update instead of insert and that causes all the issues for me.

To solve this issue, either we can use Save() instead of SaveOrUpdate() or set version to zero for new data.

Written by Sony Arouje

April 25, 2013 at 2:52 pm

Unix timestamp version type in NHibernate

with one comment

The system I am working now uses NHibernate as ORM. It’s a web service with concurrent users. So one of the core issue I need to resolve is concurrency. NHibernate support different types of concurrency models, Ayende has a good post explaining about the supported concurrency models in NHibernate. From the model I choose Versioned model because our service running in sessionless detached mode, and version is the better approach here.

From Ayende’s post, we can see NHibernate version supports below types.

  • Numeric
  • Timestamp
  • DB Timestamp

The database I am working is a legacy one and different apps using it. So concurrency check is spread across the system and the existing system uses a Unix timestamp field to check concurrency. So the webservice should also use the same field. But the issue here is this field not fall under any of the supported version type.

One of the great feature of NHibernate is, we can expand it’s functionality, we can add new user types, add new listeners, interceptors, etc. So I started thinking in that direction, to create a new Version type for Unix timestamp field. After some research in NHibernate I figured out that version type can be extended by implementing IUserVersionType. Now I know what to do, just implement IUserVersionType and add the required logic to create unix timestamp. Below is the new version type I created.

public class UnixTimestampVersion : IUserVersionType
{
    private static readonly NHibernate.SqlTypes.SqlType[] SQL_TYPES =
{ NHibernate.NHibernateUtil.Int64.SqlType };

    public object Next(object current, NHibernate.Engine.ISessionImplementor session)
    {
        return DateUtil.CurrentDateInUnixFormat();
    }

    public object Seed(NHibernate.Engine.ISessionImplementor session)
    {
        return Int64.MinValue;
    }

    public object Assemble(object cached, object owner)
    {
        return cached;
    }

    public object DeepCopy(object value)
    {
        return value;
    }

    public object Disassemble(object value)
    {
        return value;
    }

    public new bool Equals(object x, object y)
    {
        if (object.ReferenceEquals(x, y)) return true;
        if (x == null || y == null) return false;
        return x.Equals(y);
    }

    public int GetHashCode(object x)
    {
        if (x == null)
            return 0;

        return x.GetHashCode();
    }

    public bool IsMutable
    {
        get { return false; }
    }
    public object NullSafeGet(IDataReader rs, string[] names, object owner)
    {
       return NHibernateUtil.Int64.NullSafeGet(rs, names[0]);
    }

    public void NullSafeSet(IDbCommand cmd, object value, int index)
    {
       NHibernateUtil.Int64.NullSafeSet(cmd, Convert.ToInt64(value), index);
    }
    public object Replace(object original, object target, object owner)
    {
        return original;
    }

    public Type ReturnedType
    {
        get { return typeof(Int64); }
    }

    public NHibernate.SqlTypes.SqlType[] SqlTypes
    {
        get { return SQL_TYPES; }
    }

    public int Compare(object x, object y)
    {
        return ((Int64)x).CompareTo((Int64)y);
    }
}

IUserVersionType has a Next function, there we need to implement the functionality to create the next value for the timestamp. I have a DateUtil that creates the Unix timestamp based on the current time. Let’s see how to use the new version type in hbm mapping file.

<hibernate-mapping default-access="property" xmlns="urn:nhibernate-mapping-2.2" auto-import="true">
   <class name="Myapp.Domain.User,Myapp.Domain" lazy="true" table="CLASIX_USER"
       optimistic-lock="version"
       dynamic-update="true"
       select-before-update="true">
    <id name="UserName" column="USERNAME" access="property"/>    
    <version name="ChangeDate" column="CHANGE_DATE"
          type="Myapp.Infrastructure.Persistence.UnixTimestampVersion,
          MyAppp.Infrastructure.Persistence"/>
  </class>
</hibernate-mapping>

It’s very easy to configure the new version type in NHibernate mapping, see the configuration in bold italics.

Happy coding…

Written by Sony Arouje

April 9, 2013 at 2:29 pm

NHibernate and Oracle Long Varchar field

with 3 comments

I am working on a project to create a webservice on top of a Legacy Oracle db. As usual I used NHibernate as the ORM. Every thing is working as expected until I hit a table with a field type of ‘Long’. NHibernate freezes whenever it try to insert records to this table. NHibernate logging was enabled and I could see no action is taking place after issuing the Insert command to this table. So to pin point the issue I commented out the filed with LONG type from the hbm mapping. Then I repeated the test, this time insertion went well without any freezing.

I confirmed that the issue is with this particular Oracle Long datatype field. I guessed that parameter type NHibernate set for this filed is the culprit. I explicitly set the type in hbm file and tried many types supported by NHibernate, but in vain. I wasted so much time trying different types in hbm and googling for a solution, at last I decided to come up with a custom type to solve this issue. I got a starting point from a blog post of nforge.

Let’s see the Custom type I created for Oracle Long.

using System;
using System.Data;
using NHibernate.UserTypes;
using NHibernate;
using Oracle.DataAccess.Client;
namespace Net.Infrastructure.Persistence
{
    public class OracleLongVarcharType:IUserType
    {
        private static readonly NHibernate.SqlTypes.SqlType[] SQL_TYPES =
            { NHibernate.NHibernateUtil.StringClob.SqlType };

        public object Assemble(object cached, object owner)
        {
            return owner;
        }

        public object DeepCopy(object value)
        {
            return value;
        }

        public object Disassemble(object value)
        {
            return value;
        }

        public bool Equals(object x, object y)
        {
            if ( object.ReferenceEquals(x,y) ) return true;
            if (x == null || y == null) return false;
            return x.Equals(y);
        }

        public int GetHashCode(object x)
        {
            if (x == null)
                return 0;

            return x.GetHashCode();
        }

        public bool IsMutable
        {
            get { return false; }
        }

        public object NullSafeGet(System.Data.IDataReader rs, string[] names, object owner)
        {
            object obj = NHibernateUtil.String.NullSafeGet(rs, names[0]);
            if (obj == null) return null;
            string val = Convert.ToString(obj);
            return val;
        }

        public void NullSafeSet(System.Data.IDbCommand cmd, object value, int index)
        {
            if (value == null)
                ((IDataParameter)cmd.Parameters[index]).Value = DBNull.Value;
            else
            {
                OracleCommand oraCmd = cmd as OracleCommand;
                if (oraCmd != null)
                {
                    oraCmd.Parameters[index].OracleDbType = Oracle.DataAccess.Client.OracleDbType.Long;
                    oraCmd.Parameters[index].Value = Convert.ToString(value);
                }
                else
                {
                    ((IDataParameter)cmd.Parameters[index]).Value = Convert.ToString(value);
                }

            }
        }

        public object Replace(object original, object target, object owner)
        {
            return original;
        }

        public Type ReturnedType
        {
            get { return typeof(string); }
        }

        public NHibernate.SqlTypes.SqlType[] SqlTypes
        {
            get { return SQL_TYPES; }
        }
    }
}

I don’t think the implementation need much explanation. Pay attention to NullSafeGet and NullSafeSet. In NullSafeSet I cast the IDBCommand to Oracle command, then reassign the parameter type as OracleDbType.Long. That’s it, we created a new custom type to handle Oracle Long type.

Let’s see how to add this new type to the mapping in hbm file.

<property name="TextData" column="TEXT_DATA" not-null="false" access="property" 
type="Net.Infrastructure.Persistence.OracleLongVarcharType,Net.Infrastructure.Persistence"/>

The Insert command NHibernate create before adding the custom type is as shown below

INSERT INTO TEXT_STORAGE (TEXT_DATA, CHANGE_DATE, CHANGE_USER, TEXT_NUMBER) VALUES (:p0, :p1, :p2, :p3);:p0 = ‘Purchase order text’ [Type: String], :p1 = 1352287328 [Type: Int64 (0)], :p2 = ‘sarouje’ [Type: String (0)], :p3 = 100588726 [Type: Int64 (0)]

after adding the Custom type

INSERT INTO TEXT_STORAGE (TEXT_DATA, CHANGE_DATE, CHANGE_USER, TEXT_NUMBER) VALUES (:p0, :p1, :p2, :p3);:p0 = ‘Purchase order text’ [Type: String (0)], :p1 = 1352287328 [Type: Int64 (0)], :p2 = ‘sarouje’ [Type: String (0)], :p3 = 100588726 [Type: Int64 (0)]

Update

Once I did some testing I realize that NHibernate is not fetching data from the table with Long type. After some search I came to know that, while creating the Oracle Command we should set InitialLONGFetchSize to a non zero value. By default OracleCommand set InitialLONGFetchSize to zero. If the InitialLONGFetchSize is zero then data retrieval is deferred until that data is explicitly requested by the application. Even I request explicitly nothing is returning. So only option left is set  InitialLONGFetchSize to a non zero. Then the question is how will I get the Command to set this property. I researched for Listeners, Interceptors, etc, nothing helped me. So I decided to inherit from OracleDataClientDriver and create my own as shown below.

using NHibernate.Driver;
using Oracle.DataAccess.Client;
namespace Net.Infrastructure.Persistence
{
    public class OracleDriverExtended:OracleDataClientDriver 
    {
        public override void AdjustCommand(System.Data.IDbCommand command)
        {
            OracleCommand cmd = command as OracleCommand;
            if (cmd != null)
                cmd.InitialLONGFetchSize = -1;
        }
    }
}

Now we have to instruct NHibernate to use the new driver I created, update the driver info in hibernate.cfg.xml as shown below.

<property name="connection.driver_class">Net.Infrastructure.Persistence.OracleDriverExtended,
Net.Infrastructure.Persistence</property>

I reran the test and now I could see the data from the Long field. Relieved….

Hope this post will help some one. Happy coding.

Written by Sony Arouje

November 7, 2012 at 5:42 pm

NHibernate Error – ‘nhIdOutParam’ No size set for variable length data type

with one comment

I am working on a project where I have to connect to an Oracle database. I used NHibernate as my ORM, every thing worked as expected until the Save operation. The table I was dealing with has a ROWID field an auto generated field by Oracle. Here we cannot use the native generator of NHibernate, I felt the best fit here is ‘trigger-identity’ generator. As shown below I configured the rowid in my hbm file.

    <id name="_rowId" column="RowId" access="field">
      <generator class="trigger-identity"></generator>
    </id>

To my surprise Nunit throws the error “System.Exception : Parameter ‘:nhIdOutParam’: No size set for variable length data type: String.” whenever I try to save the entity.

I analyzed the insert query generated by NHibernate and every things is fine. Next option for me is google, like every one else I started searching in google, I got so many forums where people reported this issue but no solid answer. The error stack trace shows that the error is from System.Data.OracleClient, I felt like the issue is with the Oracle client I am using, here I am using the client from Microsoft not the native ODP.Net provided by Oracle. It seems like system.data.OracleClient is unable to handle the ‘returning’ statement added by NHibernate.

Nhibernate will create the Insert statement as shown below

Insert into Table (filed1, field2) values (p1, p2) returning RowId into :nhIdOutParam

I changed the NHibernate configuration to use the Oracle client and referred Oracle.DataAccess.dll to my project. Compiled the project and run the NUnit test, wow I got the Green bar after 4hrs of struggling. In my previous NHibernate configuration (hibernate.cfg.xml) the driver class property was

<property name="connection.driver_class">NHibernate.Driver.OracleClientDriver</property>

This configuration forces NHibernate to use the Oracle client provided with .NET. To instructed NHibernate to use the native oracle assembly (Oracle.DataAccess.dll) change the configuration as below

<property name="connection.driver_class">NHibernate.Driver.OracleDataClientDriver</property>

 

Hope this post may help some one to save some time.

Written by Sony Arouje

March 21, 2012 at 7:35 pm

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: