EclipseLink – 23 – Criteria API – 01– Select

Merhaba Arkadaslar
Onceki bolumlerde JPQL konusunu inceledik , boylelikle JPQL kullanarak nasil sorgular yazabilecegimizi incelemis olduk. Aslina bakarsak JPQL , SQL ile son derece benzerlik gostermekteydi. Bir diger yaklasim olarak Query olusturmak icin kullanacagimiz yontem Criteria API yaklasimidir. Criteria API , JPA 2.0 versiyonuyla birlikte gelen bir ozelliktir.

Hello JPA Criteria API

Criteria API’yi en temel JPQL query uzerinden inceleyemeye baslayabiliriz. Tum Employee kayitlarini getirdigimiz JPQL sorgumuzu hatirlayalim ;

SELECT e from Employee31 e;

JPQL sorgumuzu Criteria API kullanarak yapmak istersek ;

@Override
public List<Employee31> getAllEmployees() {
    CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
    CriteriaQuery<Employee31> criteriaQuery = criteriaBuilder.createQuery(Employee31.class);
    Root<Employee31> empRoot = criteriaQuery.from(Employee31.class);
    criteriaQuery.select(empRoot); 
    TypedQuery<Employee31> query = entityManager.createQuery(criteriaQuery); 
    return query.getResultList();
}
  • Oncelikle EntityManager objemizi kullanarak CriteriaBuilder objemizi olusturuyoruz.
    CriteriaBuilder arabirimi , Criteria API icin ana kapidir (main gateway) , kalbi konumundadir.
    CriteriaBuilder  objesini EntityManager objesi uzerinden getCriteriaBuilder metodunu cagirarak elde ederiz (obtain)
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
  • javax.persistence.criteria.CriteriaBuilder arabirimin sorgular/query icin 3 tane metot destekler.CriteriaQuery IS-A Query degildir! CriteriaQuery , AbstractQuery arabirimini kalitmaktadir , AbstractQuery de CommonAbstractCriteria arabirimini kalitmaktadir.
CriteriaQuery<Object> createQuery();
<T> CriteriaQuery<T> createQuery(Class<T> resultClass);
CriteriaQuery<Tuple> createTupleQuery();
CriteriaQuery<Employee31> criteriaQuery = criteriaBuilder.createQuery(Employee31.class);
  • Daha sonrasinda CriteriaQuery objesi uzerinden from metodunu kullaniyoruz. Geriye Root objesi donmektedir. root of query yani sorgunun cikis noktasi/kok dizini olarak isimlendirebilecegimiz Root objesini from metodunu cagirarak elde ederiz.Root arabirimi , From arabirimini kalitmaktadir. From arabirimi de Path arabirimini kalitmaktadir. Hiyerarsiyi inceleyecek olursak ;
public interface Root<X> extends From<X, X> { //}
public interface From<Z, X> extends Path<X>, FetchParent<Z, X> { //}
public interface Path<X> extends Expression<X> { // }
public interface Expression<T> extends Selection<T> { // }
public interface Selection<X> extends TupleElement<X> { // }
public interface TupleElement<X> { // }
<X> Root<X> from(Class<X> entityClass);
  • Daha sonrasinda CriteriaQuery instance’i uzerinden select metodunu cagiriyoruz ve arguman olarak javax.persistence.criteria.Root objesini veriyoruz.
  • Son olarak onceki orneklerimizde oldugu gibi EntityManager uzerinden createQuery metodunu kullaniyoruz ve arguman olarak String JPQL ifadesi yerine CriteriaQuery objesini arguman olarak veriyoruz ve geriye getResultList metodunu kullanarak List sonucunu donuyoruz.
TypedQuery<Employee31> query = entityManager.createQuery(criteriaQuery); 
     return query.getResultList();

CriteriaAPITest.java

System.out.println("getAllEmployees");
List<Employee31> allEmployees=jpqlService.getAllEmployees();
for(Employee31 emp : allEmployees){
    System.out.println(emp);
}

Ornegimizi calistirdigimizda ;

getAllEmployees
Employee31 [id=1, name=John, surname=Robbins, salary=55000]
Employee31 [id=2, name=Rob, surname=Freeman, salary=53000]
Employee31 [id=3, name=Peter, surname=Gunton, salary=40000]
Employee31 [id=4, name=Frank, surname= Sadler, salary=41000]
Employee31 [id=5, name=Scott, surname=Brown, salary=60000]
Employee31 [id=6, name=Rod , surname=Johnson , salary=62000]
Employee31 [id=7, name=Sue, surname=Bellows, salary=54000]
Employee31 [id=8, name=Stephanie, surname=Whitmore, salary=45000]
Employee31 [id=9, name=Jennifer, surname=Libby, salary=52000]
Employee31 [id=10, name=Sarah, surname=Proval, salary=59000]
Employee31 [id=11, name=Marcus, surname=Ragno, salary=35000]
Employee31 [id=12, name=Joe, surname=Hatlen, salary=36000]
Employee31 [id=13, name=Jack, surname=Snooze, salary=43000]

Selecting Single Expressions

Eger sadece Employee’lere ait name alanini getirmek istiyorsak bu durumda JPQL ifademizi su sekilde yazabiliriz ;

Select DISTINCT e.name from Employee31 e

Criteria API kullandigimizda su sekilde yazabiliriz. Burada dikkat edecegimiz nokta empRoot.get metodunu name alanini getirmek icin kullaniyoruz.
Ikinci nokta olarak distinct(true) metodunu kullanarak sorgu icin distinct keywordunu eklemis oluruz.

@Override
public List<String> getEmployeesName() {
    CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
    CriteriaQuery<String> criteriaQuery = criteriaBuilder.createQuery(String.class);
    Root<Employee31> empRoot = criteriaQuery.from(Employee31.class);
    criteriaQuery.select(empRoot.get("name")).distinct(true);
    TypedQuery<String> query = entityManager.createQuery(criteriaQuery);
    return query.getResultList();
}
System.out.println("getEmployeesName");
List<String> allEmployeeNames= jpqlService.getEmployeesName(); 
for(String empName:allEmployeeNames){
    System.out.println(empName);
}

Ornegimizi calistirdigimizda;

getEmployeesName
Peter
Joe
John
Frank
Sue
Stephanie
Marcus
Jack
Sarah
Rob
Scott
Jennifer
Rod 

Selecting Multiple Expressions

Employee Entity icin salary ve name alanlarini getirmek istersek ;

Select e.name , e.salary , e.department.name FROM Employee e

JPQL ifadesi bir kac yontem kullanarak Criteria API icin uygun formata donusturebiliriz.
Burada onemli nokta ;

  • CriteriaQuery icin javax.persistence.Tuple arabirimini kullaniyoruz. Tuple cok ogeli anlamina gelmektedir.
  • Bir diger nokta olarak select metodu icerinde criteriaBuilder.tuple metodunu kullaniyoruz.
    empRoot objesi uzerinden get metodunu kullanarak name ve salary ifadesini getiriyoruz. Dikkat edecek olursak deparment ifadesini getirdikten sonra tekrar get metodunu kullaniyoruz ve department’a ait name bilgisini getiriyoruz.
@Override
public List<Tuple> getEmployeesDeptSalary() {
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<Tuple> criteriaQuery = criteriaBuilder.createQuery(Tuple.class); 
Root<Employee31> empRoot = criteriaQuery.from(Employee31.class);
criteriaQuery.select(criteriaBuilder.tuple(empRoot.get("name"), empRoot.get("salary"),empRoot.get("department").get("name")));
TypedQuery<Tuple> query = entityManager.createQuery(criteriaQuery);
return query.getResultList();
}

Geriye List<Tuple> donmustuk.  Tuple objesi uzerinden get metodunu kullanarak ilgili alanlara erisim sagliyoruz.

System.out.println("getEmployeesDeptSalary");
List<Tuple> allEmployeesDeptSalary= jpqlService.getEmployeesDeptSalary(); 
for(Tuple tp : allEmployeesDeptSalary){
    System.out.println(tp.get(0) + " " + tp.get(1) +" "+ tp.get(2));
}

Ornegimizi calistirdigimizda ;

getEmployeesDeptSalary
John 55000 QA
Rob 53000 QA
Peter 40000 QA
Frank 41000 Engineering
Scott 60000 Engineering
Rod  62000 Engineering
Sue 54000 Engineering
Stephanie 45000 Engineering
Jennifer 52000 QA
Sarah 59000 Engineering
Marcus 35000 Accounting

Bir baska yaklasim olarak createTupleQuery metodunu kullanabiliriz. Bu metod geriye CriteriaQuery<Tuple> objesi donmektedir. Dolayisiyla createQuery(Tuple.class) metodu ile ayni anlama gelecektir.
Bir diger nokta olarak select metodu icerisinde tuple metodunu cagirmak yerine CriteriaQuery de yer alan multiselect metodunu kullanabiliriz.

CompoundSelection<Tuple> tuple(Selection<?>... selections);
CriteriaQuery<T> multiselect(Selection<?>... selections);
@Override
public List<Tuple> getEmployeesDeptSalaryV2() {
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<Tuple> criteriaQuery = criteriaBuilder.createTupleQuery();
Root<Employee31> empRoot = criteriaQuery.from(Employee31.class);
criteriaQuery.multiselect(empRoot.get("name"), empRoot.get("salary"), empRoot.get("department").get("name"));
TypedQuery<Tuple> query = entityManager.createQuery(criteriaQuery);
return query.getResultList();
}

CriteriaApiTest.java

System.out.println("getEmployeesDeptSalaryV2");
List<Tuple> allEmployeesNameAndSalary = jpqlService.getEmployeesDeptSalaryV2();
for (Tuple tp : allEmployeesNameAndSalary) {
    System.out.println(tp.get(0) + " " + tp.get(1) + " " + tp.get(2));
}

JPQL de Constructor Expressions kullanmistik. Benzer sekilde bir yapiyi Criteria API icin uygulayalim ;

EmployeeDetails.java

public class EmployeeDetails {

	private String name;
	private int salary;
	private String departmentName;

	public EmployeeDetails(String name, int salary, String departmentName) {
		super();
		this.name = name;
		this.salary = salary;
		this.departmentName = departmentName;
	}
...
}

Dikkat edecek olursak createQuery(EmployeeDetails.class) olarak kullandik. Burada dilersek multiselect metodunu kullanabiliriz.
Ya da select metodu icerisinde construct metodunu kullanabiliriz. EmployeeDetails.class literalini arguman olarak verdikten sonra EmployeeDetails sinifinda tanimladigimiz yapilandiriciya uygun sekilde ifadeleri sirasiyla yaziyoruz.

@Override
public List<EmployeeDetails> getEmployeeDetails() {
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<EmployeeDetails> criteriaQuery = criteriaBuilder.createQuery(EmployeeDetails.class);
Root<Employee31> empRoot = criteriaQuery.from(Employee31.class);

// criteriaQuery.multiselect(empRoot.get("name"), empRoot.get("salary"),
// empRoot.get("department").get("name"));
 
criteriaQuery.select(criteriaBuilder.construct(EmployeeDetails.class, empRoot.get("name"),
empRoot.get("salary"), empRoot.get("department").get("name")));
TypedQuery<EmployeeDetails> query = entityManager.createQuery(criteriaQuery);
return query.getResultList();
}

CriteriaApiTest.java

System.out.println("getEmployeeDetails");
List<EmployeeDetails> allEmployeeDetails = jpqlService.getEmployeeDetails();
for (EmployeeDetails empDetails : allEmployeeDetails) {
    System.out.println(empDetails.getName() + " " + empDetails.getSalary() + " "
    + empDetails.getDepartmentName());
}

Bu uc ornegimiz de bize ayni sonucu verecektir;

getEmployeeDetails
John 55000 QA
Rob 53000 QA
Peter 40000 QA
Frank 41000 Engineering
Scott 60000 Engineering
Rod  62000 Engineering
Sue 54000 Engineering
Stephanie 45000 Engineering
Jennifer 52000 QA
Sarah 59000 Engineering
Marcus 35000 Accounting

Kaynak kodlar : Injavawetrust.jpa
Yazimi burada sonlandiriyorum.
Herkese Bol Javali Gunler dilerim.
Be an oracle man , import java.*;
Levent Erguder
OCP, Java SE 6 Programmer
OCE, Java EE 6 Web Component Developer

Print Friendly, PDF & Email

Leave a Reply

Your email address will not be published. Required fields are marked *