我有两个相关的对象:ProgramSession和ProgramTask,具有一对多的关系。 ProgramSession有许多ProgramTasks。所以对象看起来像这样:
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; }
}
}
和映射......
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" />
当我尝试更改ProgramTask的ProgramSession时会出现问题。
如果我从旧会话的ProgramSession.ProgramTasks列表属性中删除ProgramTask,然后将其添加到新会话的同一属性中,NHibernate会告诉我将重新保存已删除的对象。
如果我只是更改ProgramTask.ProgramSession对象的值,我没有问题保存。但是,如果我不立即保存,我会得到奇怪的行为,因为在刷新NHibernate会话之前,ProgramSession.ProgramTasks属性(在两个会话上)都不会同步。
更改ProgramTask.ProgramSession对象而不直接修改列表,会创建无效状态。以下面的代码为例:
programTask.ProgramSession = newProgramSession;
Assert.That(newProgramSession.ProgramTasks.Contains(programTask)); // fails
Assert.That(!oldProgramSession.ProgramTasks.Contains(programTask)); // fails
这在稍后执行的代码中更成问题,假定ProgramTasks集合与ProgramSession属性同步。例如:
foreach(var programTask in programSession.ProgramTasks)
{
// whatever
}
我曾经解决的一个问题是查询列表。我无法在任何地方使用它,这显然是一个糟糕的解决方案,但它强调了这个问题:
var tasksActuallyInSession =
programSession.ProgramTasks
.Where(task => task.ProgramSession == programSession)
.ToList();
有没有办法处理这种情况?最佳做法?难道我做错了什么?映射不正确吗?我需要设置一些超级秘密的NHibernate标志吗?
答案 0 :(得分:1)
不确定我是否理解你在这里所做的一切。一些想法:
如果您决定移动ProgramTasks
,那么它们会变得独立,不应使用cascade="all-delete-orphan"
进行映射。如果您这样做,当您从ProgramTask
中删除时,NH会从数据库中删除ProgramSession
。
使用cascade="none"
映射它并自己控制对象的生命周期。 (这意味着:在存储ProgramSession
之前存储它。当它不再使用时删除它。)
不确定这是否也是一个问题,但请注意,如果您有反向引用,则代码负责使引用保持一致。当然,在存储到数据库并加载到空会话之后,引用会被清理,这是因为数据库中只有一个外键。但这不是它应该做的方式。 NH管理您的参考资料不是责任。 (它唯一的责任就是坚持你在内存中所做的事情。)所以你需要在内存中保持一致,并实现你的业务逻辑,就像没有NHibernate一样。