关系对
大多数情况下,我们可以将 @OneToMany
和 @ManyToOne
视为一对,表示关系的 2 个方面。因此,@OneToMany 具有关系的“多”方面,而 @ManyToOne 具有关系的“一”方面。
mappedBy
mappedBy
属性应在大多数 @OneToMany 中定义。mappedBy 属性有效地引用关系的另一方。
示例:客户有多个联系人
@Entity
public class Customer ...
// mappedBy referring to the other side of this relationship
@OneToMany(mappedBy="customer")
List<Contact> contacts;
...
在 Contact 实体 Bean 中关系的另一方,我们定义 @ManyToOne
属性,其中 mappedBy
引用。
@Entity
public class Contact ...
// the customer property referred to by @OneToMany(mappedBy="customer")
@ManyToOne(optional=false)
Customer customer;
...
双向
当我们使用 @OneToMany
和 @ManyToOne
对映射关系的双方时,我们可以将其描述为双向关系。可以从两个方向查看、导航和加载关系。
当我们有双向关系时,没有限制或局限性。
不映射 @OneToMany
我们可能选择不映射关系的 @OneToMany
方面的原因是当基数很高(比如数千)
时,我们认为我们永远不想允许应用程序向该方向导航关系,因为这样做可能会加载太多对象。
例如,如果一个客户有 100 万个订单,并且我们从该客户导航到其所有订单,我们可能会将 100 万个订单实例加载到内存中,这通常是我们不想做的事情。在这种情况下,我们可以在客户查询中使用 filterMany
来过滤每个客户的订单(例如,上周创建的订单)。或者,我们可以从另一个方向(从订单到客户)加载图形。
省略 @OneToMany 实际上意味着我们无法从该方向导航或加载关系,而是强制应用程序始终使用另一个方向(来构建对象图)。
不映射 @ManyToOne
当我们不映射 @ManyToOne 时,这会增加一个限制并暗示一个所有权关系
。
例如,假设 Order
有许多 OrderDetail
。当我们在 OrderDetail 中不映射 @ManyToOne 侧时
Order 有详细信息
@Entity
@Table(name = "orders")
public class Order ...
// we MUST have cascade persist here for this
// unidirectional case (no @ManyToOne)
@OneToMany(cascade = CascadeType.ALL)
List<OrderDetail> details;
...
OrderDetail 没有匹配的 @ManyToOne
@Entity
public class OrderDetail ...
// Does not have - @ManyToOne(optional = false) Order order;
这实际上增加了这样的限制:要插入新的 OrderDetails,我们必须从 Order 级联持久化才能这样做。也就是说,@ManyToOne 实际上表示 OrderDetail 底层表上的外键列,并且要填充该外键列,我们必须从 Order 级联持久化
。
这也意味着外键值永远不会改变,因此从概念上我们可以将此视为“所有权”关系
。在此示例中,每个 OrderDetail 都“归”一个 Order 所有。
就我个人而言,我总是映射 @ManyToOne