Entity Relationships
- 총 4가지 타입이 존재
- 1) @OneToOne
- 2) @OneToMany, @ManyToOne
- 3) @ManyToMany
- 총 2가지 방향성이 존재
- 1) bidirectional(양방향)
- 2) unidirectional(단방향)
Entity Relation 속성
1) Cascading: 연관된 개체에 같은 연산을 적용할 것인지의 여부
- CascadeType: ALL, PERSIST, MERGE, REMOVE, REFRESH
- 디폴트는 no-operation
2) Fetch: 관련된 개체를 회수하는 전략
- FetchType
- LAZY: 연관된 개체가 필요할때 메모리에 로드
- EAGER: 연관된 개체가 조기에 같이 로드
- 디폴트는 다음과 같음
Mapping | Default Fetch Type |
---|---|
@OneToOne | FetchType.EAGER |
@OneToMany | FetchType.LAZY |
@ManyToOne | FetchType.EAGER |
@ManyToMany | FetchType.LAZY |
- @OneToOne은 참조하는게 하나 밖에 없으므로 조기에 읽어들이는게 디폴트
- @OneToMany는 참조하는게 여러개이므로 나중에 읽어들이는게 디폴트
- @ManyToOne는 참조하는게 하나 밖에 없으므로 조기에 읽어들이는게 디폴트
@ManyToMany는 참조하는게 여러개이므로 나중에 읽어들이는게 디폴트
- 예시
- 한 고객이 여러 주문을 할수 있기에 OneToMany
- Customer개체를 조회 할 때 연관하고 있는 Order개체도 같이 메모리상에 로드 할 것이냐 말 것인지 설정
Entity Relationship의 구체적인 예시
1. OneToMany Unidirectional
- foreign key를 ‘Many’에 속하는쪽에 두어야함
- category: parent 테이블(One-side), product: child 테이블 (Many-side)
- 따라서 child테이블이 foreign key를 가지게됨
- @ManyToOne어노테이션을 통해 hibernate는 어떤 객체가 child객체인지 알게됨
- @OneToMany어노테이션을 통해 hibernate는 어떤 객체가 parent객체인지 알게됨
- @JoinColum어노테이션을 통해 hibernate는 join할때 사용되는 컬럼을 알게됨
예제
- 하나의 카테고리에 여러 개의 상품들이 존재할 수 있음
- Product쪽에서만 Category쪽을 참조하므로 Unidirectional(단방향)
- @ManyToOne(cascade=CascadeType.ALL) -> Product 입장에서 봤을때 많은 상품들이 하나의 카테고리에 속하기 때문에 ManyToOne
- Category입장에서는 반대
- @JoinColumn(name=”category_id”) -> 나중에 foreign key로 매핑이되서 저장
- 객체 지향 에선 Reference를 가지고 매핑이 되는데 실제테이블에서 JoinColumn으로 매핑이된다
- 아래의 클라이언트 코드를 실행하면 cascading에 의해서 product를 저장할때 해당되는 category로 함께 저장이 된다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
sessionFactory = new Configuration().configure()
.buildSessionFactory();
Category category1 = new Category("Computer");
Product product1 = new Product("Notebook",200,
"Awesome notebook",category1);
Product product2 = new Product("Desktop", 150,
"Powerful PC", category1);
Category category2 = new Category("Car");
Product product2 = new Product("Sonata", 2000,
"Popular car", category2);
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
session.save(product1);
session.save(product2);
session.save(product3);
tx.commit();
session.close();
2. OneToMany Bidirectional
- 자바의 관점에서 두 개체가 서로 참조하고 있는 상태
- 데이터베이스의 관점에서 한 레코드가 다른 레코드를 foreign-key로 참조하고 있는 상태
- 자바의 관점에서 Many쪽에서 One쪽으로 참조할때는 레퍼런스 객체가 하나만 존재하게 됨
- 즉, @ManyToOne은 참조하고 있는 개체가 단일 인스턴스
- 자바의 관점에서 One쪽에서 Many쪽으로 참조할때는 레퍼런스 객체가 여러개 존재하게 됨
- 즉, @OneToMany는 참조하고 있는 개체가 복수 인스턴스
- mappedBy속성값을 통해 child클래스의 parent클래스를 가리키는 레퍼런스를 지정해줘야함
- 주어진 mappedBy값을 통해 hibernate는 외래키 컬럼을 사용하여 해당 collection을 로드하게됨
- One쪽에 CascadeType과 FetchType을 명시(데이터베이스 관점에서 참조되는 입장이기에)
예제
- Product는 Many쪽이므로 @ManyToOne이고 단일 인스턴스 타입
- Category는 One쪽이므로 @OneToMany이고 복수 인스턴스 타입
- Product쪽에서 JoinColumn을 지정
- One(Category)쪽에서 @OneToMany어노테이션의 속성으로 mappedBy가 설정되야함
- mappedBy에 Many(Product)쪽의 JoinColum의 필드명을 설정해줘야함
- 아래의 클라이언트 코드를 실행하면 cascading에 의해서 product도 함께 저장됨
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
sessionFactory = new Configuration().configure().buildSessionFactory();
// 1) Instantiate parent object
Category category1 = new Category("Computer");
// 2) Instantiate child objects and set the parent object in the child objects
Product product1 = new Product("Notebook", 200,"Awesome notebook",
category1);
Product product2 = new Product("Desktop", 150, "Powerful PC",category1);
// 3) Set the collection of child objects on the parent
category1.getProducts().add(product1);
category1.getProducts().add(product2);
Category category2 = new Category("Car");
Product product3 = new Product("Sonata", 2000,
"Popular car",category2);
category2.getProducts().add(product3); // category2 -> product3
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
// 4) Save the parent
session.save(category1);
session.save(category2);
tx.commit();
session.close();
3. OneToOne Unidirectional
- OneToMany와 동일하게 구현
예제
- optional=false: 값이 꼭 존재해야함
- unique=true: 1:1이기 때문에 unique해야만함
- 위와 같은 조건에 위배되면 hibernate에 의해 Exception이 발생함
- 아래의 클라이언트 코드를 실행하면 cascading에 의해서 person도 함께 저장됨
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
sessionFactory =
new Configuration().configure().buildSessionFactory();
Person person = new Person();
person.setFirstName("Namyun");
person.setLastName("Kim");
License license = new License();
license.setLicense_number("123456");
license.setIssue_date(new Date());
license.setPerson(person);
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
session.save(license);
tx.commit();
session.close();
4. OneToOne bidirectional
- 아래의 그림과 같이 양방향이게 mappedBy속성을 지정해줘야함
cascade를 Person쪽에 지정해줘야함
- 아래의 클라이언트 코드를 실행하면 cascading에 의해서 license도 함께 저장됨
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
sessionFactory =
new Configuration().configure().buildSessionFactory();
Person person = new Person();
person.setFirstName("Namyun");
person.setLastName("Kim");
License license = new License();
license.setLicense_number("123456");
license.setIssue_date(new Date());
license.setPerson(person);
person.setLicense(license);
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
session.save(person);
tx.commit();
session.close();
5. ManyToMany Unidirectional
예제
- 저자는 여러 책을 쓸수 있고 책은 여러 저자에 의해 쓰여질 수 있기에 ManyToMany관계
- 다음 그림과 같이 join table을 사용
- 각각의 primary key를 가지고 있는 제3의 테이블
- 테이블명: 테이블1_테이블2(author_book)
- Book쪽에 @ManyToMany어노테이션을 사용
- @JoinTable어노테이션을 통해 join table을 명시
- name: join table명
- joinColumns: 참조하는 테이블의 조인 컬럼명(book_id)
- inverseJoinColumns: 참조되는 테이블의 조인 컬럼명(author_id)
- 아래의 클라이언트 코드를 실행하면 cascading에 의해서 author도 함께 저장됨
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
Book book1 = new Book();
book1.setTitle("spring book");
Book book2 = new Book();
book2.setTitle("hibernate book");
Book book3 = new Book();
book3.setTitle("java book");
Author author1 = new Author();
author1.setName("alice");
Author author2 = new Author();
author2.setName("bob");
Author author3 = new Author();
author3.setName("trudy");
Set<Author> springAuthors = new HashSet<Author>();
Set<Author> hibernateAuthors = new HashSet<Author>();
Set<Author> htmlAuthors = new HashSet<Author>();
springAuthors.add(author1);
springAuthors.add(author2);
springAuthors.add(author3);
hibernateAuthors.add(author1);
hibernateAuthors.add(author2);
htmlAuthors.add(author2);
htmlAuthors.add(author3);
book1.setAuthors(springAuthors);
book2.setAuthors(hibernateAuthors);
book3.setAuthors(htmlAuthors);
sessionFactory = new Configuration().configure().
buildSessionFactory();
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
session.save(book1);
session.save(book2);
session.save(book3);
tx.commit();
session.close();