Database

[JPA] JPA의 다양한 연관관계 매핑

로춘남 2023. 1. 19. 16:48
728x90

연관관계참조

다대일(@ManyToOne) [단방향, 양방향]
일대다(@OneToMany) [단방향, 양방향]
일대일(@OneToOne) [주 테이블 단방향, 양방향], [대상 테이블 양방향]
다대다(@ManyToMany) [단방향, 양방향]

다대일(@ManyToOne) - 단방향

member -> team

      @Entity
      public class Member {

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

        private String username;

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

         ....
      }
        @Entity
        public class Team {

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

          private String name;

           ...
       }
  • @Joincolumn을 사용해서 member team 필드를 teim_id 와 매핑. member.team 필드로 회원 테이블의 team_id 외래키를 관리한다.

다대일(@ManyToOne) - 양방향

member <-> team

       @Entity
        public class Team {

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

          private String name;

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

           ...
       }
  • 다대일 관계의 반대방향은 항상 일대다 , 일대다 관계의 반대방향은 항상 다대일 이다.
  • 양방향은 외래키가 있는 쪽이 연관관계의 주인이다.
  • 양방향 연관관계는 항상 서로를 참조해야 한다.
  • 양방향 연관관계에서 주인은 항상 다(N)쪽이다. member <- team
  • @OneToMany[1:N]
      @Entity
      public class Member {

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

        private String username;

        ...
      }
  • 일대다 관계는 자바 컬렉션 Collection, List, Set, Map 중에 하나를 사용 해야 한다.
  • 자신이 매핑한 테이블의 외래키가 아닌, 반대쪽 테이블에 있는 외래키를 관리한다.
  • 일대다 단방향 관계를 매핑 할떄는 @joincolumn을 명시 해야함 그렇지 않으면 연결테이블 중간에 두고 조인테이블 전략 기본으로 사용해서 매핑.
  • Member는 Team을 모른다. 연관관계 정보는 Team 엔티티의 mebers가 관리.
    • Member를 저장 할때는 Member 테이블의 TEAM_ID에 아무 값도 저장되지 않는다.
    • Team 엔티티를 저장할 때 Team.member의 참조 값을 확인해서 회원 테이블에 있는 TEAM_ID 외래키를 업데이트.

@OneToMany[1:N, N:1]

     @Entity
      public class Team {

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

        private String name;

        @OneToMany
        @JoinColumn(name = "TEAM_ID")
        private List<Member> members = new ArrayList<Member>();

         ...
     }
       @Entity
        public class Member {

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

          private String username;

          @ManyToOne
          @JoinColumn(name = "TEAM_ID", insertable = false, updatable = false)
          private Team team;

           ...
       }
  • 일대다 양방향 매핑은 존재 하지 않는다.(@OneToMany는 연관관계의 주인이 될수 없다.)
  • 일대다 양방향 = 일대다 단방향 + 다대일 단방향
  • 같은 키를 관리하므로 문제가 발생 할 수 있어 (insetable=false, updatable =false) 추가한다.(읽기 전용)

@OneToOne[1:1]

  1. 주 테이블에 외래키
  2. 대상 테이블에 외래키

1. 주 테이블에 외래 키(단방향)

Member -> Locker

      @Entity
      public class Member {

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

        private String username;

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

         ....
      }
    @Entity
    public class Locker {
      @Id @GeneratedValue
      @Column(name = "LOCKER_ID")
      private Long id;

      private String name;
      ...
    }

1.주 테이블에 외래키(양방향)

    @Entity
    public class Locker {
      @Id @GeneratedValue
      @Column(name = "LOCKER_ID")
      private Long id;

      private String name;

      @OneToOne(mappedBy = "locker")
      private Member member;
      ...
    }

2.대상 테이블에 외래키(양방향)

  @Entity
  public class Member {

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

    private String username;

    @OneToOne(mappedBy ="member")
    private Locker locker
    ....
  }
    @Entity
    public class Locker {
      @Id @GeneratedValue
      @Column(name = "LOCKER_ID")
      private Long id;

      private String name;

      @OneToOne
      @JoinColumn(name = "MEMBER_ID")
      private Member member;
      ...
   }
  • 일대일 관계는 그 반대도 일대일 관계다.
  • 일대일 관계는 주 테이블이나 대상 테이블 둘중 어느곳이나 외래키를 가질 수 있다.
  • 일대일 관계중 대상 테이블에 외래 키가 있는 단방향 관계는 JPA에서 지원하지 않는다.

@ManyToMany[N:N]

  • 정규화된 테이블 2개로 다대다 관계를 표현 할 수 없어서 연결 테이블을 사용.
  @Entity
  public class Member {

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

    private String username;

    @ManyToMany
    @JoinTable(name = "MEMBER_PRODUCT", joinColumns = @JoinColumn(name = "MEMBER_ID"),
               inverseJoinColumns = @JoinColumn(name = "PRODUCT_ID"))
    private List<Product> products = new ArrayList<Product>();

    ..   
  }
  @Entity
  public class Product {

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

    private String name;

    ..   
  }
  • 회원과 상품 엔티티를 @ManyToMany로 매핑.
  • @ManyToMany와 @JoinTable을 사용해서 연결 테이블을 바로 매핑.
  • @JoinTable(name : 연결테이블을 지정, joinColumns : 현재 방향인 회원과 매핑할 조인 컬럼 정보를 지정. inverseJoinColumns : 반대 방향인 상품과 매핑할 조인 컬럼 정보를 지정)
    @ManyToMany(fetch = FetchType.EAGER)
    @JoinTable(name = "mt_user_role", joinColumns = { @JoinColumn(name = "urid") }, inverseJoinColumns = @JoinColumn(name = "role_id"))
    private Set<Role> roles = new HashSet<Role>();
  public void save(){

    Product product = new Product();
    em.persist(product);

    Member member = new Member();   
    member.getProducts().add(product);
    em.persist(member);
  }
  insert into PRODUCT
  insert into MEMBER
  insert into MEMBER_PRODUCT
  @Entity
  public class Product {

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

   @ManyToMany(mappedBy = "products") //역방향 추가
   private List<Member> members;

    ..   
  }
  • @ManyToMany(연결 엔티티 필요)
  @Entity
  public class Product {

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

    private String name;

    ..   
  }
  @Entity
  @IdClass(MemberProductId.class)
  public class MemberProduct {

    @Id 
    @ManyToOne
    @JoinColumn(name = "MEMBER_ID")
    private Member member; //MemberProductId.member와 연결

    @Id
    @ManyToOne
    @JoinColumn(name = "PRODUCT_ID")
    private Product product; //MemberProductId.product와 연결

    private int orderAmount;

    ..   
  }

@ManyToMany(새로운 기본 키 사용)

  @Entity
  public class Order {

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

   @ManyToOne
   @JoinColumn(name = "MEMBER_ID")
   private Member member;

   @ManyToOne
   @JoinColumn(name = "PRODUCT_ID")
   private Product product;

   private int orderAmount;

   ...
 }
728x90