What's the difference between @JoinColumn and mappedBy when using a JPA @OneToMany association

后端 未结 8 1933
日久生厌
日久生厌 2020-11-22 02:35

What is the difference between:

@Entity
public class Company {

    @OneToMany(cascade = CascadeType.ALL , fetch = FetchType.LAZY)
    @JoinColumn(name = \"c         


        
相关标签:
8条回答
  • 2020-11-22 03:06

    The annotation mappedBy ideally should always be used in the Parent side (Company class) of the bi directional relationship, in this case it should be in Company class pointing to the member variable 'company' of the Child class (Branch class)

    The annotation @JoinColumn is used to specify a mapped column for joining an entity association, this annotation can be used in any class (Parent or Child) but it should ideally be used only in one side (either in parent class or in Child class not in both) here in this case i used it in the Child side (Branch class) of the bi directional relationship indicating the foreign key in the Branch class.

    below is the working example :

    parent class , Company

    @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;
        }
    
    
    }
    

    child class, Branch

    @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;
        }
    
    
    }
    
    0 讨论(0)
  • 2020-11-22 03:07

    Since this is a very common question, I wrote this article, on which this answer is based on.

    Unidirectional one-to-many association

    As I explained in this article, if you use the @OneToMany annotation with @JoinColumn, then you have a unidirectional association, like the one between the parent Post entity and the child PostComment in the following diagram:

    When using a unidirectional one-to-many association, only the parent side maps the association.

    In this example, only the Post entity will define a @OneToMany association to the child PostComment entity:

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

    Bidirectional one-to-many association

    If you use the @OneToMany with the mappedBy attribute set, you have a bidirectional association. In our case, both the Post entity has a collection of PostComment child entities, and the child PostComment entity has a reference back to the parent Post entity, as illustrated by the following diagram:

    In the PostComment entity, the post entity property is mapped as follows:

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

    The reason we explicitly set the fetch attribute to FetchType.LAZY is because, by default, all @ManyToOne and @OneToOne associations are fetched eagerly, which can cause N+1 query issues. For more details about this topic, check out this article.

    In the Post entity, the comments association is mapped as follows:

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

    The mappedBy attribute of the @OneToMany annotation references the post property in the child PostComment entity, and, this way, Hibernate knows that the bidirectional association is controlled by the @ManyToOne side, which is in charge of managing the Foreign Key column value this table relationship is based on.

    For a bidirectional association, you also need to have two utility methods, like addChild and removeChild:

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

    These two methods ensure that both sides of the bidirectional association are un sync. Without synchronizing both ends, Hibernate does not guarantee that association state changes will propagate to the database.

    For more details about the best wat to synchronize bidirectional associations with JPA and Hibernate, check out this article.

    Which one to choose?

    The unidirectional @OneToMany association does not perform very well, so you should avoid it.

    You are better off using the bidirectional @OneToMany which is more efficient.

    0 讨论(0)
提交回复
热议问题