Zapytanie JPQL: jak filtrować wiersze w relacji?

Jestem nowy w JPA 2.0 i jest kilka rzeczy, których nie rozumiem.

Mam kilka stolików:

<code>

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

</code>

i

<code>

    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)

</code>

Związek jest prosty „jeden do wielu” (każdy klient może złożyć wiele zamówień).

Zawartość tabel:

<code>

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

</code>

i

<code>

    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

</code>

Oto jak opisałem moje zajęcia:

<code>

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

</code>

i

<code>

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

</code>

Wszystko działa dobrze, następujące zapytanie JPQL daje oczekiwane wyniki:

<code>`select c from Customer c`</code>

zwraca trzy obiekty typu Klient, z których każdy zawiera zamówienia należące do tego klienta.

Ale teraz chcę wyodrębnić listę klientów, którzy mają zamówienia w statusie „N”, wraz z powiązanymi zamówieniami (oczywiście tylko zamówienia „N” statusu). W dawnych dobrych czasach napisałbym zapytanie SQL w następujący sposób:

<code>

    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'

</code>

i zwróciłby następujący zestaw wyników:

<code>

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

</code>

Poniższe zapytanie JPQL nie daje jednak oczekiwanych wyników:

<code>`select distinct c from Customer c join c.orders o where o.status = 'N'`</code>

zwraca prawidłowy zestaw klientów (klient „elppa” nie ma żadnego statusu „N” i jest prawidłowo wykluczony), ale każdy klient zawiera pełny zestaw zamówień, niezależnie od statusu. Wydaje się, że klauzula „gdzie” jest oceniana tylko w celu określenia, który zestaw klientów musi zostać wyodrębniony, a następnie dostawca trwałości zaczyna nawigować w relacji, aby wyodrębnić pełny zestaw zamówień. Trochę o tym myśląc muszę przyznać, że ma to sens.

Następnie wypróbowałem inne zapytanie JPQL:

<code>`select c, o from Customer c join c.orders o where o.status = 'N'`</code>

to zapytanie JPQL daje wyniki podobne do wyników uzyskanych w poprzednim zapytaniu SQL: każdy wynik (zgodnie z oczekiwaniami 4 wyniki) jest tablicą 2-obiektową, pierwszy obiekt jest typu Klient, a drugi jest typu Order. Jednak ponownie obiekty typu Klient zawierają pełny zestaw powiązanych zleceń (tym razem oczekiwałem). Nie wspominając już o tym, że teraz zamówienia nie są zawarte w obiektach klienta, ale są zwracane oddzielnie, tak jak w zestawie wyników SQL.

Teraz pytanie brzmi: czy możliwe jest napisanie zapytania JPQL, które odfiltrowuje, a nie tylko klientów, którzy nie mają zamówienia w stanie „N”, ale powiązane zamówienia (pobrane podczas nawigacji w związku), które nie są w stanie ” N? To, co chciałbym uzyskać, to wynik 2 klientów, w którym każdy klient ma tylko status „N”.

Przeczytałem samouczek Java EE 6, a jeden z przykładów (aplikacja do składania zamówień) ma podobny schemat do mojego, ale nie mogłem znaleźć takiego zapytania (w pobranym kodzie źródłowym).

Chociaż uważam, że powyższe jest standardowym zachowaniem, używam serwera Oracle Weblogic 12c (za pośrednictwem adaptera Eclipse), a dostawcą trwałości wydaje się być EclipseLink.

Z góry dziękuję.

Z poważaniem,

Stefano

questionAnswers(1)

yourAnswerToTheQuestion