Wednesday, July 14, 2010

Playing Around with JPA Criteria API

It's still about multiselect like the one discussed in 005 - JPA Projective Query in EL & Hibernate, but instead of using named query, I will use the Criteria API instead.
Let's use the same query as the other article:
SELECT new com.arizal.flight.FlightNumber" +
          "(f.number, f.airline) " +
           " FROM Flight f WHERE f.departure.code='SYD'")

This can be expressed using Criteria as follow:



public static void main(String args[]) {
    EntityManagerFactory emf = 
      Persistence.createEntityManagerFactory("jpa");
    EntityManager em = emf.createEntityManager();
    try {
      CriteriaBuilder cb = em.getCriteriaBuilder();
      CriteriaQuery<FlightNumber> criteriaQ = 

         cb.createQuery(FlightNumber.class);
      Root<Flight> flight = criteriaQ.from(Flight.class);
      criteriaQ.select(
        cb.construct(
            FlightNumber.class, 
            flight.get("number")
            flight.get("airline"))).
      where(cb.equal(flight.get("departure").get("code")"SYD"));
      TypedQuery<FlightNumber> query = em.createQuery(criteriaQ);
      List<FlightNumber> fnList = query.getResultList();

      for (FlightNumber fn : fnList) {
        System.out.println(fn.getAirline() " " + fn.getNumber());
      }
    finally {
      em.close();
      emf.close();
    }
Pretty simple, isn't it ?



Yeah, but let's see closer. Unlike SQL where we do first the selection followed by FROM (e.g. SELECT number, airline FROM flight), CriteriaBuilder imposes the use of FROM first (Root<Flight> flight = criteriaQ.from(Flight.class);) followed by select.
We do then: FROM flight SELECT number, airline. 



Could have been better, don't you think ?



Oh, yes. The code works for both Hibernate and EclipseLink. Hibernate does not suffer from this bug: http://opensource.atlassian.com/projects/hibernate/browse/HHH-5348 

No comments: