[Spring JPA #4] 관계 맵핑
- 📚 Spring/Spring JPA
- 2020. 6. 28. 10:04
| @ManyToOne
package org.kyhslam.jpa;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
@Entity
public class Study {
@Id @GeneratedValue
private Long id;
private String name;
// 하나의 계정으로 여러 study를 만들 수 있기 때문에 MaytoOne이다.
// (뒤에께 해당 컬럼에 해당)
// 햇갈릴 경우에는 앞쪽이 해당클래스(Study)이고 뒤쪽이 해당 컬럼(Account)
@ManyToOne
private Account owner;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Account getOwner() {
return owner;
}
public void setOwner(Account owner) {
this.owner = owner;
}
}
- @ManyToOne은 현재 Study 엔티티가 Account엔티티와 N:1 관계를 맺는다는 의미이다. 따라서 study 테이블에 account테이블의 컬럼을 참조하는 외래키를 생성하게 된다.
- 햇갈릴 경우 앞쪽(Many)이 해당클래스(Study)이고 뒤쪽(One)이 해당 컬럼(Account) 이라고 생각하면 된다.
package org.kyhslam.jpa;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
@Entity
public class Account {
@Id @GeneratedValue
private long id;
private String username;
private String password;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
spring.datasource.url=jdbc:postgresql://localhost:5432/springboot
spring.datasource.username=kyhslam
spring.datasource.password=pass
spring.jpa.hibernate.ddl-auto=create
spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true
package org.kyhslam.jpa;
import org.hibernate.Session;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.transaction.Transactional;
@Component
@Transactional
public class JpaRunner implements ApplicationRunner {
@PersistenceContext
EntityManager entityManager;
@Override
public void run(ApplicationArguments args) throws Exception {
Account account = new Account();
account.setUsername("kyhslam");
account.setPassword("jpa");
Study study = new Study();
study.setName("Spring Data JPA");
study.setOwner(account);
Session session = entityManager.unwrap(Session.class);
session.save(account);
session.save(study);
// 이거도 가능
//entityManager.persist(account);
//entityManager.persist(study);
}
}
결과
Hibernate:
alter table if exists study
drop constraint if exists FK210g5r7wftvloq2ics531e6e4
Hibernate:
drop table if exists account cascade
Hibernate:
drop table if exists study cascade
Hibernate:
drop sequence if exists hibernate_sequence
Hibernate: create sequence hibernate_sequence start 1 increment 1
Hibernate:
create table account (
id int8 not null,
password varchar(255),
username varchar(255),
primary key (id)
)
Hibernate:
create table study (
id int8 not null,
name varchar(255),
owner_id int8,
primary key (id)
)
Hibernate:
alter table if exists study
add constraint FK210g5r7wftvloq2ics531e6e4
foreign key (owner_id)
references account
springboot=# \dt
List of relations
Schema | Name | Type | Owner
--------+---------+-------+---------
public | account | table | kyhslam
public | study | table | kyhslam
(2 rows)
springboot=# select * from study;
id | name | owner_id
----+-----------------+----------
2 | Spring Data JPA | 1
(1 row)
springboot=# select * from account;
id | password | username
----+----------+----------
1 | jpa | kyhslam
(1 row)
| @OneToMany
소스
package org.kyhslam.jpa;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import java.util.HashSet;
import java.util.Set;
@Entity
public class Account {
@Id @GeneratedValue
private long id;
private String username;
private String password;
@OneToMany
private Set<Study> studies = new HashSet<>();
public Set<Study> getStudies() {
return studies;
}
public void setStudies(Set<Study> studies) {
this.studies = studies;
}
생략..
}
package org.kyhslam.jpa;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
@Entity
public class Study {
@Id @GeneratedValue
private Long id;
private String name;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
ㅅ스
package org.kyhslam.jpa;
import org.hibernate.Session;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.transaction.Transactional;
@Component
@Transactional
public class JpaRunner implements ApplicationRunner {
@PersistenceContext
EntityManager entityManager;
@Override
public void run(ApplicationArguments args) throws Exception {
Account account = new Account();
account.setUsername("kyhslam");
account.setPassword("jpa");
Study study = new Study();
study.setName("Spring Data JPA");
account.getStudies().add(study);
//entityManager.persist(account);
Session session = entityManager.unwrap(Session.class);
session.save(account);
session.save(study);
//entityManager.persist(account);
// entityManager.persist(study);
}
}
| 양방향 맵핑
- FK 가지고 있는 쪽이 오너이다. 따라서 기본값은 @ManyToOne 가지고 있는 쪽이 주인이다.
- 주인이 아닌쪽(@OneToMany)에서 mappedBy 사용해서 관계를 맺고 있는 필드를 설정해야 한다.
- @ManyToOne(이쪽이 주인)
- @OneToMany(mappedBy)
- 주인한테 관계를 설정해야 DB에 반영이 된다.
- 관계가 주인인쪽에 관계를 맵핑해야 한다.
Account
package org.kyhslam.jpa;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import java.util.HashSet;
import java.util.Set;
@Entity
public class Account {
@Id @GeneratedValue
private long id;
private String username;
private String password;
@OneToMany(mappedBy = "owner")
private Set<Study> studies = new HashSet<>();
public Set<Study> getStudies() {
return studies;
}
public void setStudies(Set<Study> studies) {
this.studies = studies;
}
// 이상적인 추가 메소드
public void addStudy(Study study) {
this.studies.add(study);
study.setOwner(this);
}
// 삭제
public void removeStudy(Study study) {
this.studies.remove(study);
study.setOwner(null);
}
}
study
package org.kyhslam.jpa;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
@Entity
public class Study {
@Id @GeneratedValue
private Long id;
private String name;
@ManyToOne
private Account owner;
public Account getOwner() {
return owner;
}
public void setOwner(Account owner) {
this.owner = owner;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
- Study 엔티티에 @ManyToOne을 추가해서 양방향 매핑에 대한 정보를 설정해야 합니다. Account 엔티티에 어떤 컬럼과 매핑할 것인지에 대한 정보가 설정되어 있으므로 그와 관련된 정보는 여기서 부가하지 않았습니다.
package org.kyhslam.jpa;
import org.hibernate.Session;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.transaction.Transactional;
@Component
@Transactional
public class JpaRunner implements ApplicationRunner {
@PersistenceContext
EntityManager entityManager;
@Override
public void run(ApplicationArguments args) throws Exception {
Account account = new Account();
account.setUsername("kyhslam");
account.setPassword("jpa");
Study study = new Study();
study.setName("Spring Data JPA");
account.getStudies().add(study);
study.setOwner(account); // 이 부분을 빼먹으면 데이터가 저장되지 않는다
//entityManager.persist(account);
Session session = entityManager.unwrap(Session.class);
session.save(account);
session.save(study);
//entityManager.persist(account);
// entityManager.persist(study);
}
}
결과 화면
springboot=# select * from study;
id | name | owner_id
----+-----------------+----------
2 | Spring Data JPA |
(1 row)
springboot=# select * from study;
id | name | owner_id
----+-----------------+----------
2 | Spring Data JPA | 1
(1 row)
springboot=# select * from account;
id | password | username
----+----------+----------
1 | jpa | kyhslam
(1 row)
'📚 Spring > Spring JPA' 카테고리의 다른 글
[Spring JPA #6] Fetch (0) | 2020.07.15 |
---|---|
[Spring JPA #5] 엔티티 상태와 Cascade (0) | 2020.07.14 |
[Spring JPA #3] Entity 매핑 및 Value 타입 (0) | 2020.06.27 |
[Spring JPA #2] JPA 엔티티 매핑 용어 정리 (0) | 2020.06.27 |
[Spring JPA #1] JPA 및 ORM 이란? (0) | 2020.06.22 |