目次
概要
@ManyToOneや@OneToManyといったリレーションをエンティティに設定していないまたは設定できない状況にあるが、結合した結果を取得したいという状況を想定しています。
方法としては「JOIN ON」を使います。
NativeQueryとはほんの若干だけ記述が違いがあります。
実装
エンティティ
ItemとCategoryがあるとします。
ItemにCategoryIdを持ちますがリレーションはありません。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
import lombok.Data; import org.hibernate.annotations.Where; import javax.persistence.*; import java.time.LocalDate; @Data @Entity(name = "item") @Where(clause = "delete_flg = 0") public class Item { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Integer id; private String name; private Integer quantity; private String description; /** * Category.nameとはリレーションが無いため、CriteriaでJOINできない。 * そのため、JPQL または、NativeQueryを構築する。 */ private Integer categoryId; // 共通 private LocalDate createdDate; private String createdUser; private LocalDate updatedDate; private String updatedUser; @Column(columnDefinition = "integer default 0") private Integer deleteFlg; } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
import lombok.Data; import org.hibernate.annotations.Where; import javax.persistence.*; import java.time.LocalDate; @Data @Entity(name = "category") @Where(clause = "delete_flg = 0") public class Category { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Integer id; private String name; // 共通 private LocalDate createdDate; private String createdUser; private LocalDate updatedDate; private String updatedUser; @Column(columnDefinition = "categorydefault 0") private Integer deleteFlg; } |
レポジトリ
JPQLとnativeQueryの例を同時に記載しています。
■JPQLがNativeQueryと異なる箇所
・クエリ上のテーブル名はEntityアノテーションのname属性に一致する必要があります。
・SELECT句には取得対象のエンティティを指定しますが、その際に「.*など」でカラムの指定は不要です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
import com.example.shiragakiMenta.model.Item; import org.springframework.data.domain.*; import org.springframework.data.jpa.repository.JpaRepository; import org.thymeleaf.util.StringUtils; import javax.persistence.*; public interface ItemRepository extends JpaRepository<Item, Integer> { default Page<Item> findByCategoryJoinedItems(EntityManager emf, String categoryName) { if (StringUtils.isEmpty(categoryName)) { return new PageImpl<>(findAll()); } // JPQLの場合、Entityアノテーションのname属性に一致するエンティティ名で指定する必要がある final StringBuilder jpqlQStr = new StringBuilder( "SELECT i FROM item i " + "LEFT JOIN category c ON i.categoryId = c.id WHERE 0 = 0"); // NativeQueryの場合、テーブル名の大文字小文字は区別しない final StringBuilder nativeQueryStr = new StringBuilder( "SELECT i.* FROM Item i " + "LEFT JOIN Category c ON i.categoryId = c.id WHERE 0 = 0"); // 動的クエリ if (categoryName != null) { jpqlQStr.append(" AND c.name = :categoryName"); nativeQueryStr.append(" AND c.name = :categoryName"); } TypedQuery jpqlQuery = emf.createQuery(jpqlQStr.toString(), Item.class); Query nativeQuery = emf.createNativeQuery(nativeQueryStr.toString(), Item.class); // データバインド if (categoryName != null) { jpqlQuery.setParameter("categoryName", categoryName); nativeQuery.setParameter("categoryName", categoryName); } // Pageable return new PageImpl<>(jpqlQuery.getResultList()); // return new PageImpl<>(nativeQuery.getResultList()); } } |
まとめ
- JPQLにおいてもJOIN ON句の構文はNativeQueryと同じ。
- テーブル名はエンティティのname属性と一致させる。
- フィールドの指定は不要。
参考
【JPA徹底入門】JPQLによる検索処理 – JOIN ON
コメント