ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • JPA 연관관계 매핑
    spring boot 2023. 1. 12. 13:18

     

    RDBMS를 사용할 때는 테이블 하나만 사용해서 애플리케이션의 모든 기능을 구현하기란불가능합니다. 대체로 설계가 복잡해지면 각 도메인에 맞는 테이블을 설계하고 연관관계를 설정해서 조인(Join)등의 기능을 활용합니다. 연관관계를 맺는 두 엔티티 간에 생성할 수 있는 연관관계의 종류는 다음과 같습니다.

    1. One To One : 일대일(1:1)
    2. One To Many : 일대다(1:N)
    3. Many To One : 다대일(N:1)
    4. Many To Many : 다대다(N:N)

     

    1. 일대일 매핑


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    @Getter
    @Setter
    @AllArgsConstructor
    @NoArgsConstructor
    @Builder
    @Entity
    @ToString(callSuper = true)
    @Table(name = "example")
    public class Example {
     
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Long number;
     
        private String name;
     
        private String email;
     
        @OneToOne(mappedBy = "example")
        @ToString.Exclude   // StackOverflowError 가 발생하기 때문에 Exclude를 통해 제외 설정을 해준다.
        private ExampleDetail exampleDetail;
     
    }
    cs

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    @Getter
    @Setter
    @AllArgsConstructor
    @NoArgsConstructor
    @Builder
    @Entity
    @ToString(callSuper = true)
    @Table(name = "example_detail")
    public class ExampleDetail {
     
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Long id;
     
        private String description;
     
        @OneToOne
        @JoinColumn(name = "example_number")
        private Example example;
     
    }
    cs

     

    일대일 매핑은 하나의 엔티티에 다른 하나의 엔티티 정보만 매핑되는 구조라고 볼 수 있습니다. 일대일 매핑을 구현하기 위해서는 위에 Example과 ExampleDetail 엔티티처럼 두개의 엔티티가 필요합다. @OneToOne 어노테이션을 사용해서 일대일 매핑을 시키는 것인데 이때 두 엔티티 중 하나의 엔티티에만 @OneToOne 어노테이션을 써놓을 경우 단방향 매핑이라고 합니다. 말그대로 한 방향에서만 일대일 매핑을 한다는 뜻입니다. 그리고 서로 단방향 매핑을 하게되면 양방향 매핑이 됩니다. 위에 Example 클래스를 보면 @OneToOne 어노테이션에 mappedBy 가 정의 되어 있는것을 볼 수 있는데요, 양방향 매핑을 할 경우에는 한쪽의 테이블에서만 외래키를 바꿀 수 있도록 정의 하는 것이 좋습니다. 따라서 한쪽에게만 외래키를 주도록 설정을 해주어야 하는데 이때 사용되는 속성 값이 mappedBy 입니다. 그 밑에 @ToString.Exclude 어노테이션을 StackOverflowError 가 발생하는 것에 대비하여 설정해줍니다. ExampleDetail 클래스를 보면 @JoinColumn 어노테이션에 name 이 지정되어 있는데요 이는 매핑할 외래키의 이름을 설정합니다.

     

    2. 다대일, 일대다 매핑

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    @Getter
    @Setter
    @AllArgsConstructor
    @NoArgsConstructor
    @Builder
    @Entity
    @ToString(callSuper = true)
    @Table(name = "example")
    public class Example {
     
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Long number;
     
        private String name;
     
        private String email;
     
        @ManyToOne
        @JoinColumn(name = "exampleOne_id")
        private ExampleOne exampleOne;
     
    }
    cs

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    @Entity
    @Getter
    @Setter
    @ToString
    @NoArgsConstructor
    @AllArgsConstructor
    @Builder
    @Table(name = "exampleOne")
    public class ExampleOne {
     
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Long id;
     
        private String description;
     
    }
     
     
    cs
     
    다대일 매핑은 하나의 데이터가 여러개의 데이터에 매핑되는 형식입니다. @ManyToOne 어노테이션을 사용하여 매핑해주고 하나의 컬럼에 여러개의 데이터를 매핑해줘야 하므로 @JoinColumn 어노테이션을 이용하여 매핑할 컬럼을 지정해주어야 합니다.
     
     
     
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    @Entity
    @Getter
    @Setter
    @ToString
    @NoArgsConstructor
    @AllArgsConstructor
    @Builder
    @Table(name = "exampleOne")
    public class ExampleOne {
     
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Long id;
     
        private String description;
     
        @OneToMany(fetch = FetchType.EAGER)
        @JoinColumn(name = "exampleOne_id")
        private List<ExampleDetail> exampleDetails = new ArrayList<>();
     
    }
    cs
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    @Getter
    @Setter
    @AllArgsConstructor
    @NoArgsConstructor
    @Builder
    @Entity
    @ToString(callSuper = true)
    @Table(name = "example_detail")
    public class ExampleDetail {
     
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Long id;
     
        private String description;
     
    }
    cs
     
    일대다 매핑이 여러개의 데이터들이 하나의 컬럼에 매핑되는 형식입니다. @OneToMany 어노테이션을 이용해서 매핑을 해주고 @JoinColumn 어노테이션을 이용해서 외래키를 지정해줍니다. 일대다 연관관계의 경우 여러 엔티티가 포함될 수 있어 ExampleOne 클래스의 exampleDetails처럼 컬렉션 형식으로 (Collection, List, Map) 필드를 생성합니다.

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    @Getter
    @Setter
    @AllArgsConstructor
    @NoArgsConstructor
    @Builder
    @Entity
    @ToString(callSuper = true)
    @Table(name = "example")
    public class Example {
     
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Long number;
     
        private String name;
     
        private String email;
     
     
        @ManyToOne
        @JoinColumn(name = "exampleOne_id")
        private ExampleOne exampleOne;
     
    }
    cs
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    @Entity
    @Getter
    @Setter
    @ToString
    @NoArgsConstructor
    @AllArgsConstructor
    @Builder
    @Table(name = "exampleOne")
    public class ExampleOne {
     
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Long id;
     
        private String description;
     
        @OneToMany(mappedBy = "exampleOne", fetch = FetchType.EAGER)
        @ToString.Exclude
        private List<Example> exampleList = new ArrayList<>();
     
    }
    cs

    위에 코드는 다대일 양방향 매핑을 하는 과정을 보여준 코드입니다. ExampleOne 클래스를 보면'fetch = FetchType.EAGER'라는 것이 있는데요 이렇게 선언한 이유는 @OneToMany의 기본 fetch 전량이 LAZY이기 때문입니다. LAZY는 지연로딩이고 EAGER는 즉시로딩입니다. 지연로딩과 즉시로딩은 엔티티를 조회할 때 적용되는데요, 지연로딩을 할경우 exampleList가 출력이 불가능하게 되고 직접 사용할 때만 사용이 가능하게 합니다. 즉시로딩을 할 경우 exampleList를 출력이 가능하게 해줍니다. 따라서 변수가 위처럼 collection 형식인 경우 지연로딩을 하고 단일 엔티티인 경우 즉시로딩을 하는 것이 효율적입니다.

     

    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
    @Getter
    @Setter
    @AllArgsConstructor
    @NoArgsConstructor
    @Builder
    @Entity
    @ToString(callSuper = true)
    @EqualsAndHashCode
    @Table(name = "exampleTwo")
    public class ExampleTwo {
     
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Long number;
     
        private String name;
     
        private String email;
     
        @ManyToMany
        @ToString.Exclude
        private List<ExampleThree> exampleThrees = new ArrayList<>();
     
    }
    cs
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    @Getter
    @Setter
    @AllArgsConstructor
    @NoArgsConstructor
    @Builder
    @Entity
    @EqualsAndHashCode
    @ToString(callSuper = true)
    @Table(name = "exampleThree")
    public class ExampleThree {
     
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Long id;
     
        private String description;
     
        @ManyToMany
        @ToString.Exclude
        private List<ExampleTwo> exampleTwos = new ArrayList<>();
     
    }
     
    cs

     다대다 매핑은 다수의 엔티티들끼리 매핑되는 관계입니다. 위에 두 클래스들을 보면 @EqualsAndHashCode 어노테이션이 쓰였는데요 이를 사용하면 @JoinColumn, @JoinTable과 같은 어노테이션을 사용하여 외래키를 선언 할 필요 없이 두 클래스의 동일성을 판단하여 서로 매핑해줍니다.

    댓글

Designed by Tistory.