JPA Hibernate Lazy 多对一获取代理

JPA Hibernate Lazy many-to-one fetch proxy

我正在使用 JPA 2.1 和 Hibernate 4.3.7

我尝试调整我的应用程序,因此我将关系变为惰性关系并仅获取我需要的内容

我在多对一关系方面遇到问题,当我再次加载实体时转为惰性时,Hibernate 通过代理替换实体,即使我获取了实体并且该代理在视图中不起作用应用程序的一部分 (JSF)。 当多对一处于急切模式时,问题消失了,但即使我不需要它们,hibernate 也会为每个多对一执行一次 select

@Entity
public class Department {
    @Id
    private Integer id;

    //...
}

1/

@Entity
public class Employee {
    @Id
    private Integer id;

    @ManyToOne(fetch = FetchType.LAZY, optional = true)
    @JoinColumn(name = "id_department", referencedColumnName = "id")
    private Department department;

    //...
}

JPQL 查询:

SELECT e FROM Employee e LEFT JOIN FETCH e.department WHERE e.id=:id

=> 一个 select 查询 => 更快但是部门的类型是 Department_$$_jvst3ac_5f (employee.getDepartment().getClass().getCanonicalName()) 和这个代理在应用程序的视图部分不起作用

2/

@Entity
public class Employee {
    @Id
    private Integer id;

    @ManyToOne(fetch = FetchType.EAGER, optional = true)
    @JoinColumn(name = "id_department", referencedColumnName = "id")
    private Department department;

    //...
}

JPQL 查询:

SELECT e FROM Employee e WHERE e.id=:id

=> 两个 selects => 较慢但部门作为部门加载并且在应用程序的视图部分一切正常

关系是单向的,部门没有员工的引用

在使用 FETCH JOIN 时是否可以让部门没有代理?


在 Luiggi 的响应之后,我将精确地指出数据是通过惰性多对一 + fetch join 获取的。当我执行 employee.getDepartment().toString() 时,我有 Department{ id=11, ...} 但是这个部门的 class 仍然是 Department_$$_jvst3ac_5f。出于我不知道的原因,即使获取了数据,JSF/PrimeFaces selectOneMenu 组件也无法在 HibernateProxy 中正常工作

我尝试使用 Hibernate 注释 @LazyToOne(LazyToOneOption.FALSE) 除了 @ManyToOne(fetch = FetchType.LAZY) 但结果与 @ManyToOne(fetch = FetchType.EAGER) 一个人...

问题是,当您使用延迟加载时,您将获得 class 的代理(正如您已经说过的),并且此代理可以从数据库中获取数据 只有当 hibernatesession还在营业。将数据返回到视图时,您的会话似乎正在关闭,因此当尝试在视图中使用延迟加载的字段时,您会遇到异常。

可能的解决方案:

  • 将该字段保持为急切提取状态,并为针对您的实体的每个查询支付开销(这可能不太好并且会影响性​​能,但这是一个解决方案)。
  • 在关闭 Hibernate 会话之前,将您的字段保持为惰性并使用正确的 get 方法,以便代理在会话关闭后检索要使用的相关数据。