views:

352

answers:

4

I'm trying to migrate an app from NHibernate 1.x to 2.1, and I've noticed something odd: my immutable objects are being deleted in my integration tests.

For example, this test used to pass:

[Test, ExpectedException(typeof(NHibernate.HibernateException))]
public void DeleteExistingInstanceThrows()
{
 // Note: NHib transaction is opened/rolled back in test setup/teardown
 m_testRecordId = CreateRecordInDB();
 var dao = new NHibFactory().GetTransDao();
 var obj = dao.GetById((long)m_testRecordId, false);

 dao.Delete(obj);
 dao.CommitChanges();

 Assert.IsFalse(TestRecordExists(m_testRecordId));
}

The call to CommitChanges should throw, because of trying to delete an instance whose type is mapped with mutable="false". However, after updating the expected exception type, this test now fails (because no exception is thrown). I've checked the database and traced through the test, and the record is created, the instance is loaded, and the record gets deleted again afterwards.

The class in question is mapped to the same table as another class - it is more-or-less intended as a read-only view of a subset of that data. Here's the class mapping:

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
 <class name="Sample.Trans, Sample" table="tblTrans" mutable="false">

  <id name="Id" column="transId" unsaved-value="0">
   <generator class="identity" />
  </id>

  <property name="Amount" column="amount" type="Decimal" />

  <!-- ...a half dozen other mapped fields... -->
 </class>
</hibernate-mapping>

I expect I'm missing something basic, but I've been scouring the web for any reason why the mutable attribute might be ignored, and I've come up empty.

UPDATE:

Logging with Log4Net, it's clear that NHibernate was sending the delete command to the database.

A: 

Why are you expecting an exception? You create row in db and then delete it, maybe you don't need expected exception?

Sly
It should raise an exception because mutable=false. From the docs: "Immutable classes, mutable="false", may not be updated or deleted by the application".
Remi Despres-Smyth
A: 

Did you say you roll back the transaction after test? So the row is rolled back, not deleted. A database profiler should help here.

Canton
+3  A: 

After having dug into it, I found this block of code commented out in the DefaultDeleteEventListener's OnDelete method:

/*
if ( !persister.isMutable() ) {
throw new HibernateException(
"attempted to delete an object of immutable class: " +
MessageHelper.infoString(persister)
);
}*/

As a result, no exception is raised when attempting to delete an immutable instance, and the deletion does actually occur afterwards as if the instance were mutable.

I've sent a note to an NHibernate maintainer with my findings - looks like a bug to me.

Noted by another poster, this issue was fixed in release 2.1.1 from Oct 31 2009.

Remi Despres-Smyth
A: 

I had exactly the same problem in the same situation (upgrading from 1.x). The bug was fixed in 2.1.1 which was released Oct 31.

/Emil

Emil Åström
Thanks for the heads-up.
Remi Despres-Smyth