使用 NHibernate 进行级联更新一对多

Posted

技术标签:

【中文标题】使用 NHibernate 进行级联更新一对多【英文标题】:Cascade Update one-to-many with NHibernate 【发布时间】:2013-05-15 14:44:29 【问题描述】:

我正在努力解决 NHibernate 映射问题。我正在使用 Repository/UnitOfWork 模式,我正在尝试通过更新方法级联持久化我的对象。例如:我可以更改 Foo,添加/更新/删除 Bar 对象,一切都可以。但是当我尝试将 Son 和 Daughter 对象添加到“Bar”并更新 Foo (以持久 Bar 及其子对象)时,Son 和 Daughter 对象不会持久保存到 DB,只有 Foo 和所有 Bars (没有 Son/Daughter 对象) .

public class Foo

    public int FooID get; set;
    public string Name get; set;
    public virtual IList<Bar> Bars get; set;    
    public Foo()
    
public class Bar

    public int BarID get; set;
    public string Name get; set;
    public Foo Foo get; set;
    public virtual IList<Son> Sons get; set;
    public virtual IList<Daughter> Daughters get; set;
    public Bar()
    
public class Son

    public int SonID get; set;
    public string Name get; set;
    public virtual Bar Bar get; set;
    public Son()
    
public class Daughter

    public int DaughterID get; set;
    public string Name get; set;
    public virtual Bar Bar get; set;
    public Daughter()
    

//on Foo.hbm.xml I have:
...
<bag name="Bar" table="Bar" inverse="true" cascade="all-delete-orphan" lazy="false">
  <key column="FooID" />
  <one-to-many class="Bar" />
</bag>

//on Bar.hbm.xml I have
...
<many-to-one name="Foo" column="FooID" class="Foo" lazy="false" />
<bag name="Son" table="Son" inverse="true" cascade="all-delete-orphan" lazy="false">
  <key column="SonID" />
  <one-to-many class="Son" />
</bag>

<bag name="Daughter" table="Daughter" inverse="true" cascade="all-delete-orphan" lazy="false">
  <key column="DaughterID" />
  <one-to-many class="Daughter" />
</bag>

//on Son/Daughter.hbm.xmlI have
...
<many-to-one name="Bar" column="BarID" class="Bar" lazy="false" />

我哪里做错了?提前谢谢!

【问题讨论】:

在将 Test1 和 Test2 作为测试添加到您的集合之前尝试持久化它。 嗨@DavidC 谢谢你的回答。但是如果我在运行时创建 Bar,我没有 BarID 来映射我的 Son/Daughter 对象。我拥有的唯一预先存在的对象是 Foo。这样,那些“Bar”对象可以被持久化,因为我已经有了 FooID。因此,NHibernate 必须首先找到一种方法来持久化我的“Bar”对象(在它们上放置一个 ID),然后存储相应的儿子/女儿对象(与 BarID 进行映射)。 如果您让 NHibernate 生成您的 ID,只要您将一个新对象“附加”到当前会话,它就会获得一个身份。然后,您只需将它们添加到持久化集合中。我已经看到这项工作只是将它们添加到持久化集合中不会刷新到数据库。 例如调用 session.Save(newObject),然后会填充 newObject.Id。假设您使用 nhibernate 来生成您的身份。 是的@DavidC,我看到 nHibernate 填充了 Bar 的 ID 属性,但是我应该怎么做,用最近持久化的填充 Son/Daughter "Bar" 属性?例如:首先,持久化 Foo 和 Bar(现在我们有 Foo.Bar 和 Bar.ID),然后持久化 Bar.Son (Son.Bar = Bar,所以在 Son Table 我们有对 Bar (Son.BarID = BarID) 的引用)) ? 【参考方案1】:

试试下面的测试:

    var newFoo = new Foo();
    var newBar = new Bar();
    var newSon = new Son();

    _session.Save(newBar);

    newSon.Bar = newBar;
    newBar.Sons.Add(newSon);
    Foo.Bar = newBar;

【讨论】:

如果您没有在答案中添加描述,请尝试提供注释代码。 对不起,我以为OP上的评论链就够了。 尽可能将所有内容汇总到答案中总是很好的。 (它不会在审查队列中被标记。):-) 感谢@DavidC 的澄清。我做了你所说的事情,还有一个优点:我已经将我的 hbm.xml cascade="all-delete-orphan" 映射标记更改为 cascade="all"。我这样做是因为我得到了瞬态对象异常。现在一切正常。谢谢。 非常欢迎您,祝您使用 nHibernate 好运。它有一个陡峭的学习曲线,但一旦你习惯了它就很棒。

以上是关于使用 NHibernate 进行级联更新一对多的主要内容,如果未能解决你的问题,请参考以下文章

NHibernate Definitive Cascade 应用指南

hibernate一对多单向关联时更新问题

Nhibernate一对多关系复合键问题

当设置了级联保存更新属性时,NHibernate 会不必要地更新对象吗?

三大框架 之 Hibernate查询(一对多多对多查询关系)

Hibernate初探之一对多映射 继续学习