Help us understand the problem. What is going on with this article?

Repositoryを使った検索で特定カラムだけをPOJOへマッピングする

More than 1 year has passed since last update.

概要

Spring Data JPAのRepositoryを使った検索で必要なカラムだけを取得する方法があったのでコードを書いて動かしてみました。
いままではJPQLでSELECT new com.example.domain.Fuga(...) FROM Hoge AS hoge ...のような書き方をしていたのですが、だいぶ簡単に実装できるようになりました。

環境

  • Windows10 Professional
  • Java 1.8.0_144
  • Spring Boot 1.5.6
    • Spring Data JPA 1.11.6
    • Hibernate 5.0.1
    • Lombok
  • MySQL 5.6.25

参考

サンプルコード

Entityクラス

package com.example.domain.entity;

import com.example.domain.StandardType;
import lombok.*;

import javax.persistence.*;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.List;

@Entity
@Table(name="item")
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@ToString(exclude = {"itemStocks"})
@EqualsAndHashCode(exclude = {"itemStocks"})
public class Item implements Serializable {

    private static final long serialVersionUID = -3153084093423004609L;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    @Column(name="name", nullable = false)
    private String name;
    @Column(name="price", nullable = false)
    private Integer price;
    @Column(name="sales_from", nullable = false)
    private LocalDateTime salesFrom;
    @Column(name="sales_to", nullable = false)
    private LocalDateTime salesTo;
    @Enumerated(EnumType.ORDINAL)
    @Column(name="standard_type", nullable = false)
    private StandardType standardType;
    @JoinColumn(name = "category_id", nullable = false)
    @ManyToOne
    private Category category;
    @Column(name="del_flag", nullable = false)
    private Boolean delFlag;
    @Column(name="create_at", nullable = false)
    private LocalDateTime createAt;
    @Column(name="update_at", nullable = false)
    private LocalDateTime updateAt;

    @OneToMany(mappedBy = "item", cascade = CascadeType.ALL)
    private List<ItemStock> itemStocks;
}

Dtoクラス

Itemエンティティのうちid、name、priceだけを持つDtoクラスです。
Repositoryで検索した結果をこのクラスにマッピングします。

package com.example.domain.dto;

import lombok.Value;

@Value
public class ItemNameAndPrice {
    private Long id;
    private String name;
    private Integer price;
}

Repositoryクラス

package com.example.domain.repository;

import com.example.domain.entity.Item;
import org.springframework.data.jpa.repository.JpaRepository;

public interface ItemRepository extends JpaRepository<Item, Long> {
    // Class-based projections用の検索メソッド
    <T> T findOneById(Long id, Class<T> type);
}

findOneを使った検索

Item item = repository.findOne(1L);

発行されるSQL

select
    item0_.id as id1_1_0_,
    item0_.category_id as categor10_1_0_,
    item0_.create_at as create_a2_1_0_,
    item0_.del_flag as del_flag3_1_0_,
    item0_.name as name4_1_0_,
    item0_.price as price5_1_0_,
    item0_.sales_from as sales_fr6_1_0_,
    item0_.sales_to as sales_to7_1_0_,
    item0_.standard_type as standard8_1_0_,
    item0_.update_at as update_a9_1_0_,
    category1_.id as id1_0_1_,
    category1_.create_at as create_a2_0_1_,
    category1_.del_flag as del_flag3_0_1_,
    category1_.name as name4_0_1_,
    category1_.update_at as update_a5_0_1_ 
from
    item item0_ 
inner join
    category category1_ 
       on item0_.category_id=category1_.id 
where
    item0_.id=?

Class-based projections

ItemNameAndPrice nameAndPrice = repository.findOneById(1L, ItemNameAndPrice.class);

内部的にDtoをnewしているのは変わりません。

select new com.example.domain.dto.ItemNameAndPrice(
    generatedAlias0.id,
    generatedAlias0.name,
    generatedAlias0.price) 
from
    Item as generatedAlias0 
where
    generatedAlias0.id=:param0

発行されるSQL

select
    item0_.id as col_0_0_,
    item0_.name as col_1_0_,
    item0_.price as col_2_0_ 
from
    item item0_ 
where
    item0_.id=?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした