[인프런 김영한] 연관관계 매핑 기초 - 단방향 연관관계

2021. 2. 4. 18:31프로그래밍 언어/Spring Framework

[인프런 김영한] 연관관계 매핑 기초 - 단방향 연관관계


해당 글은 인프런 김영한강사님의 영상을 보고 정리한 글입니다.

Spring Boot, Spring Data JPA를 사용해 실습하였습니다.

김영한 인프런 : www.inflearn.com/users/@yh

 

인프런 - 김영한의 강의들을 만나보세요.

우아한형제들 개발 팀장 (전: 카카오, SK플래닛) 저서: 자바 ORM 표준 JPA 프로그래밍

www.inflearn.com


▣ Goal

 

1. 객체와 테이블 연관관계의 차이를 이해

2. 객체의 참조와 테이블의 왜래 키를 매핑


▣ 다대일[N:1]

| 테이블 연관관계로 Member 테이블에 Team의 FK가 있다.

이 때의 주인은 Member가 된다.


◈ 객체를 테이블에 맞추어 모델링

(참조 대신 왜래키를 그대로 사용(Long TeamId)하는 방법, 하면 안되요!)

 

▣ 코드

@Entity
@Setter
@Getter
public class Team {

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

    private String name;

}
@Entity
@Setter
@Getter
public class Member {

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

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

    @Column(name = "TEAM_ID")
    private Long teamId; //team_id

}

| Team을 참조하는게 아닌, Team의 id의 값을 참조하는 방식.

 

 

▣ 예제

@SpringBootApplication
public class JpatestApplication {

    private static TeamRepository teamRepository;
    private static MemberRepository memberRepository;

    public JpatestApplication(TeamRepository teamRepository, MemberRepository memberRepository) {
        this.teamRepository = teamRepository;
        this.memberRepository = memberRepository;
    }

    public static void main(String[] args) {
        SpringApplication.run(JpatestApplication.class, args);

        Team team = new Team();
        team.setName("TeamA");
        teamRepository.save(team);

        Member member = new Member();
        member.setUsername("member1");
        member.setTeamId(team.getId()); // ??? 왜래키 식별자를 그대로 사용함.
        memberRepository.save(member);
        
        Member findMember = memberRepository.findById(member.getId()).get();
        Long findTeamId = findMember.getTeamId();
        Team findTeam = teamRepository.findById(findTeamId).get();
        ...
       
    }

}

| Team의 Id값만 있기 떄문에 Team에 대한 값을 바로 가지고오지 못하며, Member에서 TeamId를 찾고 다시 TeamId로 Team을 찾아야하는 번잡스러운 과정이 있다.

연관관계라는게 없기 때문에 계속 DB에 물어봐야 하고 객체지향스럽지 않다.

 

 

 

| 실제로 값을 insert해 보면 테이블 관계에서는 맞다.

※TEAM_ID 값이 1이고, MEMBER_ID값이 2인 이유

- H2 DB에서는 create sequence hibernate_sequence start with 1 increment by 1 쿼리로 인해 테이블 공용으로 사용.

 

 

 

※ 문제

객체를 테이블에 맞추어 데이터 중심으로 모델링 하면, 협력관계를 만들 수 없다.

-> 테이블은 왜래키로 조인을 사용해서 연관된 테이블을 찾는다.

-> 객체는 참조를 사용해서 연관된 객체를 찾는다.

-> 테이블과 객체 사이에는 이런 큰 간격이 있다.

 

 


 

 

◈ 객체를 테이블에 맞추어 모델링 -> 객체 지향 모델링으로 변경

 

▣ 코드

@Entity
@Setter
@Getter
public class Member {

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

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

//    @Column(name = "TEAM_ID")
//    private Long teamId; //team_id

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

}

| Long teamId가 아닌, Team을 그대로 참조한다.

 

 

 

▣ 예제

@SpringBootApplication
public class JpatestApplication {

    public static void main(String[] args) {
        SpringApplication.run(JpatestApplication.class, args);
    }

    private static TeamRepository teamRepository;
    private static MemberRepository memberRepository;

    public JpatestApplication(TeamRepository teamRepository, MemberRepository memberRepository) {
        this.teamRepository = teamRepository;
        this.memberRepository = memberRepository;
        
        Team team = new Team();
        team.setName("TeamA");
        teamRepository.save(team);

        Member member = new Member();
        member.setUsername("member1");
//        member.setTeamId(team.getId());
        member.setTeam(team);
        memberRepository.save(member);


        // 조회
        // 기존) member를 찾고 member의 teamid를 찾아서 team을 찾았음.
        // 이후) member를 찾고 member의 team을 찾음
        Member findMember = memberRepository.findById(member.getId()).get();
        Team findTeam = findMember.getTeam();
        System.out.println("findTeam = " + findTeam.getName());
   
    }
}

````````````````````````````````````````````````````````````````````````````

// 결과 (SQL문)
    select
        member0_.member_id as member_i1_0_0_,
        member0_.team_id as team_id3_0_0_,
        member0_.username as username2_0_0_,
        team1_.team_id as team_id1_1_1_,
        team1_.name as name2_1_1_ 
    from
        member member0_ 
    left outer join
        team team1_ 
            on member0_.team_id=team1_.team_id 
    where
        member0_.member_id=?


findTeam = TeamA

| 결과를 보면 left outer join을 이용해 select하는것을 확인할 수 있다.