有什么区别:
@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;
...
}
@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时要做的
拯救有父母陪伴的孩子
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;
}
}
@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() {
...
}
@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时要做的
拯救有父母陪伴的孩子
JPA是一个分层的API,不同的级别有自己的注释。最高级别是(1)实体级别,它描述持久类,然后是(2)关系数据库级别,它假设实体映射到关系数据库,以及(3)java模型。
一级注释:@Entity, @Id, @OneToOne, @OneToMany, @ManyToOne, @ManyToMany。
仅使用这些高级注释就可以在应用程序中引入持久性。但是您必须根据JPA所做的假设来创建数据库。这些注释指定了实体/关系模型。
二级注释:@Table, @Column, @JoinColumn,…
如果您对JPA的默认值不满意,或者需要映射到现有数据库,则影响从实体/属性到关系数据库表/列的映射。这些注释可以被看作是实现注释,它们指定了映射应该如何完成。
在我看来,最好是尽可能多地使用高级注释,然后根据需要引入低级注释。
要回答这些问题:@OneToMany/mappedBy是最好的,因为它只使用来自实体域的注释。@oneToMany/@JoinColumn也很好,但它使用了一个实现注释,这并不是严格必要的。
注释@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;
}