Home > Backend Development > ๐Ÿ“š[Backend Development] @OneToMany๋ž€ ๋ฌด์—‡์ผ๊นŒ์š”?

๐Ÿ“š[Backend Development] @OneToMany๋ž€ ๋ฌด์—‡์ผ๊นŒ์š”?
Backend Ddevelopment

โ€œ๐Ÿ“š[Backend Development] @OneToMany๋ž€ ๋ฌด์—‡์ผ๊นŒ์š”?โ€

๐ŸŽ Intro.

  • @OneToMany๋Š” ์ผ๋Œ€๋‹ค(1:N) ๊ด€๊ณ„๋ฅผ ๋งคํ•‘ํ•  ๋•Œ ์‚ฌ์šฉํ•˜๋Š” ์–ด๋…ธํ…Œ์ด์…˜์ž…๋‹ˆ๋‹ค.
  • ์ฆ‰, ํ•˜๋‚˜(One)์˜ ์—”ํ‹ฐํ‹ฐ๊ฐ€ ์—ฌ๋Ÿฌ ๊ฐœ(Many)์˜ ์—”ํ‹ฐํ‹ฐ๋ฅผ ์ฐธ์กฐํ•˜๋Š” ๊ตฌ์กฐ์ž…๋‹ˆ๋‹ค.

โœ…1๏ธโƒฃ @OneToMany ์˜ˆ์ œ.

  • ๊ฒŒ์‹œ๊ธ€(Article)๊ณผ ๋Œ“๊ธ€(Comment) ๊ด€๊ณ„๋ฅผ ์˜ˆ๋กœ ๋“ค์–ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.
  • ํ•˜๋‚˜์˜ ๊ฒŒ์‹œ๊ธ€(Article)์—๋Š” ์—ฌ๋Ÿฌ ๊ฐœ์˜ ๋Œ“๊ธ€(Comment)์ด ๋‹ฌ๋ฆด ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

1๏ธโƒฃ Article ์—”ํ‹ฐํ‹ฐ(๊ฒŒ์‹œ๊ธ€)

@Entity
public class Article {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    private String title;
    private String content;
    
    @OneToMany(mappedBy = "article") // Comment ์—”ํ‹ฐํ‹ฐ์˜ article ํ•„๋“œ๊ฐ€ ๊ด€๊ณ„์˜ ์ฃผ์ธ
    private List<Comment> comments = new ArrayList<>();
    
    // Getter, Setter
}

2๏ธโƒฃ Comment ์—”ํ‹ฐํ‹ฐ(๋Œ“๊ธ€)

@Entity
public class Comment {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    private String content;
    
    @ManyToOne
    @JoinColumn(name = "article_id") // comment ํ…Œ์ด๋ธ”์— article_id FK ์ƒ์„ฑ
    private Article article;
    
    // Getter, Setter
}

โœ…2๏ธโƒฃ @OneToMany(mappedBy = โ€œarticleโ€)์˜ ์˜๋ฏธ

  • Comment ์—”ํ‹ฐํ‹ฐ์˜ article ํ•„๋“œ๋ฅผ ์ฐธ์กฐํ•˜์—ฌ ์–‘๋ฐฉํ–ฅ ๊ด€๊ณ„๋ฅผ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.
  • ์™ธ๋ž˜ ํ‚ค๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ์ฃผ์ธ์€ Comment.article ํ•„๋“œ์ด๋ฉฐ, Article ์—”ํ‹ฐํ‹ฐ๋Š” mappedBy๋ฅผ ํ†ตํ•ด ์ฝ๊ธฐ ์ „์šฉ์ž…๋‹ˆ๋‹ค.
  • ์ฆ‰, Comment ์—”ํ‹ฐํ‹ฐ๊ฐ€ ๊ด€๊ณ„์˜ ์ฃผ์ธ์ด๊ณ , Article ์—”ํ‹ฐํ‹ฐ์—์„œ๋Š” ์ง์ ‘ FK๋ฅผ ๊ด€๋ฆฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. (โžž @JoinColumn์ด Comment ์ชฝ์—๋งŒ ์žˆ๋Š” ์ด์œ )

โœ…3๏ธโƒฃ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ํ…Œ์ด๋ธ” ๊ตฌ์กฐ.

  • ์œ„ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•˜๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ํ…Œ์ด๋ธ”์ด ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค.

๐Ÿ“Œ article ํ…Œ์ด๋ธ” (๊ฒŒ์‹œ๊ธ€)

id title content
1 โ€œHello JPAโ€ โ€œJPA ๋ฐฐ์šฐ๊ธฐโ€
2 โ€œSpring Bootโ€ โ€œSpring ๊ณต๋ถ€โ€

๐Ÿ“Œ comment ํ…Œ์ด๋ธ” (๊ฒŒ์‹œ๊ธ€์— ์—ฐ๊ฒฐ๋œ ๋Œ“๊ธ€, article_id FK ํฌํ•จ)

id content article_id(FK)
1 โ€œ์ข‹์€ ๊ธ€์ด๋„ค์š”!โ€ 1
2 โ€œ์œ ์ตํ•œ ์ •๋ณด ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค.โ€ 1
3 โ€œSpring ์ตœ๊ณ !โ€ 2
  • ๐Ÿ“Œ article_id ์ปฌ๋Ÿผ์ด ๊ฒŒ์‹œ๊ธ€(Article)์„ ์ฐธ์กฐํ•˜๋Š” ์™ธ๋ž˜ ํ‚ค(FK)์ž…๋‹ˆ๋‹ค.
    • ์ฆ‰, ํ•˜๋‚˜์˜ Article์—๋Š” ์—ฌ๋Ÿฌ ๊ฐœ์˜ Comment๊ฐ€ ์—ฐ๊ฒฐ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

โœ…4๏ธโƒฃ ๋ฐ์ดํ„ฐ ์กฐํšŒ.

โœ… ํŠน์ • ๊ฒŒ์‹œ๊ธ€์— ์†ํ•œ ๋Œ“๊ธ€ ๊ฐ€์ ธ์˜ค๊ธฐ.

  • ์–‘๋ฐฉํ–ฅ ๊ด€๊ณ„๊ฐ€ ์„ค์ •๋˜์–ด ์žˆ์œผ๋ฏ€๋กœ, ํŠน์ • ๊ฒŒ์‹œ๊ธ€์— ๋‹ฌ๋ฆฐ ๋Œ“๊ธ€์„ ์‰ฝ๊ฒŒ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
Article article = entityManager.find(Article.class, 1L);
List<Comment> comments = article.getComments(); // ํ•ด๋‹น ๊ฒŒ์‹œ๊ธ€์˜ ๋ชจ๋“  ๋Œ“๊ธ€ ๊ฐ€์ ธ์˜ค๊ธฐ

๐Ÿš€5๏ธโƒฃ ๋‹จ๋ฐฉํ–ฅ @OneToMany vs ์–‘๋ฐฉํ–ฅ @OneToMany

1๏ธโƒฃ ๋‹จ๋ฐฉํ–ฅ @OneToMany

@Entity
public class Article {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    private String title;
    private String content;
    
    @OneToMany
    @JoinColumn(name = "article_id") // FK๋ฅผ ์ง์ ‘ ๊ด€๋ฆฌ (์ฃผ์ธ ์—ญํ• )
    private List<Comment> comments = new ArrayList<>();
    
    // Getter, Setter
}

โœ… ์žฅ์ .

  • ๋‹จ์ˆœํ•œ ๊ตฌ์กฐ.
  • ๋ถˆํ•„์š”ํ•œ mappedBy ์—†์ด @JoinColumn์„ ํ†ตํ•ด FK ์ง์ ‘ ๊ด€๋ฆฌ ๊ฐ€๋Šฅ

โŒ ๋‹จ์ .

  • ๋ฐ์ดํ„ฐ ์‚ฝ์ž… ์‹œ ์ถ”๊ฐ€์ ์ธ SQL ์‹คํ–‰ ๋ฐœ์ƒ
  • @OneToMany ๋‹จ๋ฐฉํ–ฅ ๊ด€๊ณ„์—์„œ @JoinColumn์„ ์‚ฌ์šฉํ•˜๋ฉด INSERT ์ฟผ๋ฆฌ๊ฐ€ ๋‘ ๋ฒˆ ์‹คํ–‰๋จ (โžž ๋Œ“๊ธ€ ์‚ฝ์ž… ํ›„, ๊ฒŒ์‹œ๊ธ€ ID ์—…๋ฐ์ดํŠธ)

2๏ธโƒฃ ์–‘๋ฐฉํ–ฅ @OneToMany + @ManyToOne

@Entity
public class Article {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    private String title;
    private String content;
    
    @OneToMany(mappedBy = "article") // Comment์˜ article ํ•„๋“œ๋ฅผ ์ฃผ์ธ์œผ๋กœ ์„ค์ •
    private List<Comment> comments = new ArrayList<>();
    
    // Getter, Setter
}

โœ… ์žฅ์ .

  • ์„ฑ๋Šฅ ์ตœ์ ํ™” ๊ฐ€๋Šฅ (FK๋Š” Comment.article์ด ๊ด€๋ฆฌ).
  • INSERT ์ฟผ๋ฆฌ ์‹คํ–‰์ด ํ•œ ๋ฒˆ๋งŒ ๋ฐœ์ƒ.
  • ๊ฐ์ฒด ๊ทธ๋ž˜ํ”„ ํƒ์ƒ‰์ด ํŽธ๋ฆฌํ•จ (article.getComments() ๊ฐ€๋Šฅ).

โŒ ๋‹จ์ 

  • mappedBy๋กœ ์ธํ•ด ๋ฐ์ดํ„ฐ ์ €์žฅ์ด Comment ์ชฝ์—์„œ ์ด๋ฃจ์–ด์ ธ์•ผ ํ•จ.

โœ…6๏ธโƒฃ ์ •๋ฆฌ

  • โœ”๏ธ @OneToMany๋Š” ํ•˜๋‚˜(One)์˜ ์—”ํ‹ฐํ‹ฐ๊ฐ€ ์—ฌ๋Ÿฌ ๊ฐœ(Many)์˜ ์—”ํ‹ฐํ‹ฐ๋ฅผ ์ฐธ์กฐํ•  ๋•Œ ์‚ฌ์šฉ.
  • โœ”๏ธ ์–‘๋ฐฉํ–ฅ ๊ด€๊ณ„์—์„œ๋Š” @OneToMany(mappedBy = โ€œํ•„๋“œ๋ช…โ€) + @ManyToOne ์กฐํ•ฉ ์‚ฌ์šฉ
  • โœ”๏ธ ๋‹จ๋ฐฉํ–ฅ @OneToMany๋ณด๋‹ค๋Š” ์–‘๋ฐฉํ–ฅ์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ผ๋ฐ˜์ 
  • โœ”๏ธ ์™ธ๋ž˜ ํ‚ค(FK)๋Š” @ManyToOne ์ชฝ์—์„œ ๊ด€๋ฆฌํ•˜๋ฉฐ, @OneToMany๋Š” ์ฝ๊ธฐ ์ „์šฉ
  • ๐Ÿ“Œ ๊ฒŒ์‹œ๊ธ€-๋Œ“๊ธ€ ๊ด€๊ณ„์ฒ˜๋Ÿผ 1:N ๊ด€๊ณ„๊ฐ€ ํ•„์š”ํ•  ๋•Œ @OneToMany๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.