PersistenceSpecification saves differently than Session.Flush

63 views
Skip to first unread message

kberridge

unread,
Dec 30, 2009, 11:23:43 AM12/30/09
to Fluent NHibernate
I have a parent/child relationship that I am writing persistence tests
for. The child's lifetime is bound to the parent's lifetime, and the
FK column from child to parent does not allow null.

I have setup my mappings like this:

public ParentMap()
{
...

HasMany( x => x.Children ).Cascade.AllDeleteOrphan().Inverse()
}

public ChildMap()
{
...

References ( x => x.Parent ).Not.Nullable();
}


I have written a test that uses the PersistenceSpecification class
like this:

Action<Parent, Child> listItemSetter = ( p, c ) => p.AddChild( c );
new PersistenceSpecification<Parent>( session, new EqualityComparer
() )
.CheckList( c=> c.Children, children, listItemSetter )
.VerifyTheMappings();

Note: I'm using FluentNH 1.0.0.602

When I run this, I get an error that says:
"NHibernate.PropertyValueException: not-null property references a
null or transient value"

This is problem #1. It seems that it is not executing the Action I
provided.

To continue trying to see what was going on, I removed
the .Not.Nullable() from the child's mapping and tried it again with
ShowSQL on.

What I get is:
1. Insert Child
2. Insert Parent
3. Update Child

This is problem #2, it should Insert Parent then Insert Child.

To verify this I wrote another test that does the same thing but
doesn't use the PersistenceSpecification. This test looks like this:

Parent p = new Parent();
p.AddChild( c );

session.Save( p );
session.Flush();

What I get is:
1. Insert Parent
2. Insert Child

This is the correct result. Note that I haven't changed the mappings
at all.

If I then add the .Not.Nullable back in the Child's mappings, this
second test still works.

Why is the PersistenceSpecification saving differently than regular
NH?
And am I not setting up my Action correctly (or something), causing
PersistenceSpecification to not use my listItemSetter?

Thanks,
Kevin Berridge

kberridge

unread,
Jan 3, 2010, 1:58:40 PM1/3/10
to Fluent NHibernate
I've looked into what is happening here. I downloaded the latest
source (#606) and walked through my test code. My first problem (the
list item setter not being used) is not happening anymore. It's
possible it wasn't happening in the first place either but because of
the order PersistenceSpecification does things in I was confused.

I now understand problem #2 as well. The reason why
PersistenceSpecification is saving the child before the parent is
because that's how it's written to work!

Specifically, CheckList calls RegisterCheckedProperty passing in the
ReferenceList. That calls HasRegistered, which loops over every item
in the list and calls TransactionalSave. That starts a transaction,
calls Save on the session, and commits the transaction.

Thus, PersistenceSpecification is attempting to save all the children
before saving the parent and also before using the listItemSetter.

This doesn't work when the child has a Not.Nullable() reference to its
parent. In my specific case, Save shouldn't be called for the child.
Using the listItemSetter is enough because it will set the parent
pointer on the child and add the child to the parent's collection,
which has Cascade.AllDeleteOrphan, so NH will automatically insert the
child after inserting the parent.

So that's what's happening, but I'm assuming the code is written the
way it is for a good reason. Any idea how it would need to be updated
to support both scenarios?
1. Where Save cannot be called on the Child
2. Where Save must be called on the Child

Thanks,
Kevin Berridge

On Dec 30 2009, 11:23 am, kberridge <kevin.w.berri...@gmail.com>
wrote:

kberridge

unread,
Jan 4, 2010, 2:20:08 PM1/4/10
to Fluent NHibernate
I just stumbled across a similar post which people seem to be working
on a solution for here:
http://groups.google.com/group/fluent-nhibernate/browse_thread/thread/cfafedaaccb48fb6

Thanks,
Kevin

Reply all
Reply to author
Forward
0 new messages