JPA공부함에 있어서 내용은 인프런 김영한님 강의와 책을 참고하여 정리한 것입니다 (필기 및 공부정리용)
https://www.inflearn.com/course/ORM-JPA-Basic#
연관관계 매핑
객체의 참조와 테이블의 외래키를 매핑
테이블에서는 외래키를 사용해서 각각의 테이블의 값을 가져올 수 있지만
객체를 단순히 테이블매핑해서 생성을 한다면 값을 참조가 불가능하다
Team team = new Team();
team.setName("TeamA");
em.persist(team);
Member member = new Member();
member.setName("member1");
member.setTeamId(team.getId());
em.persist(member);
Member findMember = em.find(Member.class, member.getId());
Team findTeam = em.find(Team.class, findMember.getTeamId());
위 코드를 보면 단순히 테이블과 객체를 순수하게 매핑을 한것이다
member에 teamid를 넣기 위해서는 team으로부터 값을 얻어와야지만 할 수가 있는 것이다
또한 조회를 함에 있어서도 해당 멤버가 어떤 팀소속인지 알기 위해서는 두개를 전부 조회를 해야하는 것이다
select * from member m join team t on m.teamid = t.teamid
sql을 이용하면 단순히 이렇게 조인으로만 해결이 되는 문제를 객체지향스럽지 못하게 값을 전부 읽어와서 얻어온다는 것은 옳지 않다
이를 해결하기 위해서 연관관계 매핑이 필요한 것이다
단방향 연관관계
위의 문제를 해결하기 위해서 단순히 Member객체에 Team team
의 변수를 생성을 하면 된다
public class Member{
...
//@Column(name="TEAM_ID")
//private Long teamId;
@ManyToOne //다대일 매핑
@JoinColumn(name="TEAM_ID")//매핑할 테이블 칼럼 지정
private Team team;
}
Team team = new Team();
team.setName("TeamA");
em.persist(team);
Member member = new Member();
member.setName("member1");
member.setTeam(team);
em.persist(member);
Member findMember = em.find(Member.class, member.getId());
Team findTeam = findMember.getTeam(); //team으로부터 찾을 필요가 없다
수정이나 삭제에 관해서도 단순히 member.setTeam(newTeam)
member.setTeam(null)
과 같이 수행 할 수 있다
양방향 연관관계(서로다른 단방향 연관관계 두개)
일단 단방향 매핑 만으로 완료를 해야한다 추후 필요하면 양방향매핑을 설계
위의 코드는 단방향 연관관계이다 단순히 member에서 team으로의 참조만 가능할 뿐 역으로는 불가능 하다 앞서 말했듯이 sql을 이용하면 외래키 하나만을 가지고 두개다 조회가 가능하지만 객체내에서는 두개의 참조값이 필요하게 된다
public class Team {
@Id @GeneratedValue
@Column(name="TEAM_ID")
private Long id;
private String name;
@OneToMany(mappedBy = "team")//member의 team변수로 참조
private List<Member> members = new ArrayList<>();
}
member에서는 다대일 관계지만 team을 기준으로는 일대다 관계이므로 OneToMany를 사용한다
조회방법
Team team = em.find(Team.class, "team1");
List<Member> members = team.getMembers();
for (Member member : members) {
System.out.println("member = " + member);
}
양방향 연관관계 주인
두 객체 연관관계중 어떤 것으로 테이블의 외래키를 관리하는지를 정하기 위해서 정해야 한다
Member.team의 값, team.members의 값중 어떤 값을 변경해서 테이블의 외래키 값을 업데이트 시킬 것인지 둘중 하나로 지정을 해줘야한다
!외래키가 있는 곳을 주인으로 정한다!
- 주인이 아닌 곳은 조회만 가능 수정 불가
- 주인은 mappedBy(~에 참조가 되어있다)속성 사용 x
Member
@ManyToOne
@JoinColumn(name="TEAM_ID")
private Team team;
}
Team
@OneToMany(mappedBy = "team")
private List<Member> members = new ArrayList<>();
위의 코드를 보면 Member의 team변수는 테이블의 TEAM_ID칼럼에 매핑되어있지만 Team의 members변수는 Member객체의 team변수에 참조되어있다
Member member = new Member();
member.setName("member1");
em.persist(member);
Team team = new Team();
team.setName("TeamA");
team.getMembers().add(member);
em.persist(team);
현재 Member가 연관관계의 주인으로 지정을 해두었다
하지만 team에서 members참조값을 통해서 변경을 하게 된다면 insert쿼리는 두번이 나가지만 DB에는 적용이 되지 않은 것을 볼 수 있다
단순히 읽기전용이지 테이블이랑은 매핑이 되어있지 않은 것을 알 수 있다
하지만 값을 세팅은 해줘야 한다 em.flush()
em.clear()
를 하지않고 team.getMembers()
를 통해서 list를 얻어온다면 1차캐시에는 값이 없기때문에 찾아올 수 없다
혹시라도 두개 값을 세팅을 까먹을 수도 있을 것을 방지해 연관관계주인 쪽에서 값을 세팅을 할때 아래 코드처럼 값을 넣어주면 된다
주인 쪽에서 값을 세팅해도 되고 반대쪽에서 해도 된다 하지만 두개 모두 사용을 해서 무한루프가 생길 것을 방지해야 한다
public void changeTeam(Team team){
this.team = team;
team.getMembers().add(this);
}
'공부기록 > JPA' 카테고리의 다른 글
JPA-프록시 (0) | 2022.01.26 |
---|---|
JPA-고급매핑2 (0) | 2022.01.20 |
JPA 고급매핑1 (0) | 2022.01.20 |
JPA 엔티티 (0) | 2021.12.26 |
JPA시작 (0) | 2021.12.24 |