본문 바로가기

Backend/Spring

JPA @ManyToOne Join (Only JpaRepository)

JPA에서 @ManyToOne 어노테이션으로 조인한 Entity를 Join으로 조회하려고 해요.

Inner Join과 Left Outer Join 모두 다뤄보겠습니다.

JpaRepository<T, ID>를 이용할거구요. Native Query는 사용하지 않을거에요.

 

작업 환경은 Spring Boot 2.1.9 + JDK 11 버전입니다.

 

1. BoardEntity

@Entity
@Table(name = "board")
@Getter
@Setter
public class BoardEntity implements Serializable {
	
	private static final long serialVersionUID = 1L;

	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private Long boardId;
	
	@Column(length = 100)
	private String title;

	@Column(length = 4000)
	private String content;

	@Column(updatable = false)
	private Long regBy;
	
	@CreationTimestamp
	@Column(updatable = false)
	private LocalDateTime regDt;
	
	@UpdateTimestamp
	private LocalDateTime updDt;
	
	@ManyToOne
	@JoinColumn(name = "regBy", insertable = false, updatable = false)
	@JsonIgnore
	private UserEntity user;

}

2. UserEntity

@Entity
@Table(name = "user", indexes = @Index(name = "idx_user_1", columnList = "email", unique = true))
@Getter
@Setter
public class UserEntity implements Serializable {
	
	private static final long serialVersionUID = 1L;
	
	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private Long userId;

	@Column(length = 100)
	private String nickname;

	@Column(length = 512)
	private String password;

	@Column(length = 256)
	private String email;
	
	@CreationTimestamp
	@Column(updatable = false)
	private LocalDateTime regDt;
	
	@UpdateTimestamp
	private LocalDateTime updDt;

}

3. BoardMapping

public interface BoardMapping {
	
	Long getBoardId();

	String getTitle();
	
	Long getRegBy();

	LocalDateTime getRegDt();

	LocalDateTime getUpdDt();
	
	UserEntity getUser();

}

4. BoardRepository

public interface BoardRepository extends JpaRepository<BoardEntity, Long> {
	
	Page<BoardMapping> findAllBy(Pageable pageable);

}

 

조인 쿼리가 적용된 것을 확인할 수 있습니다.

 

 

위의 BoardEntity에서 @ManyToOne에 optional = false 설정을 해주면 inner join으로 조회를 할 수 있습니다.

@ManyToOne(optional = false)

 

 

응답 데이터

 

 

 

유저 정보를 모두 담고 있어서 패스워드나 주요 정보들이 노출되네요.

닉네임만 게시글의 등록자로 가져오고 싶어요.

 

BoardMapping을 좀 수정해볼게요.

getUser 뒤에 subfix로 UserEntity의 필드명을 붙여주면 해당 컬럼을 가져올 수 있어요.

getUserNickname으로 받아올 수 있으나 전 regNm이라는 필드로 내려주고 싶어요.

그래서 userNickname은 @JsonIgnore을 붙여서 응답 필드에서 없애고 regNm에 userNickName을 세팅해줬습니다.

 

public interface BoardMapping {
	
	Long getBoardId();

	String getTitle();
	
	Long getRegBy();
	
	Long getViewCnt();

	LocalDateTime getRegDt();

	LocalDateTime getUpdDt();
	
	default String getRegNm() {
		return getUserNickname();
	}
	
	@JsonIgnore
	String getUserNickname();

}

 

 

원하는 데이터만 화면에 응답해줄 때 이 방법을 종종 쓰곤 해요.

 

필요할 때마다 인터페이스를 새로 만들어줘야하고, 복잡한 경우 인터페이스가 지져분해지는 경우도 있습니다.

그래도 알아둬서 나쁠 건 없을 것 같네요.