Spring #5 user-artist 연관관계

ims·2020년 10월 31일
0

BlueDot-Spring

목록 보기
6/13

테이블 : User - Artist

질문

처음에 상속관계로 접근하려고 했었는데, 상속관계로 맺으려면 아래와 같은 문제가 생긴다.

https://www.inflearn.com/questions/85190
(김영한 강사님께 질문)

질문내용

일단 상태 중 일부를 잘라보면, 위와 같이 database를 설계했습니다.
(그림 - 위 db 사진 참조)

Artist가 User의 상태 전부를 갖고 있으므로 Artist가 User를 상속받게 Entity 설계를 했습니다.

그런데 이와 같이 설계를 하면 Artist는 독립적인 Id가 없습니다. 그래서 artist_id에 직접적으로 접근할 수가 없어서 두가지 문제가 발생합니다.

첫번째로 아티스트를 생성하려면 직접적으로 접근해서 생성하지 못하고, 유저 정보가 생성될 때만 생성할 수 있습니다. 그래서 artist를 생성할 때 현재 다음과 같이 생성되게 로직을 짰습니다.

만약 7번 유저가 이미 등록돼있고, 7번 유저에 대해서 artist 등록을 한다고 가정해보겠습니다. 그러면 아래와 같은 로직을 따라갑니다.

7번 유저를 가져옴 -> builder를 통해서 artist를 생성. 그러면 8번 유저가 생성되고 8번 유저가 artist와 연결됨 -> 7번 유저는 삭제

그런데 위와 같이 로직을 따르는게 최적화에 있어서 좋지 못하다는 생각이 듭니다. 또한 7번 유저 인덱스가 비어서 빈 인덱스가 생겼기 때문에 데이터를 볼때도 좋지 않을 것 같다는 생각이 듭니다.

두번째로 artist_id가 없기 때문에 artist와 다른 테이블을 mapping 시킬 때 까다로운 부분이 있습니다. 그래서 artist_id를 따로 만들어야 하나 생각이 들다가도 로직상으로 맞지 않는 것 같기도 합니다.

대충 Artist에 id값이 없어서 까다롭다는 이야기

강사님 답변

해당 유저를 아티스트로 바꾸는게 나중에 일어난다면 유저와 아티스트를 명확하게 분리해야 합니다.
상속보다 위임을 사용해야 한다. 상속은 현업에서 거의 사용되지 않는다.

위임이란?

위임은 한 클래스가 다른 클래스를 멤버변수로 갖는 것. 즉 @OneToOne을 하라는 이야기. 여기서 주의할 것은 DB랑 OOP 사이에서 헷갈려 하지말고,두 개를 따로 봐야한다. 여기서 위임이란 자바단에서 이야기 하는 것.

해결과정

artist에는 user_id가 없기 때문에 오류가 생긴다.

문제해결

  1. 양방향 관계는 최대한 갖지 않는 것이 좋다. user쪽에서는 artist 정보를 갖고 있을 필요가 없다. --> user쪽에 있는 artist는 지워줘도 된다

@MapsId, referencedColumnName

@referencedColumnName

https://medium.com/@SlackBeck/jpa-joincolumns-%EC%82%AC%EC%9A%A9%EC%8B%9C-%EC%A3%BC%EC%9D%98-%EC%82%AC%ED%95%AD-7bc22b98ed9b

  1. @MapsId , referencedColumnName="user_id" 지정

다시 오류

attempted to assign id from null one-to-one property

이렇게 하니까 됐는데, 다시 아티스트 저장하는 코드에서 오류가 생겼다.

해결 : user를 저장안해서 생긴 문제였다.

다시오류

org.hibernate.AssertionFailure: null identifier @OneToOne relationship

Stackoverflow 1

https://stackoverflow.com/questions/28508385/org-hibernate-assertionfailure-null-identifier-onetoone-relationship

종속 테이블에 cascade = CascadeType.ALL 을 달아주니까 해결됐다.

생기는 원인

Every bidirectional association has two sides : the owner side, and the inverse side. The inverse side is the one which has the mappedBy attribute. The owner side is the other one. JPA/Hibernate only cares about the owner side. So if you just initialize the inverse side, the association won't be persisted.

https://stackoverflow.com/questions/16380008/persist-onetoone-relation-with-springdata-jpa

초기화의 문제인 것 같다.

코드

Artist.java

@Getter
@NoArgsConstructor
@AllArgsConstructor
@Builder
@Accessors(chain = true)
@Entity
public class Artist{

    @Id
    @Column(name = "artist_id")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @MapsId
    @OneToOne(fetch = FetchType.LAZY,cascade = CascadeType.ALL)
    @JoinColumn(name = "artist_id", referencedColumnName="user_id")
    private User user;

    private String img;

}

User.java

@Getter
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
@Entity
public class User {

    @Id
    @Column(name = "user_id")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;

    private String email;

    private String password;

    private String nickname;

    private Integer money;

}

해결하면서 사용했던 것

@SuperBuilder

@native query 말고 jpql이나 querydsl

(스승이 써보라고 한것)

@PrimaryKeyJoinColumn

user.java

@PrimaryKeyJoinColumn
@OneToOne(mappedBy = "user")
@JsonManagedReference
private Artist artist;
profile
티스토리로 이사했습니다! https://imsfromseoul.tistory.com/ + https://camel-man-ims.tistory.com/

0개의 댓글