marco-fiset
marco-fiset

Reputation: 1933

Is NHibernate 3.1 broken?

I've been following the Summer of NHibernate series. So far so good, everything is working as expected, even though I am using NHibernate 3.1 and the videos use version 1.2.

I just encountered a problem, however, and it seems like a HUGE bug to me. I am now at Session #3 where we insert, update and delete customers from the database. Here is the Customer class :

public class Customer
{
    private int customerId;
    private string firstName;
    private string lastName;

    public virtual int CustomerId
    {
        get { return customerId; }
        set { customerId = value; }
    }

    public virtual string FirstName 
    {
        get { return firstName; }
        set { firstName = value; }
    }

    public virtual string LastName
    {
        get { return lastName; }
        set { lastName = value; }
    }
}

And here is the mapping file :

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" namespace="DataTransfer" assembly="DataTransfer">
  <class name="DataTransfer.Customer, DataTransfer" table="Customer">
    <id name="CustomerId" column="CustomerId" type="Int32" unsaved-value="0">
      <generator class="native"></generator>
    </id>
    <property name="FirstName" column="FirstName" type="string" length="50" not-null="false" />
    <property name="LastName" column="LastName" type="string" length="50" not-null="false" />
  </class>
</hibernate-mapping>

The configuration file is nothing too fancy :

<?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.OdbcDriver</property>
    <property name="connection.connection_string">Dsn=datasource;uid=user</property>
    <property name="dialect">NHibernate.Dialect.MySQLDialect</property>
    <property name="show_sql">true</property>
    <mapping assembly="DataTransfer"></mapping>
  </session-factory>
</hibernate-configuration>

Now here is the problem. When I insert a new Customer like so :

public int AddCustomer(Customer customer)
{
    int newId = (int)session.Save(customer);
    session.Flush();

    return newId;
}

newId will ALWAYS be equal to zero, and customer.Id is never updated to the identity value generated by the database even though the insert statement was successful, as I can see the new customer in the database. This happens when I use NHibernate 3.1

But, if I change the references of my projet to NHibernate 1.2 without changing a single line of code, newId will contain the actual inserted Id and customer.Id will be updated.

I was wondering if this strange behaviour of NHibernate 3.1 is normal, or if I must do something special for it to work the way I expect it, but to me, it looks like a bug.

Upvotes: 2

Views: 667

Answers (1)

sbohlen
sbohlen

Reputation: 2019

Starting with NHibernate 2.1.2, you must wrap all database interactions (even queries) within an explicit NHibernate transaction. There's a complex list of edge-cases that make this so, but for now just take it on faith that this is the case. Because of this, the typical pattern you should use here for this example needs to look similar to the following snippet:

public int AddCustomer(Customer customer)
{
    int newId;

    using(var tx = session.BeginTransaction())
    {
        newId = (int)session.Save(customer);
        tx.Commit();
    }

    return newId;
}

Prior to NH 2.1.2, NH provided implicit transactions if you weren't explicit about them but certainly under NH 3.1 its required for you to be explicit about the NH transaction boundaries. Note that in the above example, the tx.Commit() call implicitly flushes the session for you (assuming that you have not modified the default setting for FlushMode, of course).

Upvotes: 3

Related Questions