【问题标题】:NHibernate: Parent list properties and related child properties are not synchronizedNHibernate:父列表属性和相关子属性不同步
【发布时间】:2009-11-27 14:16:17
【问题描述】:

我有两个相关的对象:ProgramSession 和 ProgramTask,具有一对多的关系。一个 ProgramSession 有许多 ProgramTask。所以对象看起来像这样:

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 对象的值,则保存没有问题。但是,如果我不立即保存,我会出现奇怪的行为,因为 ProgramSession.ProgramTasks 属性(在两个会话上)直到 NHibernate 会话刷新后才会同步。

更改 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 标志吗?

【问题讨论】:

  • 我相信你的意思是把属性放在你在问题中定义的类中。
  • 你是对的。感谢您的提醒。

标签: nhibernate collections nhibernate-mapping


【解决方案1】:

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

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

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

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

【讨论】:

  • 级联选项成功了。我做了一些更多的研究,并在某些关系上确定了 cascade="delete" 。这种方法的一个警告是,我现在需要跟踪哪些实体是新的,以便我可以决定是在实体上调用 Save() 还是 Update(),而在我使用 SaveOrUpdate() 之前。所以这实际上加深了我对 NHibernate 的依赖,但它确实有效。谢谢。
猜你喜欢
  • 2023-01-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-09-25
  • 2020-05-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多