关系对

大多数情况下,我们可以将 @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