본문 바로가기

Tips

Spring Data JPA N:N 매핑 참고사항

[N:N 관계]

N:N 테이블의 관계에서는 <중간 객체>를 생성하여 1:N, N:1 관계로 만든다.

<중간 객체>는 양쪽의 객체를 FK로 가지고 있다. 

 

1. N:1 관계 먼저 매핑

N클래스

@ManyToOne : N클래스에서 1클래스 객체를 필드로 작성 = N:1 관계 명시

@JoinColumn(name="1 테이블의 PK 컬럼명")

 

1클래스

@OneToMany (mappedby="N클래스에서 가지고있는 1클래스의 필드명")

N:1 관계에서 1클래스에서 작성하며, N클래스를 List/Set 형태로 필드 선언 후 애너테이션 추가.

 

 

2. N:1 매핑이 종료된 이후, 1쪽에서 N쪽의 정보를 참조할 기능이 필요하다면 1:N 추가하여 양방향 처리.

1클래스

@OneToMany (mapped ="N클래스에서 필드로 선언한 1클래스의 객체명")

N클래스를 List/Set<N클래스명> 형태로 필드 선언

 

 

N:N -> N:1, 1:N 변경 시 -> [결론]

1 클래스 :
@OneToMany(mappedby= "N클래스에 있는 1 클래스의 필드명")
List<N클래스> 변수명 = new ArrayList<>();

N 클래스 : 
@ManyToOne
@JoinColumn(name = "1 테이블의 PK 컬럼명)
1객체 변수명;


[DB속 조인 테이블에 값을 채우는 방법]
1. 엔티티 클래스에 필요한 필드들을 위와 같이 설정
2. 1의 객체를 생성할 때, 해당 1 객체에 필요한 필드 설정 후 DB에 저장.
3. 조인테이블 객체를 생성
4. 생성 후 조인테이블 객체에 1관계의 객체들을 set로 지정
5. 1객체에 조인테이블 객체 추가해주기.
6. 조인테이블 객체를 조인테이블 도메인의 repository를 생성하여 저장하기

    @Transactional
    @PostMapping("/{library-Id}")
    public ResponseEntity postMember(@PathVariable("library-Id")@Positive Long libraryId,
                                     @RequestBody @Valid MemberDto.Post post) throws Exception {

        Member member = mapper.memberDtoPostToMember(post);
        member.setLibraryId(libraryId);
        Member createdMember = memberService.createMember(member);

        LibraryMember libraryMember = new LibraryMember();
        libraryMember.setMember(member);
        libraryMember.setLibrary(libraryService.findLibrary(libraryId));
        member.getLibraryMembers().add(libraryMember);

        libraryMemberRepository.save(libraryMember);

        MemberDto.Response response = mapper.memberToMemberDtoResponse(createdMember);
        response.setUrl(url + response.getMemberId());
        HttpHeaders headers = new HttpHeaders();
        headers.add("Access-Control-Expose-Headers","Authorization");
        return new ResponseEntity(response, headers, HttpStatus.CREATED);
    }

[1:N 관계에서 1객체를 지울 때 주의사항]
1. 1 : N 관계에 있는 객체들 중 1 객체를 삭제할 때는 1객체를 외래키 로써 가지고 있는 N 객체를 지워야함.

1객체 삭제 전 JPQL을 사용하여 1객체의 id를 사용해 N객체를 먼저 지워야 한다.

Ex) Member : MemberBook

        memberBookRepository.deleteByMember_Id(memberId);
        memberService.deleteMember(memberId);

<MemberBookRepository>

    @Transactional
    @Modifying
    @Query("DELETE FROM MemberBook mb WHERE mb.member.id =:memberId")
    void deleteByMember_Id(@Param("memberId") Long memberId);

2. @OneToMany 애너테이션에서 cascade = CascadeType.REMOVE or ALL 을 사용

하지만 N 관계에 있는 객체가 1객체의 애그리거트 루트 (핵심 관계)가 아닐 경우라면 지양해야 한다.
즉, 1관계, N관계 객체가 서로 밀접한 관계가 아니라면,
MemberBook 객체가 Member 객체 없이 존재 할 수 있다면 Cascade 사용하면 안된다.


B-4 : [1:1 관계]

양쪽의 엔티티 클래스 필드에 상대 클래스 객체 선언.

@OneToOne(mappedby="상대클래스 필드에 선언된 본인 클래스명", cascade = CascadeType.PERSIST)

@JoinColumn(name="상대1클래스_테이블의_PK컬럼명)

상대_1클래스_필드

 

'Tips' 카테고리의 다른 글

JUnit Test 코드 TIP  (0) 2023.05.16
Spring Data JPA VS JPQL and QueryDsl  (0) 2023.05.15
Mapstruct @Mapping(target = , source = )  (0) 2023.05.13
Spring Data JPA - 자동 완성 메서드 규칙  (0) 2023.05.12
JPQL 예시  (0) 2023.05.12