EclipseLink – 18 – Query – 01

Merhaba Arkadaslar

JPA , veritabanindan kayitlarin/entity getirilmesi icin 2 yaklasim sunar. Birincisi Query yaklasimi ikincisi Criteria API yaklasimidir.

Query yaklasiminda temel olarak JPQL kullanilir bununla birlikte SQL de kullanilabilir.
Burada ilk olarak JPQL a giris yapacagiz , sonrasinda biraz daha detayli olacak sekilde JPQL e devam edecegiz. JPQL den sonra Criteria API konusuna gecis yapacagiz.

JPQL (Java Persistence Query Language)

En basit JPQL query’imiz ;

Select e from Employee e

Dikkat edecek olursak JPQL bildigimiz SQL ‘e benzemektedir. Burada dikkat etmemiz gereken nokta Employee tablo adi degil Entity adidir. Yani Employee yerine employee yazarsak bu SQL icin sorun teskil etmezken JPQL icin sorun teskil edecektir.

Yani SQL de sorgu tabloya yapilirken JPQL icin sorgu Entity icindir.
Burada tek bir entity tipine ait (Employee) tum objeler/instance getirilmektedir.

JPA , sorgulari/query calistirmak icin Query ve TypedQuery arabirimleri kullanir. TypedQuery , Query interface’ini kalitmaktadir. TypedQuery ‘i kullandigimizda generic yapi kullanabiliriz.

public interface TypedQuery<X> extends Query { ... }

EmployeeServiceImpl.java

...
@Override
public List findAllEmployees() {
	//Query query = entityManager.createQuery("Select e from Employee27 e", Employee27.class);
	TypedQuery<Employee27> query = entityManager.createQuery("Select e from Employee27 e", Employee27.class);
	return query.getResultList();

}
...

Eger sadece Employee’lere ait name alanini getirmek istiyorsak bu durumda ;

Select e.name from Employee e
@Override
public List<String> getEmployeeNames() {		
	TypedQuery<Employee27> query = entityManager.createQuery("Select e.name from Employee27 e", String.class);
	return query.getResultList();
}

Query Parameters

JPQL iki tip query parameter binding destegi saglar. Birincisi JDBC query parameter destegine benzer sekilde calisir. (Positional Binding)

@Override
public String getEmployeeNameById(int id) {

	TypedQuery<String> query = entityManager.createQuery("Select e.name from Employee27 e where e.id= ?1",
			 String.class).setParameter(1, id);
	return query.getSingleResult();
}

Query parameter ?1 ?2 seklinde kullanilir ve setParameter metodu ile ilgili query parameter sorguya dahil edilebilir.

Bir diger nokta olarak getSingleResult() , getResultList() metodunun aksine bir List  donmez.
Typed<X> generic yapisinda tanimladigimiz tip donus tipi olacaktir ve sorgu sonucu tek bir sonuc donecektir. getSingleResult metodu kullanildiginda eger sonuc bulamazsa exception firlatilir.

javax.persistence.NoResultException: getSingleResult() did not retrieve any entities.

Ya da bir den fazla sonuc bulunduysa bu durumda yine exception firlatacaktir.
Tabi burada id sonucuna gore unique olacaktir fakat asagidaki orneklerde “name” alanina gore sorguladigimiz metotta yine getSingleResult metodunu kullanacagiz , bu durumda ayni isimli Employee oldugunca exception firlatacaktir.

javax.persistence.NonUniqueResultException: More than one result was returned from Query.getSingleResult()
X getSingleResult();
List<X> getResultList();

Ikinci yaklasim olarak Spring NamedParameterJdbcTemplate’te oldugu gibi 2nokta ve parametre adi seklinde kullanabiliriz. (Named Parameter)

@Override
public String getEmployeeNameById(int id) {

	// TypedQuery<String> query =
	// entityManager.createQuery("Select e.name from Employee27 e where e.id= ?1",
	// String.class).setParameter(1, id);

	TypedQuery<String> query = entityManager.createQuery("Select e.name from Employee27 e where e.id= :empId",
			String.class).setParameter("empId", id);
	return query.getSingleResult();
}

:empId olarak bir parametre ismi verdik. setParameter metodunda bu verdigimiz parametre ismiyle eslesecek sekilde empId ismini verdik.

Defining Queries

JPQL query’leri icin 3 tip yaklasim vardir.

  • Dynamic Query
  • Named Query
  • Dynamic Named Query

Dynamic Query
Dynamic Query yaklasimi simdiye kadar inceledigimiz query yaklasimidir. EntityManager’da yer alan createQuery metodu ile olusturdugumuz query calistirmaktayiz.

Dynamic Query yaklasiminda her zaman parameter kullanilmalidir. Aksi durumda SQL Injection’a acik olacaktir.

@Override
public int getEmployeeSalaryByName(String name) {
	TypedQuery<Integer> query = entityManager.createQuery("Select e.salary from Employee27 e where e.name= " + name,
			Integer.class);
	return query.getSingleResult();
}

Ornegin yukaridaki kod malicious kodlara aciktir . Ornegin kullanici tarafindan bir input alanina yazilan degere gore sorgu yapildigini dusunursek kod icerisinde SQL sorgusuna OR gibi bir SQL kodu eklemek mumkun olabilir.

int salary=employeeService.getEmployeeSalaryByName("'XXXX' OR e.name='James' ");
@Override
public int getEmployeeSalaryByName(String name) {
//		TypedQuery<Integer> query = entityManager.createQuery("Select e.salary from Employee27 e where e.name= " + name,
//				Integer.class);

	TypedQuery<Integer> query = entityManager.createQuery(
			"Select e.salary from Employee27 e where e.name=:nameParam", Integer.class).setParameter("nameParam",
			name);
	return query.getSingleResult();
}

setParameter metodunu kullandigimizda durumda malicious kodlar engellenecektir.

Named Query
Named Query’ler @NamedQueries ve @NamedQuery annotation’i kullanilarak tanimlanir.
@NamedQuery ve @NamedQueries annotation’larini entity sinif deklarasyonunu yaptigimiz noktada yapabiliriz yani sinifin uzerinde , bu da okunabilirlik (readability) acisindan katki saglayacaktir.

@Entity
@NamedQuery(name = "Employee.findAll", 
query = "SELECT e FROM Employee28 e")

@NamedQueries({
	@NamedQuery(name = "Employee.findByPrimaryKey", 
			query = "SELECT e FROM Employee28 e WHERE e.id = :id"),
	@NamedQuery(name = "Employee.findByName",
			query = "SELECT e FROM Employee28 e WHERE e.name = :name")})
public class Employee28 {
///

//
}

Named Query’ler verimlilik saglamaktadir. Named Query’ler calisma zamaninda /runtime JPQL’den SQL e donusturulur ve daha sonra kullanilmak icin cache’lenir. Ayni zamanda String concat islemi sadece bir kez yapilacagi icin de verimlilik saglanacaktir.

Named Query’ler tum Persistence Unit’te gecerlidir. Bu nedenle ayni isimle birden fazla query tanimlanamaz.

	@Override
	public List findAllEmployees() {
		TypedQuery query = entityManager.createNamedQuery("Employee.findAll", Employee28.class);
		return query.getResultList();
	}

	@Override
	public Employee28 getEmployeeById(int id) {
		TypedQuery query = entityManager.createNamedQuery("Employee.findByPrimaryKey", Employee28.class)
				.setParameter("id", id);
		return query.getSingleResult();
	}

	@Override
	public Employee28 getEmployeeByName(String name) {
		TypedQuery query = entityManager.createNamedQuery("Employee.findByName", Employee28.class)
				.setParameter("name", name);
		return query.getSingleResult();
	}

Dynamic Named Query
Dynamic Named Query ozelligi JPA 2.1 ile gelen addNamedQuery metodu ile saglanmaktadir. addNamedQuery metodu EntityManagerFactory interface’inde yer almaktadir.

Dynamic Query’i , NamedQuery’e addNamedQuery metodunu kullanarak cevirebiliriz.

private static final String QUERY = "SELECT e.salary FROM Employee28 e  where e.id = :empId ";
public EmployeeServiceImpl() {

	entityManagerFactory = Persistence.createEntityManagerFactory("EmployeePersistenceUnit");
	entityManager = entityManagerFactory.createEntityManager();
	entityTransaction = entityManager.getTransaction();
	
	//create Dynamic Named Query
	TypedQuery<Integer> query = entityManager.createQuery(QUERY, Integer.class);
	entityManagerFactory.addNamedQuery("Employee.findSalary", query);
}
...
@Override
public int getEmployeeSalaryById(int id) {
	TypedQuery<Integer> query= entityManager.createNamedQuery("Employee.findSalary", Integer.class).
			setParameter("empId", id);
	return query.getSingleResult();

}
..

Kodlarin tam halini kaynak dosyada bulabilirsiniz.

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 *