読者です 読者をやめる 読者になる 読者になる

Spring Data JPA で遊んでみる 〜その6〜

次はメソッドの定義です。Spring Data JPA はメソッドからクエリを自動生成しますが、そのメソッド名には命名規則があります。

まず戻り値はRepositryに指定している総称型のエンティティのListか、もしくは、そのエンティティにします。Listの場合はJPAのgetResultListが、エンティティの場合はgetSingleResultが呼ばれるという感じですかね?中身見てないのでわかりませんが。定義はこんなんです。

    Emp findByName(String name);
    List<Emp> findByDept(Dept dept);

次にメソッド名のprefixは、findBy、readBy、getByが使用出来ます。単にfind、read、getとか使えるような記述がマニュアルに書いてあったのですが、エラーになっちゃいました。ようわからん。次のメソッドはすべて同じ意味です。

List<Emp> findByDept(Dept dept);
List<Emp> readByDept(Dept dept);
List<Emp> getByDept(Dept dept);
List<Emp> dept(Dept dept);

よくわからんのですがプレフィクスはなくてもいいみたいです。いろいろ使えるみたいですが、findByが個人的には一般的な気がするので、他のはわりとどうでもいいやという。

プレフィックに続いてエンティティのプロパティを指定してい行きます。その指定に合わせて、引数でそのプロパティを受け取るようにします。複数の条件を組み合わせる場合はAnd、Orで組み合わせられます。その他にもプロパティの後にキーワードを設定することで条件を設定できます(これはJPA限定みたいですけど)。

マニュアルそのままですが、いろいろあります。

Keyword Sample JPQL snippet
And findByLastnameAndFirstname … where x.lastname = ?1 and x.firstname = ?2
Or findByLastnameOrFirstname … where x.lastname = ?1 or x.firstname = ?2
Between findByStartDateBetween … where x.startDate between 1? and ?2
LessThan findByAgeLessThan … where x.age < ?1
GreaterThan findByAgeGreaterThan … where x.age > ?1
IsNull findByAgeIsNull … where x.age is null
IsNotNull,NotNull findByAge(Is)NotNull … where x.age not null
Like findByFirstnameLike … where x.firstname like ?1
NotLike findByFirstnameNotLike … where x.firstname not like ?1
OrderBy findByAgeOrderByLastnameDesc … where x.age = ?1 order by x.lastname desc
Not findByLastnameNot … where x.lastname <> ?1
In findByAgeIn(Collection ages) … where x.age in ?1
NotIn findByAgeNotIn(Collection age) … where x.age not in ?1

例えばこんな感じで定義できます。

List<Emp> findByDeptAndIdGreaterThan(Dept dept, Long id);

基本はメソッド名で指定したプロパティを引数に取るようにしますが、特別な引数があります。それが、PageableとSortです。

    Page<Emp> findByDeptAndIdGreaterThan(Dept dept, Long id, Pageable pageable);
    List<Emp> findByDeptAndIdGreaterThan(Dept dept, Long id, Sort sort);

Pageableを使用する場合は戻り値の型にPageを指定できますが、Listでも問題ありません。Pageableを使用する場合は必ずentityManagerFactoryのBeanの定義の中にjpaVendorAdapterを定義しないと動きません(ちょっとはまった)。

  <bean class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" id="entityManagerFactory">
    <property name="persistenceUnitName" value="persistenceUnit" />
    <property name="dataSource" ref="dataSource" />
    <property name="jpaVendorAdapter">
      <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
    </property>
  </bean>

あとProperty expressionsというのもあります。これは関連エンティティをたぐってプロパティを指定するような場合に使用出来ます。例えば

List<Emp> findByDeptNameLike(String name);

これはx.dept.nameのプロパティを条件にしています。引数もこの場合はDeptの型ではなく、その関連をたぐったプロパティの型になります。DeptのnameはStringなので、ここではStringを指定しています。

場合によっては、このProperty expressionsはうまく行かない時があります。プロパティの名前がかぶっているようなときです。そんなときはアンスコをプロパティの区切りに指定できます。

List<Emp> findByDept_NameLike(String name);

これは先程の定義とまったく同じ意味です。

サンプルはこのへん。
https://github.com/yamkazu/springdata-jpa-example/tree/querycreation

だんだんテストとか適当になって来ましたが。。。