有什么区别:
@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表示该实体是关系的所有者(也就是说:对应的表有一个指向引用表的外键的列),而属性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表示该实体是关系的所有者(也就是说:对应的表有一个指向引用表的外键的列),而属性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也很好,但它使用了一个实现注释,这并不是严格必要的。
让我简单说一下。
不管映射如何,您都可以在任意一侧使用@JoinColumn。
我们把它分成三种情况。
1)分公司到公司的单向映射。
2)公司到分公司的双向映射。
3)从公司到分公司只能单向映射。
因此任何用例都可以归入这三类。让我来解释一下如何使用@JoinColumn和mappedBy。
1)分公司到公司的单向映射。
在Branch表中使用JoinColumn。
2)公司到分公司的双向映射。
使用mappedBy在公司表描述@Mykhaylo Adamovych的回答。
3)公司到分公司的单向映射。
在Company表中使用@JoinColumn即可。
@Entity
public class Company {
@OneToMany(cascade = CascadeType.ALL , fetch = FetchType.LAZY)
@JoinColumn(name="courseId")
private List<Branch> branches;
...
}
这就是说,在基于外键“courseId”映射在分支表中,得到我所有分支的列表。注意:在这种情况下你不能从分支获取公司,从公司到分支只存在单向映射。
@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时要做的
拯救有父母陪伴的孩子