인프런 커뮤니티 질문&답변

탁형님의 프로필 이미지
탁형

작성한 질문수

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

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

해결된 질문

작성

·

302

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;

    }

}

답변 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()으로 받는 순간, 해당 팀도 영속성 컨텍스트에서 가져옵니다.

감사합니다.

탁형님의 프로필 이미지
탁형

작성한 질문수

질문하기