[스프링 활용] 엔티티 클래스 개발

atdawn·2024년 6월 3일

SPRING BOOT+JPA

목록 보기
20/49

참고 : 인프런 [ 실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발 - 김영한 ]


참고

  • 예제에서는 설명을 쉽게하기 위해 엔티티 클래스에 Getter, Setter를 모두 열고, 최대한 단순하게 설계
  • 실무에서는 가급적 Getter는 열어두고, Setter는 꼭 필요한 경우에만 사용하는 것을 추천
  • 엔티티를 변경할 때는 Setter 대신에 변경 지점이 명확하도록 변경을 위한 비즈니 스 메서드를 별도로 제공해야 한다.

~/domain/Member.java

@Entity //엔티티 클래스
@Getter @Setter
public class Member {

    @Id @GeneratedValue
    @Column(name="member_id")
    private Long id;

    private String name;

    @Embedded //내장 타입
    private Address address;

    @OneToMany(mappedBy = "member") //order 테이블에 있는 member에 의해 매핑됨.
    private List<Order> orders = new ArrayList<>();

}

~/domain/Order.java

    @Id @GeneratedValue
    @Column(name="order_id")
    private Long id;

    @ManyToOne
    @JoinColumn(name="member_id")
    private Member member; //연관관계 주인

    @OneToMany(mappedBy = "order") //order 필드에 의해 매핑됨
    private List<OrderItem> orderItems;

    @OneToOne
    @JoinColumn(name = "delivery_id")
    private Delivery delivery; //연관관계 주인

    //java 8이후로는 LocalDateTime를 사용하면 hibernate가 db의 date와 알아서 매핑해줌
    private LocalDateTime orderDate; //주문시간

    @Enumerated(EnumType.STRING)
    private OrderStatus status; //주문상태 [ORDER,CANCEL]

}

@Column(name=" ") : 객체의 변수 이름과 컬럼명이 다를때 사용
⏱️JPA 연관관계 매핑 복습

Order와 Member의 양방향 연관관계

Member -> Order : 일대다 @OneToMany
Order -> Member : 다대일 @ManyToOne

//Order
@JoinColumn(name="member_id") //FK인 member_id 컬럼과 매핑
private Member member;

  • 연관관계의 주인 : 테이블에서 FK를 가지고 있는 객체
    => Order 클래스
    => Order 클래스에서 Member객체를 업데이트 할 수 O
    => Member 클래스에서는 Order객체를 조회만 가능.

    자신이 연관관계의 주인이 아닌 것을 표시하는 설정
    연관관계 주인이 아닌 클래스의 매핑관계 어노테이션에 MappedBy="매핑될 필드명" 을 추가해준다.

//Member
   @OneToMany(mappedBy = "member") //order 테이블에 있는 member에 의해 매핑됨.
    private List<Order> orders = new ArrayList<>();
    ```

_~/domain/Address.java_
```java
@Embeddable
 @Getter
 public class Address {
     private String city;
     private String street;
     private String zipcode;
     protected Address() {
     }
     public Address(String city, String street, String zipcode) {
         this.city = city;
         this.street = street;
         this.zipcode = zipcode;
}
}

참고: 값 타입은 변경 불가능하게 설계해야 한다.
@Setter 를 제거하고, 생성자에서 값을 모두 초기화해서 변경 불가능한 클래스를 만들자. JPA 스펙상 엔티티나
임베디드 타입( @Embeddable )은 자바 기본 생성자(default constructor)를 public 또는 protected 로 설정해야 한다. public 으로 두는 것 보다는 protected 로 설정하는 것이 그나마 더 안전하다.
JPA가 이런 제약을 두는 이유는 JPA 구현 라이브러리가 객체를 생성할 때 리플랙션 같은 기술을 사용할 수 있도 록 지원해야 하기 때문이다.

임베디드 타입
city,street,zipcode 세개의 데이터를 하나의 Address라는 객체로 표현한다면 더욱 가독성이 좋다. (객체지향적)

JPA Entity에서 하나의 Column을 하나의 객체로써 사용할때 @Embedded,@Embeddable 어노테이션을 사용한다.

  • 임베디드 객체로 사용할 클래스에 @Embeddable 어노테이션 추가
  • Entity클래스의 객체 필드 바로 위에 @Embedded 어노테이션을 부여

~/domain/OrderStatus.java

public enum OrderStatus {
    ORDER,CANCLE
}

열거체 enum 클래스

//enum 선언
enum 열거체이름 { 상수1이름, 상수2이름, ... }
//enum 객체 생성
Enum클래스명.상수이름;

~/domain/OrderItem.java

@Entity
@Getter @Setter
public class OrderItem {

    @Id @GeneratedValue
    @Column(name="order_item_id")
    private Long id;

    @ManyToOne
    @JoinColumn(name="item_id")
    private Item item; //연관관계 주인

    @ManyToOne
    @JoinColumn(name="order_id")
    private Order order; //연관관계 주인

    private int orderPrice; //주문 당시 가격
    private int count; //주문 수량
}

~/domain/Item.java

@Entity
@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE) //한테이블에 다 넣음
@DiscriminatorColumn(name="dtype") //부모 클래스에 선언 하위 클래스를 구분하는 용도의 컬럼
@Getter @Setter
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<>();

}

~/domain/item/Album.java

@Entity
@DiscriminatorValue("A") //dtype이 B로 들어감
@Getter @Setter
public class Album extends Item {

    private String artist;
    private String etc;
}

}

⏱️상속관계 매핑 복습

~/domain/item/Category.java

@Entity
@Getter @Setter
public class Category {

    @Id @GeneratedValue
    @Column(name = "category_id")
    private Long id;

    private String name;

    @ManyToMany
    @JoinTable(name = "category_item",
            joinColumns = @JoinColumn(name = "category_id"),
            inverseJoinColumns = @JoinColumn(name = "item_id") ) //중간테이블 필요.
    private List<Item> items = new ArrayList<>();

    //셀프 양방향 연관관계
    @ManyToOne
    @JoinColumn(name = "parent_id")
    private Category parent; //내 부모

    @OneToMany(mappedBy = "parent")
    private List<Category> child =new ArrayList<>();
}

셀프 양방향 연관관계의 경우 다른 엔티티에 적용한 것처럼 해주면 된다.

⏱️@JoinTable 복습

참고: 실무에서는 @ManyToMany 를 사용하지 말자
@ManyToMany 는 편리한 것 같지만, 중간 테이블( CATEGORY_ITEM )에 컬럼을 추가할 수 없고, 세밀하게 쿼리
를 실행하기 어렵기 때문에 실무에서 사용하기에는 한계가 있다. 중간 엔티티( CategoryItem 를 만들고 @ManyToOne , @OneToMany 로 매핑해서 사용하자. 정리하면 다대다 매핑을 일대다, 다대일 매핑으로 풀어내
서 사용하자.


엔티티를 모두 생성한 후 스프링부트어플리케이션을 실행해보자.
H2 콘솔을 확인해 보면

모두 제대로 생성된것을 확인할 수 있다!

profile
복습 복습 복습

0개의 댓글