I am having a problem with what should be a fairly simple (I would think) NHibernate use case.
I have a classic Parent and a Child entity like so:
public class Parent
{
public virtual int ParentId { get; set; }
public virtual string Name { get; set; }
public virtual IList<Child> Children { get; set; }
}
public class Child
{
public virtual int ChildId { get; set; }
public virtual Parent Parent { get; set; }
public virtual string Name { get; set; }
}
And mappings as follows:
public class ParentMap : ClassMap<Parent>
{
public ParentMap()
{
Id(x => x.ParentId).GeneratedBy.Native();
Map(x => x.Name);
HasMany(x => x.Children).KeyColumn("ParentId").Cascade.SaveUpdate();
}
}
public class ChildMap : ClassMap<Child>
{
public ChildMap()
{
Id(x => x.ChildId).GeneratedBy.Native();
Map(x => x.Name);
References(x => x.Parent).Column("ParentId").ReadOnly().Not.Nullable();
}
}
Lastly, I have a simple tests:
[Test]
public void Test_save_family()
{
var parent = new Parent();
var child = new Child {Parent = parent};
parent.Children = new List<Child>{child};
SessionManager.WithSession(
session =>
{
session.Save(parent);
session.Flush();
});
}
The test fails with a System.Data.SqlClient.SqlException : Cannot insert the value NULL into column 'ParentId'. This is correct in that the column is non-nullable but why is it inserting null?
If I remove the null constraint, the save works because NHibernate first inserts the parent, then inserts the child, then updates the ParentId column on the child record as shown in this output:
NHibernate: INSERT INTO [Parent] (Name) VALUES (@p0); select SCOPE_IDENTITY();@p0 = NULL
NHibernate: INSERT INTO [Child] (Name) VALUES (@p0); select SCOPE_IDENTITY();@p0 = NULL
NHibernate: UPDATE [Child] SET ParentId = @p0 WHERE ChildId = @p1;@p0 = 2, @p1 = 1
This seems bizarre to me as in almost all cases foreign key columns of this sort are declared non-nullable and hence the foreign key must be provided at insert. So why is NHibernate not setting the foreign key on the initial insert of the child row and how to I fix this?