在 Hibernate 中,如何自动检索父 id 并在子插入中将其用作外键?

Posted

技术标签:

【中文标题】在 Hibernate 中,如何自动检索父 id 并在子插入中将其用作外键?【英文标题】:In Hibernate, how to automatically retrieve parent id and use it in child insertion as foreign key? 【发布时间】:2014-10-16 08:36:40 【问题描述】:

我想要的操作:如果需要,在子表中插入一行会自动在父表中插入一行,否则使用父表中现有行的id作为插入行中的外键子表。

我想知道是否有任何方法可以使用单个 session.save(child) 语句在休眠中执行上述操作。

我正在使用带有 Java 和 SQLite 的 Hibernate。 以下是我对数据库和配置的详细说明:

父表:

id (int): primary key, description (text): unique

表子:

id(int): primary key, address (text), parent_id (integer): foreign key refers Parent(id)  [UNIQUE ( address, parent_id )]

POJO 家长:

int id, String description, Set<Child> children, [getters and setters] 

POJO 孩子:

int id, String address, Parent parent, [getters and setters]

父.hbm:

...
<id column="id" name="id" type="long">
    <generator class="native"/>
</id>
<property column="description" name="description" type="string" unique="true" />
<set fetch="select" inverse="true" lazy="true" name="children" table="Child">
    <key>
        <column name="parent_id" not-null="true"/>
    </key>
    <one-to-many class="Child"/>
</set>
...

Child.hbm:

....
<id column="id" name="id" type="long">
    <generator class="native"/>
</id>
<property column="address" name="address" type="string"/>
<many-to-one cascade="save-update" class="Parent" fetch="select" name="parent">
    <column name="parent_id" not-null="true"/>
</many-to-one>
...

到目前为止,如果父级(具有相同的“描述”)不存在,则父级与子级一起插入。否则,由于唯一的“描述”要求,父级插入失败,因此不会插入子级。

由于插入子对象时我不知道父对象的id(我只知道父对象的描述),因此我无法执行 session.load(Parent.class, parentId) 来检索父对象并使用它插入孩子。我现在正在做的事情如下:

Parent parent = new Parent();
parent.setDescription("D1");

Child child = new Child();
child.setAddress("A1");

parent.getChildren().add(child);
child.setParent(parent);
session.save(child);

我知道我总是可以先通过执行查询select id from Parent where description="D1" 来查找父 ID,然后如果结果集为空,则按照我现在的做法保存子 ID(它也会插入父 ID),如果结果不为空,使用session.load()加载父对象并使用它插入子对象。但我认为 hibernate 可以在单个 session.save(child) 后面为我处理这个问题。可以吗?

【问题讨论】:

我也有同样的问题。你找到解决办法了吗? 【参考方案1】:

试试这个步骤;

1.更改您的 Parent.hbm

 ...
<id column="id" name="id" type="long">
    <generator class="native"/>
</id>
<property column="description" name="description" type="string" unique="true" />
<set fetch="select" inverse="true" lazy="true" name="children" table="Child" cascade="save-update">
    <key>
        <column name="parent_id" not-null="true"/>
    </key>
    <one-to-many class="Child"/>
</set>
...

2.改变你的 Child.hbm

....
<id column="id" name="id" type="long">
   <generator class="native"/>
</id>
<property column="address" name="address" type="string"/>
<many-to-one class="Parent" fetch="select" name="parent">
    <column name="parent_id" not-null="true"/>
</many-to-one>
...

3.并根据需要在父级之前添加子级

Parent parent = new Parent();
parent.setDescription("D1");

Child child = new Child();
child.setAddress("A1");
child.setParent(parent);

session.save(child);
Set<Child> childsSet = new HashSet<Child>();
childsSet.add(child);

parent.setChildren(childsSet);
session.save(parent);

【讨论】:

在 Parent 中没有包含描述的行时有效,但在随后插入与具有相同描述的父关联的子(具有不同地址)时失败(需要唯一的列描述)。后一种情况是我的应用程序中更常见的情况,其中将插入已存在父级的子级,但有时它可能具有数据库中尚不存在的父级,在这种情况下,也需要插入父级。我希望应用程序逻辑通过使用单个 session.save(child) (或 session.save(parent) )来了解这些情况

以上是关于在 Hibernate 中,如何自动检索父 id 并在子插入中将其用作外键?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Hibernate 插入记录正确自动生成主键 ID

如何在JPA / JAVA / Hibernate的两列中插入自动生成的ID

如何在 ServiceStack OrmLite 中检索自动递增的 ID?

Hibernate的注解和检索

使用 JPA Hibernate 自动保存子对象

Hibernate检索策略