@Entity
@Getter @Builder
@NoArgsConstructor
@AllArgsConstructor
@Table(name = "mentors")
public class Mentor {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@OneToOne
private User user;
private String majorCareer;
@OneToMany(mappedBy = "mentor", fetch = FetchType.LAZY, orphanRemoval = true)
private List<MentorMentoringField> mentoringFields;
private String introduction;
private String company;
private String department;
private String profilePicture;
}
➡️ OneToOne은 잘 사용하지 않는다고 했지만, 우리는 로그인한 유저 아이디하나당 1개의 mentor지원이 가능하기 때문에 OneToOne을 사용했다.
➡️ 처음 계획할 때는 MentoringField를 그냥 string으로 만들어줬는데 코드를 짜고 실제 운영될 서비스를 생각해 보니 멘토와 멘토링필드는 다대다 관계가 되어야할 것 같아서 중간 테이블을 만들고 연결해주었다.
➡️ jpa 연관관계 삭제 : orphanRemoval = true를 붙여주면 된다.
멘토에게 멘토링필드를 넣다가 기존에 넣었던 필드를 지우고 다른 필드를 넣고 싶어졌다.
그런데 여기서 문제가 생겼다.
멘토가 가지고 있는 필드를 지우면 필드 자체가 데이터베이스에서 삭제되기 떄문에 다른 멘토들에서도 이 필드들이 삭제되어버리는 것이다. 그래서 해당 유저의 원하는 필드만을 지우기 위해 'jpa 연관관계 삭제'를 검색해보니 orphanRemoval = true를 붙여주면 된다고 했다. 그래서 orphanRemoval = true를 붙이고 삭제를 해보니 내가 원하는대로 잘 삭제되었다.
다른 멘토링필드로 바꾸기 위해 삭제를 할 필요가 생겼다.
@RestController
@RequiredArgsConstructor
@RequestMapping("/api/v1/mentors")
public class MentorController {
private final MentorService mentorService;
private final KakaoService kakaoService;
@PostMapping
public void insert(@RequestBody MentorRequest request,@CookieValue(value = "Token", required = false) Cookie cookie) {
User user = kakaoService.getUserInfo(cookie.getValue());
mentorService.save(request,user);
}
@GetMapping("{id}")
public MentorResponse getById(@PathVariable("id") Long id) {
return mentorService.findById(id);
}
@GetMapping
public List<MentorResponse> getAll() {
List<MentorResponse> all = mentorService.findAll();
return all;
}
@DeleteMapping("{id}")
public void deleteById(@PathVariable("id") Long id) {
mentorService.deleteMentorId(id);
}
@PutMapping("{id}")
public void changeDate(@PathVariable("id") Long id,
@RequestBody MentorRequest request) {
mentorService.changeDate(id, request);
}
//멘토에 필드 저장
@PostMapping("/field")
public void save(@RequestBody ConnectRequest request) {
mentorService.connect(request);
}
// 멘토링 필드를 리스트로 받는 과정에 코드를 수정하여 그에 맞게 수정이 조금 필요함.
@DeleteMapping("{userId}/{mentoringFieldId}")
public void deleteMentoringField(@PathVariable("userId") Long userId,
@PathVariable("mentoringFieldId") Long mentoringFieldId) {
mentorService.mentorFieldDelete(userId, mentoringFieldId);
}
}
@Service
@RequiredArgsConstructor
@Transactional
public class MentorService {
private final MentorRepository mentorRepository;
private final UserRepository userRepository;
private final MentoringFieldRepository fieldRepository;
private final MentorMentoringFieldRepository mentoringFieldRepository;
//멘토 등록
public void save(MentorRequest request,User user) {
Mentor mentor = Mentor.builder()
.user(user)
.majorCareer(request.getMajorCareer())
.mentoringFields(null)
.introduction(request.getIntroduction())
.company(request.getCompany())
.department(request.getDepartment())
.picture(request.getPicture())
.build();
mentorRepository.save(mentor);
}
//id로 찾기
public MentorResponse findById(Long id) {
Optional<Mentor> byId = mentorRepository.findById(id);
MentorResponse mentorResponse = MentorResponse.builder()
.mentorId(byId.get().getId())
.company(byId.get().getCompany())
.department(byId.get().getDepartment())
.majorCareer(byId.get().getMajorCareer())
.picture(byId.get().getPicture())
.username(byId.get().getUser().getUsername())
.introduction(byId.get().getIntroduction())
.mentoringFields(byId.get().getMentoringFields() != null ?
byId.get().getMentoringFields()
.stream()
.map(MentorMentoringField::getMentoringField)
.map(MentoringFieldDto::new)
.toList()
: new ArrayList<>())
.build();
return mentorResponse;
}
//멘토 전체 찾기
public List<MentorResponse> findAll() {
List<Mentor> all = mentorRepository.findAll();
return all.stream().map(m-> new MentorResponse(m)).toList();
}
//멘토 삭제
public void deleteMentorId(Long id) {
mentorRepository.deleteById(id);
}
//멘토 정보 업데이트
public MentorResponse changeDate(Long id, MentorRequest request) {
Optional<Mentor> byId = mentorRepository.findById(id);
if (byId.isEmpty()) throw new RuntimeException("멘토 정보가 없습니다.");
User user = userRepository.findById(id).orElseThrow();
Mentor mentor = new Mentor(id, user, request.getMajorCareer(), null,
request.getIntroduction(), request.getCompany(), request.getDepartment(), request.getPicture());
Mentor save = mentorRepository.save(mentor);
return new MentorResponse(save);
}
//멘토와 멘토링필드 연결
public void connect(ConnectRequest request) {
Mentor mentor = Mentor.builder()
.id(request.getMentorId())
.build();
MentoringField mentoringField = MentoringField.builder()
.id(request.getMentoringFieldId())
.build();
//중복처리
MentorMentoringField mentorMentoringField = mentoringFieldRepository.findByMentorAndMentoringField(mentor, mentoringField)
.orElse(null);
if (mentorMentoringField == null) {
mentorMentoringField = MentorMentoringField.of(mentor, mentoringField);
mentoringFieldRepository.save(mentorMentoringField);
}
}
//유저가 가지고 있는 field 지우기
public void mentorFieldDelete(Long userId, Long mentoringFieldId) {
Mentor mentor = Mentor.builder()
.id(userId)
.build();
MentoringField mentoringField = MentoringField.builder()
.id(mentoringFieldId)
.build();
MentorMentoringField mentorMentoringField = mentoringFieldRepository.findByMentorAndMentoringField(mentor, mentoringField)
.orElse(null);
mentoringFieldRepository.delete(mentorMentoringField);
}
}
@Repository
public interface MentorRepository extends JpaRepository<Mentor, Long> {
}
@Getter
@AllArgsConstructor
@NoArgsConstructor
public class MentorRequest {
private Long userId;
private String majorCareer;
private String introduction;
private String company;
private String department;
private Long mentoringFieldId;
private String profilePicture;
}
@AllArgsConstructor //모든 필드를 인자로 받는 생성자를 생성
@NoArgsConstructor // 파라미터 없는 디폴트 생성자를 생성
@Getter
@Builder
public class MentorResponse {
private Long userId;
private Long mentorId;
private String majorCareer;
private String introduction;
private String company;
private String department;
private String profilePicture;
private String username;
private String phoneNumber;
private String email;
private List<MentoringFieldDto> mentoringFields = new ArrayList<>();
//Mentor 엔티티의 정보를 MentorResponse 객체로 변환
public MentorResponse(Mentor mentor) {
this.userId = mentor.getUser().getId();
this.mentorId = mentor.getId();
this.majorCareer = mentor.getMajorCareer();
this.introduction = mentor.getIntroduction();
this.company = mentor.getCompany();
this.department = mentor.getDepartment();
this.profilePicture = mentor.getProfilePicture();
this.username = mentor.getUser().getUsername();
this.phoneNumber = mentor.getUser().getPhoneNumber();
this.email = mentor.getUser().getEmail();
//연관관계 끊어주기.
//mentoringFields라는 필드를 초기화하는 부분
//Mentor 엔티티에서 가져온 MentoringField 정보를 MentorResponse 객체의 mentoringFields 필드로 설정하는 역할
this.mentoringFields = mentor.getMentoringFields() != null ? //Mentor 엔티티에 연결된 MentoringField들이 존재한다면 이 블록이 실행
mentor.getMentoringFields()
.stream()
.map(MentorMentoringField::getMentoringField)
.map(MentoringFieldDto::new)
.toList() //앞선 연산들을 통해 생성된 MentoringFieldDto 스트림을 리스트로 변환
:new ArrayList<>();
}
}
✅ 연관관계 끊는 방법 이해하기.
'mentor.getMentoringFields().stream()'
➡️ mentoringFields 필드에 연결된 MentoringField 엔티티들을 스트림으로 변환.
이 스트림을 통해 각 MentoringField에 대한 작업을 수행할 수 있게된다.
'.map(MentorMentoringField::getMentoringField)'
➡️ MentoringField 엔티티에 있는 getMentoringField 메서드를 호출하여, 각 MentoringField 엔티티를 MentoringField 객체로 변환.
➡️ 이 메서드 호출에 의해 MentoringField 엔티티의 정보를 가져오는 것
'.map(MentoringFieldDto::new)'
➡️ 앞서 얻은 MentoringField 객체들을 MentoringFieldDto로 변환하는 것이다. 이 때, MentoringFieldDto의 생성자가 호출된다.
'.map(MentoringFieldDto::new)'
➡️ 앞선 연산들을 통해 생성된 MentoringFieldDto 스트림을 리스트로 변환
@Getter
@AllArgsConstructor
@NoArgsConstructor
public class MentorDto {
private Long mentorId;
private String majorCareer;
private String introduction;
private String company;
private String department;
private String profilePicture;
public MentorDto(Mentor mentor) {
this.mentorId = mentor.getId();
this.majorCareer = mentor.getMajorCareer();
this.introduction = mentor.getIntroduction();
this.company = mentor.getCompany();
this.department = mentor.getDepartment();
this.profilePicture = mentor.getProfilePicture();
}
}
크으으 잘 만들었네요 스트림도 쓰고 굿!