Close

JPA Criteria API - Path Navigation

[Updated: Dec 11, 2018, Created: Sep 2, 2018]

Path navigation is nothing but accessing entity properties by using dot (.) operator (for example in JPQL: employee.name, employee.address.city).

In JPA Criteria API, path navigation is performed by the use of Path interface (a subinterface of Expression). The interfaces Root, From and Join are the subinterfaces of Path.

A Path instance can be further navigated via Path#get() method.

Quick example:

CriteriaQuery<Item> query = criteriaBuilder.createQuery(Item.class);
  Root<Customer> customer = query.from(Customer.class);
  ListJoin<Order, Item> items = customer.join(Customer_.orders)
                                        .join(Order_.items);
  query.select(items)
       .where(criteriaBuilder.equal(customer.get(Customer_.shipmentInfo)
                                    .get(ShipmentInfo_.address)
                                    .get(Address_.state), "NJ"));

Example

Entities

@Entity
public class Customer {
  @Id
  @GeneratedValue
  private long id;
  private String name;
  @OneToMany(cascade = CascadeType.ALL)
  private List<Order> orders;
  @OneToOne(cascade = CascadeType.ALL)
  private ShipmentInfo shipmentInfo;
    .............
}
@Entity
@Table(name = "CustomerOrder")
public class Order {
  @Id
  @GeneratedValue
  private long id;
  private LocalDate date;
  @OneToMany(cascade = CascadeType.ALL)
  private List<Item> items;
    .............
}
@Entity
public class Item {
  @Id
  @GeneratedValue
  private long id;
  private String name;
  BigDecimal price;
    .............
}
@Entity
public class ShipmentInfo {
  @Id
  @GeneratedValue
  private long id;
  private String phone;
  @OneToOne(cascade = CascadeType.ALL)
  private Address address;
    .............
}
@Entity
public class Address {
  @Id
  @GeneratedValue
  private long id;
  private String street;
  private String city;
  private String state;
  private String zipCode;
    .............
}

Performing path navigation

public class ExampleMain {
  private static EntityManagerFactory entityManagerFactory =
          Persistence.createEntityManagerFactory("example-unit");

  public static void main(String[] args) {
      try {
          persistCustomers();
          findOrderItems();
      } finally {
          entityManagerFactory.close();
      }
  }

  public static void persistCustomers() {
      EntityManager em = entityManagerFactory.createEntityManager();
      em.getTransaction().begin();
      Customers.getCustomers().forEach(em::persist);
      em.getTransaction().commit();

      System.out.println("-- Customers persisted --");
      CriteriaBuilder cb = em.getCriteriaBuilder();
      CriteriaQuery<Customer> query = cb.createQuery(Customer.class);
      query.select(query.from(Customer.class));
      em.createQuery(query).getResultList().forEach(System.out::println);
      em.close();
  }

  private static void findOrderItems() {
      System.out.println("-- find order items placed from state NJ --");
      EntityManager em = entityManagerFactory.createEntityManager();
      CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder();
      CriteriaQuery<Item> query = criteriaBuilder.createQuery(Item.class);
      Root<Customer> customer = query.from(Customer.class);
      ListJoin<Order, Item> items = customer.join(Customer_.orders)
                                            .join(Order_.items);
      query.select(items)
           .where(criteriaBuilder.equal(customer.get(Customer_.shipmentInfo)
                                   .get(ShipmentInfo_.address)
                                   .get(Address_.state), "NJ"));

      em.createQuery(query).getResultList().forEach(System.out::println);
  }
}
-- Customers persisted --
Hibernate: select customer0_.id as id1_1_, customer0_.name as name2_1_, customer0_.shipmentInfo_id as shipment3_1_ from Customer customer0_
Customer{id=1, name='Mike', orders=[Order{id=4, date=2018-07-05, items=[Item{id=5, name='Desktop', price=621}, Item{id=6, name='Monitor', price=530}, Item{id=7, name='SSD', price=733}, Item{id=8, name='Keyboard', price=464}]}], shipmentInfo=ShipmentInfo{id=2, phone='387121', address=com.logicbig.example.Address@2b87581}}
Customer{id=9, name='Sara', orders=[Order{id=12, date=2017-04-07, items=[Item{id=13, name='Backpack', price=406}, Item{id=14, name='Lamp', price=381}, Item{id=15, name='Saucepan', price=695}, Item{id=16, name='Food Processor', price=253}]}], shipmentInfo=ShipmentInfo{id=10, phone='941117', address=com.logicbig.example.Address@61d01788}}
Customer{id=17, name='Charlie', orders=[Order{id=20, date=2017-01-22, items=[Item{id=21, name='Chivas', price=366}, Item{id=22, name='Merlot', price=262}, Item{id=23, name='Sapphire', price=245}, Item{id=24, name='Johnnie', price=707}]}], shipmentInfo=ShipmentInfo{id=18, phone='654184', address=com.logicbig.example.Address@56ccd751}}
-- find order items placed from state NJ --
Hibernate: select item4_.id as id1_5_, item4_.name as name2_5_, item4_.price as price3_5_ from Customer customer0_ inner join Customer_CustomerOrder orders1_ on customer0_.id=orders1_.Customer_id inner join CustomerOrder order2_ on orders1_.orders_id=order2_.id inner join CustomerOrder_Item items3_ on order2_.id=items3_.Order_id inner join Item item4_ on items3_.items_id=item4_.id cross join ShipmentInfo shipmentin5_ cross join Address address6_ where customer0_.shipmentInfo_id=shipmentin5_.id and shipmentin5_.address_id=address6_.id and address6_.state=?
Item{id=5, name='Desktop', price=621.00}
Item{id=6, name='Monitor', price=530.00}
Item{id=7, name='SSD', price=733.00}
Item{id=8, name='Keyboard', price=464.00}

The equivalent JPQL of above example will be:

public class ExampleMain2 {
  private static EntityManagerFactory entityManagerFactory =
          Persistence.createEntityManagerFactory("example-unit");

  public static void main(String[] args) {
      try {
          persistCustomers();
          findOrderItems();
      } finally {
          entityManagerFactory.close();
      }
  }

  public static void persistCustomers() {
      EntityManager em = entityManagerFactory.createEntityManager();
      em.getTransaction().begin();
      Customers.getCustomers().forEach(em::persist);
      em.getTransaction().commit();

      System.out.println("-- Customers persisted --");
      CriteriaBuilder cb = em.getCriteriaBuilder();
      CriteriaQuery<Customer> query = cb.createQuery(Customer.class);
      query.select(query.from(Customer.class));
      em.createQuery(query).getResultList().forEach(System.out::println);
      em.close();
  }

  private static void findOrderItems() {
      System.out.println("-- find order items placed from state NJ using JPQL --");
      EntityManager em = entityManagerFactory.createEntityManager();
      TypedQuery<Item> query = em.createQuery("Select itm from Customer c"
              + " JOIN c.orders o JOIN o.items itm where"
              + "  c.shipmentInfo.address.state = 'NJ'", Item.class);
      query.getResultList()
           .forEach(System.out::println);
  }
}
-- Customers persisted --
Hibernate: select customer0_.id as id1_1_, customer0_.name as name2_1_, customer0_.shipmentInfo_id as shipment3_1_ from Customer customer0_
Customer{id=1, name='Mike', orders=[Order{id=4, date=2017-03-14, items=[Item{id=5, name='Desktop', price=689}, Item{id=6, name='Monitor', price=541}, Item{id=7, name='SSD', price=787}, Item{id=8, name='Keyboard', price=749}]}], shipmentInfo=ShipmentInfo{id=2, phone='908399', address=com.logicbig.example.Address@2b87581}}
Customer{id=9, name='Sara', orders=[Order{id=12, date=2017-04-15, items=[Item{id=13, name='Backpack', price=472}, Item{id=14, name='Lamp', price=241}, Item{id=15, name='Saucepan', price=284}, Item{id=16, name='Food Processor', price=255}]}], shipmentInfo=ShipmentInfo{id=10, phone='735346', address=com.logicbig.example.Address@61d01788}}
Customer{id=17, name='Charlie', orders=[Order{id=20, date=2017-10-05, items=[Item{id=21, name='Chivas', price=500}, Item{id=22, name='Merlot', price=315}, Item{id=23, name='Sapphire', price=696}, Item{id=24, name='Johnnie', price=437}]}], shipmentInfo=ShipmentInfo{id=18, phone='692075', address=com.logicbig.example.Address@56ccd751}}
-- find order items placed from state NJ using JPQL --
Hibernate: select item4_.id as id1_5_, item4_.name as name2_5_, item4_.price as price3_5_ from Customer customer0_ inner join Customer_CustomerOrder orders1_ on customer0_.id=orders1_.Customer_id inner join CustomerOrder order2_ on orders1_.orders_id=order2_.id inner join CustomerOrder_Item items3_ on order2_.id=items3_.Order_id inner join Item item4_ on items3_.items_id=item4_.id cross join ShipmentInfo shipmentin5_ cross join Address address6_ where customer0_.shipmentInfo_id=shipmentin5_.id and shipmentin5_.address_id=address6_.id and address6_.state='NJ'
Item{id=5, name='Desktop', price=689.00}
Item{id=6, name='Monitor', price=541.00}
Item{id=7, name='SSD', price=787.00}
Item{id=8, name='Keyboard', price=749.00}

As seen in outputs, in both of above cases the same select statement was executed by Hibernate to find 'items'.

Example Project

Dependencies and Technologies Used:

  • h2 1.4.197: H2 Database Engine.
  • hibernate-core 5.3.5.Final: Hibernate's core ORM functionality.
    Implements javax.persistence:javax.persistence-api version 2.2
  • hibernate-jpamodelgen 5.3.5.Final: Annotation Processor to generate JPA 2 static metamodel classes.
  • JDK 1.8
  • Maven 3.5.4

Path Navigation Example Select All Download
  • jpa-criteria-api-path-navigation
    • src
      • main
        • java
          • com
            • logicbig
              • example
                • ExampleMain.java
          • resources
            • META-INF

    See Also