如何使用JPA-EntityGraph仅加载实体@Basic属性的子集?

时间:2018-11-26 23:31:53

标签: java hibernate jpa wildfly jpa-2.1

我发现了关于实体图的documentation ...阅读后,我想到了您可以使用实体图来检索给定实体的@Basic字段的子集(到目前为止,我一直使用实体图来更轻松地检索关系,例如,加载Employee [包括其所有属性]和关联的Department [包括其所有属性])...

因此,我决定使用一个小测试来尝试一下:

@Entity
@Table(name = "employee")
@NamedEntityGraphs({
    @NamedEntityGraph(
        name = "OnlyName",
        attributeNodes = @NamedAttributeNode(value = "name")
    )
})
public class Employee implements Serializable {
    ...
    @Id
    @Column(name = "code", updatable = false)
    private Long code;

    @Basic(fetch = FetchType.LAZY)
    @Column(name = "name", nullable = false)
    private String name;

    @Basic(fetch = FetchType.LAZY)
    @Column(name = "last_name", nullable = false)
    private String lastName;

    @Lob @Basic(fetch = FetchType.LAZY)
    @Column(name = "picture", nullable = false)
    private byte[] picture;

    public Employee() {
       super();
    }
    ...
}

然后,使用以下代码检索我的实体:

    private Employee retrieveFromDatabase(long code) {
        EntityGraph<Employee> graph;                // Material Entity Graph

        Map<String, Object> map = new HashMap<>();

        graph = (EntityGraph<Employee>) this.em.createEntityGraph("OnlyName");
        map.put("javax.persistence.fetchgraph", graph);


        return this.em.find(Employee.class, code, map);
    }

现在,此代码始终返回一个Employee,其中包含从数据库中获取的所有字段。甚至Hibernate日志也显示一个查询,该查询选择了所有员工字段:

Hibernate: select employee0_.code as code1_0_0_, employee0_.last_name as last_name2_0_0_, employee0_.name as name3_0_0_, employee0_.picture as picture4_0_0_ from employee employee0_ where employee0_.code=?

当我期望这样的查询时:select employee0_.code as code1_0_0_, mployee0_.name as name3_0_0_ from employee employee0_ where employee0_.code=?

那么,我做错了什么?休眠不是supported的功能吗?

注意:对于测试,我使用的是休眠5.0.10和wildfly10 ...

谢谢!

1 个答案:

答案 0 :(得分:2)

实际上,您没有做错任何事情。但是,您Hibernate ORM User Guide (v5.0.x)中缺少一条重要的信息。在2.3.2节中,我们找到了它:

  

fetch-FetchType(默认为EAGER

     

定义此属性是应立即获取还是应延迟获取。 JPA说,EAGER是提供程序(休眠)的一项要求,即在提取所有者时应提取值,而LAZY只是提示在访问属性时要提取值。 Hibernate对于基本类型将忽略此设置,除非您使用字节码增强功能。有关获取和字节码增强的更多信息,请参见BytecodeEnhancement

因此:即使您要向em.find(..)方法提供查询提示,也要由JPA提供程序-这里:Hibernate-决定是否急切地获取基本属性。在您的情况下,Employee实体仅包含@Basic个属性。

作为参考,以及更多背景信息和更详细的解释,另请参阅此tutorial。它涵盖了"javax.persistence.fetchgraph""javax.persistence.loadgraph"查询提示之间的差异,并提供了示例代码来演示JPA持久性提供程序Hibernate的上述行为。

旁注:我检查了。

  • .. Hibernate ORM用户指南5.15.25.3:所有版本都包含关于默认策略的相同语句,以忽略基本属性。
  • ..官方JPA 2.1 specification document。在(PDF)第117页的第3.7.4节中,我们发现:
      

    允许持久性提供程序获取由获取图或负载图指定的超出的其他实体状态。

JPA规范中的后一个引用支持 ORM用户指南,可以这样实现。

我的建议

按照《 Hibernate ORM用户指南》(请参见上文)中的说明 BytecodeEnhancement

希望有帮助。