EntityManagerは、データの永続管理を受け持つオブジェクトです。データベースと接続して、さまざまな処理を行います。@PersistenceContextは、Dependency Injection (依存性注入)を行うためのAnnotationです。EntityManagerは、コンテナから依存性注入されます。
@PersistenceContext(unitName="summer2006") private EntityManager em;
EntityBeanは、データベースのテーブルとの関係において、ライフサイクルを持っています。
ここで重要な役割を持つのがPersistence Identityです。これは、@Idアノテーションで修飾されたプロパティのことです。EntityBeanのインスタンスを識別するために使われます。また、データベースのテーブル中の主キーと対応しています。
EntityBeanのライフサイクルを表にすると、次のようになります。
Persistence Identityを 持つかどうか |
Persistence Context との結びつき |
|
new | 持たない | 結びついていない |
managed | 持つ | 結びついている |
detached | 持つ | 結びついていない (以前は結びついていた) |
removed | 持つ | 結びついている (DBから削除予定) |
整理すると、次のようになります。
public Employee findEmployeeByEmpNo(int empNo) { return em.find(Employee.class, empNo); }
EntityManagerのfindメソッドは、データベースからempNoという主キーで指定したデータを検索し、検索結果としてEmployeeオブジェクトを返します。
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に移行しています。
@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 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を使って実行しています。