해결됨
자바 ORM 표준 JPA 프로그래밍 - 기본편
양방향 연관관계에서 연관관계 편의 메서드 위치에 대해 질문드립니다.
[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예)[질문 내용]안녕하세요. 좋은 강의 덕분에 양질의 지식을 비교적 수월하게 습득하고 있습니다.양방향 연관관계에서 편의 메서드는 어디에 위치하는게 좋은지 여쭙고자 합니다.(비슷한 질문들을 봤지만 이러한 경우에 어떤게 가장 좋은 선택일지 궁금하여 질문드립니다.)비슷한 질문1 : https://www.inflearn.com/questions/16308비슷한 질문2 : https://www.inflearn.com/questions/99330 현재상태위와 같이 일대다(1:N) 관계가 있고 Team 을 애그리거트 루트로 잡았습니다.도메인 룰은 다음과 같습니다.Team 은 반드시 이름이 있어야한다.Player는 반드시 이름과 나이가 있어야한다.Player는 반드시 Team에 소속되어야하며, 하나의 Team 에만 소속될 수 있다.player 의 Team 은 변경될 수 없다.엔티티 코드 입니다. (연관관계 편의 메서드를 애그리거트 루트쪽에 두었습니다.)(두 엔티티는 동일한 패키지에 있습니다. package com.example.jpa.module.team.domain;)@Entity
public class Team {
@Id @GeneratedValue
private Long teamNo;
private String name;
@OneToMany(mappedBy = "team", cascade = CascadeType.ALL)
private List<Player> players = new ArrayList<>();
//생성자
public Team(String name) {
this.name = name;
}
//연관관계 편의 메서드
public void addPlayer(Player player) {
player.setTeam(this);
this.players.add(player);
}
}@Entity
public class Player {
@Id @GeneratedValue
private Long playerNo;
private String name;
private Integer age;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "team_no")
private Team team;
//생성자
public Player(String name, int age) {
this.name = name;
this.age = age;
}
void setTeam(Team team) {
this.team = team;
}
}service 계층 코드입니다.Team team = new Team("team1");
Player player = new Player("kim", 24);
team.addPlayer(player);
teamRepository.save(team);Team 이 Player 를 완전히 소유하는 관계이기 때문에 애그리거트 루트를 Team 으로 잡았고 연관관계 메서드 또한 Team 에 있는게 자연스러워 보입니다.(예시가 Team-Player라 결합도가 좀 떨어지는것 처럼 느껴지는데 주문-주문항목 이나 게시글-첨부파일 같은 관계로 봐주시면 감사하겠습니다.)문제점연관관계 편의 메서드 addPlayer(..)가 호출되기 전까지 Player의 도메인 룰이 깨진 상태가 됩니다.도메인 룰 3번 "Player 는 반드시 Team에 소속되어야 한다" 를 위반하게 됩니다.Player의 setTeam(..) 메서드를 클래스 외부에 공개해야 합니다.같은 패키지라 public 으로 공개하진 않았지만 해당 메서드로 인해 도메인 룰 4번 "player 의 Team 은 변경될 수 없다." 를 위반할 여지가 생겼습니다.setTeam(..) 메서드에 this.team != null 인 경우 예외를 발생시켜 도메인 룰을 지킬 수 있지만 좋은 방법인지 잘 모르겠습니다..시도한 방법Player의 생성자에 Team을 받도록 합니다.public Player(Team team, String name, int age) {
this.team = team;
this.name = name;
this.age = age;
}근데 이렇게 하니 그냥 연관관계 편의 메서드를 Player에 두는게 나은것 같아 생성될때 연관관계를 맺도록 정적 팩토리 메서드를 작성했습니다.public static Player createAndLink(Team team, String name, int age) {
Player player = new Player(team, name, age); //생성자 private 으로 변경
team.getPlayers().add(player); //반대편 연관관계 설정
return player;
}일단 도메인 룰은 모두 만족하는 듯 보이나 service 계층 코드가 뭔가 부자연스럽습니다.Team team = new Team("team1");
Player player = Player.createAndLink(team, "kim", 24);
teamRepository.save(team);위 코드를 보면 player를 생성하고 사용하지 않는것 처럼 보여 불필요한 코드로 인식됩니다.(인텔리제이에서도 player가 미사용 중이라고 나옵니다.)혹시 위와 같은 상황에서 어떻게 해결하는게 가장 좋은 방법일까요?(긴 글 읽어주셔서 감사합니다.)