26

是否有任何 Internet 资源对 NHibernate 的所有级联设置有明确的指南,其中将包括类结构、HBM 的示例以及每个级联设置对与 NH 的所有关系的操作的含义。

如果有以最正确的方式完成常见关联的示例,例如设置一个状态表,您将永远不会最终级联删除状态,或者删除具有 CreatedBy User 属性的对象,这将是有帮助的永远不会以级联方式删除用户等。

4

4 回答 4

60

以下内容改编自 NHibernate 3.0 的 Java Hibernate 参考http://docs.jboss.org/hibernate/stable/core/manual/en-US/html/objectstate.html#objectstate-transitive(即当前的 svn 主干) .

对于 NHibernate Session 的每个基本操作——包括 Persist()、Merge()、SaveOrUpdate()、Delete()、Lock()、Refresh()、Evict()、Replicate()——都有对应的级联样式。级联样式分别命名为persist、merge、save-update、delete、lock、refresh、evict、replication。Save() 和 Update() 的级联样式是 save-update;对于 SaveAndUpdateCopy() 它是合并;对于 PersistOnFlush() 它是持久的。而remove是delete的别名。

如果您希望一个操作沿关联级联,您必须在映射文档中指出这一点。例如:

<one-to-one name="person" cascade="persist"/>

级联样式可以组合:

<one-to-one name="person" cascade="persist,delete,lock"/>

您可以使用 cascade="all" 指定所有操作应沿关联级联。默认的 cascade="none" 指定没有操作被级联。

一种特殊的级联样式 delete-orphan 仅适用于一对多关联,并指示应将 Delete() 操作应用于从关联中删除的任何子对象。并且 all-delete-orphan 与 all,delete-orphan 相同。

建议:

  • 在 <many-to-one> 或 <many-to-many> 关联上启用级联通常没有意义。Cascade 通常对 <one-to-one> 和 <one-to-many> 关联很有用。
  • 如果子对象的生命周期受限于父对象的生命周期,则通过指定 cascade="all-delete-orphan" 使其成为生命周期对象。
  • 否则,您可能根本不需要级联。但是,如果您认为您将经常在同一个事务中与父母和孩子一起工作,并且您想节省一些输入,请考虑使用 cascade="persist,merge,save-update"。

使用 cascade="all" 映射关联(单值关联或集合)将关联标记为父/子样式关系,其中父的保存/更新/删除导致子的保存/更新/删除或孩子们。不被父级引用的子级不会被自动删除,除非是用 cascade="delete-orphan" 映射的 <one-to-many> 关联。父/子关系的级联操作的精确语义如下:

  • 如果将父级传递给 Persist(),则所有子级都传递给 Persist()
  • 如果将父级传递给 Merge(),则所有子级都传递给 Merge()
  • 如果将父级传递给 Save()、Update() 或 SaveOrUpdate(),则所有子级都传递给 SaveOrUpdate()
  • 如果一个临时的或分离的孩子被一个持久的父母引用,它被传递给 SaveOrUpdate()
  • 如果删除父级,则将所有子级传递给 Delete()
  • 如果一个孩子被一个持久的父母取消引用,没有什么特别的事情发生——如果需要,应用程序应该明确地删除孩子——除非 cascade="delete-orphan",在这种情况下,“孤立”的孩子被删除。
于 2010-02-11T00:42:12.057 回答
4

接受的答案使用 HBM 文件详细解释了这一点。此答案与按代码映射相同。它们几乎相同;只是映射到他们的 HBM 字符串。

文章形式Ayende很好地解释了这一点:

  • none - 不做任何级联,让用户自己处理。
  • 保存更新 - 当对象被保存/更新时,检查关联并保存/更新任何需要它的对象(包括保存/更新多对多场景中的关联)。
  • delete - 当对象被删除时,删除关联中的所有对象。
  • delete-orphan - 当对象被删除时,删除关联中的所有对象。除此之外,当一个对象从关联中删除并且不与另一个对象关联(孤立)时,也将其删除。
  • all - 当一个对象被保存/更新/删除时,检查关联并保存/更新/删除找到的所有对象。
  • all-delete-orphan - 当一个对象被保存/更新/删除时,检查关联并保存/更新/删除找到的所有对象。除此之外,当一个对象从关联中删除并且不与另一个对象关联(孤立)时,也将其删除。

此外,这个问题解释了Cascade.

[Flags]
public enum Cascade
{
    None = 0,
    Persist = 2,
    Refresh = 4,
    Merge = 8,
    Remove = 16,
    Detach = 32,
    ReAttach = 64,
    DeleteOrphans = 128,
    All = 256,
}
private static IEnumerable<string> CascadeDefinitions(this Cascade source)
{
    if (source.Has(Cascade.All))
    {
        yield return "all";
    }
    if (source.Has(Cascade.Persist))
    {
        yield return "save-update, persist";
    }
    if (source.Has(Cascade.Refresh))
    {
        yield return "refresh";
    }
    if (source.Has(Cascade.Merge))
    {
        yield return "merge";
    }
    if (source.Has(Cascade.Remove))
    {
        yield return "delete";
    }
    if (source.Has(Cascade.Detach))
    {
        yield return "evict";
    }
    if (source.Has(Cascade.ReAttach))
    {
        yield return "lock";
    }
    if (source.Has(Cascade.DeleteOrphans))
    {
        yield return "delete-orphan";
    }
}

请注意,Cascade.All不包括Cascade.DeleteOrphans. 在这种情况下,您可能需要使用Cascade.All | Cascade.DeleteOrphans.

或者,您可以使用Include扩展方法Cascade.All.Include(Cascade.DeleteOrphans)

结合Cascade,您可能还需要调查Inverse;它指定了关联的所有者。有关更多详细信息,请参阅问题和答案。

于 2019-07-24T10:01:32.037 回答
3

这可能是显而易见的建议,但我建议浏览Ayende的旧帖子。在他的网站上快速搜索NHibernate 和 cascade 发现了一些有趣的帖子。但是,对于您的需求,它们可能有点稀缺。

即使它本身不是互联网资源,我也会推荐NHibernate in Action。它在第 3、4 和 6 章中深入讨论了级联。本书针对 NHibernate 1.2。不过,我确实相信本书的新版本将针对 NHibernate 3.0 版本。可能值得关注。

尽管我很想看到一份关于级联的权威指南,但我还没有看过。也许您可以在您自己的博客上用您自己的帖子总结一些讨论级联的博客帖子。

于 2010-02-07T10:15:25.453 回答
3

我不知道任何“权威”指南,但我知道的最好的资源是来自 Ayende 的博客文章,他是 NHibernate 的权威专家之一:

NHibernate Cascades:all、all-delete-orphans 和 save-update 之间的区别

对我来说,我实际上只使用cascade="none"and cascade="all"all-delete-orphan有时是一种选择。其他一切都是可疑的。例如,为什么我要隐式创建一个实例,因为它被引用了,而它的寿命比包含对象的寿命长?对我来说,只有两种情况:对象是依赖对象或独立对象。

于 2010-02-09T13:32:57.093 回答