스프링부트 공부기록(26) - 영화 리뷰 프로젝트 :: 다대다 관계 설계
my code archive
article thumbnail
반응형

💡구현 목표

  • 영화(Movie)와 회원(Member)이 있고 회원이 영화에 대한 리뷰(Review)를 기록하는 시나리오를 기반으로 프로젝트를 구성함.
  • 한 편의 영화는 여러 회원의 평가가 행해질 수 있다.
  • 한 명의 회원은 여러 영화에 대해 평점을 줄 수 있다.

💡다대다 관계의 특징

다대다 관계(M:N)는 논리적 설계와 실제 테이블 설계가 다르게 됨.

  • 영화 엔티티와 회원 엔티티는 양쪽 모두 독립적인 엔티티로 설계가 가능함.(대부분 명사인 경우)
  • 사람에 해당하는 회원 입장에서는 여러 편의 영화를 평가한다는 구조가 됨.
  • 영화 입장에서는 한 편의 영화는 여러 회원이 존재한다는 관계가 성립하게 됨.

다대다(M:N)를 해결하기 위해서는 실제 테이블 설계에 매핑(mapping) 테이블을 사용함. (=연결 테이블)

  • 여기에서는 리뷰 테이블을 중간에 추가하기로 함.

매핑 테이블의 특징은

  • 매핑 테이블의 작성 이전에 다른 테이블들이 먼저 존재해야함.
  • 매핑 테이블은 주로 '명사'가 아닌 '동사', '히스토리'에 대한 데이터를 보관하는 용도.
  • 매핑 테이블은 중간에서 양쪽 PK를 참조하는 형태로 사용됨.

결론 : JPA에서 다대다(M:N)을 처리하는 방식 중 별도 엔티티를 설계하고 @ManyToOne을 이용해서 처리하는 방식으로 구현할 예정.

 


🤍영화 리뷰 프로젝트

1. 엔티티 클래스 설계

 

  • 매핑 테이블은 주로 동사나 히스토리를 의미 -> 여기에서는 '회원이 영화에 대해 평점을 준다'는 행위로 매핑 테이블이 필요함.
  • 회원(Member)이라는 주어와 영화(Movie)라는 목적어가 있지만 이에 대한 '평점을 준다'는 부분이 없기 때문에 연결 매핑 테이블로 리뷰(Review) 테이블을 설계함.
  • Review 엔티티는 @ManyToOne을 이용해서 양쪽을 참조하는 구조가 됨.

 

2. 완성된 테이블 ERD

 

3. 각각 Repository를 생성 후 더미 데이터를 넣는 작업

 

  • MemberRepository
public interface MemberRepository extends JpaRepository<Member, Long> {
}
@Test
    public void insertMembers(){
        IntStream.rangeClosed(1,100).forEach(i->{
            Member member = Member.builder()
                    .email("r"+i+"@zerock.org")
                    .pw("1111")
                    .nickname("reviewer"+i).build();
            memberRepository.save(member);
        });
    }

총 100명의 회원을 추가함.

  • MovieImageRepository, MovieRepository
public interface MovieImageRepository extends JpaRepository<MovieImage,Long> {
}
public interface MovieRepository extends JpaRepository<Movie, Long> {
}
//영화 및 영화 이미지를 추가하는 테스트
    @Commit
    @Transactional
    @Test
    public void insertMovies(){
        IntStream.rangeClosed(1,100).forEach(i->{
            Movie movie = Movie.builder().title("Movie..."+i).build();
            System.out.println("-----------------------------------");
            movieRepository.save(movie);
            int count = (int) (Math.random()*5)+1;  //1,2,3,4
            for (int j=0;j<count;j++){
                MovieImage movieImage = MovieImage.builder().uuid(UUID.randomUUID().toString())
                        .movie(movie)
                        .imgName("test"+j+".jpg").build();
                imageRepository.save(movieImage);
                System.out.println("=================================");
            }
        });
    }

 

  • 영화와 영화 이미지는 같은 시점에 insert처리가 되어야하므로 Movie 객체를 우선 save해줌.
  • save 실행 이후 Movie 객체는 PK에 해당하는 mno값이 할당되므로 이를 이용해서 영화 이미지를 추가함.

  • ReviewRepository
public interface ReviewRepository extends JpaRepository<Review,Long> {
}
 @Test
    public void insertMoviewReviews(){
        //200개의 리뷰 등록
        IntStream.rangeClosed(1,200).forEach(i->{
            //영화 번호
            Long mno = (long)(Math.random()*100)+1;
            //리뷰어 번호
            Long mid = ((long)(Math.random()*100)+1);
            Member member = Member.builder().mid(mid).build();

            Review movieReview = Review.builder()
                    .member(member)
                    .movie(Movie.builder().mno(mno).build())
                    .grade((int) (Math.random()*5)+1)
                    .text("이 영화에 대한 느낌..."+i)
                    .build();

            reviewRepository.save(movieReview);
        });
    }
  • 200개의 리뷰를 저장함.
  • 영화 번호와 회원은 임의의 값으로 DB에 존재하는 값으로 생성해서 처리, 영화 평점과 리뷰의 내용을 작성해서 MovieReview 객체를 생성해서 저장함.
  • 임의로 만들어졌기 때문에 중간에 리뷰가 없는 영화도 있음.

반응형
profile

my code archive

@얼레벌레 개발자👩‍💻

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!

반응형