Powered by SmartDoc

EntityManager と Query Language

EntityManager

EntityManagerは、データの永続管理を受け持つオブジェクトです。データベースと接続して、さまざまな処理を行います。@PersistenceContextは、Dependency Injection (依存性注入)を行うためのAnnotationです。EntityManagerは、コンテナから依存性注入されます。

	@PersistenceContext(unitName="summer2006")
	private EntityManager em;

EntityBeanのライフサイクル

EntityBeanは、データベースのテーブルとの関係において、ライフサイクルを持っています。

ここで重要な役割を持つのがPersistence Identityです。これは、@Idアノテーションで修飾されたプロパティのことです。EntityBeanのインスタンスを識別するために使われます。また、データベースのテーブル中の主キーと対応しています。

EntityBeanのライフサイクルを表にすると、次のようになります。

Persistence Identityを
持つかどうか
Persistence Context
との結びつき
new 持たない 結びついていない
managed 持つ 結びついている
detached 持つ 結びついていない
(以前は結びついていた)
removed 持つ 結びついている
(DBから削除予定)

整理すると、次のようになります。

EntityManagerでの処理

EntityManager#find

public Employee findEmployeeByEmpNo(int empNo) {
		return em.find(Employee.class, empNo);
}

EntityManagerのfindメソッドは、データベースからempNoという主キーで指定したデータを検索し、検索結果としてEmployeeオブジェクトを返します。

EntityManager#persist

public void addEmployee(int empNo, String eName, double sal) {
	Employee emp = new Employee();
	emp.setEmpNo(empNo);
	emp.setEname(eName); 
	emp.setSal(sal);
	em.persist(emp);
}

EntityManagerのpersistメソッドで、Entity Beanを永続化しています。ライフサイクルはnewからmanagedに移行しています。

EntityManager#remove

@Stateless
public class EmployeeDemoSessionEJB
			implements EmployeeDemoSession {
	public void removeEmployee(Integer employeeId) {
		Employee employee = em.find(Employee.class, employeeId);
		em.remove(employee);
	}
}

EntityManagerのremoveメソッドで、データベースで管理されているオブジェクトを削除できます。ライフサイクルはremovedに移行します。

データベースの更新

続いて、データベースの更新について考えてみましょう。

// EmployeeClient.java より
Employee emp3 = ef.findEmployeeByEmpNo(empNo);
emp3.setSal(100000);

このクライアントプログラムでEmployeeの内容を変化させても、データベースには反映されません。SesionFacadeから渡されているemp3は、detachedになっているからです。

そこで、このようにしてみます。

// EmployeeClient.java より
Employee emp3 = ef.findEmployeeByEmpNo(empNo);
emp3.setSal(100000);
ef.updateEmployee(emp3);

// EmployeeFacadeBean.java より
// detouched な EntityBean が managed に
public void updateEmployee(Employee emp) {
		em.merge(emp);
}

updateEmployeeメソッドを実行することで、detouchedなEntityBeanがmanagedに移行します。

また、このような解決法もあります。

// EmployeeClient.java
ef.setSal(1, 50.0);

// EmployeeFacadeBean.java
// Facadeの中で find したものを操作すればOK
public void setSal(int empNo, Double sal) {
		emp = (Employee)em.find(Employee.class, empNo);
		emp.setSal(sal);
}

SessionFacadeでfindメソッドを実行し、取得したオブジェクトのプロパティを操作すれば、変更内容がテーブルにそのまま反映されます。

Java Persistence Query Language

Java Persistence Query Languageは、Java Persistence APIでデータベースを操作するためのクエリー言語です。SQLとは違い、オブジェクトをそのまま利用できます。また、データベースに依存しないかたちでクエリーを記述できるようになります。Java Persistence Query Languageは、EJB 2.1で用意されていた"EJB QL"を拡張したものとなっています。

さっそく、サンプルアプリケーションを見てみましょう。

public Collection<Employee> findAllEmployees() {
	Collection<Employee> employees = em.createQuery(
		"SELECT employee FROM Employee employee")
		.getResultList();
	return employees;
}

EntityManager#createQueryの引数として、クエリーを指定しています。このクエリーは、getResultListの働きにより、Employeeのコレクションを返します。

public Collection<Employee> findEmployeesByLastName(String lastName) {
	Collection<Employee> employees = em.createQuery(
		"SELECT employee FROM Employee employee 
			WHERE employee.lastName = :lastname")
		.setParameter("lastname", lastName).getResultList();
	return employees;
}

この例では、クエリーの中に":lastname"というパラメータが組み込まれています。このパラメータは、setParmeter("lastname", lastName)の処理によって、lastNameオブジェクトに置き換えられます。

public int changeCityName(String oldName, String newName) {
	int result = em.createQuery(
		"UPDATE address SET address.city = :newName
			WHERE address.city = :oldName")
		.setParameter("newName", newName)
		.setParameter("oldName", oldName).executeUpdate();
	return result;
}

この例のように、UPDATEやDELETEを使うことができます。executeUpdateメソッドを使ってクエリーを実行しています。

@NamedQuery(
	name="findProjectByName",
	queryString="SELECT project FROM Project project 
				WHERE project.name = :name"
)
public class ... {
	public Project findProjectByName(String name) {
		Project proj = (Project)em.createNamedQuery("findProjectByName")
			.setParameter("name", name).getSingleResult();
		return proj;
	}
}

この例では、@NamedQuery Annotationによって、findProjectByNameという名前で指定されるクエリーをあらかじめ用意しておきます。そして、EntityManager#createNamedQueryを使って実行しています。