woowacourse-study / 2022-jpa-study

🔥 우아한테크코스 4기 JPA 스터디 (22.06.13~22.07.02) 🔥
5 stars 1 forks source link

[섹션 4, 섹션 5] 오찌 제출합니다. #9

Closed Ohzzi closed 2 years ago

Ohzzi commented 2 years ago

섹션 4. 엔티티 매핑

객체와 테이블 매핑 어노테이션

@Entity

JPA를 사용해서 테이블과 매핑할 클래스에 붙이는 어노테이션

@Table

엔티티와 매핑할 테이블을 지정하는 어노테이션

데이터베이스 스키마 자동 생성

JPA는 데이터베이스 스키마를 자동으로 생성하는 기능을 지원

properties

spring.jpa.hibernate.ddl-auto=create
spring.jpa.hibernate.show-sql=true

yaml

spring:
  jpa:
    hibernate:
      ddl-auto: create
      show-sql: true

ddl-auto: 자동으로 테이블을 생성할 지 결정하는 속성

JPA 자체적으로도 스키마 자동 생성 기능을 지원(update, validate 지원 x)

이름 매핑 전략 변경

DDL 생성 시 제약 조건 걸기

length 속성을 통해 문자 크기 지정(varchar(10)), nullable=false 속성을 통해 not null 제약 조건 적용

@Entity
@Table(name = "MEMBER")
public class Member {

    @Id
    @Column(name = "ID")
    private String id;

    @Column(name = "NAME", nullable = false, length = 10)
    private String username;
    ...
}

기본 키 매핑

@Id 어노테이션을 통해서 기본 키 매핑 가능

기본 키 조건

기본키로는 자연 키와 대리 키 사용 가능

@GeneratedValue 어노테이션을 추가하여기본 키 직접 생성 대신 데이터베이스에서 제공하는 기본 키 자동 생성 기능 사용 가능

필드와 컬럼 매핑

섹션 5. 연관관계 매핑 기초

객체와 DB의 연관관계 차이점

MemberTeam을 필드로 가지는 연관관계

단방향 연관관계

가장 기초적인 다대일[N:1] 연관관계(Member(N)가 Team(1)을 필드로 가지는 연관관계)

@Entity
public class Member {

    @Id
    @Column(name = "MEMBER_ID")
    private String id;

    private String username;

    @ManyToOne
    @JoinColumn(name = "TEAM_ID")
    private Team team;

    public void setTeam(Team team) {
        this.team = team;
    }

    ...
}
@Entity
@Getter
public class Team {

    @Id
    @Column(name = "TEAM_ID")
    private String id;

    private String name;

    ...
}

MemberTeam 단방향 연관관계(Member → Team만 조회 가능)

연관 관계 저장

Team team1 = new Team("team1", "팀1");
em.persist(tema1);

Member member1 = new Member("member1", "회원1");
member1.setTeam(team1);
em.persist(member1);

연관관계 조회

연관관계를 조회하는 방법은 2가지

연관관계 수정

Team team2 = new Team("team2", "팀2");
em.persist(team2);

Member member = em.find(Member.class, "member1");
member.setTeam(team2);

연관관계 제거

Member membe1 = em.find(Member.class, "member1");
member.setTeam(null);

양방향 연관관계

TeamMember로 접근하는 관계를 추가

@Entity
@Getter
public class Team {

    @Id
    @Column(name = "TEAM_ID")
    private String id;

    private String name;

    @OneToMany(mappedBy = "team")
    private List<Member> members = new ArrayList<>();

    ...
}

연관관계의 주인

엄밀히 말해 객체에는 양방향 연관관계란 존재하지 않음. 단방향 연관관계 2개가 존재.

반면 데이터베이스 테이블은 외래 키 하나로 양방향 조인이 가능.

일대다 컬렉션 조회

Team team = em.find(Team.class, "team1");
List<Member> members = team.getMembers();

양방향 연관관계 저장

Team team1 = new Team("team1", "팀1");
em.persist(team1);

Member member1 = new Member("member1", "회원1");
member1.setTeam(team1);
em.persist(member1);

// 연관관계의 주인이 아닌 방향은 값을 설정하지 않아도 데이터베이스에 외래 키 값이 정상 입력됨
// team1.getMembers().add(member1);

주의

Member member1 = new Member("member1", "회원1");
em.persist(member1);

Team team1 = new Team("team1", "팀1");
team1.getMembers().add(member1);
em.persist(team1);
Team team1 = new Team("team1", "팀1");
em.persist(team1);

Member member1 = new Member("member1", "회원1");
member1.setTeam(team1);
em.persist(member1);

team1.getMembers().add(member1);

연관관계 편의 메서드

member.setTeam(team)team.getMembers().add(member)를 모두 호출할 때 실수로 누락 가능성 있음

→ 두 코드가 하나의 코드인 것 처럼 사용해야 안전

public class Member {

    ...
    private Team team;

    public void setTeam(Team team) {
        this.team = team;
        team.getMembers().add(this);
    }
}

이렇게 Member.setTeam 하나로 양방향의 연관관계를 모두 입력해주도록 하면 연관관계를 맺어주는 메서드를 한 번만 호출해도 됨 (연관관계 편의 메서드)

양방향 연관관계 시 순환참조 주의

Member.toString에서 getTeam을 호출하고, Team.toString에서 getMember를 호출하면 어느쪽에서 toString을 호출하든 무한루프에 빠짐(엔티티를 JSON으로 변환할 때 많이 생기는 문제)

정리