연관관계 매핑

김성인·2023년 9월 27일
0

🧷SpringBoot JPA

목록 보기
9/10

1) 단방향 연관관계

1-1) N : 1 (다대일)

연관관계의 주인만 (외래키를 가지는) 대상 엔티티를 바라 볼 수 있음.
객체에서 양방향 관계를 맺고 싶으면 두 엔티티 클래스에 서로의 객체 필드를 삽입해야한다.

  • 객체 : 필드 참조를 통해 연관관계 맺음(클래스 Id)
  • 테이블 : 외래키를 통해 연관관계를 맺음

객체 참조를 통해 객체 그래프 형태를 가질 수 있다..!

1-2) 객체 관계 매핑

@ManyToOne

다대일(N:1) 관계 매핑 어노테이션

  • optional : false | true , 엔티티 존재 여부 확인
  • fetch : 페치 전략 설정 (Lazy/ Eager 로딩)
  • cascade : 영속성 설정
  • targetEntity : 연관된 엔티티의 타입정보 설정 -> Generic으로 대체 가능
// 둘 다 동등
@OneToMany
private List<EntityClass> entities;

@OneToMany(targetEntity=EntityClass.class)
private List entities;

@JoinColumn

외래키 매핑 어노테이션 : 참조하는 객체 필드 위에 명시

  • name : 매핑할 외래키 이름
  • referencedColumnName : 외래키가 참조하는 대상 테이블 칼럼명 (default: 참조하는 테이블 기본키 칼럼 명)
  • foreignKey : 외래키 제약 조건 직접 지정 (DDL 조건)
  • unique, nullable, insertable, updatable, columnDefinition, table
    생략 시 : 필드명_참조 테이블의 칼럼명
@ManyToOne
@JoinColumn(name = "참조 객체 필드의 기본키 칼럼 명")

1-3) 다대일 사용

JPA 에서 엔티티를 연관관계를 통해 저장할 시 모든 연관된 엔티티는 영속상태를 유지하여야함.

  • JPA가 참조한 객체 필드의 식별자를 외래키로 사용하여 등록 쿼리를 생성함.
  • 객체 그래프를 통한 엔티티 객체 직접 참조
  • JPQL 사용
    String jpql = "select m from Entity m join m.ForeginEntity t where t.id= :ForeignKey"
    EntityManager.createQuery(jpql, Entity.calss).setParameter( "ForeignKey" , "값");

영속성 컨텍스트내에 존재하는 엔티티들은 연관관계 설정 시 변경감지를 엔티티 매니저에서 자동으로 해줌.

1-4) 연관관계 삭제

  • 연관관계를 맺는 참조 객체 필드를 null로 변경한 후, 영속성 컨텍스트에서 참조한 외래 엔티티를 제거해줘야함.
  • 외래키 제약 조건을 지켜야하기 때문

2) 양방향 연관관계

외래키를 가지는 엔티티 뿐만이 아니라 외래키의 대상이 되는 엔티티도 반대편을 바라볼 수 있는 연관관계
(두 단방향이 서로 바라보는)

테이블은 외래키 하나를 통해 서로 양방향으로 바라 볼 수 있지만, 객체는 그렇지 않다.

2-1) 객체 관계 매핑

@OneToMany

@Entity
public class EntityClass{
	@Id
    private Long id;
    
    @ManyToOne
    @JoinColumn(name="foriegn_id") //참조 외래키
    private Foreign foreign; // 참조 필드명
}
// JoinColumn 미설정시 : foreign(필드명)_foreign_id(조인 엔티티 대상 Id칼럼명) 형태로 외래키 칼럼명 이용

@Entity
public class Foreign{
	@Id
    @ColumnName(name="foreign_id") // 참조 외래키
    private Long id;
    
    @OneToMany(mappedBy="foreign") // 참조 필드명
    private List<EntityClass> entities = new ArrayList<entityClass>();
}
  • mappedBy : 양방향 매핑에서 참조 당하는 엔티티 클래스에 명시해 줌(조인을 당하는)
    -> 외래키가 하나이지만, 객체 참조가 둘 인 상황을 해결하기 위함.
    -> 외래키를 관리하는 주체를 결정하기위해 해당 옵션을 사용.
    주체가 아닌 칼럼 @OneToMany에 보통 옵션을 붙여서 주로 사용된다.
  • JPA 에서 연관관계를 맺을 떄 외래키를 관리하는 주체는 테이블을 따라가면 된다고 생각하게 된다.
  • 외래키를 가지는 테이블은 참조를 하는 테이블이 되니 해당 엔티티는 다(N)이 되고, 참조를 당하는 테이블은 일(1)의 연관관계를 가지면 된다.
    @ManyToOne - 다대일 (FK를 가지는 엔티티)
    @OneToMany - 일대다 (mapped by = "상대 엔티티 클래스 필드") -> 본인의 ID가 다른 엔티티에서 FK로 사용될 때

2-2) 영속성 컨텍스트

@ManyToOne

다 쪽을 맡은 엔티티에 연관관계를 설정해야 영속성 컨텍스트에 반영됨.
연관관계 설정 전 FK를 가지는 대상 엔티티는 영속성 컨텍스트에 반드시 포함되어 있어야한다.

@OneToMany

참조를 당하는 엔티티에 아무리 값을 변경하여도 영속성 컨텍스트와 DB에 반영되지 않음.

// 1) 잘못된 경우
EntityClass ec1 = new EntityClass(1);
EntityManager.persist(ec1);

Foreign f1 = new Foreign(1);
f1.getEntities().add(ec1);  

EntityManger.persist(f1);
// 영속성 컨텍스트에 아무런 영향도 주지 않음.
// 외래키를 관리하는 주체가 아니기 때문
// 2) 올바른 경우
Foreign f1 = new Foreign(1);
EntityMaanger.persist(f1); // 조인될 (참조될) 엔티티를 먼저 영속성 컨텍스트에 유지

EntityClass ec1 = new EntityClass(1); // 해당 엔티티를 참조하는 다(N) 엔티티를 생성 후
ec1.setForeign(f1); // 연관관계 설정

EntityManager.persist(ec1);

2-3) 객체 관점

영속성 컨텍스트 뿐만 아니라, 객체 관점에서도 서로 간의 양방향 연관관계를 이어줄 필요가 있다.

  • 영속성 컨텍스트에 연관관계를 매핑하여도, 트랜젝션 커밋을 통해 DB에 반영하기 전까지,
  • 현재 일(참조되는)인 엔티티는 다(N)인 엔티티를 바라보지 못한다.
  • 그래서 일(1)인 엔티티에서 다(N)를 조회해도 결과가 나타나지 않기 때문에, 객체 관점에서는 영속성 컨텍스트에 등록함과 동시에 객체 컬렉션 참조도 같이 진행해주는 것이 올바르다.

Setter 를 통해서 객체 관점에서 연관관계를 만들어주는 메서드 구현, 이때 무한루프가 발생하지 않도록 주의해야함.


나캐싱 기능이 있어도, DB 액세스 접근을 늘어나겠지만 트랜잭션을 미리 한 다음
일대다인 엔티티에서 다(N)를 조회하여 DB에 저장된 연관관계를 통해서 데이터에 접근하는게 더 나을것 같다고 생각이 든다..

공부를 하면서 좀 더 구현을 하며 바라봐야겟다.

0개의 댓글