springboot.ver2

정재호·2024년 9월 24일

연관관계가 맺어질때 연관관계의 주인
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)

  • 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();


  • REST API를 만들때 순환참조 문제 해결
    이래서 무한루프 상호참조 순환참조
    @JsonIgnore // 순환참조를 해결합니다. rest 만들떄
    여러개면 1개만 만든다.





일반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;
  }

}

레스트 서버 탑재

profile
성장하는 하루가 되자

0개의 댓글