有什么区别:

@Entity
public class Company {

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

and

@Entity
public class Company {

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

当前回答

单向一对多关联

如果你使用@OneToMany注释和@JoinColumn,那么你就有一个单向的关联,就像下图中父Post实体和子PostComment之间的关联一样:

当使用单向一对多关联时,只有父端映射该关联。

在这个例子中,只有Post实体定义了与子PostComment实体的@OneToMany关联:

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

双向一对多关联

如果您使用带有mappedBy属性集的@OneToMany,那么您就有了一个双向关联。在我们的例子中,Post实体都有一个PostComment子实体的集合,并且子PostComment实体有一个指向父Post实体的引用,如下图所示:

在PostComment实体中,post实体属性映射如下:

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

我们显式地将fetch属性设置为FetchType的原因。LAZY是因为默认情况下,所有的@ManyToOne和@OneToOne关联都是急切获取的,这可能会导致N+1个查询问题。

在Post实体中,评论关联映射如下:

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

@OneToMany注释的mappedBy属性引用子PostComment实体中的post属性,通过这种方式,Hibernate知道双向关联是由@ManyToOne控制的,它负责管理这个表关系所基于的外键列值。

对于双向关联,你还需要有两个实用工具方法,比如addChild和removecchild:

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

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

这两种方法确保双向关联的双方是同步的。如果两端不同步,Hibernate不能保证关联状态更改会传播到数据库。

选择哪一个?

单向的@OneToMany关联性能不太好,所以应该避免使用它。

您最好使用更有效的双向@OneToMany。

其他回答

注释@JoinColumn表示该实体是关系的所有者(也就是说:对应的表有一个指向引用表的外键的列),而属性mappedBy表示这一侧的实体是关系的逆,所有者位于“另一个”实体中。这也意味着您可以从用“mappedBy”注释的类中访问另一个表(完全双向关系)。

特别是,对于问题中的代码,正确的注释应该是这样的:

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

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

@JoinColumn可以在关系的双方使用。问题是关于在@OneToMany端使用@JoinColumn(罕见情况)。这里的重点是物理信息复制(列名)以及未优化的SQL查询,这将产生一些额外的UPDATE语句。

根据文件:

由于在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() {
    ...
} 

部队通过部队属性与士兵产生双向多的关系。您不必(一定不)在mappedBy端中定义任何物理映射。

要将一个双向的1映射到多,将一对多的端映射为所属端,您必须删除mappedBy元素,并将多对一的@JoinColumn设置为可插入的,并将可更新的设置为false。此解决方案未经过优化,将产生一些额外的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() {
    ...
}

mappedBy注释理想情况下应该总是在双向关系的父端(Company类)中使用,在这种情况下,它应该在Company类中指向子类(分支类)的成员变量' Company '

注释@JoinColumn用于指定加入实体关联的映射列,这个注释可以在任何类(父类或子类)中使用,但理想情况下,它应该只用于一方(无论是在父类或在子类中,而不是在两者中)在这种情况下,我在双向关系的子方面(分支类)中使用它,指示分支类中的外键。

下面是工作示例:

母公司,公司

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


}

JPA是一个分层的API,不同的级别有自己的注释。最高级别是(1)实体级别,它描述持久类,然后是(2)关系数据库级别,它假设实体映射到关系数据库,以及(3)java模型。

一级注释:@Entity, @Id, @OneToOne, @OneToMany, @ManyToOne, @ManyToMany。 仅使用这些高级注释就可以在应用程序中引入持久性。但是您必须根据JPA所做的假设来创建数据库。这些注释指定了实体/关系模型。

二级注释:@Table, @Column, @JoinColumn,… 如果您对JPA的默认值不满意,或者需要映射到现有数据库,则影响从实体/属性到关系数据库表/列的映射。这些注释可以被看作是实现注释,它们指定了映射应该如何完成。

在我看来,最好是尽可能多地使用高级注释,然后根据需要引入低级注释。

要回答这些问题:@OneToMany/mappedBy是最好的,因为它只使用来自实体域的注释。@oneToMany/@JoinColumn也很好,但它使用了一个实现注释,这并不是严格必要的。

单向一对多关联

如果你使用@OneToMany注释和@JoinColumn,那么你就有一个单向的关联,就像下图中父Post实体和子PostComment之间的关联一样:

当使用单向一对多关联时,只有父端映射该关联。

在这个例子中,只有Post实体定义了与子PostComment实体的@OneToMany关联:

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

双向一对多关联

如果您使用带有mappedBy属性集的@OneToMany,那么您就有了一个双向关联。在我们的例子中,Post实体都有一个PostComment子实体的集合,并且子PostComment实体有一个指向父Post实体的引用,如下图所示:

在PostComment实体中,post实体属性映射如下:

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

我们显式地将fetch属性设置为FetchType的原因。LAZY是因为默认情况下,所有的@ManyToOne和@OneToOne关联都是急切获取的,这可能会导致N+1个查询问题。

在Post实体中,评论关联映射如下:

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

@OneToMany注释的mappedBy属性引用子PostComment实体中的post属性,通过这种方式,Hibernate知道双向关联是由@ManyToOne控制的,它负责管理这个表关系所基于的外键列值。

对于双向关联,你还需要有两个实用工具方法,比如addChild和removecchild:

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

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

这两种方法确保双向关联的双方是同步的。如果两端不同步,Hibernate不能保证关联状态更改会传播到数据库。

选择哪一个?

单向的@OneToMany关联性能不太好,所以应该避免使用它。

您最好使用更有效的双向@OneToMany。