gpt4 book ai didi

java - Hibernate 可以在更新分离的对象时删除孤立的集合吗?

转载 作者:太空狗 更新时间:2023-10-29 22:47:33 24 4
gpt4 key购买 nike

我知道删除孤立的子对象是 SO 上的一个常见问题,也是 Hibernate 新手的一个常见问题,而且相当标准的答案是确保您有 cascade=all,delete- 的一些变体orphancascade=all-delete-orphan 在子集合上。

我希望能够让 Hibernate 检测到子集合已从父对象中清空/删除,并在更新父对象时从数据库中删除子表中的行。例如:

Parent parent = session.get(...);
parent.getChildren().clear();
session.update(parent);

Parent 类的当前映射如下所示:

<bag name="children" cascade="all-delete-orphan">
<key column="parent_id" foreign-key="fk_parent_id"/>
<one-to-many class="Child"/>
</bag>

这在更新附加对象时对我来说很好用,但我有一个用例,在这个用例中我们希望能够获取一个分离的对象(它已由远程客户端通过 HTTP/发送到我们的 API 方法) JSON),并将其直接传递给 Hibernate session - 以允许客户端能够以他们喜欢的任何方式操作父对象并保持更改。

在我的分离对象上调用 session.update(parent) 时,子表中的行是孤立的(FK 列设置为空)但未删除。请注意,当我调用 session.update() 时,这是 Hibernate Session 第一次看到这个对象实例 - 我没有重新附加或合并对象与任何其他 session 中的 Session方法。我依靠客户端传递其标识符对应于数据库中实际对象的对象。例如,我的 API 服务方法中的逻辑是这样的:

String jsonString = request.getParameter(...);
Parent parent = deserialize(jsonString);
session.update(parent);

当传递给 session.update(parent) 时,Hibernate 是否可以检测分离的父对象中的孤立子集合?还是我以某种方式误用了分离对象?

我希望我可以避免与 Hibernate 进行任何类型的复杂交互,以将更改持久保存到分离的实例中。我的 API 方法在调用 session.update(parent) 后不需要进一步修改分离的对象,此方法仅负责持久化远程客户端应用程序所做的更改。

最佳答案

你的映射(简化)

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="br.com._3988215.model.domain">
<class name="Parent" table="PARENT">
<id name="id">
<generator class="native"/>
</id>
<bag cascade="all,delete-orphan" name="childList">
<key column="PARENT_ID" not-null="false"/>
<one-to-many class="Child"/>
</bag>
</class>
<class name="Child" table="CHILD">
<id name="id" column="CHILD_ID">
<generator class="native"/>
</id>
</class>
</hibernate-mapping>

生产

PARENT
ID

CHILD
CHILD_ID
PARENT_ID

按照你说的

I would like to be able to have Hibernate detect that child collection has been removed from the parent object, and have the rows in the child table deleted from the database when the parent object is updated

有点像

Parent parent = session.get(...);
parent.getChildren().clear();

session.update(parent);

你说它工作正常因为你有一个附加的父实例

现在让我们看下面的(注意Assert.assertNull(second))

public class WhatYouWantTest {

private static SessionFactory sessionFactory;

private Serializable parentId;

private Serializable firstId;
private Serializable secondId;

@BeforeClass
public static void setUpClass() {
Configuration c = new Configuration();
c.addResource("mapping.hbm.3988215.xml");

sessionFactory = c.configure().buildSessionFactory();
}

@Before
public void setUp() throws Exception {
Parent parent = new Parent();
Child first = new Child();
Child second = new Child();

Session session = sessionFactory.openSession();
session.beginTransaction();

parentId = session.save(parent);
firstId = session.save(first);
secondId = session.save(second);

parent.getChildList().add(first);
parent.getChildList().add(second);

session.getTransaction().commit();
session.close();
}

@Test
public void removed_second_from_parent_remove_second_from_database() {
Parent parent = new Parent();
parent.setId((Integer) parentId);

Child first = new Child();
first.setId((Integer) firstId);

/**
* It simulates the second one has been removed
*/
parent.getChildList().add(first);

Session session = sessionFactory.openSession();
session.beginTransaction();

session.update(parent);

session.getTransaction().commit();
session.close();

session = sessionFactory.openSession();
session.beginTransaction();

Child second = (Child) session.get(Child.class, secondId);
Assert.assertNull(second);

session.getTransaction().commit();
session.close();
}
}

不幸的是,测试没有通过。你能做什么???

  • 启用长时间运行的对话

Hibernate 引用资料说

Extended (or Long) Session - The Hibernate Session may be disconnected from the underlying JDBC connection after the database transaction has been committed, and reconnected when a new client request occurs. This pattern is known as session-per-conversation and makes even reattachment unnecessary. Automatic versioning is used to isolate concurrent modifications and the Session is usually not allowed to be flushed automatically, but explicitely.

免责声明:我没有任何使用长时间运行对话的场景。 Java EE 有状态 session bean 支持长时间运行的对话。但它支持的是 JPA(不是 Hibernate)

或者您可以创建一个替代映射,使您的 child 成为复合元素。因为它的生命周期依赖于父对象,所以你可以依赖复合元素来得到你想要的

创建一个名为 AlternativeParent 的类它扩展了 Parent

public class AlternativeParent extends Parent {}

现在它的映射(注意 Child 作为复合元素而不是普通的 @Entity)

<class name="AlternativeParent" table="PARENT">
<id name="id">
<generator class="native"/>
</id>
<bag name="childList" table="CHILD">
<key column="PARENT_ID" not-null="false"/>
<composite-element class="Child">
<property column="CHILD_ID" name="id"/>
</composite-element>
</bag>
</class>

现在在 Child 类中实现一个方便的 equals 方法

public boolean equals(Object o) {
if (!(o instanceof Child))
return false;

Child other = (Child) o;
// identity equality
// Used by composite elements
if(getId() != null) {
return new EqualsBuilder()
.append(getId(), other.getId())
.isEquals();
} else {
// object equality
}
}

如果我重构上面显示的测试用例(现在改用 AlternativeParent)

@Test
public void removed_second_from_parent_remove_second_from_database() {
AlternativeParent parent = new AlternativeParent();
parent.setId((Integer) parentId);

Child first = new Child();
first.setId((Integer) firstId);

/**
* It simulates the second one has been removed
*/
parent.getChildList().add(first);

Session session = sessionFactory.openSession();
session.beginTransaction();

session.update(parent);

session.getTransaction().commit();
session.close();

session = sessionFactory.openSession();
session.beginTransaction();

Child second = (Child) session.get(Child.class, secondId);
Assert.assertNull(second);

session.getTransaction().commit();
session.close();

}

我看到一个绿色条

关于java - Hibernate 可以在更新分离的对象时删除孤立的集合吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3988215/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com