NHibernate:父列表属性和相关的子属性未同步

时间:2009-11-27 14:16:17

标签: nhibernate collections nhibernate-mapping

我有两个相关的对象: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标志吗?

1 个答案:

答案 0 :(得分:1)

不确定我是否理解你在这里所做的一切。一些想法:

如果您决定移动ProgramTasks,那么它们会变得独立,不应使用cascade="all-delete-orphan"进行映射。如果您这样做,当您从ProgramTask中删除时,NH会从数据库中删除ProgramSession

使用cascade="none"映射它并自己控制对象的生命周期。 (这意味着:在存储ProgramSession之前存储它。当它不再使用时删除它。)

不确定这是否也是一个问题,但请注意,如果您有反向引用,则代码负责使引用保持一致。当然,在存储到数据库并加载到空会话之后,引用会被清理,这是因为数据库中只有一个外键。但这不是它应该做的方式。 NH管理您的参考资料不是责任。 (它唯一的责任就是坚持你在内存中所做的事情。)所以你需要在内存中保持一致,并实现你的业务逻辑,就像没有NHibernate一样。