연관관계가 맺어질때 연관관계의 주인
mappedBy = "book"
book이 주인이 아니다.
1:N
1 - book
N - reviews
@Service
@Getter
@NoArgsConstructor
@AllArgsConstructor
@Entity
public class Book {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false, unique = true)
private String title;
private int price;
private String author;
private int page;
//@OneToMany : LAZY 기본 fetch = FetchType.LAZY , EAGER는 즉시
// mappedBy 연관관계의 주인이 내가 아니다.
@OneToMany (mappedBy = "book", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private List<Review> reviews;
}


끊어지고 나서 컨트롤로 넘어갑니다.


리뷰는 메모리에 없어서 뿌릴수 없음


뷰 단에서 열려 있어서 가능했지만
n+1 문제가 있을 가능성이라서 바람직하지않다.
open-in view: false 로 변경 가져올수 없어서 에러발생
중간 메모리 공간 프록시 > db접근해야하나 끊겨져 있어서 안됨

방법1.
@OneToMany (mappedBy = "book", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
public List<Book> getAllBooks(){
// Book정보와 Review정보 함께 가져오기 ?
// 1. 서비스 계층에서 reviews를 미리 로드하여,뷰 계층에서LazyInitializationException을 방지
List<Book> books=bookRepository.findAll(); // Book
books.forEach(book-> Hibernate.initialize(book.getReviews()));
return null;
}
하이버네이트가 해줍니다.

여기서 에러가 납니다.
방법2.
// JPQL을 이용해서 패치조인(fetch join)
@Query("select b from Book b LEFT JOIN FETCH b.reviews")
public List<Book> findAllWithReviews();
}
public List<Book> getAllBooks(){
// Book정보와 Review정보 함께 가져오기 ?
// 1. 서비스 계층에서 reviews를 미리 로드하여,뷰 계층에서LazyInitializationException을 방지
//List<Book> books=bookRepository.findAll(); // Book
//books.forEach(book-> Hibernate.initialize(book.getReviews()));
return bookRepository.findAllWithReviews();
}


방법3.
// Entity Graph를 이용
@EntityGraph(attributePaths = {"reviews"})
@Query("select b from Book b")
public List findAllWithReviews();






일반DTO를 만들고 Book꺼를 가져옵니다.

Book은 엔티티지 Table이 아니라 레파지토리에 못넣습니다.
ui.toast.com

별도 DTO를 만들어서 사용합니다.
import java.util.List;
@Service
@RequiredArgsConstructor
public class BookService {
private final BookRepository bookRepository;
// @Transactional(readOnly = true) // 성능상 이점
public List<Book> getAllBooks(){
// Book정보와 Review정보 함께 가져오기 ?
// 1. 서비스 계층에서 reviews를 미리 로드하여,뷰 계층에서LazyInitializationException을 방지
//List<Book> books=bookRepository.findAll(); // Book
//books.forEach(book-> Hibernate.initialize(book.getReviews()));
// JSON으로 바꿀때 합니다. 리턴 되기전에 Book을 DTO 형식으로 바꿉니다. 컨버팅작업을 합니다.
List<Book> books=bookRepository.findAllWithReviews();
// Book <---순환참조--->Review
return null;
}
// Book->BookDTO
private BookDTO convertToDTO(Book book){
return null;
}
// Review->ReviewDTO
}
1번 기초


Array 리스트 만들어서 리턴해라

- REST API를 만들때 순환참조 문제 해결
1. @JsonIgnore
2. JSON 변환시 Entity를 DTO로 변환
@Service
@RequiredArgsConstructor
public class BookService {
private final BookRepository bookRepository;
// @Transactional(readOnly = true) // 성능상 이점
public List<BookDTO> getAllBooks(){
// Book정보와 Review정보 함께 가져오기 ?
// 1. 서비스 계층에서 reviews를 미리 로드하여,뷰 계층에서LazyInitializationException을 방지
//List<Book> books=bookRepository.findAll(); // Book
//books.forEach(book-> Hibernate.initialize(book.getReviews()));
// JSON으로 바꿀때 합니다. 리턴 되기전에 Book을 DTO 형식으로 바꿉니다. 컨버팅작업을 합니다.
List<Book> books=bookRepository.findAllWithReviews();
// Book <---순환참조--->Review
//List<BookDTO> bookDTOS = books.stream().map(this::convertToDTO).collect(Collectors.toList());
//return bookDTOS; DTOS로 받아서 써도 됩니다.
return books.stream().map(this::convertToDTO).collect(Collectors.toList());
}
// Book->BookDTO
private BookDTO convertToDTO(Book book) {
BookDTO bookDTO=new BookDTO();
bookDTO.setId(book.getId()) ;
bookDTO.setTitle(book.getTitle());
bookDTO.setPrice(book.getPrice());
bookDTO.setAuthor(book.getAuthor());
bookDTO.setPage(book.getPage());
// Review->ReviewDTO
List<ReviewDTO> reviews=book.getReviews().stream().map(this::convertToDTO).collect(Collectors.toList());
bookDTO.setReviews(reviews);
return bookDTO;
// 리뷰 컨버팅 2개 있어야합니다.
}
// 리뷰를 담아줍니다.
// Review->ReviewDTO
private ReviewDTO convertToDTO(Review review){
ReviewDTO reviewDTO = new ReviewDTO();
reviewDTO.setId(review.getId());
reviewDTO.setCost(review.getCost());
reviewDTO.setContent(review.getContent());
reviewDTO.setCreatedAt(review. getCreatedAt());
return reviewDTO;
}
}
@Service
@RequiredArgsConstructor
public class BookService {
private final BookRepository bookRepository;
@Transactional(readOnly = true)
public List<Book> getAllBooks () {
return bookRepository.findAllWithReviews();
}
// @Transactional(readOnly = true) // 성능상 이점
public List<BookDTO> getAllBooksDTO(){
// Book정보와 Review정보 함께 가져오기 ?
// 1. 서비스 계층에서 reviews를 미리 로드하여,뷰 계층에서LazyInitializationException을 방지
//List<Book> books=bookRepository.findAll(); // Book
//books.forEach(book-> Hibernate.initialize(book.getReviews()));
// JSON으로 바꿀때 합니다. 리턴 되기전에 Book을 DTO 형식으로 바꿉니다. 컨버팅작업을 합니다.
List<Book> books=bookRepository.findAllWithReviews();
// Book <---순환참조--->Review
//List<BookDTO> bookDTOS = books.stream().map(this::convertToDTO).collect(Collectors.toList());
//return bookDTOS; DTOS로 받아서 써도 됩니다.
return books.stream().map(this::convertToDTO).collect(Collectors.toList());
}
// Book->BookDTO
private BookDTO convertToDTO(Book book) {
BookDTO bookDTO=new BookDTO();
bookDTO.setId(book.getId()) ;
bookDTO.setTitle(book.getTitle());
bookDTO.setPrice(book.getPrice());
bookDTO.setAuthor(book.getAuthor());
bookDTO.setPage(book.getPage());
// Review->ReviewDTO
List<ReviewDTO> reviews=book.getReviews().stream().map(this::convertToDTO).collect(Collectors.toList());
bookDTO.setReviews(reviews);
return bookDTO;
// 리뷰 컨버팅 2개 있어야합니다.
}
// 리뷰를 담아줍니다.
// Review->ReviewDTO
private ReviewDTO convertToDTO(Review review){
ReviewDTO reviewDTO = new ReviewDTO();
reviewDTO.setId(review.getId());
reviewDTO.setCost(review.getCost());
reviewDTO.setContent(review.getContent());
reviewDTO.setCreatedAt(review. getCreatedAt());
return reviewDTO;
}
}
레스트 서버 탑재
