使用JPA @OneToMany关联时@JoinColumn和mappedBy之间有什么区别

时间:2012-08-13 16:17:29

标签: java hibernate jpa orm one-to-many

有什么区别:

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

8 个答案:

答案 0 :(得分:503)

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

答案 1 :(得分:198)

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

根据documentation

由于多对一(几乎)始终是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端定义任何物理映射。

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

答案 2 :(得分:35)

正如我在enter image description here中所解释的,如果将chmod 755 /var/tmp/nginx/client_body_temp注释与@OneToMany一起使用,那么您将具有单向关联。

如果您将@JoinColumn属性与@OneToMany一起使用,则您将具有双向关联,这意味着您需要在{{1} }参考。

this article,因此应避免使用它。

最好使用unidirectional @OneToMany association does not perform very well

答案 3 :(得分:31)

理想情况下,注释 mappedBy 应始终用于双向关系的父方(公司类),在这种情况下,它应该在公司类中指向成员变量&#39;公司&#39; Child类(分类)

注释 @JoinColumn 用于指定用于加入实体关联的映射列,此注释可用于任何类(父级或子级),但理想情况下应仅在一侧使用(在父类或Child类中,不在两者中)在这种情况下,我在双向关系的Child侧(Branch类)中使用它,表示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;
    }


}

答案 4 :(得分:19)

我只想补充一点@JoinColumn并不总是必须与物理信息位置相关联,如this答案所示。即使父表没有指向子表的表数据,也可以将@JoinColumn@OneToMany组合。

<强> How to define unidirectional OneToMany relationship in JPA

<强> Unidirectional OneToMany, No Inverse ManyToOne, No Join Table

但似乎仅在JPA 2.x+中可用。它对于您希望子类只包含父类的ID而非完整引用的情况非常有用。

答案 5 :(得分:9)

我不同意ÓscarLópez在这里接受的答案。这个答案不正确!

不是@JoinColumn表示此实体是关系的所有者。相反,是@ManyToOne注释(在他的示例中)。

诸如@ManyToOne@OneToMany@ManyToMany之类的关系注释告诉JPA / Hibernate 创建映射。默认情况下,这是通过单独的方式完成的加入表格。


@JoinColumn

  

@JoinColumn的目的是创建一个 join列   还不存在。如果是这样,则此注释可用于   名称连接列。


MappedBy

  

MappedBy参数的目的是指示JPA:请勿   由于关系已被映射,因此创建另一个联接表   由该关系的相反实体提供。



请记住:MappedBy是关系批注的属性,其目的是生成一种机制以关联两个实体,默认情况下,它们通过创建联接表来实现此功能。 MappedBy暂停该过程。

不使用MappedBy的实体被称为关系的<所有者> ,因为映射的机制是通过使用三个映射注释中的一个来在其类中规定的外键字段。这不仅指定了映射的性质,还指示了联接表的创建。此外,还可以通过在外键上应用@JoinColumn注释来抑制连接表,该选项将其保留在所有者实体的表中。

因此,总而言之:@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;
}

在所有者类中添加@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;
}

答案 6 :(得分:1)

让我简化一下。
不论映射如何,都可以在任何一侧使用 @JoinColumn

我们将其分为三种情况。
1)从分支到公司的单向映射。
2)从公司到分支的双向映射。
3)仅从公司到分支的单向映射。

因此,任何用例都属于这三类。因此,让我解释一下如何使用 @JoinColumn mappedBy
1)从分支到公司的单向映射。
在分支表中使用 JoinColumn
2)从公司到分支的双向映射。
按照@Mykhaylo Adamovych的答案所述,在Company表中使用 mappedBy
3)从公司到分支机构的单向映射。
只需在“公司”表中使用 @JoinColumn

@Entity
public class Company {

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

这表示在分支表中基于外键“ courseId”的映射,获取所有分支的列表。注意:在这种情况下,您无法从分支机构获取公司,只有公司与分支机构之间存在单向映射。

答案 7 :(得分:0)

JPA是一个分层的API,不同级别具有各自的注释。最高级别是(1)描述持久性类的Entity级别,然后是(2)关系数据库级别,其中假定实体已映射到关系数据库,并且(3)Java模型。

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

2级注释:@ Table,@ Column,@ JoinColumn,... 如果您对JPA的默认设置不满意或需要映射到现有数据库,请影响从实体/属性到关系数据库表/列的映射。这些注释可视为实现注释,它们指定应如何完成映射。

我认为最好是尽可能多地粘贴高级别注释,然后根据需要引入低级别注释。

回答问题:@ OneToMany / mappedBy最好,因为它仅使用来自实体域的注释。 @ oneToMany / @ JoinColumn也可以,但在并非绝对必要的地方使用了实现注释。