SAStruts/S2JDBC JSPで画面部品を作ってみる - 130単位
の続きです。
実際に作りたかった画面部品は、テーブル結合を伴った、ネストしたプロパティを持つ項目でした。これを実現するのにまた地味に時間を食いました。というか要はMapの使い方を知らなかっただけなのですが。
エンティティとサービス
従業員に部署を結合して、所属する部署を表示させたいとします。
Employeeへ関連を定義します。
@Entity public class Employee { ... @ManyToOne Department department; }
EmployeeServiceで、結合して取得するようにします。findAll()をオーバーライドしてます。
public class EmployeeService extends AbstractService<Employee> { ... @Override public List<Employee> findAll() { return select() .innerJoin(department()) .orderBy(asc(id())) .getResultList(); }
JSP
さて、前回ようなJSPに単に追加しただけでは、ネストしたプロパティにアクセスしようとするとエラーが起きます。
<html:option value="${e.jgjycd}">${e.id} ${e.name} (${e.department.name})</html:option>
javax.el.PropertyNotFoundException: Property 'name' not found on type test.entity.Department
employeeはBeanMapになっていても、departmentがBeanMapではないためです。employeeのみにBeans#createAndCopy()を実行しただけでは、departmentというプロパティはできなくなっているようです。ひがさんの少し前の記事にも、「ネストしたプロパティは対象外」と書かれています。
そこで、employeeをMapに詰め替えてListを構築する際に、departmentも同様にMapにしてやる必要があります。Mapに値を追加するには、「put(key, value)」を使います。
<% /* インポート等省略 */ List<Employee> employeeList = employeeService.findAll(); List<BeanMap> employeeItems = new ArrayList<BeanMap>(); for (Employee employee : employeeList) { BeanMap empMap = Beans.createAndCopy(BeanMap.class, employee).execute(); BeanMap deptMap = Beans.createAndCopy(BeanMap.class, employee.department).execute(); empMap.put("department", deptMap); employeeItems.add(empMap); } %> <html:select property="searchLectureCd"> <html:option value=""></html:option> <c:forEach var="e" items="${jgyofpItems}"> <html:option value="${e.jgjycd}">${e.id} ${e.name} (${e.department.name})</html:option> </c:forEach> </html:select>
ちなみに
最初は下記のようにやろうとしてました。
empMap.department = deptMap;
もろにPHP(の連想配列)の影響なわけですが、これではダメですね。
サービスでMap取得 (失敗例)
そもそも「最初からサービスでMapを返せばいいんじゃないの」と思い、以下を試してみました。
public class EmployeeService extends AbstractService<Employee> { ... public List<BeanMap> findAllMap() { return jdbcManager .from(BeanMap.class) .orderBy(asc(id())) .getResultList(); } }
しかし結果は失敗。問い合わせ実行時に例外が発生します。
org.seasar.extension.jdbc.exception.NonEntityRuntimeException: [ESSR0704](org.seasar.framework.beans.util.BeanMap)はエンティティではありません。
Eclipse上ではエラーになりませんでしたし、SQLによる照会のselectBySql()だとMapで返せるようなので、いけるかと思ったのですが。AbstractServiceのジェネリクスでエンティティが指定されているのが関係してそうですが、今の自分の知識量ではこのくらいの推測が限界です。
というわけで、素直にJSPでMapに詰め替える方法を用いることにしました。