本章では、JOINを利用したクエリの作り方や並び替え、LIMIT・TOP句の使い方までを共有します。
JOIN句の使い方
まず JOINでの定義方法について、紹介します。Entityの関係は以下の通りです。
HogeParent
└ HogeChild
親子で「HogeParent : HogeChild = 1 : 多」の関係を想定して話を進めます。説明については、コードのコメントアウト中に記述しました。
JOIN先のコンテンツをEntityに持たせる場合、Springではクラス内に対象のメンバ変数を用意するだけです。ただ、アノテーションにひと工夫が必要です。以下サンプルです。
import javax.persistence.Basic; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.EntityListeners; import javax.persistence.FetchType; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.ManyToOne; import javax.persistence.Table; import org.springframework.data.annotation.CreatedBy; import org.springframework.data.annotation.CreatedDate; import org.springframework.data.annotation.LastModifiedBy; import org.springframework.data.annotation.LastModifiedDate; import org.springframework.data.annotation.Version; import org.springframework.data.jpa.domain.support.AuditingEntityListener; @Data @Entity // JPAでは、DBで実際に使用されているテーブル名とクラス名を別に定義できます // ↓は、実際に使用されているテーブル名 @Table(name = "hoge_parent") @EntityListeners(AuditingEntityListener.class) public class HogeParent { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column(name = "name") @Basic(Optional = false) private String name; @Column(name = "gender") @Basic(Optional = false) private Gender gender; @Column(name = "created_date_time") @Basic(optional = false) @CreatedDate private ZonedDateTime createdDateTime; @Column(name = "created_by") @Basic(optional = false) @CreatedBy private String createdBy; @Version @Column(name = "last_modified_date_time") @Basic(optional = false) @LastModifiedDate private ZonedDateTime lastModifiedDateTime; @Column(name = "last_modified_by") @Basic(optional = false) @LastModifiedBy private String lastModifiedBy; @Column(name = "deleted") @Basic(optional = false) private boolean deleted; } @Data @Entity // JPAでは、DBで実際に使用されているテーブル名とクラス名を別に定義できます // ↓は、実際に使用されているテーブル名 @Table(name = "hoge_parent") @EntityListeners(AuditingEntityListener.class) public class HogeParent { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column(name = "name") @Basic(Optional = false) private String name; @Column(name = "gender") @Basic(Optional = false) private Gender gender; @Column(name = "parent_id") @Basic(optional = false) private String parentId; // joinColumn では、nameに自身のDB上のカラム物理名、referencedColumnName に参照先のカラム物理名を指定します // また同じEntity内に、自身のカラムがある場合、「insertable = false, updatable = false」が必要です // (※サンプルではparentId) @JoinColumn(name = "parent_id", referencedColumnName = "id", insertable = false, updatable = false) @ManyToOne(fetch = FetchType.LAZY) private HogeParent hogeParent; @Column(name = "created_date_time") @Basic(optional = false) @CreatedDate private ZonedDateTime createdDateTime; @Column(name = "created_by") @Basic(optional = false) @CreatedBy private String createdBy; @Version @Column(name = "last_modified_date_time") @Basic(optional = false) @LastModifiedDate private ZonedDateTime lastModifiedDateTime; @Column(name = "last_modified_by") @Basic(optional = false) @LastModifiedBy private String lastModifiedBy; @Column(name = "deleted") @Basic(optional = false) private boolean deleted; }
LIMIT句の使い方
JPAでは、LIMIT句として、「Pageable」を使用します。Pageableは、並び順の指定、取得件数の情報が含まれます。主に、ページングを実現する際に利用されます。
まずはRepositoryクラスです。JPQLとPageableを併用して、LIMIT句を実現させています。
import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; @Repository public interface HogeChildRepository extends JpaRepository<HogeChild, Long>, JpaSpecificationExecutor<HogeChild> { @Query("SELECT e FROM HogeChild e " + "WHERE e.hogeParent.name = :name") Page<HogeChild> findChildren( @Param("name") String name, Pageable pageable); }
サービス層は以下のとおりです。Sortクラスで並び順を指定しつつ、PageRequestクラスで取得件数も指定しています。
import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Sort; @Service @Transactional public class ChildServiceImpl implements ChildService { public List<HogeChild> findLatestChild(String name, int limit) { List<HogeChild> children = childRepository .findChildren( name, new PageRequest(0, limit, new Sort( new Sort.Order(Sort.Direction.DESC, "createdDateTime"), new Sort.Order(Sort.Direction.DESC, "id")))) .getContent(); // getContent で、Pageの型からListの型に変更します return children; } }