In JPA Criteria API the map relations can be accessed via MapJoin interface.
Following are two of the various methods of From interface (extended by Root interface) which can be used to obtain MapJoin instance:
MapJoin<X, K, V> join(MapAttribute<? super X, K, V> mapAttribute);
MapJoin<X, K, V> joinMap(String mapAttributeName);
Following is MapJoin interface snippet:
package javax.persistence.criteria;
....
public interface MapJoin<Z, K, V> extends PluralJoin<Z, Map<K, V>, V> {
MapJoin<Z, K, V> on(Expression<Boolean> var1);
MapJoin<Z, K, V> on(Predicate... var1);
MapAttribute<? super Z, K, V> getModel();
Path<K> key();
Path<V> value();
Expression<Entry<K, V>> entry();
}
Quick Example:
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<Tuple> query = criteriaBuilder.createTupleQuery();
Root<Customer> customer = query.from(Customer.class);
MapJoin<Customer, String, Order> orderMap = customer.join(Customer_.orderMap);
query.multiselect(customer.get(Customer_.name), orderMap.key(),
orderMap.value().get(Order_.item), orderMap.value().get(Order_.qty));
TypedQuery<Tuple> typedQuery = entityManager.createQuery(query);
List<Tuple> list = typedQuery.getResultList();
Example
Entities
In following example we are not using Hibernate as it has a bug while using MapJoin#entry (HHH-12945). we are, instead, going to use EclipseLink as JPA provider.
@Entity
public class Customer {
@Id
@GeneratedValue
private int id;
private String name;
@OneToMany(cascade = CascadeType.ALL)
private Map<String, Order> orderMap;//orderType to Order map
.............
public void addOrder(String orderType, String itemName, int qty) {
if (orderMap == null) {
orderMap = new HashMap<>();
}
Order order = new Order();
order.setItem(itemName);
order.setQty(qty);
orderMap.put(orderType, order);
}
.............
}
@Entity
@Table(name="CustomerOrder")
public class Order {
@Id
@GeneratedValue
private long id;
private String item;
private int qty;
.............
}
Using MapJoin
public class ExampleMain {
public static void main(String[] args) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("example-unit");
try {
persistEntity(emf);
findItemQty(emf);
findOrderMapEntry(emf);
} finally {
emf.close();
}
}
private static void persistEntity(EntityManagerFactory emf) {
System.out.println("-- Persisting entities --");
EntityManager em = emf.createEntityManager();
Customer c1 = new Customer();
c1.setName("Lindsey Craft");
c1.addOrder("online", "XYZ Blender", 2);
c1.addOrder("store", "ZZZ Beer Glass", 4);
System.out.println(c1);
Customer c2 = new Customer();
c2.setName("Morgan Philips");
c2.addOrder("online", "AA Glass Cleaner", 3);
System.out.println(c2);
em.getTransaction().begin();
em.persist(c1);
em.persist(c2);
em.getTransaction().commit();
em.close();
}
private static void findItemQty(EntityManagerFactory emf) {
System.out.println("-- Finding items and keys --");
EntityManager entityManager = emf.createEntityManager();
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<Tuple> query = criteriaBuilder.createTupleQuery();
Root<Customer> customer = query.from(Customer.class);
MapJoin<Customer, String, Order> orderMap = customer.join(Customer_.orderMap);
query.multiselect(customer.get(Customer_.name), orderMap.key(),
orderMap.value().get(Order_.item), orderMap.value().get(Order_.qty));
TypedQuery<Tuple> typedQuery = entityManager.createQuery(query);
typedQuery.getResultList().forEach(
t -> System.out.printf("Customer: %s, Order-Type: %s, Order-item: %s, Order-qty: %s%n",
t.get(0), t.get(1), t.get(2), t.get(3)));
}
private static void findOrderMapEntry(EntityManagerFactory emf) {
System.out.println("-- Finding orderType/order entries --");
EntityManager entityManager = emf.createEntityManager();
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<Map.Entry> query = criteriaBuilder.createQuery(Map.Entry.class);
Root<Customer> customer = query.from(Customer.class);
MapJoin<Customer, String, Order> orderMap = customer.join(Customer_.orderMap);
query.select(orderMap.entry());
TypedQuery<Map.Entry> typedQuery = entityManager.createQuery(query);
typedQuery.getResultList()
.forEach(entry -> {System.out.printf("%s = %s%n", entry.getKey(), entry.getValue());});
}
} -- Persisting entities -- Customer{id=0, name='Lindsey Craft', orderMap={online=Order{id=0, item='XYZ Blender', qty=2}, store=Order{id=0, item='ZZZ Beer Glass', qty=4}}} Customer{id=0, name='Morgan Philips', orderMap={online=Order{id=0, item='AA Glass Cleaner', qty=3}}} -- Finding items and keys -- Customer: Morgan Philips, Order-Type: online, Order-item: AA Glass Cleaner, Order-qty: 3 Customer: Lindsey Craft, Order-Type: online, Order-item: XYZ Blender, Order-qty: 2 Customer: Lindsey Craft, Order-Type: store, Order-item: ZZZ Beer Glass, Order-qty: 4 -- Finding orderType/order entries -- online = Order{id=5, item='AA Glass Cleaner', qty=3} online = Order{id=2, item='XYZ Blender', qty=2} store = Order{id=3, item='ZZZ Beer Glass', qty=4}
See also how to do the same thing in JPQL.
Example ProjectDependencies and Technologies Used: - h2 1.4.197: H2 Database Engine.
- eclipselink 2.6.5: EclipseLink build based upon Git transaction b3d05bd.
Related JPA version: org.eclipse.persistence:javax.persistence version 2.1.1 - org.eclipse.persistence.jpa.modelgen.processor 2.6.5: EclipseLink build based upon Git transaction b3d05bd.
- JDK 1.8
- Maven 3.5.4
|
|