[java] JPA @OneToMany 연관 사용시 @JoinColumn과 MappingBy의 차이점

차이점은 무엇입니까?

@Entity
public class Company {

    @OneToMany(cascade = CascadeType.ALL , fetch = FetchType.LAZY)
    @JoinColumn(name = "companyIdRef", referencedColumnName = "companyId")
    private List<Branch> branches;
    ...
}

@Entity
public class Company {

    @OneToMany(cascade = CascadeType.ALL , fetch = FetchType.LAZY, mappedBy = "companyIdRef")
    private List<Branch> branches;
    ...
}



답변

주석은 @JoinColumn이 엔티티가 관계 의 소유자 임을 나타냅니다 (즉, 해당 테이블에 참조 된 테이블에 대한 외래 키가있는 열이 mappedBy있음 ). 반면이 특성 의 엔티티는 관계의 반대임을 나타냅니다. 소유자는 “기타”엔티티에 상주합니다. 이것은 또한 “mappedBy”(완전한 양방향 관계)로 주석이 달린 클래스에서 다른 테이블에 액세스 할 수 있음을 의미합니다.

특히 문제의 코드에서 올바른 주석은 다음과 같습니다.

@Entity
public class Company {
    @OneToMany(fetch = FetchType.LAZY, mappedBy = "company")
    private List<Branch> branches;
}

@Entity
public class Branch {
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "companyId")
    private Company company;
}


답변

@JoinColumn관계의 양쪽에 사용될 수 있습니다. 문제는 측면에서 사용 @JoinColumn하는 것에 관한 것이 었습니다 @OneToMany(드문 경우). 그리고 여기서 요점은 실제 정보 복제 (열 이름)와 일부 추가 UPDATE명령문 을 생성하는 최적화되지 않은 SQL 쿼리입니다 .

설명서 에 따르면 :

이후 하나 많은된다 (거의) 항상 오너 측 JPA에 사양의 쌍방향 관계가 많은 관계로 하나에 의해 주석된다@OneToMany(mappedBy=...)

@Entity
public class Troop {
    @OneToMany(mappedBy="troop")
    public Set<Soldier> getSoldiers() {
    ...
}

@Entity
public class Soldier {
    @ManyToOne
    @JoinColumn(name="troop_fk")
    public Troop getTroop() {
    ...
} 

TroopSoldier병력 속성 을 통해 양방향 일대 다 관계가 있습니다. mappedBy측면 에서 물리적 매핑을 정의 할 필요는 없습니다 .

으로, 많은에 양방향 하나를 매핑하려면 소유 측면으로 일대면 , 당신은 제거해야 할 mappedBy요소를 하나에 많은 설정 @JoinColumn으로 insertable하고 updatablefalse로. 이 솔루션은 최적화되지 않았으며 몇 가지 추가 UPDATE설명 이 생성됩니다 .

@Entity
public class Troop {
    @OneToMany
    @JoinColumn(name="troop_fk") //we need to duplicate the physical information
    public Set<Soldier> getSoldiers() {
    ...
}

@Entity
public class Soldier {
    @ManyToOne
    @JoinColumn(name="troop_fk", insertable=false, updatable=false)
    public Troop getTroop() {
    ...
}


답변

이것은 매우 일반적인 질문 이므로이 답변을 기반으로하는이 기사를 작성
했습니다.

단방향 일대 다 연결

이 기사 에서 설명했듯이 @OneToMany와 함께 주석 을 사용 하면 다음 다이어그램 @JoinColumn의 상위 Post엔터티와 하위 엔터티와 같은 단방향 연결이 있습니다 PostComment.

단방향 일대 다 연결

단방향 일대 다 연관을 사용하는 경우 상위 측만 연관을 맵핑합니다.

이 예에서는 Post엔터티 만 @OneToMany하위 PostComment엔터티에 대한 연결을 정의합니다 .

@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
@JoinColumn(name = "post_id")
private List<PostComment> comments = new ArrayList<>();

양방향 일대 다 연관

속성 세트 @OneToMany와 함께 with 를 사용하면 mappedBy양방향 연관이 있습니다. 이 경우 엔터티에는 다음 그림 과 같이 자식 엔터티 Post모음이 PostComment있고 자식 PostComment엔터티에는 부모 엔터티에 대한 참조가 있습니다 Post.

양방향 일대 다 연관

에서 PostComment엔티티는 post다음과 같이 개체 속성 매핑됩니다 :

@ManyToOne(fetch = FetchType.LAZY)
private Post post;

fetch속성을 명시 적으로 설정 한 이유는 FetchType.LAZY기본적으로 모든 연결 @ManyToOne@OneToOne연결을 열심히 가져 와서 N + 1 쿼리 문제를 일으킬 수 있기 때문입니다. 이 주제에 대한 자세한 내용은 이 기사를 확인 하십시오 .

에서 Post엔티티는 comments다음과 같이 연관 매핑된다 :

@OneToMany(
    mappedBy = "post",
    cascade = CascadeType.ALL,
    orphanRemoval = true
)
private List<PostComment> comments = new ArrayList<>();

mappedBy의 속성 @OneToMany주석을 참조합니다 post자식 재산 PostComment법인과이 방법은, Hibernate는 양방향 연관이에 의해 제어되는 것을 알고 @ManyToOne이 테이블 관계에 기반으로하는 외래 키 컬럼 값을 관리하는 담당 측면.

양방향 연결을 위해서는 addChildand와 같은 두 가지 유틸리티 방법이 필요합니다 removeChild.

public void addComment(PostComment comment) {
    comments.add(comment);
    comment.setPost(this);
}

public void removeComment(PostComment comment) {
    comments.remove(comment);
    comment.setPost(null);
}

이 두 가지 방법은 양방향 연결의 양쪽이 동기화되지 않도록합니다. 양쪽 끝을 동기화하지 않으면 Hibernate는 연결 상태 변경이 데이터베이스로 전파 될 것이라고 보장하지 않습니다.

JPA 및 Hibernate와 양방향 연관을 동기화하는 최상의 방법에 대한 자세한 내용은 이 기사를 확인 하십시오 .

어느 것을 선택해야합니까?

단방향 @OneToMany협회는 매우 잘 수행하지 않습니다 당신이 그것을 피해야한다, 그래서.

보다 효율적인 양방향 @OneToMany 사용하는 것이 좋습니다 .


답변

맵핑 된 주석은 이상적으로 항상 양방향 관계의 상위 측 (회사 클래스)에서 사용되어야하며,이 경우 하위 클래스의 멤버 변수 ‘회사'(브랜치 클래스)를 가리키는 회사 클래스에 있어야합니다.

@JoinColumn 어노테이션 은 엔티티 연관을 결합하기 위해 맵핑 된 열을 지정하는 데 사용 되며이 어노테이션은 모든 클래스 (Parent 또는 Child)에서 사용할 수 있지만 한쪽에서만 (부모 클래스 또는 Child 클래스가 아닌) 이상적으로 사용되어야합니다. 두 경우 모두)이 경우에는 Branch 클래스의 외래 키를 나타내는 양방향 관계의 자식 측 (지점 클래스)에서 사용했습니다.

아래는 작업 예입니다.

부모 클래스, 회사

@Entity
public class Company {


    private int companyId;
    private String companyName;
    private List<Branch> branches;

    @Id
    @GeneratedValue
    @Column(name="COMPANY_ID")
    public int getCompanyId() {
        return companyId;
    }

    public void setCompanyId(int companyId) {
        this.companyId = companyId;
    }

    @Column(name="COMPANY_NAME")
    public String getCompanyName() {
        return companyName;
    }

    public void setCompanyName(String companyName) {
        this.companyName = companyName;
    }

    @OneToMany(fetch=FetchType.LAZY,cascade=CascadeType.ALL,mappedBy="company")
    public List<Branch> getBranches() {
        return branches;
    }

    public void setBranches(List<Branch> branches) {
        this.branches = branches;
    }


}

어린이 교실, 지사

@Entity
public class Branch {

    private int branchId;
    private String branchName;
    private Company company;

    @Id
    @GeneratedValue
    @Column(name="BRANCH_ID")
    public int getBranchId() {
        return branchId;
    }

    public void setBranchId(int branchId) {
        this.branchId = branchId;
    }

    @Column(name="BRANCH_NAME")
    public String getBranchName() {
        return branchName;
    }

    public void setBranchName(String branchName) {
        this.branchName = branchName;
    }

    @ManyToOne(fetch=FetchType.LAZY)
    @JoinColumn(name="COMPANY_ID")
    public Company getCompany() {
        return company;
    }

    public void setCompany(Company company) {
        this.company = company;
    }


}


답변

답변이 제안하는 것처럼 @JoinColumn항상 물리적 정보 위치 와 관련이있을 필요는 없다는 것을 추가하고 싶습니다 . 당신은 결합 할 수 있습니다 와 부모 테이블 자식 테이블을 가리키는에는 테이블 데이터가없는 경우에도 마찬가지입니다.@JoinColumn@OneToMany

JPA에서 단방향 OneToMany 관계를 정의하는 방법

단방향 OneToMany, 반대 ManyToOne, 조인 테이블 없음

JPA 2.x+그래도 사용할 수있는 것 같습니다 . 자식 클래스에 참조의 전체가 아닌 부모의 ID 만 포함시키려는 상황에 유용합니다.


답변

나는 Óscar López의 대답에 동의하지 않습니다. 그 대답은 정확하지 않습니다!

@JoinColumn이 엔티티가 관계의 소유자임을 나타내는 것은 아닙니다 . 대신 @ManyToOne(이 예제에서)이 작업을 수행 하는 주석입니다.

의 관계는 다음과 같은 주석을 @ManyToOne, @OneToMany그리고 @ManyToMany할 JPA / 최대 절전 모드를 말할 매핑을 만듭니다. 기본적으로이 작업은 별도의 조인 테이블을 통해 수행됩니다.

@JoinColumn

조인 열 이 아직없는 경우 @JoinColumn이를 만드는 것이 목적입니다 . 그렇다면이 주석을 사용 하여 조인 열의 이름을 지정할 수 있습니다
.

매핑

MappedBy매개 변수 의 목적은 JPA에 지시 하는 것입니다 . 관계가이 관계 의 반대 엔티티에 의해 이미 맵핑되고 있으므로 다른 결합 테이블을 작성하지 마십시오 .

기억하십시오 : MappedBy기본적으로 조인 테이블을 작성하여 수행하는 두 엔티티를 연관시키는 메커니즘을 생성하는 것이 목적인 관계 주석의 특성입니다. MappedBy해당 프로세스를 한 방향으로 중지합니다.

외래 키 필드에 대한 세 가지 매핑 주석 중 하나를 사용하여 매핑의 메커니즘이 클래스 내에서 지시되기 때문에 사용하지 않는 엔터티 는 관계 MappedBy소유자 라고 합니다. 이는 맵핑의 특성을 지정할뿐만 아니라 결합 테이블 작성을 지시합니다. 또한 조인 테이블을 억제하는 옵션은 외래 키에 @JoinColumn 주석을 적용하여 소유자 엔터티의 테이블 내에 대신 유지함으로써도 존재합니다.

요약하면 : @JoinColumn새 조인 열을 만들거나 기존 열의 이름을 바꿉니다. 이 MappedBy매개 변수는 조인 테이블을 통해 또는 소유자 엔티티의 연관된 테이블에 외래 키 열을 작성하여 맵핑을 작성하기 위해 다른 (하위) 클래스의 관계 주석과 협력하여 작동합니다.

MapppedBy작동 방식 을 설명하려면 아래 코드를 고려하십시오. 경우 MappedBy매개 변수를 삭제했다, 다음 최대 절전 모드가 실제로 만들 것 두 테이블을 조인! 왜? 다 대다 관계에는 대칭이 있기 때문에 Hibernate는 한 방향을 다른 방향으로 선택하는 데 대한 근거가 없습니다.

그러므로 MappedBy우리는 Hibernate에게 말하기 위해 사용 한다. 우리는 다른 엔티티를 선택 하여 두 엔티티 사이의 관계의 맵핑을 지시했다.

@Entity
public class Driver {
    @ManyToMany(mappedBy = "drivers")
    private List<Cars> cars;
}

@Entity
public class Cars {
    @ManyToMany
    private List<Drivers> drivers;
}

소유자 클래스에 @JoinColumn (name = “driverID”)을 추가하면 (아래 참조) 조인 테이블을 만들지 않고 대신 Cars 테이블에 driverID 외래 키 열을 만들어 매핑을 구성합니다.

@Entity
public class Driver {
    @ManyToMany(mappedBy = "drivers")
    private List<Cars> cars;
}

@Entity
public class Cars {
    @ManyToMany
    @JoinColumn(name = "driverID")
    private List<Drivers> drivers;
}


답변

JPA는 계층화 된 API이며 다른 수준에는 자체 주석이 있습니다. 최상위 레벨은 (1) 지속성 클래스를 설명하는 엔티티 레벨이며, 엔티티가 관계형 데이터베이스 및 (3) Java 모델로 맵핑되는 것으로 가정하는 (2) 관계형 데이터베이스 레벨이 있습니다.

레벨 1 주석 : @Entity, @Id, @OneToOne, @OneToMany, @ManyToOne, @ManyToMany. 이러한 고급 주석 만 사용하여 애플리케이션에 지속성을 도입 할 수 있습니다. 그러나 JPA의 가정에 따라 데이터베이스를 작성해야합니다. 이러한 주석은 엔티티 / 관계 모델을 지정합니다.

레벨 2 주석 : @Table, @Column, @JoinColumn, … 관계형 데이터베이스 테이블에 엔티티 / 속성의 매핑에 영향을 / 당신은 JPA의 기본값에 만족하지 않거나 기존 데이터베이스에 매핑해야하는 경우 경우 열. 이러한 주석은 구현 주석으로 볼 수 있으며 매핑 수행 방법을 지정합니다.

제 생각에는 가능한 한 높은 수준의 주석에 충실한 다음 필요에 따라 낮은 수준의 주석을 도입하는 것이 가장 좋습니다.

질문에 대답하려면 : @OneToMany/ mappedBy는 엔티티 도메인의 주석 만 사용하므로 가장 좋습니다. @oneToMany/는 @JoinColumn또한 미세하지만 이것이 꼭 필요한 것은 구현 주석을 사용합니다.