以下のコードでは、Person EntityにPersonを保存して誕生日の月データが"8月"の人を検索しています。
@Test
void findByBirthdayBetween() {
givenPerson("martin",10,"A",LocalDate.of(1991,8,15));
givenPerson("david",9,"B",LocalDate.of(1992,7,1));
givenPerson("dennis",8,"O",LocalDate.of(1993,1,5));
givenPerson("sophia",7,"AB",LocalDate.of(1994,6,30));
givenPerson("benny",6,"A",LocalDate.of(1995,8,30));
List<Person> result = personRepository.findByMonthOfBirthday(8);
result.forEach(System.out::println);
}
Person Entityクラス、birthday Columnをオブジェクトとして保持したいので@Embedded annotationを定義しています。
package com.informanaging.project.demo.domain;
import com.informanaging.project.demo.domain.dto.Birthday;
import lombok.*;
import javax.persistence.*;
import java.time.LocalDate;
@Entity
@NoArgsConstructor
@AllArgsConstructor
@RequiredArgsConstructor
@Data
public class Person {
// 省略
@Embedded
private Birthday birthday;
// 省略
}
Birthday DTO クラス、@Embeddable annotationが定義されています。(Person Entityのbirthdayと紐付け)
package com.informanaging.project.demo.domain.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.persistence.Embeddable;
@Embeddable // Entityに所属されている
@AllArgsConstructor
@NoArgsConstructor
@Data
public class Birthday {
private int yearOfBirthday;
private int monthOfBirthday;
private int dayOfBirthday;
}
Repository クラスです。月データを受けて Personをselectします。
package com.informanaging.project.demo.repository;
import com.informanaging.project.demo.domain.Person;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import java.time.LocalDate;
import java.util.List;
// JpaRepository<Entity, Id>
public interface PersonRepository extends JpaRepository<Person, Long> {
List<Person> findByMonthOfBirthday(int monthOfBirthday);
}
それで、テストを実行すると以下のエラーが出てしまいます。
詳細を見ると、monthOfBirthdayはBirthdayクラスには定義されていますが、Person Entityには定義されていないためエラーが発生しています。
エラーを解消するために、Repository クラスにQuery annotationを定義してあげれば対応できます。
そうすると、Person EntityにmonthOfBirthday Columnを別途定義しなくていいです。
public interface PersonRepository extends JpaRepository<Person, Long> {
@Query(value = "select person from Person person where person.birthday.monthOfBirthday =?1")
List<Person> findByMonthOfBirthday(int monthOfBirthday);
}
Query annotaionを定義し、その中に実行したいSQLを作成します。作成するのはただのSQLではなくJPQLを作成しなければなりません。
普通のSQLだとTableを指定しますが、JPQLはEntityを指定します。?1はパラメータのmonthOfBirthdayです。
上記を見ると、Person Entityをfrom句に指定し、where句は「person Entityで定義しているbirthda dtoのmonthOfBirthdayをゲット!」ということで「person.birthday.monthOfBirthday」を指定します。
JPQLでパラメータとして"?1"を使いたくない場合は、@Param("A")を定義し、"?1"代わりに"A"を使えばいいです。
public interface PersonRepository extends JpaRepository<Person, Long> {
@Query(value = "select person from Person person where person.birthday.monthOfBirthday = :monthOfBirthday")
List<Person> findByMonthOfBirthday(@Param("monthOfBirthday")int monthOfBirthday);
}