3 Replies Latest reply on Apr 19, 2012 12:44 AM by 931305

    General JPA query question

      Hello world,

      I'm new to JPA 2.0 and there are few things I don't understand.

      BTW: I can't figure out the keywords to search for this question, so please pardon me if it's one of the most asked.

      Using the Preview, I've seen that alignment went straight to Hell, so I tried to make this as readable as I could using pipes in place of white spaces in the result sets.

      I have a couple of tables:

      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)

      The relationship is, of course, a "one to many" (every customer can place many orders).

      Content of the tables:



      Here's how I annotated my classes:


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

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

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

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

      @JoinColumn(name = "CUST_ID", referencedColumnName = "CUST_ID")
      private Customer customer;

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

      Everything works just fine, the following JPQL query yields the results I expected:

      select c from Customer c

      it returns three objects of type Customer, each of which contains the orders that belong to that customer.

      But now, I want to extract the list of customers that have orders in status 'N', along with the associated orders (only the status 'N' orders, of course).
      Back in the good ol' days I would have written an SQL query like this:

      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'

      and it would have returned the following result set:


      The following JPQL query, however, doesn't yield the expected results:

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

      it returns the correct set of customers (customer 'elppa' doesn't have any status 'N' order and is correctly excluded), but each customer contains the full set of orders, regardless of the status.
      It seems that the 'where' clause is only evaluated to determine which set of customers has to be extracted and then the persistence provider starts to navigate the relationship to extract the full set of orders.
      Thinking a little about it, I must admit that it makes sense.

      I then tried out another JPQL query:

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

      this JPA query yields results that are similar to the ones produced by the previous SQL query: each result (4 results as expected) is a 2-object array, the first object is of type Customer and the second object is of type Order. But, again, the objects of type Customer contain the full set of related orders (as I expected, this time). Not to mention the fact that now the orders are not contained in the Customer objects, but are returned separately, just as in an SQL result set.

      Now the question is:
      Is it possible to write a JPA query that filters out, not only the customers that don't have an order in status 'N', but the related orders (fetched during relationship navigation) that are not in status 'N' as well?
      What I'd like to be able to get is a 2-customer result where each customer contains only its status 'N' orders.

      I read the Java EE 6 Tutorial and one of the examples (the Order Application) has a schema that is similar to mine, but I couldn't find a query like this (in the downloaded source code).

      Although I think the above is standard behavior, I use an Oracle Weblogic 12c server (through its Eclipse adapter) and the persistence provider appears to be EclipseLink.

      Thanks in advance.

      Best regards,


      Edited by: user11265230 on 17-apr-2012 14.11
        • 1. Re: General JPA query question

          When returning an entity from JPQL, it gives you the entity as it is in the database. Your "select distinct c from Customer c join c.orders o where o.status = 'N'" is asking for all customers that have an order with a status of 'N', so that is what it gives you. There is no condition to filter anything on the relationship when building the Customer object in JPA - doing so would mean returning a managed entity that does not reflect what is in the database. This would affect other queries, since JPA requires that queries return the same instance of an entity regardless of the query that is used to bring it back. So a query using your "where o.status = 'N'" would cause conflicting results when used with a query using "where o.status = 'Y'". And these queries would make the EntityManager unable to determine what has changed on the returned objects.

          EclipseLink does have the ability to filter over relationships, it is just not available through standard JPA and I would strongly discourage it. Instead of querying for Customers, why not change the query to get Orders instead -
          "select o from Customer c join c.orders o where o.status = 'N'". Assuming Orders have a ManyToOne back reference to their Customer, this will mean you do not need to travers the Customer-> order relationship. If using
          "select c, o from Customer c join c.orders o where o.status = 'N'"
          I am not sure why you would use the orders from the returned customers instead of the orders returned in the results though.

          You could also return "select c.id, c.name, o.id, o.status from Customer c join c.orders o where o.status = 'N'" which is the equivalent of what you would get from the SQL you initially posted.

          1 person found this helpful
          • 2. Re: General JPA query question
            Hello Chris,

            thanks for replying. I like your solution about querying for orders in the first place (and I'm pretty sure that it applies to my real case too, that is a little more complex). I didn't even need the join anymore, in fact I was able to get the same results with the following JPQL query: select o from Order o where o.status = 'N'. The back reference to the customer did the rest.
            Having a single Customer object containing only the selected orders and ready to be consumed by a client would have been great, but, after all, what I get with your solution is exactly what I got for years and years using a SQL query similar to the one I posted: a result set in which customer data is repeated for each order that belongs to it and this result set may need a little manipulation before it can be returned to a client.
            I must confess that I'm not an ORM enthusiast today more than I was when Hibernate first came out, but who am I to stop progress? :)
            Thank you again Chris.
            Best regards,

            • 3. Re: General JPA query question
              Ooops, sorry Chris, I thought I could mark a message as both Helpful and Correct... and I started with Helpful... it's the first time I post on this forum. Your reply sure deserved 10 points.