In Criteria API, downcasting an entity to a subclass entity can be performed by using one of the CriteriaBuilder.treat() methods:
package javax.persistence.criteria;
.....
public interface CriteriaBuilder {
.....
// methods for downcasting:
<X, T, V extends T> Join<X, V> treat(Join<X, T> join, Class<V> type);
<X, T, E extends T> CollectionJoin<X, E> treat(CollectionJoin<X, T> join, Class<E> type);
<X, T, E extends T> SetJoin<X, E> treat(SetJoin<X, T> join, Class<E> type);
<X, T, E extends T> ListJoin<X, E> treat(ListJoin<X, T> join, Class<E> type);
<X, K, T, V extends T> MapJoin<X, K, V> treat(MapJoin<X, K, T> join, Class<V> type);
<X, T extends X> Path<T> treat(Path<X> path, Class<T> type);
<X, T extends X> Root<T> treat(Root<X> root, Class<T> type);
}
Quick Example (where PartTimeEmployee and ContractEmployee are the subclasses of Employee):
CriteriaQuery<Employee> query = criteriaBuilder.createQuery(Employee.class);
Root<Employee> employee = query.from(Employee.class);
Root<PartTimeEmployee> partTimeEmployee = criteriaBuilder.treat(employee, PartTimeEmployee.class);
Root<ContractEmployee> contractEmployee = criteriaBuilder.treat(employee, ContractEmployee.class);
query.select(partTimeEmployee)
.distinct(true)
.where(criteriaBuilder.or(
criteriaBuilder.greaterThan(partTimeEmployee.get(PartTimeEmployee_.weeklySalary), 1000),
criteriaBuilder.lessThan(contractEmployee.get(ContractEmployee_.hourlyRate), 75)
));
TypedQuery<Employee> typedQuery = entityManager.createQuery(query);
List<Employee> employees = typedQuery.getResultList();
Example
Entities
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@Entity
@DiscriminatorColumn(name = "EMP_TYPE")
public class Employee {
@Id
@GeneratedValue
private long id;
private String name;
.............
}
@Entity
@DiscriminatorValue("F")
public class FullTimeEmployee extends Employee {
private int annualSalary;
.............
}
@Entity
@DiscriminatorValue("P")
public class PartTimeEmployee extends Employee {
private int weeklySalary;
.............
}
@Entity
@DiscriminatorValue("C")
public class ContractEmployee extends Employee {
private int hourlyRate;
.............
}
@Entity
public class Project {
@Id
@GeneratedValue
private long id;
private String name;
@OneToMany(cascade = CascadeType.ALL)
private List<Employee> employees;
@OneToOne(cascade = CascadeType.ALL)
private Employee supervisor;
.............
}
Using CriteriaBuilder.treat() methods
public class ExampleMain {
public static void main(String[] args) throws Exception {
EntityManagerFactory emf =
Persistence.createEntityManagerFactory("example-unit");
try {
persistEntities(emf);
getByPartTimeEmployeesWeeklySalary(emf);
getByPartTimeAndContractEmployeesBySalary(emf);
getProjectByFullTimeEmployeesSalary(emf);
getProjectBySupervisorPartTimeSalary(emf);
} finally {
emf.close();
}
}
//using method: Root<T> treat(Root<X> root, Class<T> type);
private static void getByPartTimeEmployeesWeeklySalary(EntityManagerFactory emf) {
System.out.println("-- employees where PartTimeEmployee.weeklySalary < 1000 --");
EntityManager entityManager = emf.createEntityManager();
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<Employee> query = criteriaBuilder.createQuery(Employee.class);
Root<Employee> employee = query.from(Employee.class);
Root<PartTimeEmployee> partTimeEmployee = criteriaBuilder.treat(employee, PartTimeEmployee.class);
query.select(partTimeEmployee)
.distinct(true)
.where(criteriaBuilder.lessThan(partTimeEmployee.get(PartTimeEmployee_.weeklySalary), 1000));
TypedQuery<Employee> typedQuery = entityManager.createQuery(query);
List<Employee> employees = typedQuery.getResultList();
employees.forEach(System.out::println);
entityManager.close();
}
//using method: Root<T> treat(Root<X> root, Class<T> type);
private static void getByPartTimeAndContractEmployeesBySalary(EntityManagerFactory emf) {
System.out.println("-- employees where PartTimeEmployee.weeklySalary > 1000 or "
+ "ContractEmployee#hourlyRate < 75 --");
EntityManager entityManager = emf.createEntityManager();
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<Employee> query = criteriaBuilder.createQuery(Employee.class);
Root<Employee> employee = query.from(Employee.class);
Root<PartTimeEmployee> partTimeEmployee = criteriaBuilder.treat(employee, PartTimeEmployee.class);
Root<ContractEmployee> contractEmployee = criteriaBuilder.treat(employee, ContractEmployee.class);
query.select(partTimeEmployee)
.distinct(true)
.where(criteriaBuilder.or(
criteriaBuilder.greaterThan(partTimeEmployee.get(PartTimeEmployee_.weeklySalary), 1000),
criteriaBuilder.lessThan(contractEmployee.get(ContractEmployee_.hourlyRate), 75)
));
TypedQuery<Employee> typedQuery = entityManager.createQuery(query);
List<Employee> employees = typedQuery.getResultList();
employees.forEach(System.out::println);
entityManager.close();
}
//using method: ListJoin<X, E> treat(ListJoin<X, T> join, Class<E> type)
private static void getProjectByFullTimeEmployeesSalary(EntityManagerFactory emf) {
System.out.println("-- getting projects where any FullTimeEmployee.annualSalary > 100000 by using join --");
EntityManager entityManager = emf.createEntityManager();
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<Project> query = criteriaBuilder.createQuery(Project.class);
Root<Project> project = query.from(Project.class);
ListJoin<Project, Employee> employees = project.join(Project_.employees);
ListJoin<Project, FullTimeEmployee> fullTimeEmployee = criteriaBuilder.treat(employees, FullTimeEmployee.class);
query.select(project)
.distinct(true)
.where(criteriaBuilder.greaterThan(fullTimeEmployee.get(FullTimeEmployee_.annualSalary), 100000));
TypedQuery<Project> typedQuery = entityManager.createQuery(query);
List<Project> projects = typedQuery.getResultList();
projects.forEach(System.out::println);
entityManager.close();
}
//using method: Path<T> treat(Path<X> path, Class<T> type);
private static void getProjectBySupervisorPartTimeSalary(EntityManagerFactory emf) {
System.out.println("-- Projects where ((PartTimeEmployee)Project.supervisor).weeklySalary > 1000 --");
EntityManager entityManager = emf.createEntityManager();
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<Project> query = criteriaBuilder.createQuery(Project.class);
Root<Project> project = query.from(Project.class);
Path<Employee> supervisor = project.get(Project_.supervisor);
Path<PartTimeEmployee> partTimeSupervisor = criteriaBuilder.treat(supervisor, PartTimeEmployee.class);
query.select(project)
.where(criteriaBuilder.greaterThan(partTimeSupervisor.get(PartTimeEmployee_.weeklySalary), 1000));
TypedQuery<Project> typedQuery = entityManager.createQuery(query);
List<Project> projects = typedQuery.getResultList();
projects.forEach(System.out::println);
entityManager.close();
}
private static void persistEntities(EntityManagerFactory emf) throws Exception {
System.out.println("-- Persisting entities --");
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
for (Project project : createProjects()) {
em.persist(project);
System.out.println(project);
}
em.getTransaction().commit();
}
private static List<Project> createProjects() {
List<Project> projects = new ArrayList<>();
FullTimeEmployee e1 = new FullTimeEmployee();
e1.setName("Sara");
e1.setAnnualSalary(120000);
PartTimeEmployee e2 = new PartTimeEmployee();
e2.setName("Jon");
e2.setWeeklySalary(900);
ContractEmployee e3 = new ContractEmployee();
e3.setName("Tom");
e3.setHourlyRate(60);
PartTimeEmployee supervisor1 = new PartTimeEmployee();
supervisor1.setName("Tina");
supervisor1.setWeeklySalary(1300);
projects.add(Project.create(supervisor1, "Trade UI", e1, e2, e3));
FullTimeEmployee e4 = new FullTimeEmployee();
e4.setName("Mike");
e4.setAnnualSalary(80000);
PartTimeEmployee e5 = new PartTimeEmployee();
e5.setName("Jackie");
e5.setWeeklySalary(1200);
ContractEmployee e6 = new ContractEmployee();
e6.setName("Aly");
e6.setHourlyRate(90);
PartTimeEmployee supervisor2 = new PartTimeEmployee();
supervisor2.setName("Trish");
supervisor2.setWeeklySalary(900);
projects.add(Project.create(supervisor2, "Broker UI", e4, e5, e6));
return projects;
}
} -- Persisting entities -- Project{id=1, name='Trade UI', supervisor= PartTimeEmployee{id=2, name='Tina', weeklySalary=1300}, employees=[FullTimeEmployee{id=3, name='Sara', annualSalary=120000}, PartTimeEmployee{id=4, name='Jon', weeklySalary=900}, ContractEmployee{id=5, name='Tom', hourlyRate='60'}]} Project{id=6, name='Broker UI', supervisor= PartTimeEmployee{id=7, name='Trish', weeklySalary=900}, employees=[FullTimeEmployee{id=8, name='Mike', annualSalary=80000}, PartTimeEmployee{id=9, name='Jackie', weeklySalary=1200}, ContractEmployee{id=10, name='Aly', hourlyRate='90'}]} -- employees where PartTimeEmployee.weeklySalary < 1000 -- PartTimeEmployee{id=4, name='Jon', weeklySalary=900} PartTimeEmployee{id=7, name='Trish', weeklySalary=900} -- employees where PartTimeEmployee.weeklySalary > 1000 or ContractEmployee#hourlyRate < 75 -- PartTimeEmployee{id=2, name='Tina', weeklySalary=1300} PartTimeEmployee{id=9, name='Jackie', weeklySalary=1200} ContractEmployee{id=5, name='Tom', hourlyRate='60'} -- getting projects where any FullTimeEmployee.annualSalary > 100000 by using join -- Project{id=1, name='Trade UI', supervisor= PartTimeEmployee{id=2, name='Tina', weeklySalary=1300}, employees=[FullTimeEmployee{id=3, name='Sara', annualSalary=120000}, PartTimeEmployee{id=4, name='Jon', weeklySalary=900}, ContractEmployee{id=5, name='Tom', hourlyRate='60'}]} -- Projects where ((PartTimeEmployee)Project.supervisor).weeklySalary > 1000 -- Project{id=1, name='Trade UI', supervisor= PartTimeEmployee{id=2, name='Tina', weeklySalary=1300}, employees=[FullTimeEmployee{id=3, name='Sara', annualSalary=120000}, PartTimeEmployee{id=4, name='Jon', weeklySalary=900}, ContractEmployee{id=5, name='Tom', hourlyRate='60'}]}
Example ProjectDependencies and Technologies Used: - hibernate-core 5.3.7.Final: Hibernate's core ORM functionality.
Implements javax.persistence:javax.persistence-api version 2.2 - hibernate-jpamodelgen 5.3.7.Final: Annotation Processor to generate JPA 2 static metamodel classes.
- h2 1.4.197: H2 Database Engine.
- JDK 1.8
- Maven 3.5.4
|
|