有什么区别:

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

当前回答

@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() {
    ...
}

其他回答

我只是想补充一下,@JoinColumn并不总是像这个答案所暗示的那样与物理信息位置相关。即使父表中没有指向子表的表数据,也可以将@JoinColumn与@OneToMany组合在一起。

如何在JPA中定义单向的OneToMany关系

单向多对多,无反向多对一,无连接表

它似乎只在JPA 2中可用。尽管x +。当您希望子类只包含父类的ID,而不是完整的on引用时,这是非常有用的。

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

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

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

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

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

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

我不同意Óscar López这里接受的答案。这个答案是不准确的!

它不是@JoinColumn,这表明该实体是关系的所有者。取而代之的是@ManyToOne注释(在他的例子中)。

关系注释如@ManyToOne, @OneToMany和@ManyToMany告诉JPA/Hibernate创建映射。默认情况下,这是通过一个单独的连接表来完成的。

@JoinColumn

@JoinColumn的目的是创建一个连接列(如果有的话) 不存在。如果是,则可以使用此注释 命名连接列。

的MappedBy

MappedBy参数的目的是指示JPA: Do NOT 创建另一个连接表,因为已经映射了关系 通过这种关系的相反实体。

请记住:MappedBy是关系注释的一个属性,其目的是生成一种机制来关联两个实体,默认情况下,它们通过创建一个连接表来实现。MappedBy在一个方向上停止这个过程。

The entity not using MappedBy is said to be the owner of the relationship because the mechanics of the mapping are dictated within its class through the use of one of the three mapping annotations against the foreign key field. This not only specifies the nature of the mapping but also instructs the creation of a join table. Furthermore, the option to suppress the join table also exists by applying @JoinColumn annotation over the foreign key which keeps it inside the table of the owner entity instead.

总的来说:@JoinColumn要么创建一个新的连接列,要么重命名一个现有的连接列;而MappedBy参数与其他(子)类的关系注释协同工作,以便通过连接表或在所有者实体的关联表中创建外键列来创建映射。

为了说明MapppedBy是如何工作的,考虑下面的代码。如果MappedBy参数被删除,那么Hibernate实际上会创建两个连接表!为什么?因为在多对多关系中存在对称性,Hibernate没有理由选择一个方向而不是另一个方向。

因此,我们使用MappedBy告诉Hibernate,我们已经选择了另一个实体来指示两个实体之间关系的映射。

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

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

在owner类中添加@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;
}
@Entity
public class Company {
  
 @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
 @JoinColumn(name = "company_id_ref", referencedColumnName = "company_id")
 private List<Branch> branches;
  ...
}

这将给出下面的Hibernate日志

Hibernate: select nextval ('hibernate_sequence')
Hibernate: select nextval ('hibernate_sequence')
Hibernate: insert into company (name, company_id) values (?, ?)
Hibernate: insert into branch (company_id_ref, name, id) values (?, ?, ?)
Hibernate: update branch set company_id_ref=? where id=?

And

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

这将给出下面的Hibernate日志

Hibernate: select nextval ('hibernate_sequence')
Hibernate: select nextval ('hibernate_sequence')
Hibernate: insert into company (name, company_id) values (?, ?)
Hibernate: insert into branch (company_id_ref, name, id) values (?, ?, ?)

我们可以清楚地看到@joinColumn将导致额外的更新查询。 所以你不需要显式地将父实体设置为子实体, 这是我们在使用mappedBy时要做的 拯救有父母陪伴的孩子