@PostMapping("items/{itemId}/edit")
public String updateItem(@ModelAttribute("form") BookForm form) {
Book book = new Book();
book.setId(form.getId());
book.setName(form.getName());
book.setPrice(form.getPrice()); book.setStockQuantity(form.getStockQuantity());
book.setAuthor(form.getAuthor());
book.setIsbn(form.getIsbn());
itemService.saveItem(book);
return "redirect:/items";
}
위의 코드에서 Book은 itemService.saveItem 하기 전까지는 JPA에서 관리하지 않는다. 내가 만들고 내가 쓰고있을 뿐이지 아무리 코드를 추가해도 db에 올라갈 일이 없다.
이러한 엔티티들을 준영속 엔티티라 부른다. 이를 관리하는 방법은 크게 두가지가 있다.
@Transactional
public void updateItem(Long itemId, Book Param) {
Item findItem = itemRepository.findOne(itemId);
findItem.setPrice(Param.getPrice());
findItem.setStockQuantity(findItem.getPrice());
findItem.setName(findItem.getName());
}
이러한 코드를 ItemService에 추가한다. 이때 findOne으로 찾은 findItem은 이미 JPA가 관리하는 영속상태이다. 따라서 변경사항이 생기면 변경감지로 자동적으로 업데이트 된다.
public void save(Item item) {
if (item.getId() == null) {
em.persist(item);
} else {
em.merge(item);
}
}
1. merge() 를 실행한다.
2. 파라미터로 넘어온 준영속 엔티티의 식별자 값으로 1차 캐시에서 엔티티를 조회한다.
2-1. 만약 1차 캐시에 엔티티가 없으면 데이터베이스에서 엔티티를 조회하고, 1차 캐시에 저장한다.
3. 조회한 영속 엔티티( mergeMember )에 member 엔티티의 값을 채워 넣는다. (member 엔티티의 모든 값
을 mergeMember에 밀어 넣는다. 이때 mergeMember의 “회원1”이라는 이름이 “회원명변경”으로 바
뀐다.)
4. 영속 상태인 mergeMember를 반환한다.
실제로는 이러한 코드가 실행되는것이다.
@Transactional
public Item updateItem(Long itemId, Book Param) {
Item findItem = itemRepository.findOne(itemId);
findItem.setPrice(Param.getPrice());
findItem.setStockQuantity(findItem.getPrice());
findItem.setName(findItem.getName());
return findItem;
}
실무에서는 merge를 깔끔하게 사용할 수 있는 상황이 잘 안나온다. 따라서 merge 보다는 변경감지로 하나씩 해주는게 안전한다.
@PostMapping("items/{itemId}/edit")
public String updateItem(@PathVariable("itemId") long itemId, @ModelAttribute("form") BookForm form) {
itemService.updateItem(itemId, form.getName(), form.getPrice(), form.getStockQuantity());
return "redirect:/items";
}
@Transactional
public void updateItem(Long itemId, String name, int price, int stockQuantity) {
Item findItem = itemRepository.findOne(itemId);
findItem.setPrice(price);
findItem.setStockQuantity(stockQuantity);
findItem.setName(name);
}
Entity를 직접 만들기보단, 트랜잭션이 있는 서비스 계층에서 영속 상태의 엔티티를 조회하고, 엔티티의 데이터를 직접 변경하는게 더 좋은 방식이다.
만약 바꿀 param이 많다면, DTO를 만들어서 사용하는것도 방법이다.