본문 바로가기

JPA (Java Persistence API)/Relational Mapping, Java SE

Java SE기반에서 JPA Entity 클래스의 관계 매핑 예

Team, Player (1:다) 매핑을 설정하여 Player 객체를 구하면 Player가 소속된 Team정보를 함께 구할 수 있고, Team객체를 구하면 팀에 소속된 Player의 정보를 확인할 수 있게 된다.

양방향 관계 설정 절차
Player는 Team의 PK를 FK로 포함하게 되므로 관계를 소유한 측이 되며, Team은 그 반대편이므로 Team 클래스 내의 List<Player>속성에 @OneToMany(mappedBy="team") 을 설정해준다.

1. @Entity : 양쪽 클래스 모두에게 설정
2. @ManyToOne : Player 클래스의 Team속성에 설정
3. @OneToMany(mappedBy="team") : Team 클래스의 List<Player>속성에 설정, 여기서 team은 Player의 Team속성
    Player 클래스에는 Team형 속성이, Team 클래스에슨 List<Player>형 속성이 있어야 한다.
4. 위와같이 형식적인 설정을 마치면, 내용면에서도 Player에는 Team속성을, Team에는 List<Player>속성을 초기화하여 저장하면 이후에 Team에서는 Player정보를, Player에서는 Team정보를 함께 확인할 수 있는 양방향 관계가 구현된다.

src/META-INF/persistence.xml

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.0"
 xmlns="http://java.sun.com/xml/ns/persistence"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
 <persistence-unit name="players">
 
  <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>

  <class>jpatest.Player</class>
  <class>jpatest.Team</class>
 
  <properties>
   <property name="javax.persistence.jdbc.driver" value="oracle.jdbc.OracleDriver" />
   <property name="javax.persistence.jdbc.url" value="jdbc:oracle:thin:@localhost:1521:oracle" />
   <!-- I work in this example without user / password.-->
   <property name="javax.persistence.jdbc.user" value="scott" />
   <property name="javax.persistence.jdbc.password" value="tiger" />

   <!-- EclipseLink should create the database schema automatically -->

   <property name="eclipselink.ddl-generation" value="drop-and-create-tables" />
   <property name="eclipselink.ddl-generation.output-mode" value="database" />
  </properties>

 </persistence-unit>
</persistence>


jpatest.Player

package jpatest;

import java.util.*;
import java.io.Serializable;

import javax.persistence.*;

@Entity
public class Player implements Serializable{
 @Id
 @GeneratedValue
 private int id;
 private String name;
 private String phone;

 @ManyToOne(optional=true)
 private Team team;

 public Player() {}

 public Player(String name, String phone) {
 this.name = name;
 this.phone = phone;
 }

public int getId() {
 return id;
}

public void setId(int id) {
 this.id = id;
}

public String getName() {
 return name;
}

public void setName(String name) {
 this.name = name;
}

public String getPhone() {
 return phone;
}

public void setPhone(String phone) {
 this.phone = phone;
}

public Team getTeam() {
 return team;
}

public void setTeam(Team team) {
 this.team = team;
}
}



jpatest.Team

package jpatest;

import java.io.Serializable;
import java.util.*;

import javax.persistence.*;

@Entity
public class Team implements Serializable {
 
 @Id
 @GeneratedValue
 private int id;
 
 String name;
 String loc;
 
 @OneToMany(mappedBy="team") // 관계를 소유한 측 Player 클래스의 Team team 변수이름을 가리킴
 List<Player> players;
 
 public Team() {}
 
 public Team(String name, String loc) {
  this.name = name;
  this.loc = loc;
 }

 public int getId() {
  return id;
 }

 public void setId(int id) {
  this.id = id;
 }

 public String getName() {
  return name;
 }

 public void setName(String name) {
  this.name = name;
 }

 public String getLoc() {
  return loc;
 }

 public void setLoc(String loc) {
  this.loc = loc;
 }

 public List<Player> getPlayers() {
  return players;
 }

 public void setPlayers(List<Player> players) {
  this.players = players;
 }
}




jpatest.JPATetst

package jpatest;

import java.util.*;

import javax.persistence.*;
/* 2개의 Entity 클래스 간에 양방향 관계 매핑의 예 */
/* Foreign Key를 포함하고 있는 테이블이 관계를 소유한 측이며,
 * 그 반대편의 빈 클래스에 mappedBy 속성을 설정해 준다.
 * Team, Player를 저장할 때 Team에서는 Player들을, Player에는 Team을 설정해주면
 * 양방향 관계를 설정하여 저장할 수 있고 이후에 Player객체를 구하면 해당 Player가 소속된 Team정보
 * 도 함께 확인할 수 있고, Team객체를 구하면 그 팀에 소속된 모든 Player들의
 * 정보도 함께 확인할 수 있다.
 */
public class JPATest {

 private static final String PERSISTENCE_UNIT_NAME = "players";
 private static EntityManagerFactory factory;
 static {
  factory = Persistence.createEntityManagerFactory(PERSISTENCE_UNIT_NAME);
 }
 
 public static void main(String[] args)throws Exception{
  insert();
  select();
  printTeam();
 }

 public static void insert() throws Exception {
  List<Player>list = createPlayer();
  Team[] team = createTeam();
   EntityManager em = factory.createEntityManager();
  
   em.getTransaction().begin();
  
   /* 아래의 라인을 사용하지 않으면 Player 에서 Team으로 단방향 관계만 설정됨 */
   team[0].setPlayers(list); // 한팀에 모든 선수를 설정한다.
  
   for(int i=0;i<team.length;i++){
    em.persist(team[i]); // 팀 정보를 데이터베이스에 저장
   }
   for(int i=0;i<list.size();i++){
    Player p = list.get(i);
    p.setTeam(team[0]); // Player에게 Team을 설정한다
    em.persist(p);       // 테이블에 레코드 한개 저장
   }
   em.getTransaction().commit();
   em.close();
 }
 
 public static void select() throws Exception {
  EntityManager em = factory.createEntityManager();

  Query query = em.createQuery("SELECT p FROM Player p");
  List<Player> list = query.getResultList();
  for(int i=0;i<list.size();i++){
   Player p = list.get(i);
   int id = p.getId();
   String name = p.getName();
   Team team = p.getTeam();
   System.out.println("id:"+id+"\tName:"+name+"\tTeam:"+team.getName());
  }
  em.close();
 }

 public static void update(int id) throws Exception {
  EntityManager em = factory.createEntityManager();
  Player p = em.find(Player.class, id);
  em.getTransaction().begin();
  p.setPhone("3333-4444-5555");
  em.persist(p);
  em.getTransaction().commit();
  em.close();
 }
 
 public static void delete(int id) throws Exception {
  EntityManager em = factory.createEntityManager();
  Player p = em.find(Player.class, id);
  em.getTransaction().begin();
  em.remove(p);     // 테이블에서 레코드 삭제
  em.getTransaction().commit();
  em.close();
 }
 
 /* 아이디를 파라미터로 받아서 테이블에서 검색하여 Player객체를 리턴하는 메소드 */
 public static Player findById(int id){
  EntityManager em = factory.createEntityManager();
  Player p = em.find(Player.class, id);
  em.close();
  return p;
 }

 /* 양방향 관계를 설정했기 때문에 Team에서 Player정보를 포함하고 있다.*/
 public static void printTeam(){
  EntityManager em = factory.createEntityManager();
  Query query = em.createQuery("select t from Team t order by t.id");
  List<Team> list = query.getResultList();
  for(int i=0;i<list.size();i++){
   Team t = list.get(i);
   String name = t.getName();
   System.out.println("팀명:"+name);
   List<Player> pList = t.getPlayers();
   for(int k=0;k<pList.size();k++){
    Player p = pList.get(k);
    System.out.print(p.getName()+" ");
   }
   System.out.println();
  }
  em.close();
 }
 private static List<Player> createPlayer(){
  ArrayList<Player> list = new ArrayList<Player>();
  list.add(new Player("박세리","2345-7564-6578"));
  list.add(new Player("박찬호", "643-745-346"));
  list.add(new Player("박지성", "0987-789-5432"));
  list.add(new Player("김연아", "456-345-876"));
  list.add(new Player("차범근", "534-8756-7890"));
  return list;
 }
 private static Team[] createTeam(){
  Team[] t = {
    new Team("Team A", "서울시"),
    new Team("Team B", "경기도")
  };
  return t;
 }
}