You are getting the first error because, when you remove the items from the collection, NHibernate's default mode of operation is to simply break the association. In the database, NHibernate tries to set the foreign key column on the child row to null. Since you do not allow nulls in that column, SQL Server raises the error. Clearing the collection will not necessarily delete the child object, but one way to do so is to set cascade=all-delete-orphan. This informs NHibernate that it should delete the newly orphaned rows instead of setting the foreign key column.
You are getting the second error because when you call SaveOrUpdate NHibernate first deletes all of the child objects. Then, because neither relationship is marked as inverse, NHibernate also tries to set the foreign key column in your child table to null. Since the rows have already been deleted, you receive the second error. You need to set inverse=true on one side of your relationship to fix this. This is usually done on the one (primary key or parent) side. If you do not do this, NHibernate will make the appropriate updates for each side of the relationship. Unfortunately, running two updates is not the appropriate thing to do.
You should always mark one side of your relationships as the inverse side. Depending on how you code, you may or may not need to use cascading. If you want to take advantage of one shot deletes as you are trying to do using Clear(), you need to define your cascade.
NHibernate is not magic. It is only an ORM, if your children do not have their reference set to the parent, why would it assume that because the parent has a list of children that the childrens' reference, in turn, SHOULD be a reference to the parent?
I believe you answered your own question when you stated that the Child entities don't have their Parent property populated (which means it is null, which means NHibernate would be attempting to save a 'null' value for the Parent id in your Child table).
If you were to use these objects WITHOUT NHibernate it would make sense that the Parent reference needs to be set on the Child entities when they are added.
EDIT: This is for the case where you have specified 'Inverse' on your mapping. If you were to remove this call to 'Inverse,' it should work the way you wanted it to work as Inverse states that the other end (the child entity) is responsible for keeping track of the relationship. This means you need to set the reference of the parent on the child manually.
However, removing the Inverse statement would cause the Child(ren) to be saved, the parent to be saved, then the Child(ren)'s parent id to be UPDATED. Since you have a null constraint on the parent id, this means it still won't work as it would initially insert the Child with a parent id of null.
The two solutions would be to either remove this constraint, or to just add a method to the Parent called AddChild:
public void AddChild(Child childObj)
{
childObj.Parent = this;
Children.Add(childObj);
}
Add another method called RemoveChild:
public void RemoveChild(Child childObj)
{
if (Children.Contains(childObj))
{
Child.Parent = null;
Children.Remove(childObj);
}
}
Then, just use those methods for adding/removing children.
Best Answer
You can either map a collection of integers (i.e. Parent.Children as an IList<int>), or you can map a collection of objects (i.e. Parent.Children as an IList<Child>). If you map the objects then you must update the DB using objects, i.e. you will need to load the Child objects in order to save the Parent. If you choose to map the integers IDs instead, then you can update via IDs.
PS. If your IDs are some other primitive type (e.g. guids, strings, etc), then the same argument still applies.