작성
·
123
·
수정됨
0
일대다 단방향 연관관계에서,
@Entity
public class Member {
@Id @GeneratedValue
@Column(name = "MEMBER_ID")
private Long id;
@Column(name = "USERNAME")
private String name;
... getter and setter
}
@Entity
public class Team {
@Id @GeneratedValue
@Column(name = "TEAM_ID")
private Long id;
private String name;
@OneToMany
@JoinColumn(name = "TEAM_ID")
private List<Member> members = new ArrayList<>();
... getter and setter
}
Member member = new Member();
member.setName("member1");
em.persist(member);
Team team = new Team();
team.setName("teamA");
team.getMembers().add(member);
em.persist(team);
위와 같은 일대다 단방향 연관관계에서,
1. 이렇게하면 Team엔티티의 members필드인 리스트에 값을 추가 및 변경(team.getMembers.add(member), team.setMembers())하고 Team엔티티를 저장하면, MEMBER 테이블에 대한 UPDATE쿼리가 추가적으로 생성되고, MEMBER 테이블의 외래키(TEAM_ID)를 추가 및 변경할 수 있다.
이렇게 이해했는데요.
@OneToMany @JoinColumn(name = "TEAM_ID") private List<Member> members = new ArrayList<>();를 통해 MEMBER테이블에 TEAM_ID컬럼이 생기는거 같은데, 다른 여러 테이블도 있다고 가정했을때 어떤 이유로 MEMBER테이블에 TEAM_ID컬럼이 생성되는것인가요? @JoinColumn(name = "TEAM_ID")만 보고 MEMBER테이블인지 어떻게 아는것인가요..?
2. db에 위와같이 Member와 Team을 저장한다음에,
team.getMembers()을 해서 Member를 구한 다음에, Member를 통해 MEMBER테이블에 있는 Member의 TEAM_ID값을 알고싶으면 어떻게해야하나요?
제가 알기로는 team.getMembers()로 가져온 Member 객체에는 TEAM_ID를 알 수 있는 필드가 없어서 알수없다고 생각하는데 이게 맞을까요?
그럼 Member의 TEAM_ID값을 알고싶으면 양방향 연관관계로 만들어서 Member 엔티티에 @ManyToOne을 추가하고 Member 객체에서 member.getTeam().getId(); 를 통해 TEAM_ID를 직접 조회해야할까요?
답변 3
0
안녕하세요. 오리쉐리님
1. @JoinColumn(name = "TEAM_ID")
로 인해 왜 MEMBER
테이블에 TEAM_ID
컬럼이 생성되는가?
JPA에서 일대다 단방향(Team → Member) 매핑을 할 때, @OneToMany
에 @JoinColumn(name = "TEAM_ID")
을 지정하면 외래 키(FK)는 다쪽(여러 개의 Member) 테이블에 두게 됩니다. 즉, JPA는 아래와 같은 해석을 합니다:
Team과 Member는 일대다 관계.
@JoinColumn(name = "TEAM_ID")
설정으로 인해 외래 키를 가진 테이블(= Member 테이블) 에 TEAM_ID
라는 컬럼이 생긴다.
JPA가 “어느 테이블에 컬럼을 둘지”를 판단하는 로직은 다음과 같습니다.
어노테이션 위치와 연관관계 주인
지금은 Team 엔티티에 @OneToMany
가 있고, 그곳에 @JoinColumn
을 사용했습니다.
일대다 단방향에서 @JoinColumn
은 “Team
엔티티가 바라보는 Member
테이블 쪽에 FK 컬럼을 둔다”라고 해석됩니다.
실제로 다(多)쪽에 외래 키가 있어야
관계형 데이터베이스에서 “일 대 다” 구조에서는 일반적으로 “다” 테이블이 “일” 테이블을 참조하는 외래 키를 갖게 됩니다.
따라서 Member 테이블이 TEAM 테이블의 PK(TEAM_ID)를 FK로 갖게 되는 것이 자연스럽습니다.
정리하자면, JPA에서는 ‘연관관계 주인’ 개념에 따라 외래 키를 어느 테이블에 둔다고 지정하는데, 일대다 단방향 매핑에서 @OneToMany @JoinColumn
을 쓰면 그 외래 키는 자동으로 Member
테이블에 생성됩니다.
2. Member 엔티티에서 TEAM_ID
를 직접 확인하고 싶다면?
현재 코드 구조는 “Team → Member”만 바라보는 단방향 관계입니다. 즉,
@Entity
public class Team {
@Id @GeneratedValue
@Column(name = "TEAM_ID")
private Long id;
private String name;
@OneToMany
@JoinColumn(name = "TEAM_ID")
private List<Member> members = new ArrayList<>();
...
}
Team 엔티티 안에 List<Member>
가 있고, DB상으로 Member 테이블에 TEAM_ID
컬럼이 들어갑니다.
하지만 Member 엔티티 자체에는 TEAM_ID
를 나타내는 필드(또는 Team
객체에 대한 참조)가 전혀 없습니다. 다시 말해, Member 엔티티 클래스가 아래처럼 되어 있으니 TEAM_ID
를 알 수 있는 방법이 없습니다.
@Entity
public class Member {
@Id @GeneratedValue
@Column(name = "MEMBER_ID")
private Long id;
@Column(name = "USERNAME")
private String name;
// 현재 Team에 대한 필드가 없음
...
}
그렇다면 team.getMembers()
로 가져온 Member 객체에서 어떻게 FK(TEAM_ID)를 알 수 있을까요?
결론적으로 알 수 없습니다. 객체 상태에서는 해당 필드가 전혀 없기 때문입니다. 객체 지향적으로만 보면, Member는 Team을 모른다는 설정이니까요.
양방향 매핑(권장)
일반적으로 많이 사용하는 방식은 “Team ↔ Member” 양방향 매핑입니다.
예를 들어 Member 엔티티에 아래처럼 @ManyToOne
을 두고, Team까지 참조할 수 있도록 설정합니다.
@Entity
public class Member {
@Id @GeneratedValue
@Column(name = "MEMBER_ID")
private Long id;
@Column(name = "USERNAME")
private String name;
// 추가
@ManyToOne
@JoinColumn(name = "TEAM_ID")
private Team team;
...
}
이렇게 하면 member.getTeam().getId()
로 직접 Team의 id(= TEAM_ID)를 얻을 수 있습니다.
또한 양방향 시에는 mappedBy
를 통해 양쪽 엔티티 중 어디를 ‘연관관계 주인’으로 설정할지 결정하여 외래 키를 관리합니다.
Member 엔티티 내에 컬럼용 필드만 추가(읽기 전용)
@Transient
가 아닌 방식으로, 단순히 DB 컬럼만 매핑해 두고 실제 엔티티와의 연관관계는 구성하지 않는 방법이 있습니다.
예)
@Column(name = "TEAM_ID", insertable=false, updatable=false)
private Long teamId;
이렇게 해두면 Member 객체에서 teamId라는 값을 읽을 수 있긴 하지만, 이는 “단지 읽기 전용”에 가깝고, 객체 그래프상으로 Team과 연관관계를 맺는 것은 아닙니다.
@OneToMany @JoinColumn
을 Team에 선언하면, Member 테이블에 TEAM_ID
컬럼이 생깁니다. 이는 일대다 단방향 매핑에서 “다” 테이블에 외래 키가 필요하기 때문입니다.
단방향 매핑에서 Member 객체는 Team에 대한 정보를 전혀 모르므로, TEAM_ID
를 알 수 있는 방법이 없습니다.
TEAM_ID가 필요한 경우, 양방향 매핑을 통해 member.getTeam()
으로 접근 하는 방식을 주로 사용합니다.
혹은 간단히 “읽기 전용 teamId” 필드를 추가하는 방법도 있으나, 양방향 매핑처럼 자연스럽게 객체 그래프를 탐색하는 것은 어렵습니다.
감사합니다.
0
AI 답변이 이해가 되지않아 추가질문 드립니다..
1-1. @OneToMany @JoinColumn(name = "TEAM_ID") private List<Member> members = new ArrayList<>();를 통해 MEMBER테이블에 TEAM_ID컬럼이 생기는거 같은데, 다른 여러 테이블도 있다고 가정했을때 어떤 이유로 MEMBER테이블에 TEAM_ID컬럼이 생성되는것인가요? @JoinColumn(name = "TEAM_ID")만 보고 MEMBER테이블인지 어떻게 아는것인가요..? List<Member> members 에서 Member라고 지정해줬기때문에 MEMBER테이블에 TEAM_ID컬럼이 생기는것인가요?
1-2 @OneToMany와 @JoinColumn을 통해 일대다 단방향 연관관계나 일대다 양방향 연관관계를 하게되면 무조건 다쪽 테이블에 외래키 컬럼이 추가되는건가요??
0
안녕하세요, 인프런 AI 인턴입니다. 오리쉐리님.
일대다 단방향 연관관계에서의 개념과 작동 방식을 이해하는데 도움이 될 내용을 공유해 드리겠습니다.
@JoinColumn
이 작동하는 방식@OneToMany
와 @JoinColumn
을 함께 사용하면 JPA는 일반적으로 다 쪽(FK가 존재해야 하는 테이블) 엔티티에 외래 키 컬럼을 추가합니다. 이 경우 Member
엔티티의 TEAM_ID
필드가 데이터베이스에 자동으로 추가되며, 이는 Team
과 Member
간의 연관을 맺기 위함입니다. JPA는 매핑 정보(@JoinColumn
)를 기반으로 외래 키가 어떤 엔티티에 추가되어야 하는지를 결정하며, member.get(0).setTeamId(...)
가 없는 이유는, 구성된 매핑 정보(@JoinColumn
)를 통해 Member
테이블의 외래 키를 관리하기 때문입니다.
현재의 일대다 단방향 연관에서는 Member
객체에는 직접적인 TEAM_ID
에 대한 접근권한이 없습니다. 따라서, Member
객체를 통해 직접적으로 TEAM_ID
를 확인하는 방법은 없습니다. 이 역할을 위해서는 양방향 연관관계를 고려해 보는 것이 좋습니다. 즉, Member
엔티티에 @ManyToOne
으로 Team
과의 양방향 연관관계를 설정하고, member.getTeam().getId()
를 통해 TEAM_ID
를 가져오는 방식입니다.
이와 관련된 질문에 대한 기존의 유사한 질문을 참조해 보시기 바랍니다:
이 링크들에서 JPA 연관 관계에 대한 여러 실용적인 예시와 피드백을 찾아볼 수 있습니다. 연관관계 매핑은 데이터베이스와 ORM 간의 변환에서 중요한 부분이므로 다양한 사례를 통해 학습해보시면 좋습니다.
저는 질문자님의 이해를 돕고자 지식공유자님의 기존 답변을 참고하여 유사한 답변 링크를 추천해드리고 있습니다. 현재 베타 기능으로 답변이 만족스럽지 않을 수 있는 점 양해 부탁드립니다. 🙏 추가적으로 궁금한 점이 있으시면, 이어서 질문해 주세요. 곧 지식공유자께서 답변해 주실 것입니다.