[JPA] 1:N ๋งคํ•‘

1.๋“ค์–ด๊ฐ€๋ฉฐ

JPA ์—ฐ๊ด€๊ด€๊ณ„ ๋งคํ•‘์ค‘, ์‹ค๋ฌด์—์„œ ๊ฐ€์žฅ ๋งŽ์ด ์“ฐ์ด๋Š” 1:N (์ผ๋Œ€๋‹ค) ๋งคํ•‘์— ๋Œ€ํ•ด์„œ ์•Œ์•„๋ณด์ž.
์ผ๋Œ€๋‹ค ๋งคํ•‘์„ ํ•˜๊ธฐ ์œ„ํ•ด์„œ ํ•˜๋‚˜์˜ ํŒ€์— ์—ฌ๋Ÿฌ๋ช…์˜ ๋ฉค๋ฒ„๊ฐ€ ์†ํ•ด์žˆ๋Š”, 1:N ๊ด€๊ณ„๋ฅผ ์ƒ๊ฐํ•ด๋ณด์ž.
๊ด€๊ณ„ ๋งคํ•‘์—๋Š” ๋ฐฉํ–ฅ์„ฑ๊ณผ ์™ธ๋ž˜ํ‚ค์˜ ์ฃผ์ธ ๋‘ ๊ฐ€์ง€ ์ƒํ™ฉ์ด ๋ฐœ์ƒ ํ•œ๋‹ค.(๊ฐ์ฒด์™€ ํ…Œ์ด๋ธ”๊ฐ„์˜ ํŒจ๋Ÿฌ๋‹ค์ž„ ๋ถˆ์ผ์น˜ ๋•Œ๋ฌธ์—)
์ผ๋ฐ˜์ ์œผ๋กœ ๊ฐ์ฒด์—์„œ๋Š” ์ฐธ์กฐ๋ฅผ ํ†ตํ•ด์„œ ๋ฐฉํ–ฅ์„ฑ์„ ๊ฐ–๋Š”๋‹ค.

๊ฐ์ฒด์—์„œ ๋ฐฉํ–ฅ์„ฑ์ด๋ž€?

@Data
public class Member {
    private Team team;
}

memeber.getTeam() ์„ ํ†ตํ•ด์„œ team์„ ์กฐํšŒํ•  ์ˆ˜ ์žˆ๋‹ค.
์ฆ‰, member -> team๊ฐ„์˜ ๋‹จ๋ฐฉํ–ฅ(๋ฐฉํ–ฅ์„ฑ)์„ ๊ฐ–์ง€๋งŒ, ๋ฐ˜๋Œ€์˜ ๋ฐฉํ–ฅ์„ฑ์€ ์กด์žฌํ•˜์ง€ ์•Š๋Š”๋‹ค.
๋งŒ์•ฝ์— ๋ฐ˜๋Œ€ ์ƒํ™ฉ๋„ ์กด์žฌํ• ๋ ค๋ฉด

@Data
public class Team {
    private List<Member> memberList;
}

์ด๋ ‡๊ฒŒ ์„ค์ •ํ•ด์•ผ์ง€๋งŒ, team.getMemberList()๋ฅผ ํ†ตํ•ด์„œ ์ ‘๊ทผ ํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด๋ ‡๊ฒŒ ๊ฐ์ฒด๊ฐ„์˜ ์ฐธ์กฐ๋ฅผ ํ†ตํ•ด์„œ ํƒ์ƒ‰ํ•˜๋Š” ๊ณผ์ •์„ ๊ฐ์ฒด ๊ทธ๋ž˜ํ”„ ํƒ์ƒ‰์ด๋ผ๊ณ  ํ•œ๋‹ค.

์™ธ๋ž˜ํ‚ค์˜ ์ฃผ์ธ?

์—ญ์‹œ๋‚˜ ๊ฐ์ฒด์™€ ํ…Œ์ด๋ธ”๊ฐ„์˜ ํŒจ๋Ÿฌ๋‹ค์ž„ ๋ถˆ์ผ์น˜ ์ค‘์— ํ•˜๋‚˜๋กœ, ์™ธ๋ž˜ํ‚ค๋ฅผ ํ†ตํ•ด์„œ Join์„ ํ•˜๊ฒŒ ๋˜๋ฉด, ๊ฐ ํ…Œ์ด๋ธ”์—์„œ ์™ธ๋ž˜ํ‚ค๋ฅผ ์–ด๋””์— ๋‘๊ณ  ์‚ฌ์šฉํ•˜๋Š” ์ง€๋Š” ์ค‘์š”ํ•˜์ง€ ์•Š๋‹ค. ๊ณต์œ ํ•˜๋Š” ๋Š๋‚Œ.

ํ•˜์ง€๋งŒ, ๊ฐ์ฒด์—์„œ๋Š” ๊ฐ ์—”ํ‹ฐํ‹ฐ๋งˆ๋‹ค ์—ฐ๊ด€๊ด€๊ณ„ ๋งคํ•‘์„ ํ•ด์•ผ ํ•˜๊ณ , ์™ธ๋ž˜ํ‚ค์˜ ์ฃผ์ธ์„ ๋”ฐ๋กœ ์„ค์ •ํ•ด์•ผ ํ•œ๋‹ค. ๋ณดํ†ต์€ @OneToMany(mappedBy = "team") ๋ฅผ ํ†ตํ•ด์„œ mappedBy ํ”„๋กœํผํ‹ฐ์˜ ๋ฐ˜๋Œ€ํŽธ์—์„œ ์™ธ๋ž˜ํ‚ค๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค.

2.์˜ˆ์ œ ์ฝ”๋“œ

๋จผ์ € member -> team ์˜ ๋‹จ๋ฐฉํ–ฅ ๊ด€๊ณ„๋ฅผ ์‚ดํŽด ๋ณด์ž.

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

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    private String name;
    private Long age;

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

}
@Data
@Table(name = "TEAM")
@Entity
public class Team {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    private String name;

    // ์–‘๋ฐฉํ–ฅ ๊ด€๊ณ„์ผ ๋•Œ๋งŒ ์„ค์ •ํ•จ
    //@OneToMany(mappedBy = "team")
    //private List<Member> memberList;
}

Member๊ณผ Team๊ฐ„์˜ ์—ฐ๊ด€๊ด€๊ณ„ ๋งคํ•‘์—์„œ ํ•ต์‹ฌ์€

@ManyToOne ๊ณผ @JoinColumn ์˜ ์Œ์œผ๋กœ ์ด๋ฃจ์–ด์ง„๋‹ค. ํŠนํžˆ๋‚˜ JoinColumn์€ ํ‘œ์‹œํ•˜์ง€ ์•Š์•„๋„ JPA๊ฐ€ ์ž๋™์œผ๋กœ ํ•ด๋‹น ํ•„๋“œ(team)์— _ID๋ฅผ ๋ถ™์—ฌ์„œ ์ž๋™์œผ๋กœ ์ƒ์„ฑํ•ด ์ฃผ์ง€๋งŒ, ์‹ค๋ฌด์—์„œ๋Š” ๋ช…์‹œ์ ์œผ๋กœ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์„ ๊ถŒํ•œ๋‹ค.

์‹ค์ œ ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค๋ฅผ ํ†ตํ•ด์„œ ๊ฒ€ใ„ด์ฆํ•ด๋ณด์ž.

@RunWith(SpringRunner.class)
@SpringBootTest
@Rollback(false)
public class DemoApplicationTests {

    @Autowired
    private MemberRepository memberRepository;
    @Autowired
    private TeamRepository teamRepository;

    @Test
    public void save() {
        Team team = new Team();
        team.setName("AํŒ€");
        teamRepository.save(team); // team ์ €์žฅ

        Member member = new Member();
        member.setName("andrew");
        member.setAge(32L);
        member.setTeam(team); //member์˜ team setting
        memberRepository.save(member); //member ์ €์žฅ

        Optional<Member> optionalMember = memberRepository.findById(member.getId());

        //ํ…Œ์ŠคํŠธ ๊ฒ€์ฆ ์ฝ”๋“œ
        Assert.assertEquals(optionalMember.get().getTeam().getName(), "AํŒ€");
    }
}

๊ฐ๊ฐ Team๊ณผ Member๊ฐ€ ์ €์žฅ๋˜๊ณ , member.getTeam()๋ฅผ ํ†ตํ•ด์„œ ๊ฐ์ฒด ๊ทธ๋ž˜ํ”„ ํƒ์ƒ‰๊นŒ์ง€ ์ž˜ ๋˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์—ฐ๊ด€ ํฌ์ŠคํŠธ