개발정리

JPA-다대일 연관관계 매핑 본문

스프링/JPA

JPA-다대일 연관관계 매핑

coffee. 2023. 8. 31. 16:38

일반적인 SQL에서는 외래키를 사용하여 두 릴레이션을 연관 시켜 줍니다.

이때, JOIN을 사용하여 두 테이블을 연결 시켜주므로 자동으로 양방향 연관관계가 됩니다.

하지만 JPA에서는 한쪽에만 관계를 설정하면 다른쪽에서는 참조를 할 수 없게 됩니다.

 

지금부터 TEAM엔티티와 MEMBER엔티티의 예제를 통해 설명 드리겠습니다.

 

@Entity
@Data
@Table
public class Team {

	@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
	private Long team_id;
	
	@Column(name = "TEAM_NAME")
	private String teamName;

}
@Data
@Entity
@Table
public class Member {

	@Id  @GeneratedValue(strategy = GenerationType.IDENTITY)
	private Long id;
	
	@Column(name = "name")
	private String name;
	
	@ManyToOne
	@JoinColumn(name = "team_id")
	private Team team;
	
}

여러 member들은 team을 하나씩 가집니다.

member 입장에서는 manyToOne 관계가 됩니다.(많은 member들이 팀 하나를 가진다.)

 

 

public class Test {

	public static void main(String[] args) {
		
		EntityManagerFactory emf=Persistence.createEntityManagerFactory("hello");
		EntityManager em=emf.createEntityManager();
		try {
			em.getTransaction().begin();
			Team team1=new Team();
			team1.setTeamName("1조");
			em.persist(team1);
			
			Team team2=new Team();
			team2.setTeamName("2조");
			em.persist(team2);
			
			Member member1=new Member();
			member1.setName("홍길동");
			member1.setTeam(team1);
			em.persist(member1);
			
			
			Member member2=new Member();
			member2.setName("이철수");
			member2.setTeam(team2);
			em.persist(member2);
			
			
			
			em.getTransaction().commit();
			
			
		}catch(Exception e) {
			e.printStackTrace();
		}finally {
			emf.close();
		}
		
		
		

	}
	
}

1조와 2조 팀 테이블을 만들고 , member두명을 만들어 각각 팀을 할당 해주었습니다,

team테이블과 member테이블

 

이제 여기에서 member의 team_id를 이용해 team_name을 불러와 봅시다.

 

			em.getTransaction().begin();
			
			Member member=em.find(Member.class,1L);
			System.out.println(member.getTeam().getTeamName());
			
			em.getTransaction().commit();

콘솔 창에 1조 라고 뜨는것을 보실 수 있습니다.

 

이 예제에서는 member객체를 불러와 team을 가져왔는데

반대로 team객체를 가져와 member를 불러 오려면 어떻게 해야 할까요?

 

@Entity
@Data
@Table
public class Team {

	@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
	private Long team_id;
	
	@Column(name = "TEAM_NAME")
	private String teamName;
	
	
	@OneToMany(mappedBy = "team")
	private List<Member> memberList=new ArrayList<Member>();

}

team에 다음과 같이 memberList 속성을 생성하였습니다.

 

em.getTransaction().begin();
			Team team1=new Team();
			team1.setTeamName("1조");
			em.persist(team1);
			
			Team team2=new Team();
			team2.setTeamName("2조");
			em.persist(team2);
			
			Member member1=new Member();
			member1.setName("홍길동");
			member1.setTeam(team1);
			em.persist(member1);
			
			
			
			
			Member member2=new Member();
			member2.setName("이철수");
			member2.setTeam(team2);
			em.persist(member2);
			
			
			
			em.getTransaction().commit();
			
			
			em.getTransaction().begin();
			
			Team team=em.find(Team.class, 1L);
			List<Member> list=team.getMemberList();
			System.out.println("리스트 사이즈:"+team.getMemberList().size());
			for(Member member:list) {
				System.out.println(member.getName());
			}
			
			em.getTransaction().commit();

 

 

다음과 같은 코드를 실행하면 리스트의 사이즈가 0인 걸 보실수 있습니다.

양방향 매핑이 되었다면 리스트의 사이즈는 1이여야 하지 않을까요?

 

그 이유는 현재 영속 컨텍스트에 저장되어 있는 객체를 가져왔기 때문 입니다.

영속 컨테이너에 저장되어있는 객체는 양방향 매핑이 되어있지않습니다.

 

 

public class Test {

	public static void main(String[] args) {
		
		EntityManagerFactory emf=Persistence.createEntityManagerFactory("hello");
		EntityManager em=emf.createEntityManager();
		try {
			em.getTransaction().begin();
			Team team1=new Team();
			team1.setTeamName("1조");
			em.persist(team1);
			
			Team team2=new Team();
			team2.setTeamName("2조");
			em.persist(team2);
			
			Member member1=new Member();
			member1.setName("홍길동");
			member1.setTeam(team1);
			em.persist(member1);
			
			
			
			
			Member member2=new Member();
			member2.setName("이철수");
			member2.setTeam(team2);
			em.persist(member2);
			
			
			
			em.getTransaction().commit();
			em.clear();	
			
			
			em.getTransaction().begin();
			
			Team team=em.find(Team.class, 1L);
			List<Member> list=team.getMemberList();
			System.out.println("리스트 사이즈:"+team.getMemberList().size());
			for(Member member:list) {
				System.out.println(member.getName());
			}
			
			em.getTransaction().commit();
			
		}catch(Exception e) {
			e.printStackTrace();
		}finally {
			emf.close();
		}
		
		
		

	}
	
}

다음과 같이 em.clear()를 실행하면 컨텍스트의 캐시가 초기화 되어 값이 제대로 나오는 것을 보실수 있습니다.

 

참조:JPA퀵스타트 , 채규태

'스프링 > JPA' 카테고리의 다른 글

JPA-다대다 매핑  (0) 2023.09.02
JPA-일대일 매핑  (0) 2023.09.01
JPA-영속 컨텍스트  (0) 2023.08.30
JPA-설정  (0) 2023.08.29