@Entity // (name = "USERS) 이름 설정 가능 // 기본값 = 클래스 이름
@Table // (name = "USERS) 이름 설정 가능 // 사용하지 않으면 기본값 = 클래스 이름
@NoArgsConstructor // 기본 생성자 필수 // 없는 경우 에러 발생 가능
@Getter
public class Member { // 테이블 매핑
@Id
private Long memberId;
public Member(Long memberId) {
this.memberId = memberId;
}
}
@NoArgsConstructor
@Getter
@Entity
public class Member {
@Id
private Long memberId;
public Member(Long memberId) {
this.memberId = memberId;
}
}
@Configuration
public class JpaIdDirectMappingConfig {
private EntityManager em;
private EntityTransaction tx;
@Bean
public CommandLineRunner testJpaSingleMappingRunner(EntityManagerFactory emFactory){
this.em = emFactory.createEntityManager();
this.tx = em.getTransaction();
return args -> {
tx.begin();
em.persist(new Member(1L));
tx.commit();
Member member = em.find(Member.class, 1L);
System.out.println("# memberId: " + member.getMemberId());
};
}
}
Hibernate: drop table if exists member CASCADE
Hibernate: create table member (member_id bigint not null, primary key (member_id))
Hibernate: insert into member (member_id) values (?)
# memberId = 1
@NoArgsConstructor
@Getter
@Entity
public class Member {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long memberId;
public Member(Long memberId) {
this.memberId = memberId;
}
}
@Configuration
public class JpaIdIdentityMappingConfig {
private EntityManager em;
private EntityTransaction tx;
@Bean
public CommandLineRunner testJpaSingleMappingRunner(EntityManagerFactory emFactory){
this.em = emFactory.createEntityManager();
this.tx = em.getTransaction();
return args -> {
tx.begin();
em.persist(new Member());
tx.commit();
Member member = em.find(Member.class, 1L);
System.out.println("# memberId: " + member.getMemberId());
};
}
}
Hibernate: drop table if exists member CASCADE
Hibernate: create table member (member_id bigint generated by default as identity, primary key (member_id))
Hibernate: insert into member (member_id) values (default)
# memberId = 1
@NoArgsConstructor
@Getter
@Entity
public class Member {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long memberId;
public Member(Long memberId) {
this.memberId = memberId;
}
}
@Configuration
public class JpaIdIdSequenceMappingConfig {
private EntityManager em;
private EntityTransaction tx;
@Bean
public CommandLineRunner testJpaSingleMappingRunner(EntityManagerFactory emFactory){
this.em = emFactory.createEntityManager();
this.tx = em.getTransaction();
return args -> {
tx.begin();
em.persist(new Member());
Member member = em.find(Member.class, 1L);
System.out.println("# memberId: " + member.getMemberId());
tx.commit();
};
}
}
Hibernate: drop table if exists member CASCADE
Hibernate: drop sequence if exists hibernate_sequence
// 시퀀스 생성
Hibernate: create sequence hibernate_sequence start with 1 increment by 1
Hibernate: create table member (member_id bigint not null, primary key (member_id))
// 시퀀스 값을 조회
Hibernate: call next value for hibernate_sequence
# memberId = 1
Hibernate: insert into member (member_id) values (?)
@NoArgsConstructor
@Getter
@Setter
@Entity
public class Member {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long memberId;
@Column(nullable = false, updatable = false, unique = true) // (1-1)
private String email;
@Column(length = 100, nullable = false) // (1-2)
private String name;
@Column(length = 13, nullable = false, unique = true)
private String phone;
@Column(nullable = false)
private LocalDateTime createdAt = LocalDateTime.now(); // (2)
@Column(nullable = false, name = "LAST_MODIFIED_AT") // (1-3)
private LocalDateTime modifiedAt = LocalDateTime.now();
@Transient // (3)
private String age;
public Member(String email) {
this.email = email;
}
public Member(String email, String name, String phone) {
this.email = email;
this.name = name;
this.phone = phone;
}
}
@NoArgsConstructor
@Getter
@Setter
@Entity(name = "ORDERS")
public class Order {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long orderId;
// (1)
@Enumerated(EnumType.STRING)
private OrderStatus orderStatus = OrderStatus.ORDER_REQUEST;
@Column(nullable = false)
private LocalDateTime createdAt = LocalDateTime.now();
@Column(nullable = false, name = "LAST_MODIFIED_AT")
private LocalDateTime modifiedAt = LocalDateTime.now();
public enum OrderStatus {
ORDER_REQUEST(1, "주문 요청"),
ORDER_CONFIRM(2, "주문 확정"),
ORDER_COMPLETE(3, "주문 완료"),
ORDER_CANCEL(4, "주문 취소");
@Getter
private int stepNumber;
@Getter
private String stepDescription;
OrderStatus(int stepNumber, String stepDescription) {
this.stepNumber = stepNumber;
this.stepDescription = stepDescription;
}
}
}
예시의 Member 클래스 기준
1에 해당하는 클래스가 N에 해당하는 객체를 참조할 수 있는 관계
1에 해당하는 클래스엔 N에 해당하는 객체 정보가 있지만 N에 해당하는 객체는 1 객체의 정보가 없음
1:N 관계 중 N에 해당하는 테이블에서 1에 해당하는 테이블의 기본키를 외래키로 가져 1:N 단방향 연관 관계로 테이블 간의 관계를 정상적으로 표현 불가능
예시의 Order 클래스 기준
N에 해당하는 클래스가 1에 해당하는 객체를 참조할 수 있는 관계
ORDERS 테이블이 MEMBER 테이블의 member_id를 외래키로 가지듯이 Order 클래스가 Member 클래스 참조
@NoArgsConstructor
@Getter
@Setter
@Entity(name = "ORDERS")
public class Order {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long orderId;
@Enumerated(EnumType.STRING)
private OrderStatus orderStatus = OrderStatus.ORDER_REQUEST;
@Column(nullable = false)
private LocalDateTime createdAt = LocalDateTime.now();
@Column(nullable = false, name = "LAST_MODIFIED_AT")
private LocalDateTime modifiedAt = LocalDateTime.now();
@ManyToOne // (1)
@JoinColumn(name = "MEMBER_ID") // (2)
private Member member;
public void addMember(Member member) {
this.member = member;
}
public enum OrderStatus {
ORDER_REQUEST(1, "주문 요청"),
ORDER_CONFIRM(2, "주문 확정"),
ORDER_COMPLETE(3, "주문 완료"),
ORDER_CANCEL(4, "주문 취소");
@Getter
private int stepNumber;
@Getter
private String stepDescription;
OrderStatus(int stepNumber, String stepDescription) {
this.stepNumber = stepNumber;
this.stepDescription = stepDescription;
}
}
}
@NoArgsConstructor
@Getter
@Setter
@Entity
public class Member {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long memberId;
@Column(nullable = false, updatable = false, unique = true)
private String email;
@Column(length = 100, nullable = false)
private String name;
@Column(length = 13, nullable = false, unique = true)
private String phone;
@Column(nullable = false)
private LocalDateTime createdAt = LocalDateTime.now();
@Column(nullable = false, name = "LAST_MODIFIED_AT")
private LocalDateTime modifiedAt = LocalDateTime.now();
// (1)
@OneToMany(mappedBy = "member")
private List<Order> orders = new ArrayList<>();
public Member(String email) {
this.email = email;
}
public Member(String email, String name, String phone) {
this.email = email;
this.name = name;
this.phone = phone;
}
public void addOrder(Order order) {
orders.add(order);
}
}
1:N 단방향 매핑의 경우 mappedBy가 필요 없음
mappedBy의 값은 관계를 소유하고 있는 필드를 지정
객체 그래프 탐색 : 객체를 통해 다른 객체의 정보를 얻을 수 있는 것
@NoArgsConstructor
@Getter
@Setter
@Entity(name = "ORDERS_COFFEE")
public class OrderCoffee {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long orderCoffeeId;
// N:1 관계 추가
@ManyToOne
@JoinColumn(name = "ORDER_ID")
private Order order;
@ManyToOne
@JoinColumn(name = "COFFEE_ID")
private Coffee coffee;
@Column(nullable = false)
private int quantity;
public void addCoffee(Coffee coffee) {
this.coffee = coffee;
}
public void addOrder(Order order) {
this.order = order;
}
}
// 1:N 관계 추가
@OneToMany(mappedBy = "order")
private List<OrderCoffee> orderCoffees = new ArrayList<>();
public void addOrderCoffee(OrderCoffee orderCoffee) {
orderCoffees.add(orderCoffee);
}
// 1:N 관계 추가
@OneToMany(mappedBy = "coffee")
private List<OrderCoffee> orderCoffees = new ArrayList<>();
public void addOrderCoffee(OrderCoffee orderCoffee) {
orderCoffees.add(orderCoffee);
}
@OneToOne 애너테이션을 사용하며 N:1 관계 매핑과 방법은 동일
Member 클래스와 1:1 매핑한 Stamp 클래스
@NoArgsConstructor
@Getter
@Setter
@Entity
public class Stamp {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long stampId;
@Column(nullable = false)
private int stampCount;
@Column(nullable = false)
private LocalDateTime createdAt = LocalDateTime.now();
@Column(nullable = false)
private LocalDateTime modifiedAt = LocalDateTime.now();
@OneToOne
@JoinColumn(name = "MEMBER_ID")
private Member member;
public void addMember(Member member) {
this.member = member;
}
}
// 1:1 관계 매핑
@OneToOne(mappedBy = "member")
private Stamp stamp;
public void addStamp(Stamp stamp) {
this.stamp = stamp;
}