출처: http://november11tech.tistory.com/88 [Mr.november11] JPA NamedNativeQuery 사용하기 :: 사월은 봄이다.

상황(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

+ Recent posts