728x90
반응형
user와 dept 테이블을 맵핑하는 user_dept 테이블이 존재할 때, Entity의 객체 연관관계를 맵핑하여 영속 상태의 entity를 만들어 보겠습니다.
@Entity
@Table(name = "user")
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class UserEntity {
@Id
@Column(name = "user_id", nullable = false)
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long userId;
@Column(length = 50, nullable = false)
private String name;
@Column(length = 50, nullable = false)
private String lastname;
private int age;
@Column(name = "email_address", length = 200)
private String emailAddress;
@OneToMany(fetch = FetchType.LAZY, mappedBy = "userEntity", cascade = CascadeType.ALL)
private List<UserDeptEntity> userDeptList = new ArrayList<>();
}
@Entity
@Table(name = "dept")
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class DeptEntity {
@Id
@Column(name = "dept_cd", nullable = false)
private String deptCd;
@Column(name = "dept_nm", nullable = false)
private String deptNm;
@OneToMany(fetch = FetchType.LAZY, mappedBy = "deptEntity", cascade = CascadeType.ALL)
private List<UserDeptEntity> userDeptList = new ArrayList<>();
}
@Entity
@Table(name = "user_dept", uniqueConstraints = {
@UniqueConstraint(columnNames = {"user_id", "dept_cd"})
})
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class UserDeptEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne
@JoinColumn(name = "user_id")
private UserEntity userEntity;
@ManyToOne
@JoinColumn(name = "dept_cd")
private DeptEntity deptEntity;
@Builder
public UserDeptEntity(UserEntity userEntity, DeptEntity deptEntity) {
this.userEntity = userEntity;
this.deptEntity = deptEntity;
}
}
userEntity를 조회하면 연관되는 데이터가 모두 조회됩니다.
원하는 데이터를 조회하기 위해선 아래 코드처럼 Projection을 사용하여 원하는 값을 조회할 수 있습니다.
@Repository
@RequiredArgsConstructor
public class UserRepositoryCustomImpl {
private final JPAQueryFactory jpaQueryFactory;
private QUserEntity userEntity = QUserEntity.userEntity;
private QUserDeptEntity userDeptEntity = QUserDeptEntity.userDeptEntity;
public List<UserDeptDTO.DetailRes> findAllByDeptCd(UserDeptDTO.GetListReq param) {
return jpaQueryFactory.select(Projections.constructor(UserDeptDTO.DetailRes.class,
userEntity.userId, userEntity.name, userEntity.age, userDeptEntity.deptEntity.deptNm))
.from(userEntity)
.leftJoin(userDeptEntity)
.on(userEntity.userId.eq(userDeptEntity.deptEntity.userId)
.and(userDeptEntity.deptEntity.deptCd.eq(param.getDeptCd())))
.orderBy(userEntity.userId.asc())
.offset(param.getLimitOffSet())
.limit(param.getRecordCountPerPage())
.fetch();
}
}
public class UserDeptDTO {
@Getter @Setter
public static class GetListReq extends PagingCommonVO {
private String deptCd;
}
@Getter @Setter
@NoArgsConstructor
public static class DetailRes {
private long userId;
private String name;
private int age;
private String deptNm;
public DetailRes(long userId, String name, int age, String deptNm) {
this.userId = userId;
this.name = name;
this.age = age;
this.deptNm = deptNm;
}
}
}
Entity의 영속성 상태가 변경되었을 때 이를 연관된 Entity에도 전파시킬 때는 cascade를 사용합니다.
(예. dept 데이터 삭제를 하면 user_dept 테이블의 데이터도 자동으로 삭제시킬 때 cascade = CascadeType.REMOVE)
Cascade 옵션
- PERSIST
- 엔티티를 영속화할 때 연관된 엔티티도 함께 유지 (* PERSIST의 예상치 못한 동작)
- 연관 엔티티가 DB에 이미 저장이 되어있어도 다시 persist 하기 때문에 detached entity passed to persist Exception이 발생함(이경우에는 CascadeType.MERGE를 사용)
- MERGE
- 엔티티 상태를 병합할 때, 연관된 엔티티도 함께 병합
- 트랜잭션이 종료되고 detach 상태에서 엔티티가 merge()를 수행하게 되면 연관 엔티티의 추가 및 수정사항도 함께 적용됨
- REFRESH
- 엔티티를 새로 고칠 때, 연관된 엔티티도 새로고침
- REMOVE
- 엔티티를 삭제할 때, 연관된 엔티도 함께 삭제
- DETACH
- 부모 엔티티가 detach()를 수행하게 되면, 연관된 엔티티도 detach() 상태가 되어 변경사항이 반영되지 않음
- 부모 엔티티가 detach()를 수행하게 되면, 연관된 엔티티도 detach() 상태가 되어 변경사항이 반영되지 않음
- ALL
- 모든 Cascade 적용
[Reference]
728x90
반응형
'spring > spring jpa' 카테고리의 다른 글
[QueryDSL] FullText 검색을 위한 Match ... against 절 사용법 (0) | 2023.08.24 |
---|---|
[SpringBoot] QueryDSL org.apache.jasper.JasperException: Unable to compile class for JSP: (0) | 2023.08.24 |
[SpringBoot2] JPA Master/Slave 구조 분기 처리 (2) | 2023.08.23 |
[SpringBoot] JPA Projection (0) | 2021.06.23 |
[SpringBoot] Mybatis + JPA + QueryDsl 설정 (0) | 2021.06.10 |
댓글