Item 카테고리별 분류
목표
아이템 별로 카테고리를 가지며, 상품 주문시에 카테고리를 선택하면, 그 카테고리에 해당하는 아이템들만 목록에 나타난다.
Category
Category 기능을 구현하기 위한 코드를 작성했다.
@Entity
@Getter @Setter
public class Category {
@Id @GeneratedValue
@Column(name = "category_id")
private Long id;
private String name;
@OneToMany(mappedBy = "category")
private List<Item> items = new ArrayList<>();
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "parent_id")
private Category parent;
@OneToMany(mappedBy = "parent",cascade = CascadeType.ALL)
private List<Category> child = new ArrayList<>();
public void addChild(Category category){
this.child.add(category);
category.setParent(this);
}
protected Category(){
}
public Category(String name) {
this.name = name;
}
public Category(String name,Category categoryParent) {
this.name = name;
this.parent = categoryParent;
}
}
설명
다른 방법이 떠오르지 않았기 때문에 Category 엔티티를 새로 생성했다.
코드의 복잡성을 줄이기 위해 하나의 아이템은 하나의 카테고리를 가진다고 가정했다.
@ManyToOne
@JoinColumn(name = "category_id")
private Category category;
Item 객체와 양방향 맵핑을 설정했다.
FetchType.LAZY
FetchType에는 EAGER 즉시로딩, LAZY 지연로딩이 있는데, 지연로딩을 사용해야만 한다.
즉시로딩의 경우는 엔티티를 조회할 때 관련된 엔티티를 모두 조회한다.
따라서 필요없는 엔티티도 모두 데이터 베이스에서 불러오는데, 이게 심각한 성능저하를 초래한다.
각 연관관계의 default 속성은 다음과 같다.
@OneToMany: LAZY
@ManyToOne: EAGER
@ManyToMany: LAZY
@OneToOne: EAGER
default가 EAGER인 연관관계는 꼭 LAZY로 설정해야 한다.
CascadeType.ALL
CascadeType.ALL 이 붙은 속성은 해당 엔티티와 라이프 사이클을 함께하게 된다. 생성과 소멸을 엔티티와 함께 하기 때문에 라이프 사이클이 같은 경우에만 사용해야 한다.
-
addChild Method - 생성자 편의 메소드
양방향 매핑에서 FK가 있는 쪽이 아닌 곳에서 값을 설정했을 때도 다른 쪽의 값을 수정하기 위한 편의 메소드이다.
만약 그냥 Child.add로 child 를 추가하면 Parent Category 에 Child를 추가해도 Child Category 에는 Parent 가 설정되지 않는데 , 이 메소드를 통해 설정하게 되면 양쪽 모두 값이 설정된다. -
Category() 생성자
- 오버로딩
name만 추가하는 생성자, name과 parent 를 요구하는 생성자로 매개변수를 다르게 하여 오버로딩을 써봤다.
- protected
이 기본 생성자는 Category 를 이름 없이 생성하는 것을 방지하면서, jpa에서는 기본생성자를 이용할 수 있게 해준다. jpa는 protected까진 접근 가능하기 때문이다.
Category Repository
@Repository
@Transactional
public class CategoryRepository {
@PersistenceContext
private EntityManager em;
public void save(Category category){
em.persist(category);
}
public Category findOne(Long id){
return em.find(Category.class,id);
}
public List<Category> findChildCategory(){
return em.createQuery("select c from Category c where c.parent is not null", Category.class)
.getResultList();
}
}
설명
findChildCategory()
일단은
Man
top,trouser,shoe
Women
top,trouser,shoe
이렇게 두 단계로만 구성할 생각이라 createQuery문에서 parent 속성이 null이 아닌 경우에만 찾아오도록 쿼리를 작성하였다.
JPQL이기 때문에 c.parent와 같이 객체대상으로 쿼리를 작성할 수 있다.
프론트(View)
프론트는 수업에서 thymleaf 템플릿 엔진을 이용해서 제작했는데, 내 생각대로 처음부터 구현할 수 있을 정도로 thymeleaf를 공부하는 건 당장은 힘들 것 같았다.
그래서 기존에 진행했던 코드를 수정하고 추가해가면서 View 를 구성할 것이다.
Order에서 사용했던 view 코드를 가져와서 Category 선택 창을 만들었다.
@GetMapping("/items/new")
public String createItem(Model model) {
model.addAttribute("form",new ItemForm());
List<Category> categories = categoryRepository.findChildCategory();
model.addAttribute("categories", categories);
return "items/newItem";
}
model 에 child Category 만 담어서 view에 넘겨준다.
실제 화면
- 코드
<div th:replace="fragments/bodyHeader :: bodyHeader"/>
<form th:action="@{/items/new}" th:object="${form}" method="post">
<div class="form-group">
<label for="category">카테고리</label>
<select name="categoryId" id="category" class="form-control">
<option value="">카테고리선택</option>
<option th:each="category : ${categories}"
th:value="${category.id}"
th:text="${category.name}" />
</select>
</div>
Author And Source
이 문제에 관하여(Item 카테고리별 분류), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@bins1225/21.10.20저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)