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

后端 未结 8 2154
日久生厌
日久生厌 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: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 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 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.

提交回复
热议问题