Kuina-Dao 開発記 Named Query
KuinaDaoInterceptor
での Named Query サポートを SVN にコミットしました.
このテストケースのために,さっそく Diigu を使っています.でもでも...
Ant ファイル diigu/diigu-test.xml
をプロジェクトのビルダーとして登録してあるのですが,ソースをいぢった後なんかは明示的に動かしてやらないとダメっぽい?
早いところ Eclipse プラグインを提供したいと思う今日この頃です.
さて,本題.
JPA の Named Query は,エンティティのアノテーションとして指定することができます.
@Entity @NamedQuery(name="Employee.findByName" query="SELECT e FROM Employee e WHERE e.name = :name") public class Employee { ... }
あるいは,マッピングファイル (XML) で指定することもできます.
<?xml version="1.0" encoding="UTF-8"?> <entity-mappings xmlns="http://java.sun.com/xml/ns/persistence/orm" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm orm_1_0.xsd" version="1.0" > <named-query name="Employee.findByName"> <query><![CDATA[ SELECT e FROM Employee e WHERE e.name = :name ]]></query> </named-query> </entity-mappings>
個人的にはアノテーションよりマッピングファイルがお気に!
Hibernate の場合,マッピングファイルを「エンティティクラス名.xml」という名前でエンティティクラスと同じディレクトリに置けば勝手に見つけてくれるようです. META-INF/orm.xml
以外は明示的に persistence.xml
に並べないとダメらしい...
この Named Query を Kuna-Dao で利用するには次のような DAO インタフェースを用意します.
public interface EmployeeDao { List<Employee> findByName(String name); ・・・ }
こいつに KuinaDaoInterceptor
を適用すると,このメソッドを呼ぶだけで Named Query "Employee.findByName" にパラメータをバインドして実行します.
その際,KuinaDaoInterceptor
はメソッドの戻り値からエンティティ名を解決し,メソッド名と連結して Named Query を探します.
エンティティ名というのは通常はエンティティクラスの非修飾名.
でもでも,
@Entity(name="Emp") public class Employee { ... }
みたいに指定することもできちゃいます.
この場合,Kuina-Dao は "Emp.findByName" を探します.
戻り値がエンティティでない場合もあります.
例えば
<named-query name="Employee.getNameById"> <query><![CDATA[ SELECT e.name FROM Employee e WHERE e.id = :id ]]></query> </named-query>
という Named Query の場合,DAO のメソッドは
String getNameById(int id);
ってことになってしまうので,シグネチャからエンティティを見つけることができません.
そんな場合は,
@TargetEntity(Employee.class) String getNameById(int id);
とアノテーションでエンティティを教えてあげてください.
このアノテーションはインタフェースに付けることもできます.
KuinaDaoInterceptor
は,
- メソッドの戻り値型
- メソッドの
@TargetEntity
- インタフェースの
@TargetEntity
の順でエンティティを解決しようとします.
Named Query の名前をアノテーションで直接指定することもできます.
@QueryName("Employee.getNameById") String getNameById(int id);
メソッドの引数は JPQL 中の Named Parameter と解釈しますが,特殊な名前が二つあります.
firstResult
maxResults
引数の名前がこのいずれかだった場合はパラメータではなく,javax.persistence.Query
の setFirstResult(int)
あるいは setMaxResults(int)
の指定だと解釈します.
なので,
List<Employee> findByDepartmentName(String name, int firstResult, int maxResults);
なんてメソッドを用意すればページングできちゃいます.
引数に @FirstResult
アノテーションあるいは @MaxResults
アノテーションを付けることで,引数名に関わりなくページングの指定をすることもできます.
逆に @NamedParameter
を付けることで,firstResult
あるいは maxResults
という名前の引数でも Named Parameter として扱わせることができます.
なんとか動いたというレベルでしかありませんが,こんな感じで Named Query が使えます.
明日からは実行時の条件にあわせて JPQL を生成する Dynamic Query に取りかかります.