티스토리 뷰

로컬에서 개발을 하다가 DTO의 필드로 Entity를 담아서 반환한 적이 있는데, 그 때 생겼던 오류와 Entity를 DTO 필드로 사용하면 안되는 이유를 정리하려고 합니다.

 

service단에서 ContentDTO를 생성하는 부분이다. contentRepository에서 하나의 content를 찾아서 필요한 필드만 추출하여 ContentDTO를 생성한다. 이 때 해당 content는 영속성 컨텍스트에 등록된다.

처음에 ContentDto의 필드에서 Image 엔티티를 가지도록 작성하고 생성자에서 위와 같이 초기화 해주었다.

 

Image 엔티티는 Content 엔티티와 다대일 연관 관계를 가지고 FetchType.Lazy로 설정되어 있다. 

또 Content 엔티티 내부를 보면 Account 엔티티가 연관 관계로 묶여있고, FetchType.Lazy로 설정되어 있다. 여기까지는  서비스 레이어의 하나의 트랜잭션 내에서 content와 account가 한 번 조회되어 영속성 컨텍스트에 등록되어 있으므로 에러가 발생하지 않는다.

 

하지만 Account 엔티티 내부를 보면 AccountAuthority와 일대다로 연관 관계가 맺어져 있다. OneToMany의 기본적인 fetch전략은 Lazy이므로 Account 엔티티를 조회할 때 proxy만 넘어오게 된다.

 

content와 account의 경우에는 이미 영속성 컨텍스트에 등록되어 있으므로 문제가 없지만 AccountAuthority는 ContentDTO를 초기화 할 때 proxy만 존재한다.

 

Could not write JSON: failed to lazily initialize a collection of role: domain.user.data.entity.Account.accountAuthorities, could not initialize proxy - no Session; domain.user.data.entity.Account.accountAuthorities, could not initialize proxy - no Session; could not initialize proxy - no Session (through reference chain: domain.curation.dto.ContentDto["images"]->java.util.ArrayList[0]->domain.curation.entity.Image["content"]->domain.curation.entity.Content["account"]->domain.user.data.entity.Account["accountAuthorities"])]

 

Account 내부에 AccountAuthority는 lazy loading으로 proxy 객체이다. 이는 ContentDTO를 뿌려주기 위해 JSON으로 직렬화하는 과정에서 AccountAuthority객체에서 Getter로 데이터를 가져와야하는데 proxy만 존재하기 문제가 발생한다.

 

따라서 이를 해결하기 위해

AccountAuthority의 fetch 전략을 Eager로 바꾸어 테스트 해보았다.

 

세 가지 문제점이 보였다.

1. 패스워드와 이메일과 같은 개인정보 및 불필요한 정보가 다 넘어간다.

 

2. 양방향 매핑으로 순환참조가 발생하여 stack overflow가 생겼다.

 

3. AccountAuthority의 fetch 전략을 Eager로 하여 Account 조회시 불필요한 쿼리가 발생할 수 있다.

 

애초에 DTO 필드에 Entity를 사용하지 않으면 세 가지 문제를 모두 해결할 수 있다.

따라서 ImageDTO를 만들고 필요한 필드만 가져와서 넘겨주도록 수정하였다.

'java & spring' 카테고리의 다른 글

[Java/Spring] 예외 처리를 어떻게 할 것인가  (0) 2024.07.24
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday