I have two related objects: ProgramSession and ProgramTask, with a one-to-many relationship. A ProgramSession has many ProgramTasks. So the objects looks like this:
public class ProgramSession
{
public virtual IList<ProgramTask> ProgramTasks
{
get { return _programTasks; }
set { _programTasks = value; }
}
}
public class ProgramTask
{
public virtual ProgramSession ProgramSession
{
get { return _programSession; }
set { _programSession = value; }
}
}
And the mappings...
ProgramSession.hbm.xml
<bag name="ProgramTasks" lazy="false" cascade="all-delete-orphan" inverse="true" >
<key column="SessionUid"></key>
<one-to-many class="ProgramTask"></one-to-many>
</bag>
ProgramTask.hbm.xml
<many-to-one name="ProgramSession" column="SessionUid" class="ProgramSession" />
The problems begin when I try to change the ProgramSession of a ProgramTask.
If I remove the ProgramTask from the ProgramSession.ProgramTasks list property of the old session, and then add it to the same property on the new session, NHibernate tells me that the a deleted object will be resaved.
If I simply change the value of the ProgramTask.ProgramSession object, I have no problem saving. However, I get weird behavior if I do not save immediately because the ProgramSession.ProgramTasks properties (on both sessions) are not synchronized until after the NHibernate session is refreshed.
Changing the ProgramTask.ProgramSession object without directly modifying the lists as well, creates an invalid state. Take the following code as an example:
programTask.ProgramSession = newProgramSession;
Assert.That(newProgramSession.ProgramTasks.Contains(programTask)); // fails
Assert.That(!oldProgramSession.ProgramTasks.Contains(programTask)); // fails
This is more problematic in code that executed later on, that assumes the ProgramTasks collections are synchronized with the ProgramSession property. For example:
foreach(var programTask in programSession.ProgramTasks)
{
// whatever
}
One hack I used to work around this was to query the list. I can't use it everywhere, and it's clearly a bad solution, but it underscores the problem:
var tasksActuallyInSession =
programSession.ProgramTasks
.Where(task => task.ProgramSession == programSession)
.ToList();
Is there any way to handle this kind of situation? A best practice? Am I doing something wrong? Is the mapping incorrect? Is there some super-secret NHibernate flag I need to set?