이 글은 김영한의 [자바 ORM 표준 JPA 프로그래밍 - 기본편] 수강하며 정리한 글입니다.

 

👉 기본 환경

- Language: Java

- DB: H2 Database

- IDE: IntelliJ

 

 

ERD

 

 

Member Entity

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;
 
@Entity
public class Member {
 
    @Id @GeneratedValue
    @Column(name = "MEMBER_ID")
    private Long id;
 
    private String name;
    private String city;
    private String street;
    private String zipcode;
 
    @OneToMany(mappedBy = "member")
    private List<Order> orders = new ArrayList<>();
 
}
 
 
 

 

 

Order Entity

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
import javax.persistence.*;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
 
@Entity
@Table(name = "ORDERS")
public class Order {
 
    @Id @GeneratedValue
    @Column(name = "ORDER_ID")
    private Long id;
 
    @ManyToOne
    @JoinColumn(name = "MEMBER_ID")
    private Member member;
 
    @OneToMany(mappedBy = "order")
    private List<OrderItem> orderItems = new ArrayList<>();
 
    @OneToOne
    @JoinColumn(name = "DELIVERY_ID")
    private Delivery delivery;
 
    private LocalDateTime orderDate;
 
    @Enumerated(EnumType.STRING)
    private OrderStatus status;
 
}
 
 
 

- @ManyToOne + @JoinColumn

    - 다대일 관계에서 다의 위치가 연관관계 주인

 

- @OneToMany(mappedBy)

    - 일대다 관계에서 일의 위치가 조회를 위한 임의 매핑

 

- @OneToOne

   - 일대일 관계에서 연관관계 주인은 상황에 따라 선택 가능

 

- @Enumerated(EnumType.STRING)

    - enum type 사용 시, @Enumerated type.STRING 지정 필수

 

 

Delivery Entity

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import javax.persistence.*;
 
@Entity
public class Delivery {
 
    @Id @GeneratedValue
    @Column(name = "DELIVERY_ID")
    private Long id;
 
    @OneToOne(mappedBy = "delivery")
    private Order order;
 
    private String city;
    private String street;
    private String zipcode;
 
    @Enumerated(EnumType.STRING)
    private DeliveryStatus status;
 
}
 
 
 

 

 

OrderItem Entity

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import javax.persistence.*;
 
@Entity
public class OrderItem {
 
    @Id @GeneratedValue
    @Column(name = "ORDER_ITEM_ID")
    private Long id;
 
    @ManyToOne
    @JoinColumn(name = "ORDER_ID")
    private Order order;
 
    @ManyToOne
    @JoinColumn(name = "ITEM_ID")
    private Item item;
 
    @Column(name = "ORDER_PRICE")
    private int price;
    private int count;
 
}
 
 
 

 

 

Item Entity

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;
 
@Entity
public class Item {
 
    @Id @GeneratedValue
    @Column(name = "ITEM_ID")
    private Long id;
 
    private String name;
    private int price;
    private int stockQuantity;
 
    @ManyToMany(mappedBy = "items")
    private List<Category> categories = new ArrayList<>();
 
}
 
 
 

- @ManyToMany

  ⭐ 관계형 데이터베이스에서 다대다 (Many-to-Many) 관계를 직접적으로 표현하는 것은 불가능

        ▶ 연결 테이블을 추가해서 일대다, 다대일 관계로 풀어내야 함

 

 

 

Category Entity

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
import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;
 
@Entity
public class Category {
 
    @Id @GeneratedValue
    @Column(name = "CATEGORY_ID")
    private Long id;
 
    private String name;
 
    @ManyToOne
    @JoinColumn(name = "PARENT_ID")
    private Category parent;
 
    @OneToMany(mappedBy = "parent")
    private List<Category> children = new ArrayList<>();
 
    @ManyToMany
    @JoinTable(name = "CATEGORY_ITEM",
        joinColumns = @JoinColumn(name = "CATEGORY_ID"),
        inverseJoinColumns = @JoinColumn(name = "ITEM_ID")
    )
    private List<Item> items = new ArrayList<>();
}
 
 
 

- private Category parent

- private List<Category> children = new ArrayList<>()

    - 한 카테고리가 다른 카테고리를 부모로 가지는 계층 구조를 표현

    - 부모 : 자식 = 일 : 다

 

- @JoinTable

    - CATEGORY와 ITEM의 PK로 이뤄진 연결 테이블 생성

    - joinColumns

        - 현재 엔티티(Category)와 연결되는 외래키

    - inverseJoinColumns

        - 상대 엔티티(Item)와 연결되는 외래키

 

 

실행 결과

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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
Hibernate: 
    
    create table Category (
       CATEGORY_ID bigint not null,
        name varchar(255),
        PARENT_ID bigint,
        primary key (CATEGORY_ID)
    )
 
Hibernate: 
    
    create table CATEGORY_ITEM (
       CATEGORY_ID bigint not null,
        ITEM_ID bigint not null
    )
 
Hibernate: 
    
    create table Delivery (
       DELIVERY_ID bigint not null,
        city varchar(255),
        status varchar(255),
        street varchar(255),
        zipcode varchar(255),
        primary key (DELIVERY_ID)
    )
 
Hibernate: 
    
    create table Item (
       ITEM_ID bigint not null,
        name varchar(255),
        price integer not null,
        stockQuantity integer not null,
        primary key (ITEM_ID)
    )
 
Hibernate: 
    
    create table Member (
       MEMBER_ID bigint not null,
        city varchar(255),
        name varchar(255),
        street varchar(255),
        zipcode varchar(255),
        primary key (MEMBER_ID)
    )
 
Hibernate: 
    
    create table OrderItem (
       ORDER_ITEM_ID bigint not null,
        count integer not null,
        price integer not null,
        ITEM_ID bigint,
        ORDER_ID bigint,
        primary key (ORDER_ITEM_ID)
    )
 
Hibernate: 
    
    create table ORDERS (
       ORDER_ID bigint not null,
        orderDate timestamp,
        status varchar(255),
        DELIVERY_ID bigint,
        MEMBER_ID bigint,
        primary key (ORDER_ID)
    )
 
 
 
Hibernate: 
    
    alter table Category 
       add constraint FK8tepc1qkmluodspg6tnliwhit 
       foreign key (PARENT_ID) 
       references Category
 
Hibernate: 
    
    alter table CATEGORY_ITEM 
       add constraint FKf1uerpnmn49vl1spbbplgxaun 
       foreign key (ITEM_ID) 
       references Item
 
Hibernate: 
    
    alter table CATEGORY_ITEM 
       add constraint FKjip0or3vemixccl6vx0kluj03 
       foreign key (CATEGORY_ID) 
       references Category
 
Hibernate: 
    
    alter table OrderItem 
       add constraint FKabge9eqalspcejij53rat7pjh 
       foreign key (ITEM_ID) 
       references Item
 
Hibernate: 
    
    alter table OrderItem 
       add constraint FKk7lmf97wukpquk6d8blxy5neq 
       foreign key (ORDER_ID) 
       references ORDERS
 
Hibernate: 
    
    alter table ORDERS 
       add constraint FKdbs21f1yi0coxy9y0kxw4g9jf 
       foreign key (DELIVERY_ID) 
       references Delivery
 
Hibernate: 
    
    alter table ORDERS 
       add constraint FKh0db7kqr88ed8hqtcqw3jkcia 
       foreign key (MEMBER_ID) 
       references Member
 
 
 

 

이 글은 김영한의 [자바 ORM 표준 JPA 프로그래밍 - 기본편] 수강하며 정리한 글입니다.

 

👉 기본 환경

- Language: Java

- DB: H2 Database

- IDE: IntelliJ

 

 

다대다 매핑

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;
 
@Entity
public class Member {
 
    @Id @GeneratedValue
    @Column(name = "MEMBER_ID")
    private Long id;
 
    @Column(name = "USER_NAME")
    private String name;
 
    @ManyToMany
    @JoinTable(name = "MEMBER_PRODUCT")
    private List<Product> products = new ArrayList<>();
 
}
 
 
 

Member Entity

    - 연관 관계 주인

    - JoinTable 생성

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;
 
@Entity
public class Product {
 
    @Id @GeneratedValue
    @Column(name = "PRODUCT_ID")
    private Long id;
 
    @Column(name = "PRODUCT_NAME")
    private String name;
 
    @ManyToMany(mappedBy = "products")
    private List<Member> members = new ArrayList<>();
 
}
 
 
 

Product Entity

    - 단순 참조를 위한 매핑

 

⭐ 관계형 데이터베이스에서 다대다 (Many-to-Many) 관계를 직접적으로 표현하는 것은 불가능

    ▶ 연결 테이블을 추가해서 일대다, 다대일 관계로 풀어내야 함

 

중간 테이블에 새로운 컬럼을 추가하는 게 어려워 유연성이 떨어짐

    - @JoinTable을 통해서 PK, FK 관계 이외의 필드를 설정하기 어려움

 

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
Hibernate: 
    
    create table Member (
       MEMBER_ID bigint not null,
        USER_NAME varchar(255),
        primary key (MEMBER_ID)
    )
 
Hibernate: 
    
    create table MEMBER_PRODUCT (
       members_MEMBER_ID bigint not null,
        products_PRODUCT_ID bigint not null
    )
 
Hibernate: 
    
    create table Product (
       PRODUCT_ID bigint not null,
        PRODUCT_NAME varchar(255),
        primary key (PRODUCT_ID)
    )
 
 
Hibernate: 
    
    alter table Member 
       add constraint FK332130jlg9s5hyeuk7gfgi052 
       foreign key (LOCKER_ID) 
       references Locker
 
Hibernate: 
    
    alter table MEMBER_PRODUCT 
       add constraint FKfmfxdrleengm9fi0691plhcwa 
       foreign key (products_PRODUCT_ID) 
       references Product
 
Hibernate: 
    
    alter table MEMBER_PRODUCT 
       add constraint FKp9hlrsu8hrsusdymar0ddcl9o 
       foreign key (members_MEMBER_ID) 
       references Member
 
 
 

Entity 실행 결과

 

 

⭐ 다대다 매핑은 일대다 + 다대일 매핑으로 풀어내야 함

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;
 
@Entity
public class Member {
 
    @Id @GeneratedValue
    @Column(name = "MEMBER_ID")
    private Long id;
 
    @Column(name = "USER_NAME")
    private String name;
 
    @OneToMany(mappedBy = "member")
    private List<MemberProduct> memberProducts = new ArrayList<>();
 
}
 
 
 

Member Entity

    - Member : MemberProduct = 1: 다

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;
 
@Entity
public class Product {
 
    @Id @GeneratedValue
    @Column(name = "PRODUCT_ID")
    private Long id;
 
    @Column(name = "PRODUCT_NAME")
    private String name;
 
    @OneToMany(mappedBy = "product")
    private List<MemberProduct> memberProducts = new ArrayList<>();
 
}
 
 
 

Product Entity

    - Product : MemberProduct = 1: 다

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import javax.persistence.*;
import java.time.LocalDateTime;
 
@Entity
public class MemberProduct {
 
    @Id @GeneratedValue
    private Long id;
 
    @ManyToOne
    @JoinColumn(name = "PRODUCT_ID")
    private Product product;
 
    @ManyToOne
    @JoinColumn(name = "MEMBER_ID")
    private Member member;
 
    private int count;
    private int price;
 
    private LocalDateTime orderDate;
 
}
 
 
 

MemberProduct Entity

    - Member : MemberProduct = 1: 다

    - Product : MemberProduct = 1: 다

 

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
50
Hibernate: 
    
    create table Member (
       MEMBER_ID bigint not null,
        USER_NAME varchar(255),
        primary key (MEMBER_ID)
    )
 
Hibernate: 
    
    create table MemberProduct (
       id bigint not null,
        count integer not null,
        orderDate timestamp,
        price integer not null,
        MEMBER_ID bigint,
        PRODUCT_ID bigint,
        primary key (id)
    )
 
Hibernate: 
    
    create table Product (
       PRODUCT_ID bigint not null,
        PRODUCT_NAME varchar(255),
        primary key (PRODUCT_ID)
    )
 
 
Hibernate: 
    
    alter table Member 
       add constraint FK332130jlg9s5hyeuk7gfgi052 
       foreign key (LOCKER_ID) 
       references Locker
 
Hibernate: 
    
    alter table MemberProduct 
       add constraint FKjnj8ungt7v35y6lfxuxcrjbbr 
       foreign key (MEMBER_ID) 
       references Member
 
Hibernate: 
    
    alter table MemberProduct 
       add constraint FKrgt6jorh7iaec1tae84ljye8c 
       foreign key (PRODUCT_ID) 
       references Product
 
 
 

Entity 실행 결과

 

이 글은 김영한의 [자바 ORM 표준 JPA 프로그래밍 - 기본편] 수강하며 정리한 글입니다.

 

👉 기본 환경

- Language: Java

- DB: H2 Database

- IDE: IntelliJ

 

 

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
50
51
52
53
54
55
56
@Entity
public class Member {
 
    @Id @GeneratedValue
    @Column(name = "MEMBER_ID")
    private Long id;
    private String name;
    private String city;
    private String street;
    private String zipcode;
 
    @OneToMany(mappedBy = "member")
    private List<Order> orders = new ArrayList<>();
 
    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 String getCity() {
        return city;
    }
 
    public void setCity(String city) {
        this.city = city;
    }
 
    public String getStreet() {
        return street;
    }
 
    public void setStreet(String street) {
        this.street = street;
    }
 
    public String getZipcode() {
        return zipcode;
    }
 
    public void setZipcode(String zipcode) {
        this.zipcode = zipcode;
    }
 
}
 
 
 

Member : Order = 1 : 다

 

1명의 사용자가 여러개의 주문을 할 수 있으므로 Order는 List로 저장

 

private List<Order> orders; 가 아닌 private List<Order> orders = new ArrayList<>(); 이유

    - private List<Order> orders는 기본적으로 null값을 갖게 됨

    - 초기화를 하지 않고 orders에 대한 연산 실행 시, NullPointerException이 발생할 수 있음

    - 그러므로 Entity에서 초기화하여 NullPonterException 방지

 

이 글은 김영한의 [자바 ORM 표준 JPA 프로그래밍 - 기본편] 수강하며 정리한 글입니다.

 

👉 기본 환경

- Language: Java

- DB: H2 Database

- IDE: IntelliJ

 

 

1. Entity 상태

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
@Entity
public class Member {
 
    @Id @GeneratedValue
    @Column(name = "MEMBER_ID")
    private Long id;
 
    @Column(name = "USERNAME")
    private String name;
 
    @ManyToOne // Member : Team = Many : One
    @JoinColumn(name = "TEAM_ID"// JoinColum = FK
    private Team team;
    // FK가 있는 곳(Many to One에서 Many 부분)이 연관 관계의 주인
 
    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 Team getTeam() {
        return team;
    }
 
    public void setTeam(Team team) {
        this.team = team;
    }
 
 
}
 
 
 

Member.java

 

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
@Entity
public class Team {
 
    @Id @GeneratedValue
    @Column(name = "TEAM_ID")
    private Long id;
    private String name;
 
    @OneToMany(mappedBy = "team"// mappedBy: 상대 Entity의 FK field 값
    private List<Member> members = new ArrayList<>();
 
    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 List<Member> getMembers() {
        return members;
    }
 
    public void setMembers(List<Member> members) {
        this.members = members;
    }
 
 
}
 
 
 

Team.java

 

Member entity와 Team entity가 양방향으로 매핑되어있음

Member : Team = 다 : 1 관계

 

 

2-1. 데이터 저장

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
public class Main {
    public static void main(String[] args) {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
 
        EntityManager em = emf.createEntityManager();
 
        EntityTransaction tx = em.getTransaction();
        tx.begin();
 
 
        try {
 
            Member member = new Member();
            member.setName("Member1");
            em.persist(member);
 
            Team team = new Team();
            team.setName("TeamA");
            team.getMembers().add(member);
 
            em.persist(team);
 
            em.flush();
            em.clear();
            
            tx.commit();
        } catch (Exception e) {
            tx.rollback();
        } finally {
            em.close();
        }
 
 
        emf.close();
    }
 
}
 
 
 

- Member 객체 생성 후, persist

- Team 객체 생성 후, getter로 member list 호출 후 member 객체 추가

 

Team 객체에 Member를 매핑하였지만, Member 객체의 Team_id가 null값으로 입력됨

 

@OneToMany(mappedBy = "")

양방향 매핑에서 mappedBy 속성은 단순히 매핑되어있음을 안내해주는 역할일 뿐, 실제로 데이터를 매핑시켜주지 않음

 

 

2-2. 데이터 저장 - 수정

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
public class Main {
    public static void main(String[] args) {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
 
        EntityManager em = emf.createEntityManager();
 
        EntityTransaction tx = em.getTransaction();
        tx.begin();
 
 
        try {
 
            Team team = new Team();
            team.setName("TeamA");
            em.persist(team);
 
            Member member = new Member();
            member.setName("Member1");
            member.setTeam(team);
            em.persist(member);
 
            em.flush();
            em.clear();
            
            tx.commit();
        } catch (Exception e) {
            tx.rollback();
        } finally {
            em.close();
        }
 
 
        emf.close();
    }
 
}
 
 
 

- Team 객체 생성 후, persist

- Member 객체 생성 및 team 객체 주입 후, persist

 

Member 객체에 매핑한 Team 객체의 Team_id가 입력됨

 

@ManyToOne
@JoinColumn(name = "TEAM_ID")

양방향 매핑에서 실제 데이터 입력을 담당하는 필드는 @Joincolumn이 선언되어있는 필드

 

 

3. 데이터 조회

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
public class Main {
    public static void main(String[] args) {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
 
        EntityManager em = emf.createEntityManager();
 
        EntityTransaction tx = em.getTransaction();
        tx.begin();
 
 
        try {
 
            Team team = new Team();
            team.setName("TeamA");
            em.persist(team);
 
            Member member = new Member();
            member.setName("Member1");
            member.setTeam(team);
            em.persist(member);
 
//            em.flush();
//            em.clear();
 
            Team findTeam = em.find(Team.class, team.getId());
            List<Member> members = findTeam.getMembers();
 
            System.out.println("==========");
 
            for(Member m : members){
                System.out.println("member: " + m.getName());
            }
 
            System.out.println("==========");
            
            tx.commit();
        } catch (Exception e) {
            tx.rollback();
        } finally {
            em.close();
        }
 
 
        emf.close();
    }
 
}
 
 
 

- flush(), clear()를 제거하고, 같은 트랜잭션 내에서 1차 캐시에 저장된 team과 member를 바로 조회할 경우,

    member 객체에 매핑된 team 객체를 조회할 수 있지만, team 객체에서 매핑된 member 조회할 수 없음

- 1차 캐시 상태에서는 Team 객체와 Member 객체의 관계가 명시적으로 코드로 작성한 부분을 제외하고는 인식되지 않음

    ▶ 양방향으로 객체 주입

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
50
public class Main {
    public static void main(String[] args) {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
 
        EntityManager em = emf.createEntityManager();
 
        EntityTransaction tx = em.getTransaction();
        tx.begin();
 
 
        try {
 
            Team team = new Team();
            team.setName("TeamA");
            em.persist(team);
 
            Member member = new Member();
            member.setName("Member1");
            member.setTeam(team);
            em.persist(member);
 
            team.getMembers().add(member);
 
//            em.flush();
//            em.clear();
 
            Team findTeam = em.find(Team.class, team.getId());
            List<Member> members = findTeam.getMembers();
 
            System.out.println("==========");
 
            for(Member m : members){
                System.out.println("member: " + m.getName());
            }
 
            System.out.println("==========");
            
            tx.commit();
        } catch (Exception e) {
            tx.rollback();
        } finally {
            em.close();
        }
 
 
        emf.close();
    }
 
}
 
 
 

 

 

4. 코드 리팩토링

양방향으로 값을 세팅해주는 과정(setTeam, addMember)에서 일부 값만 세팅하는 실수가 발생할 수 있음

▶ 연관관계 편의 메서드를 생성하여, 하나의 메서드로 2개의 값을 세팅

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
public class Main {
    public static void main(String[] args) {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
 
        EntityManager em = emf.createEntityManager();
 
        EntityTransaction tx = em.getTransaction();
        tx.begin();
 
 
        try {
 
            Team team = new Team();
            team.setName("TeamA");
            em.persist(team);
 
            Member member = new Member();
            member.setName("Member1");
            member.changeTeam(team);
            em.persist(member);
 
            Team findTeam = em.find(Team.class, team.getId());
            List<Member> members = findTeam.getMembers();
 
            System.out.println("==========");
            for(Member m : members){
                System.out.println("member: " + m.getName());
            }
            System.out.println("==========");
            
            tx.commit();
        } catch (Exception e) {
            tx.rollback();
        } finally {
            em.close();
        }
 
 
        emf.close();
    }
 
}
 
 
 

- setTeam() 대신 changeTeam을 활용하여, setTeam과 addMember 수행

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
@Entity
public class Member {
 
    @Id @GeneratedValue
    @Column(name = "MEMBER_ID")
    private Long id;
 
    @Column(name = "USERNAME")
    private String name;
 
    @ManyToOne // Member : Team = Many : One
    @JoinColumn(name = "TEAM_ID"// JoinColum = FK
    private Team team;
 
 
    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 Team getTeam() {
        return team;
    }
 
    public void setTeam(Team team) {
        this.team = team;
    }
 
 
    public void changeTeam(Team team) {
        this.team = team;
        team.getMembers().add(this);
    }
 
}
 
 
 

 

cf. changeTeam() 대신 addMember() 사용 가능

⭐ 단, 연관관계 편의 메서드는 동일한 역할을 수행하므로 하나의 메서드만 생성

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
@Entity
public class Team {
 
    @Id @GeneratedValue
    @Column(name = "TEAM_ID")
    private Long id;
    private String name;
 
    @OneToMany(mappedBy = "team"// mappedBy: 상대 Entity의 FK field 값
    private List<Member> members = new ArrayList<>();
 
 
    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 List<Member> getMembers() {
        return members;
    }
 
    public void setMembers(List<Member> members) {
        this.members = members;
    }
 
    public void addMember(Member member) {
        member.setTeam(this);
        this.getMembers().add(member);
    }
 
}
 
 
 

 

이 글은 김영한의 [자바 ORM 표준 JPA 프로그래밍 - 기본편] 수강하며 정리한 글입니다.

 

👉 기본 환경

- Language: Java

- DB: H2 Database

- IDE: IntelliJ

 

 

1. 객체를 테이블에 맞춰 모델링

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
package jpa_basic;
 
import javax.persistence.*;
import java.util.Date;
 
@Entity
public class Member {
 
    @Id @GeneratedValue
    @Column(name = "MEMBER_ID")
    private Long id;
 
    @Column(name = "USERNAME")
    private String name;
 
    @Column(name = "TEAM_ID")
    private Long teamId;
 
    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 Long getTeamId() {
        return teamId;
    }
 
    public void setTeamId(Long teamId) {
        this.teamId = teamId;
    }
 
 
}
 
 
 

테이블에서 외래키 역할을 하는 teamId가 필드로 선언

 

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
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;
import java.util.List;
 
public class Main {
 
    public static void main(String[] args) {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
 
        EntityManager em = emf.createEntityManager();
 
        // JPA의 모든 데이터 변경은 transaction 안에서 실행
        EntityTransaction tx = em.getTransaction();
        tx.begin();
 
        try {
 
            // 객체를 테이블에 맞춰 모델링
 
            Team team = new Team();
            team.setName("TeamA");
            em.persist(team);
 
            Member member = new Member();
            member.setName("Member1");
            member.setTeamId(team.getId());
            em.persist(member);
 
            Member findMember = em.find(Member.class, member.getId());
 
            Long findTeamId = findMember.getTeamId();
            Team findItem = em.find(Team.class, findTeamId);
 
            tx.commit();
        } catch (Exception e) {
            tx.rollback();
        } finally {
            em.close();
        }
 
 
        emf.close();
 
    }
 
}
 
 
 

* DB에 맞춰진 설계 방식

    - Member와 Team 사이의 연관관계를 맺는 대신에 teamId를 사용하여 직접적인 관계를 표현

    - OOP에서는 객체 간의 관계를 통해 참조하는 것이 일반적

    - ID 값보다는 실제 객체의 참조를 사용하여 관계를 표현하는 것이 객체 지향적인 방식

    - 객체 간의 연관관계를 활용하여 코드의 가독성과 유지보수성을 높일 수 있음

 

 

2. 객체 지향 모델링

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
package jpa_basic;
 
import javax.persistence.*;
import java.util.Date;
 
@Entity
public class Member {
 
    @Id @GeneratedValue
    @Column(name = "MEMBER_ID")
    private Long id;
 
    @Column(name = "USERNAME")
    private String name;
 
    @ManyToOne // Member : Team = Many : One
    @JoinColumn(name = "TEAM_ID"// JoinColumn = FK
    private Team team;
 
    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 Team getTeam() {
        return team;
    }
 
    public void setTeam(Team team) {
        this.team = team;
    }
 
}
 
 
 

Entity Team을 필드로 선언하여 연관관계 매핑

Entity 간의 관계 설정(@ManyToOne, Member : Team = 다 : 1)

관계 설정 시, FK 설정(@JoinColumn)

 

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
package jpa_basic;
 
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;
import java.util.List;
 
public class Main {
    public static void main(String[] args) {
 
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
 
        EntityManager em = emf.createEntityManager();
 
        EntityTransaction tx = em.getTransaction();
        tx.begin();
 
        try {
 
            // 객체 지향 모델링
            Team team = new Team();
            team.setName("TeamA");
            em.persist(team);
 
            Member member = new Member();
            member.setName("Member1");
            member.setTeam(team);
            em.persist(member);
 
            Member findMember = em.find(Member.class, member.getId());
 
            Team findTeam = findMember.getTeam();
 
            tx.commit();
        } catch (Exception e) {
            tx.rollback();
        } finally {
            em.close();
        }
 
 
        emf.close();
    }
 
}
 
 
 

ID 값을 사용하는 대신 Team 객체 사용