Hi,
I have a strange error which may or may not be related to
transactions. Here is my scenario....
I have 2 entities with typical one-to-many parent child relationship.
One "Document" can have many "DocumentAudit" objects.
Parent mapping:
<?xml version="1.0"?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" auto-
import="true" assembly="Business">
<class name="Business.Domain.Document" table="DOCUMENT"
lazy="false">
<id name="Id" type="int" column="DocumentId">
<generator class="native" />
</id>
<property name="FileName" column="FileName" type="string"
length="220" />
<bag name="DocumentAudits" cascade="all" lazy="true"
inverse="true">
<key column="DocumentId" />
<one-to-many class="Business.Domain.DocumentAudit" />
</bag>
</class>
</hibernate-mapping>
And here is the child:
<?xml version="1.0"?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" auto-
import="true" assembly="Business">
<class name="Business.Domain.DocumentAudit" table="DOCUMENT_AUDIT"
lazy="true">
<cache usage="read-write"/>
<id name="Id" type="int" column="DocumentAuditId">
<generator class="native" />
</id>
<property name="Action" column="Action" type="string"
length="50" />
<property name="Actor" column="Actor" type="string"
length="50" />
<many-to-one name="Document" class="Business.Domain.Document"
fetch="select">
<column name="DocumentId" unique="true" />
</many-to-one>
</class>
</hibernate-mapping>
I have a generic data access class called BaseBroker which has Persist
and Delete methods as follows:
public void Persist(T obj)
{
using (ITransaction txn =
nHibernateDB.Session.BeginTransaction())
{
try
{
nHibernateDB.Session.Persist(obj);
txn.Commit();
}
catch
{
txn.Rollback();
throw;
}
}
}
public void Delete(T obj)
{
using (ITransaction txn =
nHibernateDB.Session.BeginTransaction())
{
try
{
nHibernateDB.Session.Delete(obj);
txn.Commit();
}
catch
{
txn.Rollback();
throw;
}
}
}
All seems OK and I've got some test fixtures covering everyday adding
and deleting of objects. All working fine.
HOWEVER, I've run into a very strange error. There is a unique index
on the Document.FileName column. I've written a test which needs to
verify that attempting to insert a Document with an existing FileName
generates the expected exception. So the steps in the test are as
follows:
1. Create new Document "doc1" with 1 new DocumentAudit child.
2. Call Persist(doc1)
3. Create new Document "doc2" with 1 new DocumentAudit child, and the
SAME FileName as doc1
4. Call Persist(doc2) -> should generate a unique index exception,
catch and verify it
5. Cleanup: call Delete(doc1) to delete the first instance that was
persisted successfully
What's happening when I run this test is this...it all goes as
expected right up to the last step when it tries to clean up and
delete doc1. Instead of deleting doc1 I get the following exception:
Test method
BusinessTests.Brokers.DocumentBrokerTests.InsertDuplicateFileNameTest
threw exception: NHibernate.Exceptions.GenericADOException: could not
insert: [Business.Domain.DocumentAudit][SQL: INSERT INTO
DOCUMENT_AUDIT (Action, Actor, DocumentId) VALUES (?, ?, ?); select
SCOPE_IDENTITY()] ---> System.Data.SqlClient.SqlException: Cannot
insert the value NULL into column 'DocumentId', table
'dbo.DOCUMENT_AUDIT'; column does not allow nulls. INSERT fails.
The statement has been terminated..
So I've put some debug into the code (in the form of Console.WriteLine
in various places). Look at the Console output (my debug bits start
with "==>"):
==> About to create 1st instance
NHibernate: INSERT INTO DOCUMENT (FileName) VALUES (@p0); select
SCOPE_IDENTITY();@p0 = 'test.txt'
NHibernate: INSERT INTO DOCUMENT_AUDIT (Action, Actor, DocumentId)
VALUES (@p0, @p1, @p2); select SCOPE_IDENTITY();@p0 = 'create', @p1 =
'testuser', @p2 = 39
==> About to create 2nd instance
NHibernate: INSERT INTO DOCUMENT (FileName) VALUES (@p0); select
SCOPE_IDENTITY();@p0 = 'test.txt'
==> Caught and handled exception
==> About to delete 1st instance
NHibernate: INSERT INTO DOCUMENT_AUDIT (Action, Actor, DocumentId)
VALUES (@p0, @p1, @p2); select SCOPE_IDENTITY();@p0 = 'create', @p1 =
'testuser', @p2 = NULL
So as you can see the bit the generated the error was the last
statement - @p2 (the DocumentId) is null.
The bizarre thing is that after the Exception is caught and handled
(and the transaction rolled back) the Delete statement should be
executed. But it doesn't do that, it's like it's still got a "queue"
of SQL statements it needs to execute, as it tries to insert into
DOCUMENT_AUDIT!
It's almost like the transaction rollback didn't flush the pending SQL
statements???
I hope somebody can help!!
Paul
--
You received this message because you are subscribed to the Google Groups
"nhusers" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to
[email protected].
For more options, visit this group at
http://groups.google.com/group/nhusers?hl=en.