【问题标题】:Hibernate @PreUpdate/@PrePersist inconsistencyHibernate @PreUpdate/@PrePersist 不一致
【发布时间】:2017-01-23 09:28:21
【问题描述】:

我遇到了一个奇怪的问题:我有一个实体和该类的侦听器,

@Entity
@EntityListeners(Listener.class)
public class Foo {

    @Id long id;

    @ElementCollection Map<String, String> map;

    // getters and setters

}

public class Listener {

    @PreUpdate
    @PrePersist
    public void preUpdate(Foo foo) {
        System.out.println(foo);
        System.out.println(foo.getMap().size());
    }

}

@Stateless
public class TestDAO {

    @PersistenceContext
    EntityManager em;

    public void testMerge(Foo foo) {
        foo.getMap().put("foo", "test");
        System.out.println(foo);
        System.out.println(foo.getMap().size());
        this.em.merge(foo);
    }

}

然后当我执行testMerge 时,我得到这个输出(更新 带有 SQL 调试):

Foo@15bcfa3c
1
Foo@671144f9
0
Hibernate: insert into Foo values ( )
Hibernate: insert into Foo_map (Foo_id, map_KEY, map) values (?, ?, ?) // 1, 'foo', 'test'

所以地图可以正确保存在数据库中,但传递给侦听器的实体有一个空地图。发生了什么?

更新:Jira 问题和测试用例 相关 Jira 问题:https://hibernate.atlassian.net/browse/HHH-11414 和测试用例:https://github.com/heruan/hibernate-testcase/tree/HHH-11414

【问题讨论】:

  • Foo 是一个新实体还是之前已经保存过?
  • 在我运行的测试中,它是一个新实体;我使用merge,因为在实际场景中它可能是新的或现有的。
  • 您知道作为参数提供给 merge 的实例仍然是一个非托管实体,并且该合并返回一个托管实体。所以你在testMerge 中打印的实例永远不会与监听器中的实例相同!
  • 我知道@KlausGroenbaek,我在问为什么监听器中的合并实例有一个空地图。

标签: hibernate jpa entitylisteners


【解决方案1】:

这是一个棘手的问题,但是如果您调试您的 testMerge 代码和侦听器方法,您可能会发现 Foo 的实际实例是不同的。 现在这是 @PreUpdate / @PostUpdate 调用的情况。

对于@PrePersist / @PostPersist,情况并非如此,因为该方法总是接收相同的实体实例。

不确定您使用的是哪个版本的 Hibernate,但我记得前段时间我在为 3.x 版本做项目时注意到。

更新

提醒您,当我在 Pre / Post Upate 测试合并时,我发现 merge() 操作可以调用事件侦听器的唯一时间是在新实体上调用它时还没有坚持。然后它本身充当persist() 操作,并调用@PrePersist 注释类。因此,您可能永远无法通过该配置实现您所寻求的目标。

【讨论】:

  • 我使用的是最新的 5.2.6,是的,我发现实例不同。我不明白为什么我会得到一个带有空地图的实例,如果地图随后正确保存在数据库中。我会再做一些测试并在这里报告。
  • 尝试使用 em.persist(..) 只是为了看看你是否得到了实际的实例。稍后我会做更多测试
  • 我拆分了@PrePersist@PreUpdate,似乎对于新实体调用了@PrePersist 方法,但与您所说的实例不同:使用不同的实例,其中地图是空的。
  • 好的,使用em.persist 代替em.merge 会触发具有相同实例和填充地图的@PrePersist。不幸的是,合并时我也需要监听器中的地图,我不明白为什么它不存在......
  • 解决@PreUpdate 调用添加@Version 字段。但是,回调中没有地图……我将在 Hibernate Jira 中触发一个问题。
猜你喜欢
  • 1970-01-01
  • 2011-05-07
  • 1970-01-01
  • 1970-01-01
  • 2019-06-11
  • 2015-11-23
  • 2014-06-08
  • 2012-03-30
相关资源
最近更新 更多