Entity, 연관관계

star_pooh·2025년 1월 3일
0

TIL

목록 보기
39/39
post-thumbnail

Entity

JPA가 관리하는 Entity로 만들기 위해서는 해당 클래스에 어노테이션을 활용해야함.

  • @Entity
    • JPA가 관리할 객체라는 것을 명시
    • PK 값을 나타내는 @Id는 반드시 필요
    • 기본 생성자 필수
    • final, enum, interface, inner 클래스에는 사용 불가
    • 필드에 final 키워드 사용 불가
  • @Table
    • 엔티티와 매핑할 테이블을 지정
    • name 속성을 사용하여 테이블 이름을 지정
@Entity
@Table(name = "car")
public class Car {
    // PK
    @Id
    private Long id;

    // 필드
    private String maker;
  
    private String model;

    // 기본 생성자
    public Tutor() {
    }

    public Tutor(Long id, String maker, String model) {
        this.id = id;
        this.maker = maker;
        this.model = model;
    }
}

기본키

  • @Id
    • 엔티티를 생성할 때 필수로 존재해야 하며, 단독으로 사용시 DB에 데이터를 저장할 때 ID값을 수동으로 설정해줘야 함
    • 가장 권장되는 방식은 Long 타입의 기본키를 사용하는 것
  • @GeneratedValue
    • ID값을 자동으로 생성해주며, strategy 속성을 사용하여 다양한 설정 가능
      • GenerationType
        • IDENTITY : MySQL, PostgreSQL에서 사용하며, PK 자동 생성
        • SEQUENCE : Oracle에서 사용하며, @SequenceGenerator와 함께 사용
        • TABLE : 키 생성용 테이블을 사용하며, @TableGenerator와 함께 사용
        • AUTO : DB 종류에 따라 자동 지정하며 GenerationType의 기본값

필드 매핑

엔티티의 필드는 테이블의 컬럼과 매핑되며, 다양한 설정 가능

  • @Column

    • 생략해도 DB 컬럼으로 매핑이 가능하지만, 다양한 옵션을 사용하기 위해 설정

      속성설명기본값
      name객체 필드와 매핑할 테이블의 컬럼 이름 설정객체 필드 이름
      nullableDDL 생성 시 null 값의 허용 여부 설정true(허용)
      uniqueDDL 생성 시 유니크 제약 조건 설정-
      columnDefinitionDDL 생성 시 컬럼 정보 설정-
      lengthDDL 생성 시 문자 길이 설정(String만 가능)255
      insertable설정된 컬럼의 INSERT 가능 여부true
      updatable설정된 컬럼의 UPDATE 가능 여부true
  • @Temporal
    • 날짜 타입을 설정
      • 객체 필드의 데이터 타입이 LocalDate, LocalDateTime인 경우에는 생략 가능
  • @Enumerated
    • enum 값을 사용하기 위해 설정(DB에는 enum 타입이 없음)
      • 속성으로 value를 사용하며, 값으로는 enum의 이름을 저장하는 EnumType.STRING을 사용
      • 값이 추가될 때마다 순서가 변하기 때문에 enum의 순서를 저장하는 EnumType.ORDINAL은 사용하지 않음
  • @Transient
    • DB 컬럼과 매핑하지 않을 때 사용
@Entity
@Table(name = "board")
public class Board {
    @Id
    private Long id;

    // @Column을 사용하지 않아도 DB 컬럼으로 매핑
    private Integer view;

    // 객체 필드 이름과 DB 컬럼 이름을 다르게 설정 가능
    @Column(name = "title")
    private String bigTitle;

    @Enumerated(EnumType.STRING)
    private BoardType boardType;

    // longtext를 설정하면 VARCHAR()를 넘어서는 큰 용량의 문자열 저장 가능
    @Column(columnDefinition = "longtext")
    private String contents;

    // 날짜 타입 (DATE, TIME, TIMESTAMP) 사용 가능
    @Temporal(TemporalType.TIMESTAMP)
    private Date createdDate;

	// LocalDate를 사용했기 때문에 @Temporal 생략 가능
    private LocalDate lastModifiedDate;
  
 	// 객체에선 필요하지만 DB에는 필요 없은 필드
    @Transient
    private int count;

    public Board() {
    }
}

💡 hibearnate.hbm2ddl.auto
애플리케이션 로딩 시점에 JPA가 DDL을 생성하기 위해 필요한 설정 값.

설정값설명
create기존 테이블을 삭제(DROP)한 후 다시 생성(CREATE)
create-drop기존 테이블을 삭제(DROP)한 후 다시 생성(CREATE)하고 애플리케이션 종료 시점에 테이블을 삭제(DROP)
update엔티티에서 변경된 사항만 DDL에 반영(데이터 타입, 컬럼명 등)
validate엔티티와 테이블이 정상적으로 매핑 되었는지 확인하며, 실패 시 예외 발생
none속성을 사용하지 않는 것으로서 아무 변화 없음
// application.properties에서의 사용 예시
hibernate.hbm2ddl.auto=create

연관관계

단방향

객체 간의 관계가 한쪽에서만 참조될 수 있는 관계. 설정이 단순하고 유지 관리가 쉬우며 불필요한 데이터 접근 방지 가능.

  • 객체가 다른 객체를 참조
  • N:1 관계일 경우, @ManyToOne, @JoinColume을 사용
  • N에 해당하는 테이블(Tutor)의 외래키와 1에 해당하는 테이블(Company)의 PK를 @JoinColumn으로 매핑
@Entity
@Table(name = "tutor")
public class Tutor {
	@Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
		
	private String name;
    // N:1 단방향 연관관계 설정
    @ManyToOne
    @JoinColumn(name = "company_id")
    private Company company;

	// 기본 생성자, getter/setter
}

양방향

객체 간의 관계가 양쪽에서 서로를 참조할 수 있는 관계. 양쪽에서 데이터에 쉽게 접근할 수 있지만, 관계를 관리할 때는 한쪽에서만 연관관계를 설정하거나 삭제하지 않도록 주의 필요.

  • DB 관점에서는 연관관계에 방향의 개념이 없음
  • 따라서 테이블에 변화는 없음
  • 양방향 연관관계 설정을 위해 mappedBy 속성을 설정
    • Tutor → Company N:1 연관관계 (단방향)
    • Company → Tutor 1:N 연관관계 (단방향)
    • 단방향 연관관계 두 개로 양방향을 설정
@Entity
@Table(name = "tutor")
public class Tutor {
	@Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
>	
	private String name;
    // N:1 단방향 연관관계 설정
    @ManyToOne
    @JoinColumn(name = "company_id")
    private Company company;
>		
	// 기본 생성자, getter/setter
}
@Entity
@Table(name = "company")
public class Company {
	@Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
>
	private String name;
>		
	// null을 방지하기 위해 ArrayList로 초기화
    // Tutor 클래스의 company 필드와 매핑
    @OneToMany(mappedBy = "company")
    private List<Tutor> tutors = new ArrayList<>();
>		
	// 기본 생성자, getter/setter
}

양방향 연관관계의 주인

mappedBy는 양방향 연관관계 설정 시 연관관계의 주인이 아닌 쪽에 선언. 이를 통해 외래 키 관리 책임을 주인 엔티티에 두고 매핑이 중복되지 않도록 함.

  • Tutor의 Company를 수정할 때 FK 수정
  • Company의 Tutor를 수정할 때 FK 수정
  • Tutor가 새로운 Company를 간다면
    • Tutor가 참조하는 Company 수정
    • Company가 참조하는 List<Tutor> 수정
    • DB 입장에서는 FK만 수정되면 되기 때문에 한 쪽에서만 FK를 관리해야함
  • 양방향 연관관계 규칙
    1. 두 개의 엔티티 중 하나를 연관관계의 주인으로 설정해야 함
    1. 연관관계의 주인은 mappedBy 속성을 사용하지 않음
    2. 연관관계의 주인이 아니면 mappedBy 속성을 사용
    3. 연관관계의 주인이 아니면 조회만 가능
    4. 연관관계의 주인만 외래키를 관리(등록, 수정)
  • 연관관계의 주인 선정 기준
    • 외래키가 있는 곳을 연관관계의 주인으로 지정
    • Company가 주인인 경우
      • Company를 수정할 때 Tutor를 수정하는 SQL이 실행되기 때문에 두 번의 SQL이 실행되어야 하므로 혼동되기 쉬움

0개의 댓글

관련 채용 정보