도메인 분석 설계
//Member
@OneToMany(mappedBy = "member")//mappedBy 연관관계주인 아님
private List<Order> orders = new ArrayList<>();
//Order
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "member_id")
private Member member; //주문 회원
//==연관관계 메서드==//
public void setMember(Member member) {
this.member = member;
member.getOrders().add(this);
}
public void addOrderItem(OrderItem orderItem) {
orderItems.add(orderItem);
orderItem.setOrder(this);
}
public void setDelivery(Delivery delivery) {
this.delivery = delivery;
delivery.setOrder(this);
}
//abstract class Item
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "dtype")
//Book extends Item
@DiscriminatorValue("B")
//Category
@ManyToMany
@JoinTable(name = "category_item",
joinColumns = @JoinColumn(name = "category_id"),
inverseJoinColumns = @JoinColumn(name = "item_id"))
private List<Item> items = new ArrayList<>();
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "parent_id")
private Category parent;
@OneToMany(mappedBy = "parent")
private List<Category> child = new ArrayList<>();
//==연관관계 메서드==//
public void addChildCategory(Category child) {
this.child.add(child);
child.setParent(this);
}
//Address
@Embeddable
protected Address() {} //값 타입은 변경 불가능하게 설계
public Address(String city, String street, String zipcode)
- 엔티티 설계시 주의점
- Setter 사용하지 x
- @XToOne 지연로딩으로 설정: N+1 문제
- 컬렉션은 필드에서 초기화 : null 문제, 영속화->내장 컬렉션으로 변경
- //private List
orders = new ArrayList<>();
- 테이블, 컬럼명 생성 전략
- 논리명(_): spring.jpa.hibernate.naming.implicit-strategy
- 물리명(필드명): spring.jpa.hibernate.naming.physical-strategy
회원 도메인 개발
//Repository
@PersistenceContext
private EntityManager em;
//Service
@Transactional(readOnly = true) //공통
//MemberService
@Transactional //변경
join-> validateDuplicateMember-> findByName-> isEmpty
-> save / IllegalStateException-> Id반환 //회원명 컬럼에 유니크
상품 도메인 개발
//Item
public void addStock(int quantity) {
this.stockQuantity += quantity;
}
public void removeStock(int quantity) {
int restStock = this.stockQuantity - quantity;
if (restStock < 0) {
throw new NotEnoughStockException("need more stock");
}
this.stockQuantity = restStock;
}
// NotEnoughStockException extends RuntimeException
주문 도메인 개발
//Order
//생성메서드
createOrder(Member member, Delivery delivery, OrderItem... orderItems)
//주문 취소
cancel(): COMP?->IllegalStateException/ CANCEL, orderItem.cancel()
//전체 주문 가격 조회
getTotalPrice(): totalPrice += orderItem.getTotalPrice();
//OrderItem
//생성메서드
createOrderItem(Item item, int orderPrice, intcount): set->item.removeStock(count);
//주문 취소
cancel(): getItem().addStock(count);
//주문상품 전체 가격 조회
getTotalPrice(): getOrderPrice() * getCount();
//OrderService
//주문
order(Long memberId, Long itemId, int count):
엔티티 조회->배송정보 생성->주문상품 생성(OrderItem.createOrderItem)
->주문 생성(Order.createOrder)->주문 저장
// 주문 취소
cancelOrder(Long orderId){
//주문 엔티티 조회
Order order = orderRepository.findOne(orderId);
//주문 취소
order.cancel();
}
검색
//OrderSearch: memberName, orderStatus //OrderRepository List<Order> findAll(OrderSearch orderSearch) : JPQL / JPA Criteria / **Querydsl** 동적쿼리
웹 계층 개발
상품수정: 준영속상태(영속성 컨텍스트가 더는 관리하지 않는 엔티티) 변경감지x
변경 감지 기능 / 병합(merge)
@PostMapping(value = "/items/{itemId}/edit") public String updateItem(@ModelAttribute("form") BookForm form){ //준영속상태 Book book = new Book(); ~~~set~~~ itemService.saveItem(book); //권장 코드 itemService.updateItem(form.getId(), form.getName(), form.getPrice()); } //변경 감지: 영속성 컨텍스트에서 엔티티를 다시 조회 Item findItem = em.find(Item.class, itemParam.getId()); Item item = itemRepository.findOne(id);-> set 더티체킹o //병합: 준영속 상태의 엔티티를 영속 상태로 변경(위험) Item mergeItem = em.merge(item);
상품 주문
//OrderController //주문 @PostMapping(value = "/order") public String order(@RequestParam("memberId") Long memberId, @RequestParam("itemId") Long itemId, @RequestParam("count") int count) { orderService.order(memberId, itemId, count); return "redirect:/orders"; } //검색 orderList(@ModelAttribute("orderSearch") OrderSearch orderSearch, Model model)
쿼리 파라미터 로그 남기기
implementation 'com.github.gavlyukovskiy:p6spy-spring-boot-starter:1.5.6'