단방향 연관관계의 이해를 위해, 다대일(N:1) 단방향 관계로 설명을 해보겠습니다.
이해를 돕기 위해, 회원(Member)과 팀(Team)의 관계를 예시로 들어보겠습니다.
위 조건에 다대일 단방향 관계를 위한 추가 조건은 아래와 같습니다.
위 관계를 통해서 객체 및 테이블 모델링을 한 결과는 아래와 같습니다.
해당 객체 모델링을 코드로 나타내어 보도록 하겠습니다.
Member 클래스 (다대일
에서 다
에 해당합니다.)
@Entity
public class Member {
@Id
@Column(name = "MEMBER_ID)
private Long id;
@Column(name = "USERNAME")
private String username;
@ManyToOne
@JoinColumn(name = "TEAM_ID")
private Team team;
// Getter, Setter, Constructor...
}
Team 클래스 (다대일
에서 일
에 해당합니다.)
@Entity
public class Team {
@Id
@Column(name = "TEAM_ID)
private Long id;
@Column(name = "NAME")
private String name;
// Getter, Setter, Constructor
}
다대일 단방향
매핑에서는 다
에 해당하는 클래스에 일
에 해당하는 클래스를 참조 필드로 작성해주시면 됩니다.
이때, 해당 참조 필드위에 @ManyToOne
과 @JoinColumn(name = "외래키 이름")
을 추가하여 줍니다.
외래키를 매핑할 때 사용합니다.
속성 | 기능 | 기본값 |
---|---|---|
name | 매핑할 외래 키 이름 | "필드명" + "_" + "참조하는 테이블의 기본 키 컬럼명" |
referencedColumnName | 외래 키가 참조하는 대상 테이블의 컬럼명 | 참조하는 테이블의 기본 키 컬럼명 |
foreignKey(DDL) | 외래 키 제약조건을 직접 지정할 수 있다. 이 속성은 테이블을 생성할 때만 사용한다. | |
unique | @Column의 속성과 같다 | |
nullable | @Column의 속성과 같다 | |
insertable | @Column의 속성과 같다 | |
updatable | @Column의 속성과 같다 | |
columnDefinition | @Column의 속성과 같다 | |
table | @Column의 속성과 같다 |
JoinColumn 어노테이션은 생략 가능합니다.
@JoinColumn을 생략하면 외래 키를 찾을 때 기본 전략을 사용합니다.
기본 전략 : 필드명 + _ + 참조하는 테이블의 컬럼명
다대일 관계에서 사용합니다.
속성 | 기능 | 기본값 |
---|---|---|
optional | false로 설정하면 연관된 엔티티가 항상 있어야 한다 | true |
fetch | 글로벌 패치 전략을 설정한다. (자세한 내용은 추후에) | @ManyToOne=FetchType.EAGER (즉시 로딩), @OneToMany=FetchType.LAZY (지연 로딩) |
cascade | 영속성 전이 기능을 사용한다. (자세한 내용은 추후에) | |
targetEntity | 연관된 엔티티의 타입 정보를 설정한다. 이 기능은 거의 사용하지 않음 |
연관관계를 등록, 수정, 삭제, 조회하는 예제를 통해 연관관계를 어떻게 사용하는지 알아보겠습니다.
public void teamSave() {
// 팀 1 저장
Team team1 = new Team(0L, "팀1");
entityManager.persist(team1); // 영속화
// 회원 1 저장
Member member1 = new Member(0L, "회원1");
member1.setTeam(team1); // 연관관계 설정 member1 → team1
entityManager.persist(member1);
// 회원 2 저장
Member member2 = new Member(1L, "회원2");
member2.setTeam(team1); // 연관관계 설정 member2 → team1
entityManager.persist(member2);
}
JPA에서 엔티티를 저장할 때 연관된 모든 엔티티는 영속 상태이어야 합니다.
위 코드를 실행하였을 때, 실행되는 SQL 은 아래와 같습니다.
INSERT INTO TEAM (TEAM_ID, NAME) VALUES (0, '팀1');
INSERT INTO MEMBER (MEMBER_ID, USERNAME, TEAM_ID) VALUES (0, '회원1', 0);
INSERT INTO MEMBER (MEMBER_ID, USERNAME, TEAM_ID) VALUES (1, '회원2', 0);
연관관계가 있는 엔티티를 조회하는 방법은 크게 2가지가 있습니다.
객체 그래프 탐색
member.getTeam() 을 사용해서 member와 연관된 team 엔티티를 조회할 수 있습니다.
Member member = entityManager.find(Member.class, 0L);
Team team = member.getTeam(); // 객체 그래프 탐색
System.out.println("팀 이름 = " + team.getName());
// 출력 결과 : 팀 이름 = 팀1
SELECT m.MEMBER_ID, m.TEAM_ID, m.USERNAME, t.TEAM_ID, t.NAME
FROM
Member m
LEFT OUTER JOIN
Team t
ON m.TEAM_ID = t.TEAM_ID
WHERE m.MEMBER_ID = 0;
객체지향 쿼리 (JPQL) 사용
String jpql = "select m.team from Member m where m.id = :memberId";
Team team = entityManager.createQuery(jpql, Team.class)
.setParameter("memberId", 0L)
.getSingleResult();
System.out.println("팀 이름 = " + team.getName());
// 출력 결과 : 팀 이름 = 팀1
SELECT t.*
FROM Team t
JOIN Member m ON t.TEAM_ID = m.TEAM_ID
WHERE m.MEMBER_ID = 0;
팀1 소속이던 회원1 을 새로운 팀2 에 소속하도록 수정해보겠습니다.
// 새로운 팀2 영속화
Team team2 = new Team(1L, "팀2");
entityManager.persist(team2);
// 회원1에 새로운 팀2 설정
Member member = entityManager.find(Member.class, 0L);
member.setTeam(team2);
수정은 entityManager.update(); 와 같은 메서드가 없으며,
조회한 엔티티의 값만 변경해두면 트랜잭션을 커밋할 때, 플러시가 일어나면서 변경 감지 기능이 작동합니다.
이때, 변경사항을 데이터베이스에 자동으로 반영해줍니다.
UPDATE MEMBER
SET
TEAM_ID = 1, ...
WHERE
MEMBER_ID = 0;
회원1 을 어느 팀에도 소속하지 않도록 변경해보겠습니다.
Member member1 = entityManager.find(Member.class, 0L);
member1.setTeam(null);
위 코드를 실행했을 때, 실행되는 SQL 은 아래와 같습니다.
UPDATE MEMBER
SET
TEAM_ID = null, ...
WHERE
MEMBER_ID = 0;
다대일
연관관계에서 다
에 연관된 엔티티인 Team 객체들 중, 팀1 을 제거해보겠습니다.
이때, 기존에 있던 연관관계를 먼저 제거하고 삭제를 수행해야 합니다.
그렇지 않으면 외래 키 제약 조건에 의해 데이터베이스에서 오류가 발생합니다.
// 나머지 회원2 에 대한 연관관계를 제거한다.
Member member2 = entityManager.find(Member.class, 1L);
member2.setTeam(null);
Member team = entityManager.find(Team.class, 0L);
entityManager.remove(team);
DELETE
FROM TEAM
WHERE TEAM_ID = 0;
When visiting the capital, choose Escorts Daryaganj for thrilling adventures filled with romance and relaxation. These escorts understand how to pamper clients with care and affection. They’re trained in offering high-class companionship, whether it's for travel, parties, or intimate moments.