참고 : 인프런 [ 실전! 스프링 부트와 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;
자신이 연관관계의 주인이 아닌 것을 표시하는 설정
연관관계 주인이 아닌 클래스의 매핑관계 어노테이션에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<>();
}
셀프 양방향 연관관계의 경우 다른 엔티티에 적용한 것처럼 해주면 된다.
참고: 실무에서는
@ManyToMany를 사용하지 말자
@ManyToMany는 편리한 것 같지만, 중간 테이블(CATEGORY_ITEM)에 컬럼을 추가할 수 없고, 세밀하게 쿼리
를 실행하기 어렵기 때문에 실무에서 사용하기에는 한계가 있다. 중간 엔티티(CategoryItem를 만들고@ManyToOne,@OneToMany로 매핑해서 사용하자. 정리하면 다대다 매핑을 일대다, 다대일 매핑으로 풀어내
서 사용하자.
엔티티를 모두 생성한 후 스프링부트어플리케이션을 실행해보자.
H2 콘솔을 확인해 보면

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