Notice
Recent Posts
Recent Comments
Link
«   2024/09   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30
Tags more
Archives
Today
Total
관리 메뉴

요리사에서 IT개발자로

스파르타 부트캠프 연관관계 맵핑 (다락방) 본문

Spring

스파르타 부트캠프 연관관계 맵핑 (다락방)

H.S-Backend 2024. 6. 18. 16:39

객체지향 설계의 목표는 자율적인 객체들의 협력 공동체를 만드는 것이다.

 

기존의 데이터베이스에서는 외래키를 사용하지만

JPA에서는 객체를 참조하는 방식으로 연관관계를 매핑할 수 있다.

 

객체간의 협력관계를 만들려면 객체 중심 설계가 우선이되야된다.

@Entity
public class Member {
    @Id @GeneratedValue
    private Long id;
    @Column(name = "USERNAME")
    private String name;
    @Column(name = "TEAM_ID")
    private Long teamId;

}
@Entity
public class Team {
    @Id @GeneratedValue
    private Long id;
    private String name;

}

Member와 Team은 서로 연관관계가 정해져있지 않아서 


// 팀 저장
Team team = new Team();
team.setName("TeamA");
em.persist(team);

// 회원 저장
Member member = new Member();
member.setName("member1");
member.setTeamId(team.getId());
        em.persist(member)

팀도 저장하고 멤버도 저장하고


// 조회
Member findMember = em.find(Member.class, member.getId());
// 팀과 회원은 연관관계가 없다.
Team findTeam = em.find(Team.class, team.getId());

멤버도 조회하고 팀도 조회해야한다. (연관관계가 없다)

 


 

단방향 객체 연관관계

@Entity
public class Member {
    @Id @GeneratedValue
    private Long id;
    @Column(name = "USERNAME")
    private String name;
    private int age;

    // member : team = n : 1 (다대일 관계)
    // 객체 연관관계 team 참조와 테이블 연관관계 TEAM_ID 외래키와 매핑
    @ManyToOne
    @JoinColumn(name = "TEAM_ID")
    private Team team;

}

Member에서는 Team을 가짐으로 team참조가 가능하다.


@Entity
public class Team {

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

    private String name;

Team에서 member로 참조할 수 없다.


양방향 객체 연관관계

@Entity
public class Team {

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

    private String name;

    // member : team = n : 1 이므로 OneToMany
    // (mappedBy = "team") : Member 클래스의 team이라는 변수와 매핑
    @OneToMany(mappedBy = "team")
    private List<Member> members = new ArrayList<>();
}

Team의 List <member> mebers를 통해 Member로 참조한다.


 

양방향 관계 객체 둘중에 하나로 외래키를 관리해야한다.


연관관계 주인 - 양방향 매핑 규칙

 

객체의 두 관계중 하나를 연관관계 주인으로 지정한다.

연관관계의 주인만이 외래 키를 관리(등록, 수정)할 수 있다.

주인이 아닌 쪽은 읽기만 가능하다.

주인은 mappedBy 속성 사용이 되지않는다.

주인이 아니면 mappedBy속성으로 주인을 지정한다.

 

외래키가 있는 곳을 주인으로 정한다.

 

위에서는 Member안의

// member : team = n : 1 (다대일 관계)
// 객체 연관관계 team 참조와 테이블 연관관계 TEAM_ID 외래키와 매핑
@ManyToOne
@JoinColumn(name = "TEAM_ID")
private Team team;

Team 이 연관관계의 주인이다.(외래키를 등록, 수정이 가능하다)


Team안의

// member : team = n : 1 이므로 OneToMany
// (mappedBy = "team") : Member 클래스의 team이라는 변수와 매핑
@OneToMany(mappedBy = "team")
private List<Member> members = new ArrayList<>();

 

List<Member> members 가 연관관계의 하인이다(읽기만 가능하다)

 


외래키가 있는 쪽을 주인으로 섬기는 이유?

객체 입장에서는 참조하는 쪽(Member)가 관계의 주체가 된다.

 

Team의 List<Member>를 수정하는데

Member 테이블의 Query가 전송되면 혼란스러워진다.

 

Member 객체는 N (@ManyToOne)

team 객체는 : 1 (@OneToMany)

 


다대일

@ManyToOne

 

일대다 

@OneToMany

 

일대일

@OneToOne

 

다대다 : 실무사용금지

@ManyToMany


단방향과 양방향

 

테이블

외래 키 하나로 양쪽 JOIN이 가능하기에 방향이라는 개념이 없다.

 

객체

참조용 필드(외래 키)가 있는 쪽만으로만 참조가 가능하다.

 

한쪽만 참조하면 단방향이고
양쪽이 서로 참조하면 양방향이다.(단방향이 두개다)

 

다대일 (N:1) - @ManyToOne 

 

단방향

테이블 입장에서 다(N)쪽에 외래키가 있어야한다.

 

객체 입장에서

참조 주체 외래키를 가지는 테이블에 연관관계 매핑을 한다. 

// 객체 연관관계 team 참조와 테이블 연관관계 TEAM_ID 외래키와 매핑
private Team team;

 


양방향에서

반대쪽 Team에 연관관계를 추가한다해서 테이블에 영향을 주지않는다 (주인이 정해져있다)

 

읽기만 가능하기에

@OneToMany(mappedBy = "team")  // member : team = n : 1 이므로 OneToMany
// (mappedBy = "team") : Member 클래스의 team이라는 변수와 매핑
private List<Member> members = new ArrayList<>();

List<Member>을 추가해준다.

 


일대일(1:1) @OneToOne

일대일은 일대일 반대도 일대일

 

주 테이블이나 대상 테이블중에 외래키 선택이 가능하다.
둘다 상관없다.

외래키에 데이터베이스 Unique 제약조건이 추가가 되어야 한다.

 

주 테이블에 외래키 단방향을 추천한다
성능 상으로도 자주 조회되는 주 테이블에 외래키를 걸어야 이득을본다.

@Entity
public class Member { // 주 테이블
    @Id
    @GeneratedValue
    @Column(name = "MEMBER_ID")
    private Long id;

    @Column(name = "USERNAME")
    private String userName;

    @OneToOne
    @JoinColumn(name = "LOCKER_ID")
    private Locker locker;

}

@Entity
public class Locker {
    @Id @GeneratedValue
    private Long id;

    private String name;
}

주 테이블에 외래키 양방향

@Entity
public class Member {

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

    @Column(name = "USERNAME")
    private String userName;

    @OneToOne
    @JoinColumn(name = "LOCKER_ID")
    private Locker locker;

}

@Entity
public class Locker {

    @Id @GeneratedValue
    private Long id;

    private String name;

    @OneToOne(mappedBy = "locker") // 읽기 전용 필드
    private Member member;

}

 


대상 테이블에 외래키 단방향

 

지원도 되지않고 방법이없다.

 

 

대상 테이블에 외래키 양방향

 

주테이블과 대상 테이블을 모두 조회해야하기에

Lazy라 하더라도

사실상 즉시로딩이 되어 의미가없다.


일대일 

주 테이블 (자주 Access하는 테이블) 에 외래키를 넣으면

 

객체지향 개발자 선호하는 방식이다

JPA매핑이 편하다

 

장점으로는

주 테이블만 조회해도 대상 테이블에 데이터가 있는지 확인이 가능하다.

 

단점으로는

대상테이블 값이 없으면 대상테이블 외래키에 null값을 허용해야한다.

DBA입장에서 치명적인 단점이다.


 

대상 테이블에 외래키를 넣는다면

 

null의 단점문제가 해결되기에 전통적인 데이터베이스 개발자 선호 방식이다.

 

장점으로는

주 테이블과 대상테이블

일대일에서 일대다 관계로 변경할 때 테이블 구조 유지가 가능하다.

List<Member> members = 읽기전용


단점으로는

항상 양방향으로 만들어야되며

JPA의 기본 프록시 기능의 한계로 지연로딩으로 설정해도

항상 즉시 로딩한다. 둘다 보여 준다.(데이터가 방대할 경우 치명적 단점)

List members = 읽기전용

 

 

 

https://hs-backend.tistory.com/202

 

스파르타 부트캠프 Entity 맵핑 (다락방)

@Entity@Table(name="MEMBER")public class Member { @Id @GeneratedValue(strategy = GenerationType.AUTO) @Column(insertable = true, updatable = false) private Long mbrSeq; @Column private String deptCd; @Enumerated(value = EnumType.STRING) // 필수 private M

hs-backend.tistory.com

 

반응형