【问题标题】:How to retrieve nested JPA entities in a single query如何在单个查询中检索嵌套的 JPA 实体
【发布时间】:2011-07-15 09:13:41
【问题描述】:

我正在尝试使用 eclipselink JPA 检索实体,并且正在寻找一种方法来减少为检索单个实体而运行的查询数量。我相信我应该使用 @JoinFetch 注释来检索与主实体相同的查询中的子实体。这适用于单级连接,但不适用于多级。

在下面的示例中,EntityA 包含 EntityB 的集合,其中包含 EntityC。当我检索 EntityA 时,我想要一个查询来返回所有 3 组实体数据。实际上,它生成 2 个查询,1 个连接 EntityA 和 EntityB,然后一个单独的查询连接 EntityB 和 EntityC。

是否可以将其合并到一个查询中?

class EntityA {
    @OneToMany(mappedBy = "entityALink", fetch = FetchType.EAGER)
    @JoinFetch
    private Collection<EntityB> entityBs;
}

class EntityB {
    @JoinColumn(name = "X", referencedColumnName = "Y")
    @ManyToOne(optional = false, fetch = FetchType.EAGER)
    private EntityA entityALink;

    @JoinColumn(name = "A", referencedColumnName = "B")
    @ManyToOne(optional = false, fetch = FetchType.EAGER)
    @JoinFetch
    private EntityC entityCLink;
}

class EntityC {

    @Id
    @Basic(optional = false)
    @Column(name = "SomeColumn")
    private String someField
}

【问题讨论】:

    标签: java optimization jpa annotations eclipselink


    【解决方案1】:

    如果您需要减少查询次数,您可以使用延迟初始化 - FetchType.LAZY 而不是 FetchType.EAGER - 这样 jpa 在需要时从数据库中获取数据。但是您必须记住,当实体与管理器断开连接时,这不起作用。因此,如果您将此实体以序列化形式发送到其他服务器(例如在多级应用程序中),您必须再次将此实体与管理器连接。如果您的应用程序在一台服务器上运行,那么您就不会有这个问题。

    总结不是您问题的确切答案,但可能有助于优化此代码。

    您问题的确切答案: 您可以使用命名查询,但是查询被解析为 sql 本机查询,并且您不确定这是否按您的意愿工作。但也许您可以使用本机查询方法?

    em.createNativeQuery("SELECT ... your queries") 
    

    为此,请阅读有关使用@SqlResultSetMapping 注解配置结果实体类...

    【讨论】:

    • 我的主要目标是在应用程序启动时尽可能快地加载一个非常大的数据集,之后不需要再次返回数据库。因此,延迟获取只是将问题推迟到需要数据之前。到目前为止的方法是使用实​​体注释来指定连接,但我现在想知道命名查询是否会提供更好的解决方案。
    • 如果您不想使用本机查询,最好使用数据库视图,并使用 A 和 B 字段创建其他实体?但这并不能解决多对一多重性的问题。但是,在您的情况下,它可以简化为单个视图吗?
    • 感谢您的建议。最后,我使用查询和延迟获取解决了这个问题。我没有期望 JPA 一次性返回我想要的所有数据(这太慢了),我选择让我的 DAO 调用 2 个单独的查询并将数据自己拼接在一起。实体之间的链接现在是惰性的而不是急切的,由查询决定带回多少数据。我正在使用 eclipselink,因此能够指定查询提示来优化表之间的连接。
    【解决方案2】:

    首先编写查询获取EntityA。

    EntityA entity = <your Query> ;
    

    然后调用

    Collection<EntityB> entityB = entity.getEntityBs();
    for(EntityB eachB : entityB){
    
        EntityC entityCLink = eachB.getEntityCLink();
    }
    

    注意:在每个实体中创建 setter 和 getter。

    【讨论】:

      猜你喜欢
      • 2015-07-24
      • 2018-12-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-12-04
      • 1970-01-01
      • 1970-01-01
      • 2014-02-15
      相关资源
      最近更新 更多