【问题标题】:How to use JPA - EntityGraph to load only a subset of entity @Basic attributes?如何使用 JPA - EntityGraph 仅加载实体@Basic 属性的子集?
【发布时间】:2019-04-28 15:52:28
【问题描述】:

我发现了这个关于实体图的documentation... 阅读后,它让我想到您可以使用实体图仅检索给定实体的@Basic 字段的子集(直到现在,我已经使用实体图快速检索关系,例如,加载一个员工[包括其所有属性]及其相关部门[包括其所有属性])...

所以,我决定用一个小测试来试试这个:

@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);
    }

现在,这段代码总是返回一个员工,其中包含从数据库中获取的所有字段;甚至 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=?

那么,我做错了什么?这个功能不是Hibernate的supported吗??

注意:为了测试,我使用的是 hibernate 5.0.10 和 wildfly10 ...

谢谢!

【问题讨论】:

    标签: java hibernate jpa wildfly jpa-2.1


    【解决方案1】:

    其实你并没有做错什么。然而,您错过了Hibernate ORM User Guide (v5.0.x) 中的一条重要信息。在第 2.3.2 节我们找到它:

    fetch - FetchType(默认为EAGER

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

    所以:即使您向em.find(..) 方法提供查询提示,也取决于JPA 提供者——这里:Hibernate——来决定是否急切地获取基本属性。在您的情况下,Employee 实体仅包含 @Basic 属性。

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

    旁注:我检查了..

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

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

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

    我的建议

    查看 Hibernate ORM 用户指南中所述的 BytecodeEnhancement(见上文)。

    希望对你有帮助。

    【讨论】:

    • 感谢您的回答...我希望将来,hibernate 完全实现此功能...您知道其他遵守指定获取计划的 jpa 实现吗?
    猜你喜欢
    • 2015-06-24
    • 2013-05-21
    • 1970-01-01
    • 1970-01-01
    • 2011-09-25
    • 2016-09-07
    • 2016-05-08
    • 2017-05-08
    • 1970-01-01
    相关资源
    最近更新 更多