본문 바로가기

개발일기/프로젝트 일기

HealthDuo-org.springframework.dao.InvalidDataAccessApiUsageException: org.hibernate.TransientPropertyValueException 오류

 

public void messageSendSave(String messageSendTitle, String receiveMemberId, String messageSendContent, String loginMember, Optional<Member> SendMemberInfo) {
    MessageSend messageSend = new MessageSend(messageSendTitle, messageSendContent, String.valueOf(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))), loginMember, receiveMemberId);
    messageSend.addMessageSendMember(SendMemberInfo.get());
    messageSendRepository.save(messageSend);//Spring JPA save기능 사용
}

해당 메서드를 테스트하기 위해

 

@Test
void  messageSendSave(){
    Member member = new Member("sendId", "123", "남자", "whdlsxo123@naver.com", LocalDate.now(), "010-2323-4343");
    Optional<Member> sendMemberInfo = Optional.of(member);
    serviceMethod.messageSendSave("messageSendTitle", "receiveId","content","loginId",sendMemberInfo);
    Optional<MessageSend> findMessageSend = messageSendRepository.findById(1L);
    assertThat(findMessageSend.get().getMessageSendTitle()).isEqualTo("messageSendTitle");
}

 

이와 같이 코드를 구성했다. 하지만

 

이와 같은 에러가 발생했다.

 

오류 메시지를 읽어보면 이유는 간단하다.

 

@Entity
@Getter @Setter @ToString
@JsonIdentityInfo(generator = ObjectIdGenerators.IntSequenceGenerator.class)
public class Member {
    @Id
    @Column(name = "MEMBER_ID")
    private String memberId;
    private String memberPassword;
    private String memberSex;
    private String memberEmail;
    private LocalDate memberDate;
    private String memberPnumber;

    @OneToMany(mappedBy = "member",cascade = CascadeType.REMOVE,orphanRemoval = true )
    List<Bbs> bbs = new ArrayList<>();

    @OneToMany(mappedBy = "member",cascade = CascadeType.REMOVE,orphanRemoval = true)
    List<Comment> comments = new ArrayList<>();

    @OneToMany(mappedBy = "member",cascade = CascadeType.REMOVE,orphanRemoval = true)
    List<MessageReceive> messageReceive = new ArrayList<>();

    @OneToMany(mappedBy = "member",cascade = CascadeType.REMOVE,orphanRemoval = true)
    List<MessageSend> messageSend = new ArrayList<>();

Member entity

 

@Entity
@Setter
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@JsonIdentityInfo(generator = ObjectIdGenerators.IntSequenceGenerator.class)
public class MessageSend {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "MESSAGE_SEND_NO")
    private Long messageSendNo;  //기본키
    private String messageSendTitle;
    private String messageSendContent;
    private String messageSendDate;
    private String sendMemberId;
    private String receiveMemberId;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "MEMBER_ID")
    private Member member;

MessageSend entity

 

 

@OneToMany(mappedBy = "member",cascade = CascadeType.REMOVE,orphanRemoval = true)
List<MessageSend> messageSend = new ArrayList<>();
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "MEMBER_ID")
private Member member;

연관관계 주인이 messageSend로 정해져 있는

 

member와 messageSend는 1:N 관계이다.

 

하지만

@Test
void  messageSendSave(){
    Member member = new Member("sendId", "123", "남자", "whdlsxo123@naver.com", LocalDate.now(), "010-2323-4343");
    Optional<Member> sendMemberInfo = Optional.of(member);
    serviceMethod.messageSendSave("messageSendTitle", "receiveId","content","loginId",sendMemberInfo);
    Optional<MessageSend> findMessageSend = messageSendRepository.findById(1L);
    assertThat(findMessageSend.get().getMessageSendTitle()).isEqualTo("messageSendTitle");
}

 

이 코드에서 영속성 콘텍스트에 member객체가 없는데 messageSendSave를 저장하려고 하니 너무 당연하게

 

에러가 나는 것이다. 따라서

@Test
void  messageSendSave(){
    Member member = new Member("sendId", "123", "남자", "whdlsxo123@naver.com", LocalDate.now(), "010-2323-4343");
    Optional<Member> sendMemberInfo = Optional.of(member);
    memberRepository.saveMember(member); //앞에 추가
    serviceMethod.messageSendSave("messageSendTitle", "receiveId","content","loginId",sendMemberInfo);
    Optional<MessageSend> findMessageSend = messageSendRepository.findById(1L);
    assertThat(findMessageSend.get().getMessageSendTitle()).isEqualTo("messageSendTitle");
}

 이와 같이 member객체를 영속성 콘텍스트에 저장하고 진행하면

 

 

성공적으로 테스트가 완료된다.

 

테스트 코드를 짜면서

 

public void messageSendSave(String messageSendTitle, String receiveMemberId, String messageSendContent, String loginMember, Optional<Member> SendMemberInfo) {
    MessageSend messageSend = new MessageSend(messageSendTitle, messageSendContent, String.valueOf(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))), loginMember, receiveMemberId);
    messageSend.addMessageSendMember(SendMemberInfo.get());
    messageSendRepository.save(messageSend);//Spring JPA save기능 사용
}

   ↑

이와 같이 messageSendTitle이 파라미터가 있어야 하는 자리에 

 

public void messageSendSave(String receiveMemberId, String receiveMemberId, String messageSendContent, String loginMember, Optional<Member> SendMemberInfo) {
    MessageSend messageSend = new MessageSend(receiveMemberId, messageSendContent, String.valueOf(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))), loginMember, receiveMemberId);
    messageSend.addMessageSendMember(SendMemberInfo.get());
    messageSendRepository.save(messageSend);//Spring JPA save기능 사용
}

 

 ↑

receiveMemberId 파라미터가 전달되는 오류도 발견했다.

 

이 오류 경험으로

 

TDD를 해야하는 이유 4가지 중

 

 

                  1. 개발자가 의도한 대로 로직이 동작하는지 명확하게 알 수 있고, 로직에 대해 보증할 수 있다.
                  2. 사전에 다양한 케이스를 고려해봄으로써 문제가 될 수 있는 잠재적 오류들을 방어할 수 있다.
                  3. 아키텍처와 로직이 깔끔해진다. 
                  4. 이후에 다른 사람이 로직을 수정하게 될 때, 로직의 변경에 대한 영향도가 명확하게 보인다.

 

1번에 해당되는 내용을 직접 경험한 거 같다.

 

추가적으로

 

백기선 님 유튜브 라이브를 보는데 켄트 백의 TTD(테스트 주도 개발)이라는 책을 꼭 보라고 조언해주셨고

 

TDD에 대해 깊은 이해를 하기 위해 책을 읽어야겠다.