[Hibernate] 4. Hibernate(하이버네이트) 테이블 관계 - One To Many ( 중간 관계 테이블 없을 시)
OneToMany-ManyToOne (관계 테이블 없을 시)
OneToMany와 ManyToOne은 두가지 경우가 있다.
- 관계테이블 없음 : 관계테이블 없이 Many쪽에서 참조컬럼을 갖는 경우
- 관계테이블 있음 : One과 Many를 연결해주는 중간 관계 테이블있고 중간 관계 테이블에서 Many 쪽이 참조 값이 Unique인 경우
각 테이블간의 결합성을 없애려고 한다면 중간 관계테이블을 두는게 좋고 아니라면 중간 관계테이블 없이 하는 것이 좋다.
OneToMany 관계에서 조심해야 될 듯은 Many가 너무 많은 갯수를 가진다면 성능상 부하가 엄청날 것이다. 예를 들어 게시판의 글쓴이와 글의 관계라고 해보자 글쓴이가 쓴 글이 엄청 많다면 문제가 생긴다. 이때는 OneToMany 관계맵핑 자체를 하면 안되고 HQL을 통해서 잘라서 가져와야 한다.
CREATE TABLE `phone` ( `phone_id` int(11) NOT NULL AUTO_INCREMENT, `phone_number` varchar(45) DEFAULT NULL, `phone_owner_id` int(11) DEFAULT NULL, PRIMARY KEY (`phone_id`), UNIQUE KEY `phone_number_UNIQUE` (`phone_number`), KEY `fk_people_phone_idx` (`phone_owner_id`), CONSTRAINT `if_people_phone` FOREIGN KEY (`phone_owner_id`) REFERENCES `people` (`PEOPLE_ID`) ON DELETE SET NULL ON UPDATE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `people` ( `PEOPLE_ID` int(11) NOT NULL AUTO_INCREMENT, `PEOPLE_NAME` varchar(45) NOT NULL, PRIMARY KEY (`PEOPLE_ID`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; |
phone 테이블에 people에 대한 참조값이 있는 경우이다.
OneToMany-ManyToOne ( Bi-directional(양방향) )
맵핑
People_Bi.java : People 테이블의 맵핑클래스이다. _Bi는 양방향을 뜻한다.
package org.onecellboy.db.hibernate.table;
import java.util.LinkedList; import java.util.List;
import javax.persistence.Basic; import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.FetchType; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.OneToMany; import javax.persistence.OneToOne; import javax.persistence.PrimaryKeyJoinColumn; import javax.persistence.Table;
@Entity @Table(name="people") public class People_Bi {
@Id @GeneratedValue(strategy=GenerationType.IDENTITY) @Column(name="PEOPLE_ID",columnDefinition="INT") private int id;
@Column(name="PEOPLE_NAME",columnDefinition="VARCHAR(45)") private String name;
@OneToOne(fetch=FetchType.LAZY,mappedBy="people", cascade = CascadeType.ALL) private People_Info_Bi people_Info;
@OneToMany(fetch=FetchType.LAZY,mappedBy="owner_people", cascade = CascadeType.ALL,orphanRemoval=true) private List<Phone_Bi> phones = new LinkedList<Phone_Bi>();
public List<Phone_Bi> getPhones() { return phones; }
public void setPhones(List<Phone_Bi> phones) { this.phones = phones; }
public People_Info_Bi getPeople_Info() { return people_Info; }
public void setPeople_Info(People_Info_Bi people_Info) { this.people_Info = people_Info; }
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; }
} |
설명
@OneToMany(fetch=FetchType.LAZY,mappedBy="owner_people", cascade = CascadeType.ALL,orphanRemoval=true) private List<Phone_Bi> phones = new LinkedList<Phone_Bi>(); |
fetch=FetchType.LAZY : Lazy Loading 하겠다는 것이다.
위의 예제에서는 phone은 소유자 없이는 존재하지 않는다라는 가정하에 관계를 만들었다. |
Phone_Bi.java
package org.onecellboy.db.hibernate.table;
import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.FetchType; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.ManyToOne; import javax.persistence.MapsId; import javax.persistence.Table;
import org.hibernate.annotations.GenericGenerator; import org.hibernate.annotations.Parameter;
@Entity @Table(name="phone") public class Phone_Bi {
@Id @GeneratedValue(strategy=GenerationType.IDENTITY) @Column(name="PHONE_ID",columnDefinition="INT") private int id;
@Column(name="PHONE_NUMBER",columnDefinition="VARCHAR(45)") private String number;
@Column(name="PHONE_OWNER_ID",columnDefinition="INT",insertable=false, updatable=false) private Integer owner_id;
@ManyToOne(optional = false) @JoinColumn(name="PHONE_OWNER_ID",referencedColumnName="PEOPLE_ID" ,nullable=true) private People_Bi owner_people;
public People_Bi getOwner_people() { return owner_people; }
public void setOwner_people(People_Bi owner_people) { this.owner_people = owner_people; }
public int getId() { return id; }
public void setId(int id) { this.id = id; }
public String getNumber() { return number; }
public void setNumber(String number) { this.number = number; }
public Integer getOwner_id() { return owner_id; }
public void setOwner_id(Integer owner_id) { this.owner_id = owner_id; }
} |
설명
@Column(name="PHONE_OWNER_ID",columnDefinition="INT",insertable=false, updatable=false) private Integer owner_id; |
name="PHONE_OWNER_ID": 맵핑된 컬럼명이다. insertable=false, updatable=false : 이 값이 왜 존재하냐면 PHONE_OWNER_ID값을 맵핑하는 변수가 owner_id 와 owner_people 이 두개 존재한다. 이 말은 맵핑 변수 owner_id 혹은 관계 변수 owner_people 의 변경에 따라 phone 테이블의 PHONE_OWNER_ID 컬럼이 변경되는 것이다. 변경할 수 있는 관계가 두개 이기 때문에 둘중 하나는 READ ONLY 즉 읽기만 가능하게 하여야 한다. 만약 이 옵션이 없다면 .....should be mapped with insert="false" update="false".... 이런 에러 메세지가 나온다. |
@ManyToOne(optional = false) @JoinColumn(name="PHONE_OWNER_ID",referencedColumnName="PEOPLE_ID") private People_Bi owner_people; |
"name 이 referencedColumnName 를 참조한다." 라고 해석하자. |
hibernate.cfg.xml 에 mapping 클래스를 지정한다.
생략... <mapping class="org.onecellboy.db.hibernate.table.People_Bi"/> <mapping class="org.onecellboy.db.hibernate.table.Phone_Bi"/> 생략... |
테스트
테스트 코드
package org.onecellboy.db.hibernate;
import static org.junit.Assert.*;
import java.io.File; import java.util.Date; import java.util.LinkedList; import java.util.List;
import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.boot.MetadataSources; import org.hibernate.boot.registry.StandardServiceRegistry; import org.hibernate.boot.registry.StandardServiceRegistryBuilder; import org.junit.After; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.FixMethodOrder; import org.junit.Test; import org.junit.runners.MethodSorters; import org.onecellboy.db.hibernate.table.People_Bi; import org.onecellboy.db.hibernate.table.People_Info_Bi; import org.onecellboy.db.hibernate.table.Phone_Bi;
/* * Bi-directional OneToMany 양방향 1:N 관계 * */ @FixMethodOrder(MethodSorters.NAME_ASCENDING) public class OneToManyBi {
static SessionFactory sessionFactory = null; static StandardServiceRegistry registry = null;
static int select_id = 0;
@BeforeClass public static void setUp() { registry = new StandardServiceRegistryBuilder().configure(new File("./conf/hibernate/hibernate.cfg.xml")) .build(); sessionFactory = new MetadataSources(registry).buildMetadata().buildSessionFactory();
}
@AfterClass public static void setDown() { sessionFactory.close(); }
@After public void testAfter() { System.out.println(); System.out.println(); }
@Test public void test01() { System.out.println("======Insert TEST======");
int test_id=0;
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
People_Bi people = new People_Bi(); people.setName("이린");
List<Phone_Bi> phones = people.getPhones();
Phone_Bi phone1=new Phone_Bi(); phone1.setNumber("010-1111-1111"); phone1.setOwner_people(people);
Phone_Bi phone2=new Phone_Bi(); phone2.setNumber("010-2222-2222"); phone2.setOwner_people(people);
Phone_Bi phone3=new Phone_Bi(); phone3.setNumber("010-3333-333."); phone3.setOwner_people(people);
phones.add(phone1); phones.add(phone2); phones.add(phone3);
session.save(people);
System.out.println("-------People insert 후에 phone 추가해 보기-------"); Phone_Bi phone4=new Phone_Bi(); phone4.setNumber("010-4444-4444"); phone4.setOwner_people(people); phones.add(phone4);
tx.commit(); session.close();
test_id = people.getId();
System.out.println(); System.out.println();
System.out.println("======Select TEST======");
session = sessionFactory.openSession(); tx = session.beginTransaction();
People_Bi people2 = session.get(People_Bi.class, test_id); System.out.println("people id : "+people2.getId()); System.out.println("people name : "+people2.getName());
for (Phone_Bi phone_Bi : people2.getPhones()) { System.out.println("people id : "+phone_Bi.getId()); System.out.println("people number :"+phone_Bi.getNumber()); System.out.println("people owner id : "+phone_Bi.getOwner_id()); }
System.out.println(); System.out.println(); System.out.println("======Delete TEST======");
session = sessionFactory.openSession(); tx = session.beginTransaction();
People_Bi people3 = session.get(People_Bi.class, test_id);
List<Phone_Bi> phones3 = people3.getPhones(); System.out.println(""+phones3.size());
phones3.remove(1);
tx.commit(); session.close();
}
} |
결과
======Insert TEST====== Hibernate: insert into people (PEOPLE_NAME) values (?) Hibernate: insert into phone (PHONE_NUMBER, PHONE_OWNER_ID) values (?, ?) Hibernate: insert into phone (PHONE_NUMBER, PHONE_OWNER_ID) values (?, ?) Hibernate: insert into phone (PHONE_NUMBER, PHONE_OWNER_ID) values (?, ?) -------People insert 후에 phone 추가해 보기------- Hibernate: insert into phone (PHONE_NUMBER, PHONE_OWNER_ID) values (?, ?)
======Select TEST====== Hibernate: select people_bi0_.PEOPLE_ID as PEOPLE_I1_0_0_, people_bi0_.PEOPLE_NAME as PEOPLE_N2_0_0_ from people people_bi0_ where people_bi0_.PEOPLE_ID=? Hibernate: select people_inf0_.PEOPLE_INFO_ID as PEOPLE_I1_1_0_, people_inf0_.PEOPLE_INFO_AGE as PEOPLE_I2_1_0_, people_inf0_.PEOPLE_INFO_BIRTHDAY as PEOPLE_I3_1_0_ from people_info people_inf0_ where people_inf0_.PEOPLE_INFO_ID=? people id : 119 people name : 이린 Hibernate: select phones0_.PHONE_OWNER_ID as PHONE_OW3_2_0_, phones0_.PHONE_ID as PHONE_ID1_2_0_, phones0_.PHONE_ID as PHONE_ID1_2_1_, phones0_.PHONE_NUMBER as PHONE_NU2_2_1_, phones0_.PHONE_OWNER_ID as PHONE_OW3_2_1_ from phone phones0_ where phones0_.PHONE_OWNER_ID=? people id : 150 people number :010-1111-1111 people owner id : 119 people id : 151 people number :010-2222-2222 people owner id : 119 people id : 152 people number :010-3333-3333 people owner id : 119 people id : 153 people number :010-4444-4444 people owner id : 119
======Delete TEST====== Hibernate: select people_bi0_.PEOPLE_ID as PEOPLE_I1_0_0_, people_bi0_.PEOPLE_NAME as PEOPLE_N2_0_0_ from people people_bi0_ where people_bi0_.PEOPLE_ID=? Hibernate: select people_inf0_.PEOPLE_INFO_ID as PEOPLE_I1_1_0_, people_inf0_.PEOPLE_INFO_AGE as PEOPLE_I2_1_0_, people_inf0_.PEOPLE_INFO_BIRTHDAY as PEOPLE_I3_1_0_ from people_info people_inf0_ where people_inf0_.PEOPLE_INFO_ID=? Hibernate: select phones0_.PHONE_OWNER_ID as PHONE_OW3_2_0_, phones0_.PHONE_ID as PHONE_ID1_2_0_, phones0_.PHONE_ID as PHONE_ID1_2_1_, phones0_.PHONE_NUMBER as PHONE_NU2_2_1_, phones0_.PHONE_OWNER_ID as PHONE_OW3_2_1_ from phone phones0_ where phones0_.PHONE_OWNER_ID=? 4 Hibernate: delete from phone where PHONE_ID=?
|
설명
테스트코드 |
Phone_Bi phone1=new Phone_Bi(); phone1.setNumber("010-1111-1111"); phone1.setOwner_people(people);
phones.add(phone1); phones.add(phone2); phones.add(phone3);
session.save(people); |
결과 |
Hibernate: insert into people (PEOPLE_NAME) values (?) Hibernate: insert into phone (PHONE_NUMBER, PHONE_OWNER_ID) values (?, ?) Hibernate: insert into phone (PHONE_NUMBER, PHONE_OWNER_ID) values (?, ?) Hibernate: insert into phone (PHONE_NUMBER, PHONE_OWNER_ID) values (?, ?) |
설명 |
양방향이기 때문에 서로가 서로를 설정해야한다. phone 에
setOwner_people()을 통해 people 을 설정해야하고 people은 list의 add를 통해 설정해야한다. people.Phones 에 phone을 add() 해주고 people을 save()하면 phone 목록은 자동으로 DB에 insert된다.
|
테스트코드 |
System.out.println("-------People insert 후에 phone 추가해 보기-------"); Phone_Bi phone4=new Phone_Bi(); phone4.setNumber("010-4444-4444"); phone4.setOwner_people(people); phones.add(phone4); |
결과 |
-------People insert 후에 phone 추가해 보기------- Hibernate: insert into phone (PHONE_NUMBER, PHONE_OWNER_ID) values (?, ?) |
설명 |
people을 insert 한 후에 phone을 또 추가해 보았다. save(), update() 명령이 없어도 자동으로 수행된다. |
테스트코드 |
phones3.remove(1); |
결과 |
Hibernate: delete from phone where PHONE_ID=? |
설명 |
리스트에서 phone만 제거하면 바로 Delete 쿼리가 발생한다. saveOrUpdate()이런 거 할 필요가 없다. |
OneToMany-ManyToOne ( Unidirectional(단방향) )
맵핑
People -> Phone
package org.onecellboy.db.hibernate.table;
import java.util.LinkedList; import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.FetchType; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.OneToMany; import javax.persistence.OneToOne; import javax.persistence.Table;
@Entity @Table(name="people") public class People_Uni { @Id @GeneratedValue(strategy=GenerationType.IDENTITY) @Column(name="PEOPLE_ID",columnDefinition="INT") private int id;
@Column(name="PEOPLE_NAME",columnDefinition="VARCHAR(45)") private String name;
@OneToMany(fetch=FetchType.LAZY, cascade = CascadeType.ALL,orphanRemoval=true) @JoinColumn(name="PHONE_OWNER_ID",referencedColumnName="PEOPLE_ID") private List<Phone_Uni> phones = new LinkedList<Phone_Uni>();
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 List<Phone_Uni> getPhones() { return phones; }
public void setPhones(List<Phone_Uni> phones) { this.phones = phones; }
} |
설명
@OneToMany(fetch=FetchType.LAZY, cascade = CascadeType.ALL,orphanRemoval=true) @JoinColumn(name="PHONE_OWNER_ID",referencedColumnName="PEOPLE_ID") |
Lazy 로딩, Cascade
All, orphanRemoval 옵션을 주었다. OneToMany 에 대해 잘 생각해봐야한다.
|
테스트
테스트코드
import static org.junit.Assert.*;
import java.io.File;
import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.boot.MetadataSources; import org.hibernate.boot.registry.StandardServiceRegistry; import org.hibernate.boot.registry.StandardServiceRegistryBuilder; import org.junit.After; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; import org.onecellboy.db.hibernate.table.People_Uni; import org.onecellboy.db.hibernate.table.Phone_Uni;
public class OneToManyUni {
static SessionFactory sessionFactory = null; static StandardServiceRegistry registry = null;
static int select_id = 0;
@BeforeClass public static void setUp() { registry = new StandardServiceRegistryBuilder().configure(new File("./conf/hibernate/hibernate.cfg.xml")) .build(); sessionFactory = new MetadataSources(registry).buildMetadata().buildSessionFactory();
}
@AfterClass public static void setDown() { sessionFactory.close(); }
@After public void testAfter() { System.out.println(); System.out.println(); }
@Test public void test() {
int test_id=0;
Session session =null; Transaction tx = null;
System.out.println("======People Insert시 People에 포함된 Phone도 자동 Insert======");
session = sessionFactory.openSession(); tx = session.beginTransaction();
People_Uni people = new People_Uni(); people.setName("단소");
Phone_Uni phone1 = new Phone_Uni(); phone1.setNumber("111-1111-1111");
Phone_Uni phone2 = new Phone_Uni(); phone2.setNumber("222-2222-2222");
Phone_Uni phone3 = new Phone_Uni(); phone3.setNumber("333-3333-3333");
people.getPhones().add(phone1); people.getPhones().add(phone2); people.getPhones().add(phone3);
session.saveOrUpdate(people);
test_id = people.getId();
try { Thread.sleep(100); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); }
tx.commit(); session.close();
System.out.println("======이미 Insert 된 People에 Phone을 추가시켰을때 자동 Insert======"); session = sessionFactory.openSession(); tx = session.beginTransaction();
People_Uni people2 = session.get(People_Uni.class, test_id);
Phone_Uni phone4 = new Phone_Uni(); phone4.setNumber("444-444-4444");
people2.getPhones().add(phone4);
tx.commit(); session.close();
System.out.println("======Insert 된 People에 서 Phone을 제거시켰을때 자동 Delete======"); session = sessionFactory.openSession(); tx = session.beginTransaction();
People_Uni people3 = session.get(People_Uni.class, test_id);
people3.getPhones().remove(1);
tx.commit(); session.close();
}
} |
결과
======People Insert시 People에 포함된 Phone도 자동 Insert====== Hibernate: insert into people (PEOPLE_NAME) values (?) Hibernate: insert into phone (PHONE_NUMBER, PHONE_OWNER_ID) values (?, ?) Hibernate: insert into phone (PHONE_NUMBER, PHONE_OWNER_ID) values (?, ?) Hibernate: insert into phone (PHONE_NUMBER, PHONE_OWNER_ID) values (?, ?) Hibernate: update phone set PHONE_OWNER_ID=? where PHONE_ID=? Hibernate: update phone set PHONE_OWNER_ID=? where PHONE_ID=? Hibernate: update phone set PHONE_OWNER_ID=? where PHONE_ID=? ======이미 Insert 된 People에 Phone을 추가시켰을때 자동 Insert====== Hibernate: select people_uni0_.PEOPLE_ID as PEOPLE_I1_0_0_, people_uni0_.PEOPLE_NAME as PEOPLE_N2_0_0_ from people people_uni0_ where people_uni0_.PEOPLE_ID=? Hibernate: select phones0_.PHONE_OWNER_ID as PHONE_OW3_2_0_, phones0_.PHONE_ID as PHONE_ID1_2_0_, phones0_.PHONE_ID as PHONE_ID1_2_1_, phones0_.PHONE_NUMBER as PHONE_NU2_2_1_, phones0_.PHONE_OWNER_ID as PHONE_OW3_2_1_ from phone phones0_ where phones0_.PHONE_OWNER_ID=? Hibernate: insert into phone (PHONE_NUMBER, PHONE_OWNER_ID) values (?, ?) Hibernate: update phone set PHONE_OWNER_ID=? where PHONE_ID=? ======Insert 된 People에 서 Phone을 제거시켰을때 자동 Delete====== Hibernate: select people_uni0_.PEOPLE_ID as PEOPLE_I1_0_0_, people_uni0_.PEOPLE_NAME as PEOPLE_N2_0_0_ from people people_uni0_ where people_uni0_.PEOPLE_ID=? Hibernate: select phones0_.PHONE_OWNER_ID as PHONE_OW3_2_0_, phones0_.PHONE_ID as PHONE_ID1_2_0_, phones0_.PHONE_ID as PHONE_ID1_2_1_, phones0_.PHONE_NUMBER as PHONE_NU2_2_1_, phones0_.PHONE_OWNER_ID as PHONE_OW3_2_1_ from phone phones0_ where phones0_.PHONE_OWNER_ID=? Hibernate: update phone set PHONE_OWNER_ID=null where PHONE_OWNER_ID=? and PHONE_ID=? Hibernate: delete from phone where PHONE_ID=? |
설명
테스트코드 |
People_Uni people = new People_Uni(); people.setName("단소");
Phone_Uni phone1 = new Phone_Uni(); phone1.setNumber("111-1111-1111");
Phone_Uni phone2 = new Phone_Uni(); phone2.setNumber("222-2222-2222");
Phone_Uni phone3 = new Phone_Uni(); phone3.setNumber("333-3333-3333");
people.getPhones().add(phone1); people.getPhones().add(phone2); people.getPhones().add(phone3);
session.saveOrUpdate(people); |
결과 |
Hibernate: insert into people (PEOPLE_NAME) values (?) Hibernate: insert into phone (PHONE_NUMBER, PHONE_OWNER_ID) values (?, ?) Hibernate: insert into phone (PHONE_NUMBER, PHONE_OWNER_ID) values (?, ?) Hibernate: insert into phone (PHONE_NUMBER, PHONE_OWNER_ID) values (?, ?) Hibernate: update phone set PHONE_OWNER_ID=? where PHONE_ID=? Hibernate: update phone set PHONE_OWNER_ID=? where PHONE_ID=? Hibernate: update phone set PHONE_OWNER_ID=? where PHONE_ID=? |
설명 |
people 에 phone을 add 시키고 people을 save()시키면 자동 people에 add된 phone도 자동으로 insert 되었다. 눈여겨 볼 점은 people이 insert 되고 그 다음 phone이 insert 후 people의 primary key 값으로 phone의 "PHONE_OWER_ID" 컬럼값을 update 시켰다는 것이다.
양방향과 다르게 people 에서 phone으로의 단방향 관계에서는 phone 은 people에 대해 알 수 없기 때문에 초기에는 "PHONE_OWNER_ID" 값에 null을 주고 그다음 update를 통해 참조값을 넣는다.
알 수 있는 것은 1:N 관계는 무조건 서로 관계 되어야 하므로 양방향이 좋고 [0~1]:N 관계는 관계가 없을 수 도 있는 상태라 단방향이 좋다. |
테스트코드 |
People_Uni people2 = session.get(People_Uni.class, test_id);
Phone_Uni phone4 = new Phone_Uni(); phone4.setNumber("444-444-4444");
people2.getPhones().add(phone4); |
결과 |
Hibernate: select people_uni0_.PEOPLE_ID as PEOPLE_I1_0_0_, people_uni0_.PEOPLE_NAME as PEOPLE_N2_0_0_ from people people_uni0_ where people_uni0_.PEOPLE_ID=? Hibernate: select phones0_.PHONE_OWNER_ID as PHONE_OW3_2_0_, phones0_.PHONE_ID as PHONE_ID1_2_0_, phones0_.PHONE_ID as PHONE_ID1_2_1_, phones0_.PHONE_NUMBER as PHONE_NU2_2_1_, phones0_.PHONE_OWNER_ID as PHONE_OW3_2_1_ from phone phones0_ where phones0_.PHONE_OWNER_ID=? Hibernate: insert into phone (PHONE_NUMBER, PHONE_OWNER_ID) values (?, ?) Hibernate: update phone set PHONE_OWNER_ID=? where PHONE_ID=? |
설명 |
이미 존재하는 People 을 select 하고 phone을 add() 하면 자동으로 phone이 insert 된다. |
테스트코드 |
People_Uni people3 = session.get(People_Uni.class, test_id);
people3.getPhones().remove(1); |
결과 |
Hibernate: delete from phone where PHONE_ID=? |
설명 |
이제 설명하기도 입아프다. orphanRemoval=true 기 때문에 부모(people)를 잃은 자식(phone)은 삭제된다. Hibernate: update phone set PHONE_OWNER_ID=null where PHONE_OWNER_ID=? and PHONE_ID=? |