java - 如何让 Hibernate 4 停止抛出 "Deleting detached instance"?

标签 java hibernate

我必须在我的项目中使用 Hibernate 4.1.7。不幸的是,我不能决定是否迁移到新版本。

在我的上下文中,我有一个主从情况。因此,我加载主对象并将其及其所有详细信息显示在网页上。我可以按照我喜欢的方式更改主控和详细信息,甚至包括新的详细信息。我的保存代码如下:

@Override
@Transactional
public void save(Entity entity) {
    Session session = entityManager.unwrap(Session.class);
    session.saveOrUpdate(entity);
    session.flush();
}

当我尝试删除详细信息时出现问题。下面的代码显示了它是如何完成的:

myMaster.getDetails().remove(myDetail);

我希望 Hibernate 将跟踪主对象的更改(它从列表成员中丢失了详细实例),但是当我调用 save() 方法时,它会抛出 java.lang .IllegalArgumentException:正在删除分离的实例 xxxx#yyyy

如果尝试删除分离的实例,我理解这个概念,但我不明白为什么 Hibernate 认为刚刚删除的实例是分离的。

有什么想法吗?

TIA!

最佳答案

要使其按照您期望的方式工作(让 Hibernate 检查整个对象图),您需要做的就是:

@Override
@Transactional
public Entity save(Entity entity) {
    return entityManager.merge(entity);
}

当然,请确保MERGE操作从主控级联到详细信息(CascadeType.MERGECascadeType.ALL)并且orphanRemoval 设置为详细信息收集。如果 orphanRemoval 不合适,那么您必须显式删除详细信息(否则 Hibernate 会在关联的子级不再与父级关联时删除它们,这显然是不可取的)。

此外,请确保随后使用 merge 操作的结果,因为它始终返回传入的分离实例的副本(传入的实例不会被修改)。这在持久化新实例时尤其重要,因为 id 是在副本中设置的。

但是,您要付出从数据库重新加载对象图的代价,但是,如果您希望所有事情自动完成,Hibernate 没有其他方法来检查实际更改的内容,除了与数据库中的当前状态进行比较之外。

现在解释一下您在尝试中观察到的情况:

  1. 您保存的主实例已分离。您将其加载到一个事务(持久性上下文/ session )中,然后将其保存在另一个事务中。

  2. 它可以与 saveOrUpdate 配合使用。当你更新它时:

    Either save(Object) or update(Object) the given instance, depending upon resolution of the unsaved-value checks (see the manual for discussion of unsaved-value checking).

    Parameters:

    object - a transient or detached instance containing new or updated state

    如文档中所述,它旨在处理分离和 transient 实例。

  3. 您尝试合并,但出现异常,告诉您已经存在具有相同 id 的对象。唯一的解释是你尝试过这样的事情:

    @Override
    @Transactional
    public void save(Entity entity) {
        entity = entityManager.merge(entity);
        Session session = entityManager.unwrap(Session.class);
        session.saveOrUpdate(entity);
        session.flush();
    }
    

    然后会抛出异常,如 update 中所述。 javadoc:

    Update the persistent instance with the identifier of the given detached instance. If there is a persistent instance with the same identifier, an exception is thrown.

    因此,您将实例合并到当前的持久性上下文中,然后尝试 saveOrUpdate 它(委托(delegate)给 update),这导致了异常,因为您当当前持久化上下文中已经存在持久化实例时,不得更新分离实例(否则持久化实例将变得过时)。

    您不必这样做,只需合并即可,在事务结束时,Hibernate 将脏检查对象并自动将更改刷新到数据库。

关于java - 如何让 Hibernate 4 停止抛出 "Deleting detached instance"?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43279988/

相关文章:

java - 我可以监听 java 中的所有拖放事件吗?

java - Eclipse WTP + Gradle Buildship 未部署所有项目依赖项

hibernate - Grails:如何在Grails上处理Java Bean验证

hibernate - 我们如何使用 JPA2( hibernate )实体作为两个 web 应用程序之间的 DTO?

java - 返回从第 N 次出现开始的子串

java - Spring Boot应用程序无法启动嵌入式容器

java - 当 Web 应用程序没有太多请求时如何启动计划线程?

java - 能否使用 fork/join 跨线程边界安全地移植非线程安全值?

mysql - Hibernate 多对多映射和查询

java - 数组列表到 Collection<Object>