Monday, January 18, 2010

Polymorphic queries in JPQL ?!

You may be surprised to find out that JPA supports polymorphism, and that JPQL
queries are polymorphic. This means a JPQL query to retrieve a parent entity in an
entity hierarchy is not just limited to the entity, but retrieves all subclasses as well.
For example, in ActionBazaar any query to retrieve User entities will retrieve its
subclasses, such as Seller, Bidder, and Admin.
Suppose we have a query like this:
   SELECT u
   FROM User u
   WHERE u.firstName LIKE :firstName
The query will retrieve all instances of Seller, Bidder, Admin, and so forth that
match this query condition. How do you handle a polymorphic query in your client
code? Consider the following:
       query = em.createNamedQuery("findUserByName");
       query.setParameter("firstName", firstName);
       List<User> users = query.getResultList();
       Iterator i = users.iterator();
       while (i.hasNext()) {
             User user = (User) i.next();
             System.out.print("User:"+emp.getUserId());
             if (user instanceof Seller) {
                     Seller seller = (Seller) user;
                     System.out.println("Seller:" +
                            seller.getCommissionRate());
             }
             else if (user instanceof Bidder) {
                     Bidder bidder = (Bidder) bidder;
                     System.out.println("Bidder:" +
                            bidder.getDiscountRate());
             }
       }
This code snippet uses the instanceof keyword to test user. Some Java gurus
recommend you avoid using instanceof, but we use it here as a last resort.
You have to ensure that your operations are just as polymorphic as your que-
ries! In our example, you can easily convert the operations to be polymorphic by
adding a getRate method in all entities. The getRate method will return the
commissionRate for the Seller entity, whereas it will return the discount-
Rate for the Bidder entity. The resulting code should look like this:
Iterator i = users.iterator();
while (i.hasNext()) {
  User user = (User)i.next();
  System.out.print("User:" + emp.getUserId());
  System.out.println(user.getRate());

Source: Enterprise Java Beans 3 in Action,chapter 10, Manning publications, 2007
}


No comments: