【问题标题】:Execute @PostLoad _after_ eagerly fetching?急切地执行@PostLoad _after_?
【发布时间】:2011-05-28 17:59:04
【问题描述】:

使用 JPA2/Hibernate,我创建了一个实体 A,它具有到实体 X 的单向映射(见下文)。在 A 内部,我还有一个临时成员“t”,我正在尝试使用 @PostLoad 方法进行计算。计算需要访问关联的 X:

@Entity  
public class A {  
    // ...
    @Transient
    int t;

    @OneToMany(orphanRemoval = false, fetch = FetchType.EAGER)  
    private List listOfX;  

    @PostLoad
    public void calculateT() {
        t = 0;
        for (X x : listOfX)
            t = t + x.someMethod();
    }
}

但是,当我尝试加载此实体时,我收到“org.hibernate.LazyInitializationException:非法访问加载集合”错误。

 at org.hibernate.collection.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:363)
 at org.hibernate.collection.AbstractPersistentCollection.read(AbstractPersistentCollection.java:108)
 at org.hibernate.collection.PersistentBag.get(PersistentBag.java:445)
 at java.util.Collections$UnmodifiableList.get(Collections.java:1154)
 at mypackage.A.calculateT(A.java:32)

调试时查看hibernate的代码(AbstractPersistentCollection.java),发现:

1) 我的@PostLoad 方法在“listOfX”成员被初始化之前被调用
2) Hibernate 的代码有一个明确的检查,以防止在@PostLoad 期间初始化急切获取的集合:

 protected final void initialize(boolean writing) {
  if (!initialized) {
   if (initializing) {
    throw new LazyInitializationException("illegal access to loading collection");
   }
   throwLazyInitializationExceptionIfNotConnected();
   session.initializeCollection(this, writing);
  }
 }

我想解决这个问题的唯一方法是停止使用 @PostLoad 并将初始化代码移动到 getT() 访问器中,添加一个同步块。但是,我想避免这种情况。

那么,有没有办法在调用@PostLoad 之前执行急切获取?我不知道有一个 JPA 工具可以做到这一点,所以我希望有一些我不知道的东西。

另外,也许 Hibernate 的专有 API 可以控制这种行为?

【问题讨论】:

标签: jpa-2.0 hibernate3


【解决方案1】:

我不知道如何解决这个问题,但我认为一些重构可能会有所帮助,想法是将代码移动到 @PostConstruct

例如,您的班级将是:

@Entity  
public class A {  
    // ...
    @Transient
    int t;

@OneToMany(orphanRemoval = false, fetch = FetchType.EAGER)  
private List listOfX;  

@PostConstruct
public void calculateT() {
    t = 0;
    for (X x : listOfX)
        t = t + x.someMethod();
}

}

服务器将在完成 bean 的所有容器服务初始化后立即调用 PostConstruct。

【讨论】:

  • @PostConstruct 没有帮助。虽然它给了容器初始化东西的机会,但我需要初始化的字段不是由 Spring 容器设置的。由于@PostConstruct 是在构造函数之后立即调用的,所以Hibernate 甚至没有填充诸如@Id 之类的字段。
【解决方案2】:

这可能为时已晚,但 hibernate 似乎不支持默认的 jpa fetchtype 选项

@OneToMany(orphanRemoval = false, fetch = FetchType.EAGER)

你必须使用hibernate特定的:

@LazyCollection(LazyCollectionOption.FALSE)

【讨论】:

    【解决方案3】:

    错误报告的更新链接:

    https://hibernate.atlassian.net/browse/HHH-6043

    这在 4.1.8 和 4.3.0 或更高版本中已修复

    【讨论】:

      猜你喜欢
      • 2022-01-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-06-23
      • 2019-02-01
      • 1970-01-01
      • 1970-01-01
      • 2021-08-20
      相关资源
      最近更新 更多