【问题标题】:JPQL query: how to filter rows on a relationship?JPQL 查询:如何过滤关系中的行?
【发布时间】:2023-03-26 22:05:01
【问题描述】:

我是 JPA 2.0 的新手,我不明白的地方很少。

我有几张桌子:



    CUST table (for customers)
    --------------------------
    CUST_ID   (pk, integer)
    CUST_NAME (varchar)



    ORD table (for orders)
    ----------------------
    ORD_ID     (pk, integer)
    ORD_STATUS (char) can be: 'N' for new, 'S' for shipped, 'D' for delivered
    CUST_ID    (fk, integer)

这种关系是简单的“一对多”(每个客户都可以下很多订单)。

表格内容:



    CUST_ID | CUST_NAME
    -------------------
     1      | elcaro
     2      | tfosorcim
     3      | elppa



    ORD_ID | ORD_STATUS | CUST_ID
    -----------------------------
     2     | N          | 1
     3     | N          | 1
     4     | N          | 1
     5     | S          | 1
     6     | S          | 1
     7     | D          | 1
     8     | D          | 1
     9     | D          | 1
     10    | D          | 2
     11    | N          | 2
     12    | S          | 3
     13    | S          | 3

我是这样注释我的类的:



    @Entity(name = "Customer")
    @Table(name = "CUST")
    public class Customer implements Serializable
    {
        private static final long serialVersionUID = 1L;

        @Id
        @Column(name = "CUST_ID")
        private Integer id;

        @Column(name = "CUST_NAME")
        private String name;

        @OneToMany(mappedBy = "customer")
        private List<Order> orders;

        // Default constructor, getters and setters (no annotations on these)
    }



    @Entity(name = "Order")
    @Table(name = "ORD")
    public class Order implements Serializable
    {
        private static final long serialVersionUID = 1L;

        @Id
        @Column(name = "ORD_ID")
        private Integer id;

        @Column(name = "ORD_STATUS")
        private Character status;

        @ManyToOne
        @JoinColumns
        (
          {
            @JoinColumn(name = "CUST_ID", referencedColumnName = "CUST_ID")
          }
        )
        private Customer customer;

        // Default constructor, getters and setters (no annotations on these)
    }

一切正常,以下 JPQL 查询产生了我预期的结果:

`select c from Customer c`

它返回三个客户类型的对象,每个对象都包含属于该客户的订单。

但是现在,我想提取状态为“N”的客户列表以及相关的订单(当然,只有状态为“N”的订单)。 回到过去的美好时光,我会编写这样的 SQL 查询:



    select      c.cust_id,
                c.cust_name,
                o.ord_id,
                o.ord_status
    from        cust c
    inner join  ord o on (o.cust_id = c.cust_id)
    where       o.ord_status = 'N'

它会返回以下结果集:



    CUST_ID | CUST_NAME | ORD_ID | ORD_STATUS
    -----------------------------------------
     1      | elcaro    | 2      | N
     1      | elcaro    | 3      | N
     1      | elcaro    | 4      | N
     2      | tfosorcim | 11     | N

但是,以下 JPQL 查询不会产生预期的结果:

`select distinct c from Customer c join c.orders o where o.status = 'N'`

它返回正确的客户集(客户“elppa”没有任何状态“N”订单并被正确排除),但每个客户都包含完整的订单集,无论状态如何。 似乎只评估“where”子句以确定必须提取哪组客户,然后持久性提供程序开始导航关系以提取完整的订单集。 稍微想一想,我不得不承认这是有道理的。

然后我尝试了另一个 JPQL 查询:

`select c, o from Customer c join c.orders o where o.status = 'N'`

这个 JPQL 查询产生的结果与前一个 SQL 查询产生的结果相似:每个结果(预期的 4 个结果)是一个 2 对象数组,第一个对象是 Customer 类型,第二个对象是类型命令。但是,再次,客户类型的对象包含完整的相关订单集(正如我所料,这一次)。更不用说现在订单不包含在 Customer 对象中,而是单独返回,就像在 SQL 结果集中一样。

现在的问题是: 是否可以编写一个 JPQL 查询来过滤掉不仅没有处于“N”状态的订单的客户,还可以过滤掉不处于“N”状态的相关订单(在关系导航期间获取)? 我希望能够得到一个 2-customer 结果,其中每个客户只包含其状态“N”个订单。

我阅读了 Java EE 6 教程,其中一个示例(订单应用程序)的架构与我的相似,但我找不到这样的查询(在下载的源代码中)。

虽然我认为以上是标准行为,但我使用的是 Oracle Weblogic 12c 服务器(通过其 Eclipse 适配器),并且持久性提供程序似乎是 EclipseLink。

提前致谢。

最好的问候,

斯特凡诺

【问题讨论】:

    标签: jpa persistence jpql


    【解决方案1】:

    JPA处理对象,一个对象有一个身份,无论怎么查询都是一样的。无论您的 where 子句是什么,返回的 Customer 对象仍然是相同的 Customer 对象并且应该具有相同的关系。这对于缓存、对象标识和一致性很重要。

    您的第二个查询可能是做您想做的事情的正确方法。可以使用 JOIN FETCH 上的别名来做您想做的事情(从 EclipseLink 2.4 开始),但不推荐。

    看, http://wiki.eclipse.org/EclipseLink/UserGuide/JPA/Basic_JPA_Development/Querying/JPQL#JOIN_FETCH

    【讨论】:

    • 詹姆斯您好,感谢您的回复。我同意你的观点,使用 join fetch 是一种延伸(而且它也押韵)。有人建议我直接查询订单并利用对客户的反向引用。事实上,我能够通过以下查询获得正确的结果:select o from Order o where o.status = 'N'。我真的很希望每个客户都有一份仅包含所选订单的副本,但我也对这个解决方案感到非常满意。再次感谢您,再见。
    猜你喜欢
    • 2016-03-08
    • 2017-04-12
    • 2014-07-30
    • 1970-01-01
    • 2021-03-16
    • 2020-08-02
    • 1970-01-01
    • 1970-01-01
    • 2015-12-30
    相关资源
    最近更新 更多