Reputation: 1117
Saving a child of a parent object via nhibernate only sometimes results in the not inserting the child in the table. This works most of the times and only a couple of times out of many thousands, the child was missing.
This is in a large multi-threaded application.
The following is the child mapping :
<class name="Child" table="children" lazy="false" optimistic-lock="all" dynamic-update="true">
<id name="Id" column="id">
<generator class="native" />
</id>
<many-to-one name="MyParent" class="Parent" column="parent_id" not-null="true"/>
...
...
and the Child Class :
public class Child
{
public long Id { get; set; }
public Parent MyParent { get; set; }
...
..
The Parent Mapping :
<id name="Id" column="id">
<generator class="native" />
</id>
<set name="Children" table="children" cascade="none" lazy="true" inverse="true">
<key column="parent_id" not-null="true" />
<one-to-many class="Child" />
</set>
...
...
and the following is the Parent Class
public class Parent
{
public long Id { get; set; }
public ICollection<Child> Children { get; set; }
...
...
..
}
The code to add a parent and a child is shown below :
var theParent = new Parent
{
...
}
...
// start the transaction if not begun by the caller
// a few lines later...
Session.Save(theParent);
// Commit transaction only if this method began the transaction...
...
var child = new Child
{
MyParent = theParent,
...
...
}
...
// start the transaction if not begun by the caller
// a few lines later...
Session.Save(child);
// Commit transaction only if this method began the transaction...
// make sure the two-way associations are updated!
if (!child.MyParent.Children.Contains(child))
child.MyParent.Children.Add(child);
...
The mechanism to check if transaction has been begun by the caller doesn't seem to have any bugs and the caller doesn't roll back without throwing an exception and logging it. I do not find any traces of the transaction being rolled back.
In either case, why is the child missing in only few cases. This is very difficult to handle and could cause a lot of problems in production silently. What could be the cause due to which this has happened ?
Upvotes: 0
Views: 502
Reputation: 9864
I would bet your transaction handling mechanism has a flaw and the transaction is sometime not committed at all. It ends up garbage collected, causing it to be disposed and roll-backed silently. This happens in case of session Close
occurring before transaction commit too.
You may track it by logging transaction starts/commits/rollbacks with relevant context information for matching starts with commits and rollbacks.
This can be quite tricky. What is a relevant context information? It depends heavily on application type. In a web application under IIS, thread context is bad, call context is bad. They all get lost in case of asp.net thread agility switch, which occurs under load. Only HTTP context is preserved in most cases. (And beware of async await
with "callback" configured for running without any context...)
Upvotes: 1