즉 User 라는 Entity 자체가 날것으로 가져오게 되면, Entity 가 오염이 될 수 도 있다. setter , 도메인 서비스를 통해서든 어떤 일이 벌어질 수 있는 가능성을 열어둔 것이다.
아래 코드 처럼 save 메소드 안에서더티체킹(변경사항 탐지)으로 인해 유저가 갑자기 관리자가 되고, 닉네임이 끝빵왕이 될 수도 있다.
@Transactionalpublic Long save(requestDto dto) {
...
finalUseruser= userRepository.findById(dto.userid);
user.setRole(ROLE.ADMIN); // 관리자로 변경 !
user.updateNickName("끝빵왕"); // 닉네임이 변경 !finalBakerybakery= Bakery.builder()
.title(title)
.address(address)
.user(user)
.build();
return bakeryRepository.save(bakery).getId();
}
따라서 User 에그리거트도 안전하게 보호가 되고, Bakery 에그리거트에만 집중할 수 있는 방법이 필요하고 그 방법이 바로간접 참조를 이용하는 것이다.
결론 부터 이야기 해보자면,
다른 에그리거트와 관계를 맺거나 이용하기 위해선ResponseDto 를 반환하는 application layer 에 있는 서비스 객체를 통해야 하며, 날것의 Entity 클래스 그대로가 아닌 ! ResponseDto 에 있는 다른 루트 에그리거트의 아이디를 참조하는 방식인간접 참조 방식으로 관계를 설정해야 한다.
@Transactionalpublic Long save(requestDto dto) {
finalStringaddress= dto.getAddress();
finalStringtitle= dto.getTitle();
// application layer 에 있는 서비스 객체를 이용finalUserResponseDtouser= userService.findById(dto.userid);
finalBakerybakery= Bakery.builder()
.title(title)
.address(address)
.user(user.getUserId())
.build();
return bakeryRepository.save(bakery).getId();
}
기존에 있었던 @OneToOne 어노테이션과 User 타입을 지우고, Long 타입으로 변경함으로써User의 식별값만 받도록 수정했다. 또한 userid 를 Long 타입으로 매개변수를 받지 않고UserId 를 매개변수로 받음으로써, 다른 이상한 Long 값을 대입하는 실수를 방지할 수 있었다.
이렇게 간접 참조로 에그리거트 간에 관계를 맺으면 User 에그리거트도 안전하게 보호가 되고, Bakery 에그리거트에만 집중할 수 있다.
하지만 간접참조에 대한 문제점이 있는데, 그것은 N+1 Query 이다. 만약에 Bakery 리스트를 뿌려주는데 거기에 User 정보도 같이 보여줘야 한다면, Bakery 마다 User 정보를 호출하는 Query 를 사용하게 된다.
즉 User 라는 Entity 자체가 날것으로 가져오게 되면, Entity 가 오염이 될 수 도 있다. setter , 도메인 서비스를 통해서든 어떤 일이 벌어질 수 있는 가능성을 열어둔 것이다.
아래 코드 처럼 save 메소드 안에서더티체킹(변경사항 탐지)으로 인해 유저가 갑자기 관리자가 되고, 닉네임이 끝빵왕이 될 수도 있다.
@Transactionalpublic Long save(requestDto dto) {
...
finalUseruser= userRepository.findById(dto.userid);
user.setRole(ROLE.ADMIN); // 관리자로 변경 !
user.updateNickName("끝빵왕"); // 닉네임이 변경 !finalBakerybakery= Bakery.builder()
.title(title)
.address(address)
.user(user)
.build();
return bakeryRepository.save(bakery).getId();
}
따라서 User 에그리거트도 안전하게 보호가 되고, Bakery 에그리거트에만 집중할 수 있는 방법이 필요하고 그 방법이 바로간접 참조를 이용하는 것이다.
결론 부터 이야기 해보자면,
다른 에그리거트와 관계를 맺거나 이용하기 위해선ResponseDto 를 반환하는 application layer 에 있는 서비스 객체를 통해야 하며, 날것의 Entity 클래스 그대로가 아닌 ! ResponseDto 에 있는 다른 루트 에그리거트의 아이디를 참조하는 방식인간접 참조 방식으로 관계를 설정해야 한다.
@Transactionalpublic Long save(requestDto dto) {
finalStringaddress= dto.getAddress();
finalStringtitle= dto.getTitle();
// application layer 에 있는 서비스 객체를 이용finalUserResponseDtouser= userService.findById(dto.userid);
finalBakerybakery= Bakery.builder()
.title(title)
.address(address)
.user(user.getUserId())
.build();
return bakeryRepository.save(bakery).getId();
}
기존에 있었던 @OneToOne 어노테이션과 User 타입을 지우고, Long 타입으로 변경함으로써User의 식별값만 받도록 수정했다. 또한 userid 를 Long 타입으로 매개변수를 받지 않고UserId 를 매개변수로 받음으로써, 다른 이상한 Long 값을 대입하는 실수를 방지할 수 있었다.
이렇게 간접 참조로 에그리거트 간에 관계를 맺으면 User 에그리거트도 안전하게 보호가 되고, Bakery 에그리거트에만 집중할 수 있다.
하지만 간접참조에 대한 문제점이 있는데, 그것은 N+1 Query 이다. 만약에 Bakery 리스트를 뿌려주는데 거기에 User 정보도 같이 보여줘야 한다면, Bakery 마다 User 정보를 호출하는 Query 를 사용하게 된다.