inflearn logo
강의

강의

N
챌린지

챌린지

멘토링

멘토링

N
클립

클립

로드맵

로드맵

지식공유

실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발

Entity에 로직을 구현하는 경우의 고민입니다.

해결된 질문

500

탁형

작성한 질문수 5

0

안녕하세요. 강의 너무 잘 듣고 있습니다.

다름이 아니라 Entity에 로직을 구현하는 경우 영속성 컨텍스트에 관한 고민이 생겨 질문드립니다.

예를 들어, Member와 Team이 있습니다.

Member는 소속팀 참조를 위한 단방향 N:1 관계가 있고,

Team 은 해당 팀의 리더 참조를 위한 단방향 1:1 관계가 있습니다.

그리고 Team의 리더를 변경하는 기능이 있습니다. (changeLeader 메소드)

이 때 로직은,

1. TeamA의 리더로 설정하려는 MemberA가 TeamB의 리더이면, TeamB의 리더를 null로 변경한다.

2. MemberA의 현재 소속팀을 TeamA로 변경한다.

3. TeamA의 리더를 MemberA로 변경한다.

대략 이렇다면, changeLeader 메소드에서는 내부적으로 MemberA의 예전 팀인 TeamB의 changeLeader를 호출하게 될텐데, 아래 구현한 구조 상으로는 영속성 컨텍스트에서 TeamB 객체를 가져오지 않은 상태입니다. 이 경우에는 애초에 메소드 파라미터로 MemberA의 예전팀(TeamB)도 받도록 설계를 해야 하는건지, 다른 좋은 구조가 있는지 궁금합니다.

public class Member {

...

    @ManyToOne(fetch = FetchType.LAZY)

    @JoinColumn(name = "team_id")

    private Team team;

    public void changeTeam(Team team) {

        this.team = team;

    }

}

public class Team {

...

    @OneToOne(fetch = FetchType.LAZY)

    @JoinColumn(name = "leader_id")

    private Member leader;

    public void changeLeader(Member member) {

        if (member != null) {

            // ... 이전 팀의 리더 였는지 판단 ...

            // 해당 멤버의 이전 팀의 리더를 null로 변경한다.

            Team oldTeam = member.getTeam();

            if (oldTeam != null) {

                oldTeam.changeLeader(null);

            }

            // 해당 멤버의 팀을 변경한다.

            member.changeTeam(this);

        }

        // 이 팀의 리더를 해당 멤버로 변경한다.

        this.leader = member;

    }

}

JPA 웹앱 spring-boot spring java

답변 9

1

탁형

빠르고 명쾌한 대답 감사합니다~!

1

김영한

네 벌크 업데이트를 하려면 별도의 로직으로 빠지는게 맞습니다^^

건수가 몇건 없고 간단한 경우에는 엔티티 안에서 처리하면 되지만, 데이터가 많으면 벌크 연산으로 처리하는게 맞습니다^^

1

탁형

아~~ 그렇군요. 정확한 설명 감사합니다~!

1

김영한

네 여기서 읽기 전용이라는 의미는 연관관계의 주인 관점에서 FK를 손대지 않는다는 의미입니다.

연관관계를 로딩하면(읽으면) 영속상태의 엔티티를 얻을 수 있습니다^^!

0

탁형

추가 질문이 있습니다.

getMembers().forEach( m.leaveTeam() ) 같은 경우를 Bulk update를 하고 싶으면, 결국 이 부분은 로직에서 빠지고 외부에서 별도로 처리를 해야 할까요? JPA로 가면서 DDD까지 공부가 필요해지는 것 같아서 어려운 부분도 있네요ㅎㅎ

0

탁형

아, 그러면 Team에서 getMembers().forEach로 돌려도 그 Member들의 영속성 컨텍스트 객체를 얻어오고, changeTeam으로 값 변경이 가능한건가요? 잘 이해하면서 따라왔다고 생각했는데 또 헷갈리네요. Team의 members는 mappedBy라고 가정했을 때, 읽기만 가능한거라고 이해했었거든요.

0

김영한

안녕하세요. 탁형님 좋은 질문입니다.

먼저 제가 강의에서 정말 강조했던 내용! 연관관계의 주인은 비즈니스와 아무런 관계가 없다!를 떠올려주세요^^

상황에 따라 다르기는 할 것 같은데, 아마도 다음과 같이 만들면 좋지 않을까 생각합니다.

Team {

  disable() {

    getMembers().forEach( m.leaveTeam() )

  }

}

Member {

  leaveTeam() {

    this.changeTeam(null);

  }

}

도움이 되셨길 바래요^^

0

탁형

다른 질문을 여기에 이어서 하고자 합니다.

Member -> Team 단방향 N:1 관계라고 가정하고,

Team에서 해당 팀을 비활성화하는 disable()이라는 메소드를 만들고자 합니다.

이 때, 팀원 Member들의 team을 모두 null로 변경하고자 하는데,

로직 처리를 어디서 어떻게 하는 것이 좋은 구조인지 궁금합니다.

양방향 관계로 바꾼다고 해도 Team은 연관관계의 주인이 아니기 때문에,

Team의 getMembers()를 iteration하면서 member.changeTeam(null)을 하는건 맞지 않을 것 같습니다.

0

탁형

자문자답입니다.

oldTeam을 member.getTeam()으로 받는 순간, 해당 팀도 영속성 컨텍스트에서 가져옵니다.

감사합니다.

sdk 설정 오류

0

48

2

오탈자 - @Transactional

0

53

1

src/test/resources 테스트 경로 문제

0

49

1

상품 등록후 H2 db 출력 순서 바꿀 수 있나요?

0

62

1

MemberRepositoryTest 실행오류

0

77

1

boot 4.x >>> trasasction rolled back log & p6spy(영한님, 수업 자료 업데이트 해주시면 감사하겠습니다!!)

1

183

2

강의 마지막 QueryDSL 사용 부분 질문있습니다

1

137

2

클라이언트에서 isbn과 author 수정 요청을 한 경우에 대해 질문드립니다.

0

50

1

도메인 모델 패턴 vs 트랜잭션 스크립트 패턴

0

71

1

기본 생성자

0

59

1

h2 DB 연결시 jdbc url 변경 이유가 궁금합니다.

0

100

1

멤버서비스테스트 부분에서 막힙니다.

0

163

4

실무에서도 EntityManager를 이용해서 많이 작업하는 편일까요?

0

115

1

초반에 h2 다운로드 과정 꼭 필요한가요?

0

117

2

자신 필드에도 get으로 접근하는 이유가 있을까요?

0

111

1

24분 27초 연관관계 편의 메서드 위치

0

112

1

단건 주문만 가능하게 한건 의도한 부분이신가요?

0

107

2

빌드 툴, Gradle

0

57

1

h2연결은 된 것 같은데 엔티티 테이블까지 작성 후 확인해보아도 테이블이 안보입니다

0

73

2

Repository에서 EntityManager 주입 방식 차이

0

87

1

롬복과 사용자 정의 setter 메서드

0

70

1

주문 목록 조회 fetch join 질문드립니다

0

80

1

dirty checking 질문드립니다.

0

80

1

동시성 관련 질문입니다

0

72

1