상황(cause)
JPA로 잘 사용하다가 쿼리를 짜게 되었다.
Need a customized query.
문제(problem)
기존 테이블에 없는 컬럼을 만들어서 리턴을 해주고 싶은데 JPA를 사용하면 불가능하다.
I want to return a custom column but JPA does not assist it if a table does not have a column.
해결
NamedNativeQuery를 사용.
Using NamedNativeQuery.
Entity Table
위와 같이 Transient 어노테이션이 있는 replyCount를 리턴에 사용하고 싶었다..
찾아본 결과 @SqlResultSetMapping,@ConstructorResult, @NamedNativeQuery 를 사용하면 된다.
사용예)
이제 커스텀되는 클래스를 만든다./** * A Message. */ @Entity @Table(name = "message") @NamedNativeQuery( name = "Message.findAllBy", query = "SELECT id, title, (...) as replyCount from message where title like concat('%', :title , '%')" ,resultSetMapping = "Message.findAllBy" ) @SqlResultSetMappings({ @SqlResultSetMapping( name = "Message.findAllBy", classes = { @ConstructorResult( targetClass = MessageThread.class, columns = { @ColumnResult(name = "id",type = Long.class),
@ColumnResult(name = "title", type = String.class),
@ColumnResult(name = "replyCount", type = Integer.class) } ) } ) }) public class Message implements Serializable { private static final long serialVersionUID = 1L; @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @NotNull @Enumerated(EnumType.STRING) @Column(name = "type", nullable = false) private MessageType type; @Size(max = 1000) @Column(name = "title", length = 1000) private String title; @Column(name = "is_deleted") private Boolean isDeleted; @Size(max = 10000) @Column(name = "content", length = 10000) private String content; @Column(name = "created_date") private ZonedDateTime createdDate; @Column(name = "is_noticed") private Boolean isNoticed; @Column(name = "updated_date") private ZonedDateTime updatedDate = ZonedDateTime.now(); @Transient private Integer replyCount; public Long getId() { return id; } public void setId(Long id) { this.id = id; } .... Getter , Setter..... }
/** * A Message Thread. */ public class MessageThread implements Serializable { private static final long serialVersionUID = 1L; private Long id; private MessageType type; private String title; private Boolean isDeleted; private String content; private ZonedDateTime createdDate; private Boolean isNoticed; private ZonedDateTime updatedDate = ZonedDateTime.now(); private Integer replyCount; public Long getId() { return id; } public void setId(Long id) { this.id = id; }
.... Getter , Setter.....
public MessageThread (Long id, String title, Integer replyCount){ this.id = id; this.title = title;
this.replyCount = replyCount; } }
여기서 중요한 부분이 생성자다.
public MessageThread (Long id, String title, Integer replyCount){ this.id = id; this.title = title;
this.replyCount = replyCount; }
리턴을 원하는 컬럼을 생성자에 넣어줘야 받아올 수 있다.
Repository에서 파라미터 등을 넣어서 불러주고,
public interface MessageRepository extends JpaRepository<Message, Long> {List<MessageThread> findAllBy(@Param("title") String title);}
Test코드를 돌려 보면,
@Rollback
@Transactional
public class MessageServiceTest extends TestHelper {
@Autowired
private MessageRepository messageThreadRepository;
@Test
public void testGetListPlayerMessage() {
List<MessageThread> result = messageThreadRepository.findAllBy("nice");
result.forEach(p->{
System.out.println("replyCount:" + p.getReplyCount());
});
}
}
결과
replyCount:1 replyCount:1 replyCount:1 replyCount:8 replyCount:6 replyCount:2 replyCount:2 replyCount:2
유의할 점
NamedNativeQuery의 name, resultSetMapping, SqlResultSetMapping의 name과 repository의 함수명은 통일해 주는게 정신건강에 좋다.
https://blog.naver.com/napsis/221455599089
'개발 > Spring' 카테고리의 다른 글
Spring Boot JPA에서 로그 자세하게 찍어보기 (0) | 2019.10.25 |
---|---|
spring boot, maiadb] insert into table emoji (0) | 2018.12.11 |
responseentity, String to json (0) | 2018.11.23 |
junit test (0) | 2018.10.22 |
JunitTest] Mock 사용하기 (0) | 2018.08.21 |