🔖

【Spring Data JPA】SqlResultSetMappingとNamedNativeQueryの使い方メモ

2020/09/18に公開

概要

複数のテーブルを結合する際のSELECT文など、JPAの自動生成されるメソッドでは対応が困難な時があります。JPA(hibernate)のテーブルジョインの罠(n+1問題)にある通り、Entityどうしで結合関係を定義して取得することも不可能ではありませんが、やはり直接SELECT文を使いたい時はあると思います。
今回は対応の一つの方法としてSqlResultSetMappingNamedNativeQueryを使って、Entityにデータを詰める方法を書いてみたいと思います。

使い方

SqlResultSetMappingのガイド5.エンティティマッピングに書いてある通り、@SqlResultSetMappingにEntityのクラスとプロパティとカラムの紐付けを定義します。また、@NamedNativeQueryにてSQL文を定義して、SqlResultSetMappingと紐付けをします。
また、How to Use Named Queries with Spring Data JPAの記事にある通り、RepositoryではNamedNativeQueryで定義した名前でメソッド名を定義します。

実装サンプル

実装サンプルとして、urlsテーブルとdomainsテーブルがあった時に、この2テーブルを結合して情報を取得する場合の例を紹介します。

Entity

@SqlResultSetMapping(
  name = "siteInfoMap",
  entities = {
    @EntityResult(
      entityClass= SiteInfo.class,
        fields = {
				   // カラム名とプロパティ名を紐付け
          @FieldResult(name="urlId", column="url_id"),
          @FieldResult(name="url", column="url"),
          @FieldResult(name="domainId", column="domain_id"),
          @FieldResult(name="domain", column="domain")
        }
    )
  }
)
@NamedNativeQuery(
  name = "SiteInfo.getSiteInfo",
	// SqlResultSetMappingで定義した名前
  resultSetMapping = "siteInfoMap",
  query = "select u.url_id, u.url, u.domain_id, d.domain from urls u inner join domains d on d.id = u.domain_id"
)
@Entity
public class SiteInfo {
  @Id
	private Long urlId;
  private String url;
  private Long domainId;
  private String domain;

  public SiteInfo(){}

  public Long getUrlId() { return this.urlId; }
  public void setUrlId(Long urlId) { this.urlId = urlId; }
	
  public String getUrl() {  return this.url; }
  public void setUrl(String url) { this.url = url; }

  public Long getDomainId() { return this.domainId; }
  public void setDomainId(Long domainId) { this.domainId = domainId; }

  public String getDomain() { return this.domain; }
  public void setDomain(String domain) { this.domain = domain; }
}

Repositoryでは、上記で定義したクエリ名getSiteInfoでメソッドの名前を定義します。

Repository

@Repository
public interface SiteInfoRepository extends JpaRepository<SiteInfo, String> {
  List<SiteInfo> getSiteInfo();
}

Discussion