1:N관계 객체지향, JPA에서 관계

LJM·2023년 5월 14일
0

미니프로젝트(FE+BE)

목록 보기
8/12

주인과 하인이 있다고 했을때
주인은 1명이고 하인은 여러명이다. 1:N 관계이다. 보통 이렇게 생각한다.
주인을 삭제하면 하인도 모두 삭제해야하지 않나 이런 생각이 든다
그리고 하인은 하인만 삭제하면 된다.

하지만 JPA는 다른다.

1:N 관계에서 주인은 N이라고 한다. 이부분이 다른다. 삭제는 똑같다.
1이 삭제되면 N 모두 삭제해야 한다. N을 하나만 삭제하든 모두 삭제하든 N만 삭제하면 된다.

Leave(연차 정보를 담은 엔티티), Alarm(연차가 승인되거나 거절되거나 취소되거나 등의 상황 발생시 생성되는 엔티티)

Leave 와 Alarm 의 관계는 1:N 이다. 객체지향 프로그래밍에서는 Leave가 주인이다.
하지만 JPA에서는 Alarm이 주인이다

JPA에서의 관계 주인은 외래 키를 관리하는 쪽을 의미합니다. 
이는 데이터베이스 스키마에 따른 것이고, 일반적으로 N 쪽이 외래 키를 가지게 됩니다. 
이는 JPA가 객체의 상태를 데이터베이스에 어떻게 반영할지를 결정하는 방법입니다.

Leave를 삭제하려고 하면 Alarm 을 다 삭제해야 한단다. JPA에서 오류가 났다.
아니 Alarm이 주인이라고 하면서 Leave삭제할때 Alarm도 다 삭제해야 한단다.(이해가 안된다)

내 질문:
Alarm이 주인이라고 하면서 Leave삭제할때 Alarm도 다 삭제해야 한단다. JPA에서 요청하는 거잖아
JPA도 객체지향을 따른다고 봐야하는건가? Alarm이 주인이란건 삭제할때는 적용이 안된는거 같은데
JPA는 객체지향 프로그래밍과 관계형 데이터베이스 사이의 다리 역할을 하는 기술입니다.
이 두 세계는 근본적으로 많은 차이가 있으며, JPA는 이들을 최대한 효율적으로 연결하려고 
력합니다. 그러나 이 두 세계의 차이로 인해 항상 완벽하게 일치시키는 것은 불가능합니다.

관계의 주인은 JPA가 외래 키를 관리하는 방식을 정의하는 데 사용됩니다. 일대다 관계에서
일(1) 측이 주인이면 일(1) 측에 있는 외래 키를 관리하고, 다(N) 측이 주인이면 다(N)
측에 있는 외래 키를 관리합니다. 이것은 데이터베이스 스키마와 관련이 있으며, 객체지향적인
관점과는 별개입니다.

객체지향적인 관점에서는 일대다 관계에서 일(1) 측이 주인일 것으로 기대할 수 있습니다.
그러나 JPA는 데이터베이스 스키마와 관련된 이유로 다(N) 측을 주인으로 설정하는 것을 선호합니다.

따라서 JPA에서 관계의 주인이라는 개념은 데이터베이스의 외래 키 관리를 위한 것이며,
객체지향 프로그래밍의 관점과는 다르게 해석될 수 있습니다. 이런 상황에서는 JPA의
cascade 옵션 또는 연관관계 편의 메소드를 사용하여 객체지향적인 관점을 유지하면서
필요한 연산을 수행할 수 있습니다.

어렵다;;

어쨋든 Leave가 삭제될때 Alarm(Leave를 참조하는 FK 가지고 있음)도 삭제해야 한단다.
그래서 Leave 에도 Alarm을 추가해주고 양방향으로 관리해야 한단다

public class Leave {

	@Builder.Default
    @OneToMany(mappedBy = "leave", cascade = CascadeType.ALL, orphanRemoval = true)
    private List<Alarm> alarms = new ArrayList<>();

그리고 관련된 코드다 싹다 고쳤다..

그리고 엔티티를 생성할대도 신경써야 한다

Leave newLeave = 생성했다고 치자
Leave leavePS = leaveRepository.save(newLeave)

Alarm alarm = AlarmFactory.newAlarm(leavePS);
alarmRepository.save(alarm);

Leave 를 먼저 DB에 넣어야 하고 반환받은 영속성 객체를 Alarm 생성할때 Alarm에게 넣어줘야한다.
이때는 Alarm이 주인이라 그렇게 하는것이라고 이해하면 되나싶다.

내 질문: 만약 영속성객체가 아닌 newLeave를 newAlarm 에 넣으면 어떤 오류 발생하드라?
만약 Leave 객체를 데이터베이스에 저장하기 전에 Alarm 생성자에 전달하면, Alarm 객체는
아직 데이터베이스에 저장되지 않은 Leave 객체를 참조하게 됩니다. 이때 Alarm 객체를
데이터베이스에 저장하려고 하면, JPA는 Leave 객체에 할당된 ID를 찾지 못하고 오류를 발생시킬 수 있습니다.

이는 JPA가 외래 키 관계를 관리하는 방식 때문입니다. Alarm 엔티티가 Leave 엔티티를
참조하려면, Leave 엔티티가 데이터베이스에 먼저 저장되어야 하며, 해당 Leave 엔티티의
ID를 알아야 합니다. 이 ID는 Alarm 엔티티가 Leave 엔티티를 참조하는 데 사용되는 외래 키입니다.
따라서 Leave 객체가 데이터베이스에 저장되지 않은 상태에서 Alarm 객체를 저장하려고 하면, JPA는
외래 키를 생성할 수 없으므로 오류가 발생합니다.

이 문제를 해결하려면, Leave 객체를 먼저 데이터베이스에 저장하고, 이후에 Alarm 객체를
생성하여 저장해야 합니다. 이렇게 하면 Alarm 객체는 영속 상태의 Leave 객체를 참조할 수 있으며,
JPA는 외래 키를 제대로 생성할 수 있습니다.
profile
게임개발자 백엔드개발자

0개의 댓글