보통 처음에는 테이블과 Entity를 똑같이 설계한다. 이렇게 됐을 때의 문제점이 무엇일지 살펴보자.
@Entity
// 인덱스나 length 같은 칼럼 제약 조건은 매핑 애너테이션을 이용해
// 코드에 표시해주는게 좋다. DB를 까보지 않고도 알 수 있기 때문이다.
// 예를 들어 JPQL 짤 때 인덱스가 필요하면 코드만 보고 사용할 수 있다.
public class Member {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "member_id")
private Long id;
private String name;
private String city;
private String street;
private String zipcode;
}
@Entity
// DB에 order가 예약어로 걸려있어서 테이블명을 따로 지정해준다.
@Table(name = "ORDERS")
public class Order {
@Id
@GeneratedValue
@Column(name = "order_id")
private Long id;
// 누가 주문했는지 알기 위한 용도
@Column(name = "member_id")
private Long memberId;
private LocalDateTime orderDate;
// enum은 꼭 STRING으로 해준다.
@Enumerated(EnumType.STRING)
private OrderStatus status;
}
@Entity
public class OrderItem {
@Id
@GeneratedValue
@Column(name = "order_item_id")
private Long id;
@Column(name = "order_id")
private Long orderId;
@Column(name = "item_id")
private Long itemId;
@Enumerated(EnumType.STRING)
private OrderStatus status;
}
@Entity
public class Item {
@Id
@GeneratedValue
@Column(name = "item_id")
private Long id;
private String name;
private int price;
private int stockQuantity;
}
public class JpaMain {
public static void main(String[] args) {
EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("hello");
EntityManager em = entityManagerFactory.createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();
try {
Order order = em.find(Order.class, 1L);
Long memberId = order.getMemberId();
Member member = em.find(Member.class, memberId);
tx.commit();
} catch (Exception e) {
tx.rollback();
} finally {
em.close();
}
entityManagerFactory.close();
}
}
JpaMain에서는 주문한 회원을 찾기 위해
order 조회 후
거기서 memberId를 찾아
다시 member를 조회해야 하는 번거로움이 있다.
객체는 참조로 쭉쭉 찾아가야 하는데 식별자를 통해서 해야 하면 끊겨버린다. 뭔가 객체지향스럽지 않다. 이런 설계는 관계형 DB에 객체를 맞춘 것이다.