디스코드 프로젝트 실습: Entity 정의하기(JPA 어노테이션,cascade,고아객체)

2026. 3. 5. 11:17·코드잇 스프린트/실습

1.공통속성을 추상 클래스로 정의하고 상속으로 구현

현재 Entity간 공통 속성이 존재한다.

코드 중복 제거와 공통 로직을 관리하는데 있어 편하다는 장점이 있기에 따로 추상클래스로 정의하고 상속받도록 설계한다.

다만, 불필요한 필드를 강제한다는 단점도 있다.

 

위 프로젝트에서는 id,createdAt이 공통 필드 이기에 따로 정의한다.

@MappedSuperclass
@Getter
@NoArgsConstructor
public abstract class BaseEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.UUID)
    private UUID id;

    @Column(nullable = false)
    private Instant createdAt;
}

 

@MappedSuperclass

JPA에서 부모 클래스의 필드를 자식 엔티티 테이블에 매핑해주는 어노테이션

공통 필드만 상속해서 쓰고, 부모 자체는 테이블을 만들지 않도록 한다.

@Entity : 테이블 생성

@MappedSuperclass :  테이블 생성x / 필드만 상속


2. JPA의 어노테이션을 활용해 createdAt, updatedAt 속성이 자동으로 설정되도록 구현

@CreatedDate

@LastModifiedDate

Spring Data JPA Auditing 기능에서 제공하는 어노테이션이다.엔티티가 생성되거나, 수정될 때 시간을 자동으로 채워주는 기능이다.

 

Auditing 기능을 활성화 해야되므로, 메인클래스에 @EnableJpaAuditing을 추가하여 Auditing기능을 활성화한다.

@EnableJpaAuditing
@SpringBootApplication
public class Application {
}

 

 


3. 연관관계 매핑 정보를 표로 정리

엔티티관계 다중성 방향성 부모-자식관계(DB기준) 연관관계의 주인
User : BinaryContent 1:1 User → BinaryContent 단방향 부모:BinaryContent, 자식:User User
User: UserStatus 1:1 User ↔ UserStatus 양방향 부모:User, 자식: UserStatus UserStatus
User:ReadStatus 1:N ReadStatus → User 부모:User, 자식: ReadStatus ReadStatus
User:Message 1:N Message → User 부모:User, 자식: Message Message
Channel : ReadStatus 1:N ReadStatus → Channel 부모:Channel, 자식: ReadStatus ReadStatus
Channel: Message 1:N Message → Channel 부모:Channel, 자식;Message Message
Message : BinaryContent N:M Message -> BinaryContent Message_ATTACHMENTS로 쪼개짐 Message

 

자식: FK를 가지고 있는쪽.

@JoinColumn → DB 컬럼명

mappedBy → 상대 엔티티 필드명


4. JPA 어노테이션 적용

@Enumerated: Java의 enum 타입을 DB 컬럼에 어떻게 저장할지 지정하는 JPA 어노테이션

@Enumerated(EnumType.ORDINAL) :  숫자로 저장.(순서 INDEX로 저장)

(실무)@Enumerated(EnumType.STRING) : 문자로 저장.

 

@ManyToMany

Message와 BinaryContent의 관계 N:M

테이블상 Message_attachments로 분리 하였는데 컬럼이 message_id와 binaryContent_id로 되어있어

별도의 Entity를 구성하지 않았다.

 

Entity상 Message -> BinaryContent의 단방향 매핑이 이루어져있어서

Message의 attachments 변수에만 @ManyToMany를 붙여서 설계하였다.

 

@ManyToMany
    @JoinTable(name = "MESSAGE_ATTACHMENTS",
               joinColumns = @JoinColumn(name = "message_id"),
               inverseJoinColumns = @JoinColumn(name = "attachment_id"))
    private List<BinaryContent> attachments;

BinaryContent쪽에서는 Message를 조회할 일이 없기 때문에 Message 내에서만 @ManyToMany로 지정하였다.

Message와 BinaryContent는 N:M 관계이기에 실제 Table에서는 Message_Attachments를 따로 두어 1:N로 분리하였다.

 

코드에서는 Message에서 @ManyToMany를 두어 단방향으로 하였고,

@JoinTable을 사용하여 테이블 명을 두고, joinColumns = 현재 Entity의 FK(Message의 FK)

inverseJoinColumns = 상대 Entity의 FK를 지정하였다.

 

저장흐름은

message.getAttachments().add(file1);
message.getAttachments().add(file2);

messageRepository.save(message);

 

MESSAGE_ATTACHMENTS
--------------------
message_id | attachment_id
--------------------------------
msg1       | file1
msg1       | file2

이렇게 된다.


5. 영속성 전이와 고아 객체를 정의

영속성: Entity객체가 영속성 컨텍스트에의해 관리되는 상태

cascade: 부모 엔티티의 영속성 작업을 자식 엔티티에게 전파하는 기능.

부모 저장 → 자식도 같이 저장
부모 삭제 → 자식도 같이 삭제

 

예시

@OneToMany(cascade = CascadeType.ALL)
private List<Message> messages;

채널내 messages라는 메세지 목록에 cascade를 CascadeType.ALL로 설정하면,

channelRepository.save(channel);

channel 저장시, messages도 자동 저장된다.

 

고아객체: 부모 엔티티와 연관관계가 끊어진 자식 엔티티

예시

Channel
  └ Message
channel.getMessages().remove(message);

message는 부모가 없는 상태가 된다.

orphanRemoval : 부모와 관계가 끊어진 자식을 자동 삭제

 

CasecadeType.ALL vs orphanRemoval = true

userRepository.delete(user);

User 삭제시 UserStatus도 삭제된다. 즉 부모삭제시, 자식 삭제.

 

orphanRemoval은 부모삭제가 아니라 관계 제거 상황.

user.setStatus(null);

UserStatus는 부모가 없는 상태... 이럴때 삭제

 정리하자면 User 삭제시 UserStatus가 삭제되는건 cascade

user.status = null 일때 UserStatusr가 삭제되는건 orphanRemoval

 

@OneToOne
@JoinColumn(name = "profile_id")
private BinaryContent profile;

이건 BinaryContent와 User랑 독립이라 따로 cascade나 orphanRemoval 설정 x

User 삭제 되어도 BinaryContent 남아있을 수 있다.

User의 profile이 null이 되어도 해당 BinaryContent는 남아있을 수 있다.

'코드잇 스프린트 > 실습' 카테고리의 다른 글

MapStruct 라이브러리를 통해 Entity를 DTO로 자동 변환  (0) 2026.03.09
Entity를 Controller까지 그대로 노출 할때 발생할 수 있는 문제점  (0) 2026.03.09
JPA사용 직접 작성한 DDL로 테이블 생성(schema.sql)  (0) 2026.03.04
JPA ERROR : user는 PostgreSQL 예약어라서 테이블명을 따로 정해야한다.  (0) 2026.03.03
PostgreSQL DB 와 Spring Boot(InteliJ) 연동하기  (0) 2026.03.03
'코드잇 스프린트/실습' 카테고리의 다른 글
  • MapStruct 라이브러리를 통해 Entity를 DTO로 자동 변환
  • Entity를 Controller까지 그대로 노출 할때 발생할 수 있는 문제점
  • JPA사용 직접 작성한 DDL로 테이블 생성(schema.sql)
  • JPA ERROR : user는 PostgreSQL 예약어라서 테이블명을 따로 정해야한다.
과컴
과컴
벡엔드 개발자 최소기준 맞추겠습니다.
  • 과컴
    곽의 프로그램
    과컴
  • 전체
    오늘
    어제
    • 분류 전체보기 (76)
      • 위클리페이퍼 (6)
      • 파이썬 (4)
      • 코드잇 스프린트 (48)
        • Spring 이론 (7)
        • Java이론 (11)
        • 실습 (23)
      • 백엔드 개발자 최소기준 (1)
      • 코딩테스트 (5)
        • 알고리즘 (0)
        • SQL (1)
      • Git (5)
      • 스프링부트 핵심가이드 (1)
      • 트러블 슈팅 (2)
  • 블로그 메뉴

    • 홈
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    파이썬기초
    문자열
    혼공파
    백준1152
    파이썬입문
    파이썬
    백준브론즈
    백준2576
    백준1075번
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.6
과컴
디스코드 프로젝트 실습: Entity 정의하기(JPA 어노테이션,cascade,고아객체)
상단으로

티스토리툴바