Skip to content

Commit 54b652c

Browse files
authored
Merge pull request #591 from TaskFlow-CLAP/CLAP-441
CLAP-441 Member entity 조회 시 departement 조회 쿼리가 실행되지 않도록 리팩토링
2 parents 95b7b4e + be2ebd2 commit 54b652c

File tree

11 files changed

+95
-27
lines changed

11 files changed

+95
-27
lines changed

src/main/java/clap/server/adapter/outbound/persistense/MemberPersistenceAdapter.java

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,24 @@ public Optional<Member> findById(final Long id) {
3131
return memberEntity.map(memberPersistenceMapper::toDomain);
3232
}
3333

34+
@Override
35+
public Optional<Member> findByIdWithFetchDepartment(Long id) {
36+
Optional<MemberEntity> memberEntity = memberRepository.findByIdWithFetchDepartment(id);
37+
return memberEntity.map(memberPersistenceMapper::toDomain);
38+
}
39+
3440
@Override
3541
public Optional<Member> findActiveMemberById(final Long id) {
3642
Optional<MemberEntity> memberEntity = memberRepository.findByStatusAndMemberId(MemberStatus.ACTIVE, id);
3743
return memberEntity.map(memberPersistenceMapper::toDomain);
3844
}
3945

46+
@Override
47+
public Optional<Member> findActiveMemberByIdWithFetchDepartment(Long id) {
48+
Optional<MemberEntity> memberEntity = memberRepository.findActiveMemberByIdWithFetchDepartment(id);
49+
return memberEntity.map(memberPersistenceMapper::toDomain);
50+
}
51+
4052
@Override
4153
public Optional<Member> findActiveMemberByNickname(final String nickname) {
4254
Optional<MemberEntity> memberEntity = memberRepository.findActiveMemberByNickname(nickname);
@@ -85,7 +97,7 @@ public List<Member> findActiveManagers() {
8597

8698
@Override
8799
public Page<Member> findAllMembers(final Pageable pageable) {
88-
return memberRepository.findAllMembers(pageable).map(memberPersistenceMapper::toDomain);
100+
return memberRepository.findAllMembersWithFetchDepartment(pageable).map(memberPersistenceMapper::toDomain);
89101
}
90102

91103
@Override

src/main/java/clap/server/adapter/outbound/persistense/mapper/DepartmentPersistenceMapper.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@
66
import org.mapstruct.Mapper;
77
import org.mapstruct.Mapping;
88

9-
@Mapper(componentModel = "spring", uses = {MemberPersistenceMapper.class})
9+
@Mapper(componentModel = "spring")
1010
public interface DepartmentPersistenceMapper extends PersistenceMapper<DepartmentEntity, Department> {
1111

12-
@Mapping(source = "admin.memberId", target = "adminId")
12+
@Mapping(target = "adminId", ignore = true)
1313
@Mapping(source = "manager", target = "isManager")
1414
Department toDomain(DepartmentEntity entity);
1515

src/main/java/clap/server/adapter/outbound/persistense/mapper/MemberPersistenceMapper.java

Lines changed: 45 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,64 @@
11
package clap.server.adapter.outbound.persistense.mapper;
22

3+
import clap.server.adapter.outbound.persistense.entity.member.DepartmentEntity;
34
import clap.server.adapter.outbound.persistense.entity.member.MemberEntity;
5+
import clap.server.domain.model.member.Department;
46
import clap.server.domain.model.member.Member;
57
import clap.server.domain.model.member.MemberInfo;
8+
import org.hibernate.Hibernate;
69
import org.mapstruct.Mapper;
710
import org.mapstruct.Mapping;
811
import org.mapstruct.Named;
912
import org.springframework.beans.factory.annotation.Autowired;
1013

11-
@Mapper(componentModel = "spring", uses = {DepartmentPersistenceMapper.class})
14+
@Mapper(componentModel = "spring", uses = DepartmentPersistenceMapper.class)
1215
public abstract class MemberPersistenceMapper {
1316

1417
@Autowired
1518
protected DepartmentPersistenceMapper departmentPersistenceMapper;
1619

17-
@Mapping(source = "name", target = "memberInfo.name")
18-
@Mapping(source = "email", target = "memberInfo.email")
19-
@Mapping(source = "nickname", target = "memberInfo.nickname")
20-
@Mapping(source = "role", target = "memberInfo.role")
21-
@Mapping(source = "departmentRole", target = "memberInfo.departmentRole")
22-
@Mapping(source = "department", target = "memberInfo.department")
23-
@Mapping(source = "reviewer", target = "memberInfo.isReviewer")
24-
@Mapping(source = "admin", target = "admin", qualifiedByName = "toDomain")
25-
@Mapping(source = "createdAt", target = "createdAt")
26-
@Mapping(source = "updatedAt", target = "updatedAt")
27-
@Mapping(source = "memberId", target = "memberId")
20+
@Mapping(target = "memberInfo", expression = "java(memberEntityToMemberInfo(entity))")
21+
@Mapping(target = "department", expression = "java(mapDepartment(entity))")
22+
@Mapping(target = "admin", ignore = true)
23+
@Mapping(source = "entity.createdAt", target = "createdAt")
24+
@Mapping(source = "entity.updatedAt", target = "updatedAt")
25+
@Mapping(source = "entity.memberId", target = "memberId")
2826
public abstract Member toDomain(MemberEntity entity);
2927

28+
protected MemberInfo memberEntityToMemberInfo(MemberEntity memberEntity) {
29+
if (memberEntity == null) {
30+
return null;
31+
}
32+
33+
DepartmentEntity departmentEntity = memberEntity.getDepartment();
34+
Department department = (departmentEntity != null && Hibernate.isInitialized(departmentEntity))
35+
? departmentPersistenceMapper.toDomain(departmentEntity)
36+
: null;
37+
38+
return MemberInfo.builder()
39+
.name(memberEntity.getName())
40+
.email(memberEntity.getEmail())
41+
.nickname(memberEntity.getNickname())
42+
.role(memberEntity.getRole())
43+
.departmentRole(memberEntity.getDepartmentRole())
44+
.isReviewer(memberEntity.isReviewer())
45+
.department(department)
46+
.build();
47+
}
48+
49+
protected Department mapDepartment(MemberEntity entity) {
50+
DepartmentEntity department = entity.getDepartment();
51+
if (department == null) {
52+
return null;
53+
}
54+
55+
if (!Hibernate.isInitialized(department)) {
56+
return null;
57+
}
58+
59+
return departmentPersistenceMapper.toDomain(department);
60+
}
61+
3062
@Mapping(source = "memberInfo.name", target = "name")
3163
@Mapping(source = "memberInfo.email", target = "email")
3264
@Mapping(source = "memberInfo.nickname", target = "nickname")
@@ -40,6 +72,7 @@ public abstract class MemberPersistenceMapper {
4072
@Mapping(source = "memberId", target = "memberId")
4173
public abstract MemberEntity toEntity(Member member);
4274

75+
4376
@Named("toDomain")
4477
protected Member toDomainAdmin(MemberEntity admin) {
4578
if (admin == null) return null;

src/main/java/clap/server/adapter/outbound/persistense/repository/member/MemberCustomRepositoryImpl.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ public class MemberCustomRepositoryImpl implements MemberCustomRepository {
2525
private Page<MemberEntity> executeQueryWithPageable(Pageable pageable, BooleanBuilder whereClause, OrderSpecifier<?> orderSpecifier) {
2626
List<MemberEntity> result = queryFactory
2727
.selectFrom(memberEntity)
28+
.leftJoin(memberEntity.department).fetchJoin()
2829
.where(whereClause)
2930
.orderBy(orderSpecifier)
3031
.offset(pageable.getOffset())

src/main/java/clap/server/adapter/outbound/persistense/repository/member/MemberRepository.java

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
import clap.server.adapter.outbound.persistense.entity.member.MemberEntity;
44
import clap.server.adapter.outbound.persistense.entity.member.constant.MemberRole;
55
import clap.server.adapter.outbound.persistense.entity.member.constant.MemberStatus;
6+
import org.springframework.data.domain.Page;
7+
import org.springframework.data.domain.Pageable;
68
import org.springframework.data.jpa.repository.JpaRepository;
79
import org.springframework.data.jpa.repository.Query;
810
import org.springframework.data.repository.query.Param;
@@ -13,7 +15,13 @@
1315
import java.util.Set;
1416

1517
@Repository
16-
public interface MemberRepository extends JpaRepository<MemberEntity, Long>, MemberCustomRepository {
18+
public interface MemberRepository extends JpaRepository<MemberEntity, Long>, MemberCustomRepository {
19+
@Query("SELECT m FROM MemberEntity m LEFT JOIN FETCH m.department WHERE m.memberId = :id")
20+
Optional<MemberEntity> findByIdWithFetchDepartment(Long id);
21+
22+
@Query("SELECT m FROM MemberEntity m LEFT JOIN FETCH m.department WHERE m.memberId = :id AND m.status='ACTIVE'")
23+
Optional<MemberEntity> findActiveMemberByIdWithFetchDepartment(Long id);
24+
1725
List<MemberEntity> findByRoleAndStatus(MemberRole role, MemberStatus status);
1826

1927
Optional<MemberEntity> findByStatusAndMemberId(MemberStatus memberStatus, Long memberId);
@@ -26,7 +34,9 @@ public interface MemberRepository extends JpaRepository<MemberEntity, Long>, Me
2634

2735
List<MemberEntity> findByIsReviewerTrue();
2836

29-
List<MemberEntity> findAll(); // 전체 회원 조회
37+
@Query(value = "SELECT DISTINCT m FROM MemberEntity m LEFT JOIN FETCH m.department",
38+
countQuery = "SELECT COUNT(DISTINCT m) FROM MemberEntity m")
39+
Page<MemberEntity> findAllMembersWithFetchDepartment(Pageable pageable);
3040

3141
Optional<MemberEntity> findByMemberIdAndIsReviewerTrue(Long memberId);
3242

src/main/java/clap/server/adapter/outbound/persistense/repository/task/TaskCustomRepositoryImpl.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,8 @@ public List<TaskEntity> findTasksByFilter(Long processorId, List<TaskStatus> sta
117117
BooleanBuilder builder = createTaskBoardFilter(processorId, statuses, untilDateTime, request);
118118
return queryFactory
119119
.selectFrom(taskEntity)
120+
.leftJoin(taskEntity.requester).fetchJoin()
121+
.leftJoin(taskEntity.requester.department).fetchJoin()
120122
.where(builder)
121123
.orderBy(taskEntity.processorOrder.asc())
122124
.fetch();

src/main/java/clap/server/application/port/inbound/admin/FindAllMembersUsecase.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import clap.server.adapter.inbound.web.dto.common.PageResponse;
55
import org.springframework.data.domain.Pageable;
66

7+
@Deprecated
78
public interface FindAllMembersUsecase {
89
PageResponse<RetrieveAllMemberResponse> findAllMembers(Pageable pageable);
910
}

src/main/java/clap/server/application/port/outbound/member/LoadMemberPort.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,12 @@
1515
public interface LoadMemberPort {
1616
Optional<Member> findById(Long id);
1717

18+
Optional<Member> findByIdWithFetchDepartment(Long id);
19+
1820
Optional<Member> findActiveMemberById(Long id);
1921

22+
Optional<Member> findActiveMemberByIdWithFetchDepartment(Long id);
23+
2024
List<Member> findActiveManagers();
2125

2226
Optional<Member> findReviewerById(Long id);

src/main/java/clap/server/application/service/admin/DeleteMemberService.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
import clap.server.exception.ApplicationException;
1111
import clap.server.exception.code.MemberErrorCode;
1212
import lombok.RequiredArgsConstructor;
13-
import org.hibernate.Hibernate;
1413
import org.springframework.transaction.annotation.Transactional;
1514

1615
@ApplicationService
@@ -29,7 +28,6 @@ public void deleteMember(Long memberId) {
2928
if (member.getMemberInfo().getRole() == MemberRole.ROLE_MANAGER) {
3029
managerInfoUpdatePolicy.validateNoRemainingTasks(member);
3130
}
32-
Hibernate.initialize(member.getDepartment());
3331
member.softDelete();
3432
commandMemberPort.save(member);
3533
}

src/main/java/clap/server/application/service/admin/ManageMemberService.java

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,30 +6,32 @@
66
import clap.server.application.mapper.response.MemberResponseMapper;
77
import clap.server.application.port.inbound.admin.MemberDetailUsecase;
88
import clap.server.application.port.inbound.admin.UpdateMemberUsecase;
9-
import clap.server.application.port.inbound.domain.MemberService;
109
import clap.server.application.port.outbound.member.CommandMemberPort;
1110
import clap.server.application.port.outbound.member.LoadDepartmentPort;
11+
import clap.server.application.port.outbound.member.LoadMemberPort;
1212
import clap.server.common.annotation.architecture.ApplicationService;
1313
import clap.server.domain.model.member.Department;
1414
import clap.server.domain.model.member.Member;
1515
import clap.server.domain.policy.member.ManagerInfoUpdatePolicy;
1616
import clap.server.exception.ApplicationException;
1717
import clap.server.exception.code.DepartmentErrorCode;
18+
import clap.server.exception.code.MemberErrorCode;
1819
import lombok.RequiredArgsConstructor;
1920
import org.springframework.transaction.annotation.Transactional;
2021

2122
@ApplicationService
2223
@RequiredArgsConstructor
2324
class ManageMemberService implements UpdateMemberUsecase, MemberDetailUsecase {
24-
private final MemberService memberService;
25+
private final LoadMemberPort loadMemberPort;
2526
private final CommandMemberPort commandMemberPort;
2627
private final LoadDepartmentPort loadDepartmentPort;
2728
private final ManagerInfoUpdatePolicy managerInfoUpdatePolicy;
2829

2930
@Override
3031
@Transactional
3132
public void updateMemberInfo(Long adminId, Long memberId, UpdateMemberRequest request) {
32-
Member member = memberService.findById(memberId);
33+
Member member = loadMemberPort.findByIdWithFetchDepartment(memberId).orElseThrow(
34+
() -> new ApplicationException(MemberErrorCode.MEMBER_NOT_FOUND));
3335
Department department = loadDepartmentPort.findById(request.departmentId()).orElseThrow(() ->
3436
new ApplicationException(DepartmentErrorCode.DEPARTMENT_NOT_FOUND));
3537
managerInfoUpdatePolicy.validateDepartment(department, request.role());
@@ -46,7 +48,8 @@ public void updateMemberInfo(Long adminId, Long memberId, UpdateMemberRequest re
4648
@Override
4749
@Transactional(readOnly = true)
4850
public MemberDetailsResponse getMemberDetail(Long memberId) {
49-
Member member = memberService.findById(memberId);
51+
Member member = loadMemberPort.findByIdWithFetchDepartment(memberId).orElseThrow(
52+
() -> new ApplicationException(MemberErrorCode.MEMBER_NOT_FOUND));;
5053
return MemberResponseMapper.toMemberDetailsResponse(member);
5154
}
5255
}

0 commit comments

Comments
 (0)