NHibernate Definitive Cascade应用指南

时间:2010-01-13 16:35:01

标签: c# nhibernate cascade

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

如果有以最正确的方式进行公共关联的示例,例如设置状态表,您将永远不会最终级联删除状态,或者删除具有CreatedBy的对象,那将会很有帮助。用户属性永远不会以级联等方式删除用户。

4 个答案:

答案 0 :(得分:57)

以下内容改编自NHiberate 3.0的Java Hibernate引用http://docs.jboss.org/hibernate/stable/core/manual/en-US/html/objectstate.html#objectstate-transitive(即当前的svn trunk)。

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

如果要沿关联级联操作,则必须在映射文档中指明该操作。例如:

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

我要合并的级联风格:

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

您可以使用cascade =“all”指定所有操作都应该沿关联级联。默认级联=“none”指定不进行任何级联操作。

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

建议:

  • 在&lt;多对一&gt;上启用级联通常没有意义。或者&lt;多对多&gt;协会。级联通常用于&lt;一对一&gt;和&lt;一对多&gt;关联。
  • 如果子对象的生命周期受父对象的生命周期限制,请通过指定cascade =“all-delete-orphan”使其成为生命周期对象。
  • 否则,您可能根本不需要级联。但是如果你认为你经常在同一个交易中与父母和孩子一起工作,并且你想节省一些打字,可以考虑使用cascade =“persist,merge,save-update”。

使用cascade =“all”映射关联(单值关联或集合)将关联标记为父/子样式关系,其中父级的保存/更新/删除导致保存/更新/删除孩子。除了&lt;一对多&gt;的情况之外,不会自动删除被其父母未引用的孩子。与cascade =“delete-orphan”映射的关联。父/子关系的级联操作的精确语义如下:

  • 如果将父级传递给Persist(),则所有子级都将传递给Persist()
  • 如果将父级传递给Merge(),则所有子级都将传递给Merge()
  • 如果将父级传递给Save(),Update()或SaveOrUpdate(),则所有子级都将传递给SaveOrUpdate()
  • 如果一个临时或已分离的子进程被持久父进程引用,则将其传递给SaveOrUpdate()
  • 如果父项被删除,则所有子项都将传递给Delete()
  • 如果孩子被持久父母取消引用,则不会发生任何特殊情况 - 应用程序应在必要时明确删除子项 - 除非cascade =“delete-orphan”,在这种情况下,“孤立”子项将被删除。

答案 1 :(得分:3)

这可能是明显的建议,但我建议浏览Ayende制作的旧帖子。在他的网站上快速search NHibernate和级联显示了一些有趣的帖子。但是,它们可能对您的需求有点过于稀缺。

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

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

答案 2 :(得分:3)

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

NHibernate Cascades: the different between all, all-delete-orphans and save-update

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

答案 3 :(得分:0)

接受的答案将通过HBM文件对此进行详细说明。此答案与按代码映射相同。它们几乎是相同的。刚刚映射到他们的HBM字符串。

文章形式Ayende对其进行了很好的解释:

  
      
  • 无-不执行任何级联,让用户自己处理它们。
  •   
  • 保存更新-保存/更新对象时,检查关联并保存/更新需要它的任何对象(包括在多对多情况下保存/更新关联)。
  •   
  • 删除-删除对象后,删除关联中的所有对象。
  •   
  • delete-orphan-删除对象时,删除关联中的所有对象。除此之外,当一个对象从关联中删除并且不与另一个对象(孤立的)关联时,也将其删除。
  •   
  • 全部-保存/更新/删除对象时,检查关联并保存/更新/删除找到的所有对象。
  •   
  • 所有删除孤立对象-保存/更新/删除对象时,检查关联并保存/更新/删除找到的所有对象。除此之外,当一个对象从关联中删除并且不与另一个对象(孤立的)关联时,也将其删除。
  •   

此外,this问题解释了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。它指定了协会的所有者。有关更多详细信息,请参见this问题。