개발하는 쿠키
article thumbnail

문제를 발견하게 된 과정

테이블 A, B 가 연관관계 매핑이 돼있고, B가 널인 상태일때,

서비스에서 A, B를 저장하고, flush를 한 후, A를 이용해서 B를 가져오면 널을 가져오게 됩니다. => 문제상황

 

하지만, 만약 B가 널이 아닌 상태에서 A를 이용해 B를 가져오면 널이 아닌 객체를 잘 가져옵니다.

 

@Table
@Entity
@Getter
@Builder
public class A {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
    
    @OneToOne(mappedBy ="A")
    private B b;
}



@Table
@Entity
@Getter
@Builder
public class B {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
    
    @MapsId
    @OneToOne(fetch = FetchType.LAZY, optional = false)
    @JoinColumn(name = "id", nullable = false)
    private A a;
}
// 서비스 코드
@Service
@Transactional
@RequiredArgsConstructor
public class Service {
	
    private ARepository aRepository;
    
    public Test(){
        // A, B 저장
        aRepository.flush();
        
    	A a = aRepository.selectByName(name);
        String name = a.getB().name();
    }
	
}



// 레포지토리 코드
// 여기서 메서드를 통해 가져올 코드는 모두 매핑이 돼있고, 널이 아닌 entity 라고 가정합니다.
@Repository
public class ARepositoryImpl implements ARepositoryCustom {
	...
    @Override
    public A selectByName(String name) {
    	return queryFactory.selectFrom(a)
            .leftJoin(a.B, b)
            .fetchJoin()
            .where(a.name.eq(name))
            .fetch();
    }

}

문제해결을 위해 시도해본 방법들

ChatGPT에 물어봤습니다..

1. 연관관계를 올바르게 설정했는지

2. 영속성 전이를 설정했는지 cascade (연관관계 주인인 엔티티에 cascade옵션을 추가하면 종 엔티티의 저장을 자동으로 처리할 수 있습니다.)

3. 1개의 트랜젝션에서 작업했는지

4. 데이터베이스 제약조건에서 외래 키 제약조건이 설정돼 저장이 안된건 아닌지 

확인해봤습니다.

문제의 원인

A엔티티는 @OneToOne(mappedBy = "A") 어노테이션이 설정되어 있으므로 연관관계의 주인이 아닙니다.

따라서 A, B 객체를 저장할 때 B와의 연관관계를 설정해야 합니다.

@Service
@Transactional
@RequiredArgsConstructor
public class Service {
    
    private ARepository aRepository;
    private BRepository bRepository;
    
    public Test(){
        A a = A.builder()
                .name("A")
                .build();
        
        B b = B.builder()
                .name("B")
                .a(a)
                .build();
        
        a.setB(b); // A와 B의 양방향 연관관계 설정
        
        bRepository.save(b);
        aRepository.save(a);
        aRepository.flush();
        
        String name = a.getB().getName();
    }
}

문제를 해결한 방법

저장 로직을 바꿔서 flush()를 사용하지 않는 방법으로 수정했습니다.

반응형
profile

개발하는 쿠키

@COOKIE_

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