JPA를 사용하면서 원하는 데이터를 받기 위해서 NativeQuery를 작성하고 싶었는데
객체가 연관관계가 포함이 되어있어서인지 필요 없는 컬럼들도 추가를 해줘야 하는 상황이 되어버려서
다른 방법을 찾는 도중에 DTO로 바로 Mapping 시킬 수 있는 방법을 찾았습니다.
@SqlResultSetMapping, @NamedNativeQuery 를 이용해서 DTO로 받기
@SqlResultSetMapping(
name = "followingListMapping",
classes = @ConstructorResult(
targetClass = ReadFollowListResponseDto.class,
columns = {
@ColumnResult(name = "followCode", type = Integer.class),
@ColumnResult(name = "fromUserCode", type = Integer.class),
@ColumnResult(name = "followingFlag", type = Integer.class),
@ColumnResult(name = "fromUserName", type = String.class),
@ColumnResult(name = "toUserName", type = String.class),
@ColumnResult(name = "toDetailCode", type = Integer.class),
@ColumnResult(name = "fromDetailCode", type = Integer.class),
@ColumnResult(name = "toUserId", type = String.class),
@ColumnResult(name = "fromUserId", type = String.class),
@ColumnResult(name = "toUserNickname", type = String.class),
@ColumnResult(name = "fromUserNickname", type = String.class)
}
)
)
@NamedNativeQuery(
name = "findFollowingListByUserCode",
query = "select" +
" f.follow_code as followCode," +
" f.from_user_code as fromUserCode," +
" um.detail_code as toDetailCode," +
" um.user_id as toUserId," +
" um.user_name as toUserName," +
" um.user_nickname as toUserNickname," +
" um2.detail_code as fromDetailCode," +
" um2.user_id as fromUserId," +
" um2.user_name as fromUserName," +
" um2.user_nickname as fromUserNickname," +
" if(following_table.to_user_code is not null, 1, 0) as followingFlag " +
"from" +
" follow f" +
" left outer join (select" +
" to_user_code" +
" from" +
" follow" +
" where" +
" from_user_code = :toUserCode) following_table on(following_table.to_user_code = f.from_user_code)" +
"inner join user_mst um on(um.user_code = f.to_user_code)" +
"inner join user_mst um2 on(um2.user_code = f.from_user_code) "
"where" +
" f.to_user_code = :toUserCode",
resultSetMapping = "followingListMapping"
)
가지고 오고 싶은 컬럼들만 DTO로 가지고 오려고 만들었습니다.
@SqlResultSetMapping는 Mybatis의 ResultMap과 비슷하다고 생각을 하면 됩니다.
resultSetMapping으로 @SqlResultSetMapping의 name과 연결해 줍니다.
@NamedNativeQuery의 name 속성은 나중에 쿼리를 불러올 때 사용합니다.
주의
@Entity가 선언된 Class에서 선언을 해줘야 합니다.
package com.project.instagram.web.dto.friend;
import lombok.Data;
@Data
public class ReadFollowListResponseDto {
private int followCode;
private int fromUserCode;
private boolean followingFlag;
private String fromUserName;
private String toUserName;
private int toDetailCode;
private int fromDetailCode;
private String toUserId;
private String fromUserId;
private String toUserNickname;
private String fromUserNickname;
public ReadFollowListResponseDto(){}
public ReadFollowListResponseDto(int followCode, int fromUserCode, int followingFlag, String fromUserName, String toUserName, int toDetailCode, int fromDetailCode, String fromUserId,
String toUserId, String toUserNickname, String fromUserNickname) {
this.followCode = followCode;
this.fromUserCode = fromUserCode;
this.followingFlag = followingFlag > 0;
this.fromUserName = fromUserName;
this.toUserName = toUserName;
this.toDetailCode = toDetailCode;
this.toUserId = toUserId;
this.fromDetailCode = fromDetailCode;
this.fromUserId = fromUserId;
this.toUserNickname = toUserNickname;
this.fromUserNickname = fromUserNickname;
}
}
@NamedNativeQuery에서 DTO로 받기 위해서는 DTO에 생성자가 있어야 합니다.
이유는 모르겠지만 @AllArgsConstructor로는 안 되고 직접 만들어 줘야 작동합니다.
@Transactional
@Override
public List<ReadFollowListResponseDto> loadFollowUser(int userCode) {
Query query = entityManager.createNamedQuery("findFollowingListByUserCode").setParameter("toUserCode", userCode);
List<ReadFollowListResponseDto> followList = query.getResultList();
return followList;
}
entityManager.createNamedQuery("위에서 작성한 @NamedNativeQuery의 name의 값").setParameter("키", 값);
이렇게 사용한다면 원하는 데이터를 바로 DTO로 받을 수 있습니다.
처음에는 Entity로 받고 DTO로 따로 변경하는 방법을 계속해서 시도해 보았지만.. 실패하고
결국 이 방법으로 했습니다.
'DB > JPA' 카테고리의 다른 글
JPA 즉시 로딩, 지연 로딩 (0) | 2023.01.20 |
---|---|
@PrePersist... (0) | 2023.01.14 |
JPA Auditing (0) | 2023.01.07 |
JPA @Entity (0) | 2023.01.06 |
JPA 더티 체킹(Dirty Checking) (0) | 2022.12.25 |
댓글