Posts Tagged ‘nhibernate’

NHibernate’s Cascade wonder… and pain

Author: Adam Ludera (Luder) | November 13th, 2009

As could be found from Mateusz posts, we are really into Rhino and NHibernate usage. With a bit of doubt we started using quite interesting feature called cascade. By its name you can easily say what is it all about. Think of, for example, relation one-to-many, which basically means IList<T> in your parent class and reference in child one. Map (using Fluent NHibernate) would be nothing else then:

1. Parent:

HasMany(x => x.Childs).KeyColumnNames.Add("ParentId");

2. Child:

References(x => x.Parent, "ParentId").Not.Nullable();

On regular basis to create a parent with 2 children you would have to do something like:

var parent = new Parent() ;
Repositories.ParentRepository.Save(parent);

var child1 = new Child();
var child2 = new Child();
child1.Parent = child2.Parent = parent;
parent.Add(child1);
parent.Add(child2);

Repositories.ChildRepository.Save(child1);
Repositories.ChildRepository.Save(child2);
Repositories.ParentRepository.Update(parent);

Pretty dull, isn’t it? But if you go and modify your Parent Map to:

HasMany(x => x.Childs).KeyColumnNames.Add("ParentId").Cascade.SaveUpdate();

then you can do same with way fewer lines:

var parent = new Parent() ;
var child1 = new Child();
var child2 = new Child();

child1.Parent = child2.Parent = parent;
parent.Add(child1);
parent.Add(child2);

Repositories.ParentRepository.Save(parent);

How’s that?

All these coding savings are because NHib by its own checks content of Childs list once Parent gets saved or updated.
Today I went one step forward and wanted to use cascade for deletion. And it is where the pain starts :] Analogically to above code you would think to try removing children like this:

Parent.Childs.Remove(child1);

or

Parent.Childs.Clear(); //to remove all - this is actually what I was trying to do

After this you get this pretty nice exception:

NHibernate.Exceptions.GenericADOException: could not delete collection rows: [Child][SQL: UPDATE Child SET ParentId = null WHERE ParentId = @p0 AND Id = @p1] —> System.Data.SqlClient.SqlException: Cannot insert the value NULL into column ‘ParentId’, table ‘db.dbo.Child’; column does not allow nulls. UPDATE fails

A minute had to pass till I realized I was being stupid – Map says:

HasMany(x => x.Childs).KeyColumnNames.Add("ParentId").Cascade.SaveUpdate();

so why would NHib delete anything for me? There must be another option to force it to remove entities automatically. This option is called AllDeleteOrphan(). Setting this option for a bag means that if Child is removed reference from Parent it will automatically be deleted once Session flushes. However having Map like this:

HasMany(x => x.Childs).KeyColumnNames.Add("ParentId").Cascade.AllDeleteOrphan();

will fail due to same error as before.

Problem here is that NHib does first removes reference (set NULL) and once this is done tries to DELETE. Due to FK constraint it fails though.

To force NHib to “remember” about FK constraint we have to set bidirectional association. To do this just add .Inverse() option right after cascade spec, so Map will be:

HasMany(x => x.Childs).KeyColumnNames.Add("ParentId").Cascade.AllDeleteOrphan().Inverse();

That does the trick and now you can remove child entities by simply removing reference to parent, so:

Parent.Childs.Remove(child1);

or

Parent.Childs.Clear();

works like a charm ;]

Using Active Record to write less code

Author: Mateusz Kubiczek (madmatt) | April 22nd, 2009

Ayende Rahien posted a great presentation on Active Record: http://www.viddler.com/explore/oredev/videos/89. He argues that persistence is a solved problem, and it’s hard to disagree after watching it! Only recently we have started using NHibernate for persistence and we’re loving it. Maybe ActiveRecord would have had a flatter learning curve?