
Member(N) - Team(1) : 다대일 관계
다 쪽이 외래키를 가진다.
@ToString(of = {"id", "username", "age"}) // @ToString은 연관관계 없는 필드들에만 사용! 연관관계 있는 필드 작성시 무한루프 발생 가능성 존재.(Team 쪽 @ToString에서 다시 member 쪽 @ToString 호출할 경우)
@NoArgsConstructor(access = AccessLevel.PROTECTED) // JPA 기본 생성자 필수, PROTECTED까지 허용. 기본생성자 함부로 사용하지 않도록 방지.
@Getter @Setter
@Entity
public class Member {
@Id
@GeneratedValue
@Column(name = "member_id")
private Long id;
private String username;
private int age;
@ManyToOne(fetch = FetchType.LAZY) // XXXToOne LAZY 명시적 작성 필수
@JoinColumn(name = "team_id") // 연관관계 주인, name에는 외래키 작성
private Team team;
// 생성자 - 여러개 만든 이유: 예제에서 필요해서
// ver1. 이름만
public Member(String username) {
this(username, 0);
}
// ver2. 이름, 나이
public Member(String username, int age) {
this(username, age, null); // 아래 이름, 나이, 팀 3개의 파라미터를 받는 생성자 사용
}
// ver3. 이름, 나이, 팀
public Member(String username, int age, Team team) {
this.username = username;
this.age = age;
if(team != null){
this.team = team;
}
}
// 팀 변경 메서드, 연관관계 편의 메서드
public void changeTeam(Team team){
this.team = team;
team.getMembers().add(this);// Team쪽 데이터까지 관리
}
}
핵심
@ManyToOne(fetch = FetchType.LAZY)
XXXToOne은 FetchTypeLAZY명시적 작성 필수
@JoinColumn(name = "team_id")
연관관계 주인, name에는 외래키 작성
@NoArgsConstructor(access = AccessLevel.PROTECTED)
JPA는 기본 생성자 필수,PROTECTED까지 허용.
PROTECTED로 기본생성자 함부로 사용하지 않도록 방지.
@ToString(of = {"id", "name"})
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Getter @Setter
@Entity
public class Team {
@Id @GeneratedValue
@Column(name = "team_id")
private Long id;
private String name;
@OneToMany(mappedBy = "team") // 연관관계 주인의 반대, mappedBy의 값으로는 Member의 Team 필드명 작성
private List<Member> members = new ArrayList<>();
public Team(String name){
this.name = name;
}
}
핵심
@OneToMany(mappedBy = "team")
- 연관관계 주인의 반대
- mappedBy의 값으로는 Member의 Team 필드명 작성
@SpringBootTest
@Transactional
//@Commit 테이블에 데이터 남아있으면 다른 테스트에 영향을 줌. (단, 테스트 끝날 때마다 rollback해서 테스트 종료 후에는 테이블에 데이터 없음.)
class MemberTest {
@Autowired
EntityManager em;
@Test
public void testEntity() {
// given
// 팀 2개 생성, 저장
Team teamA = new Team("teamA");
Team teamB = new Team("teamB");
em.persist(teamA);
em.persist(teamB);
// 멤버 4명 생성, 저장
Member member1 = new Member("member1", 10, teamA);
Member member2 = new Member("member2", 20, teamA);
Member member3 = new Member("member3", 30, teamB);
Member member4 = new Member("member4", 40, teamB);
em.persist(member1);
em.persist(member2);
em.persist(member3);
em.persist(member4);
// em 초기화
em.flush();
em.clear();
// then
// 모든 멤버 조회 쿼리
List<Member> members = em.createQuery("select m from Member m", Member.class)
.getResultList();
// 지금은 눈으로 보기 위해서 sout으로 하고, 실제로 자동화된 테스트 작성할때는 assert 사용!
for (Member member : members) {
System.out.println("member = " + member); // @ToString
System.out.println("-> member.team = " + member.getTeam()); // member의 소속 팀 출력
}
}
}
참고
h2 DB 실행하고 Test 실행해야한다.
안그러면 아래와 같은 에러 뜬다.
실행성공

System.out 확인

h2 DB에서 실제로 확인
