跳转到内容

Java 持久化/多对一

来自维基教科书,开放的书,开放的世界

多对一

[编辑 | 编辑源代码]

Java 中的 多对一 关系是指源对象有一个属性引用另一个对象,即目标对象。例如典型的 Java 案例,一个对象持有对另一个对象的引用。多对一 关系可以是单向的。但是,目标对象通常具有指向源对象的逆关系。这将是目标对象中的 一对多 关系规范。Java 和 JPA 中的所有关系都是单向的,也就是说,如果源对象引用目标对象,则不能保证目标对象也与源对象有关系。这与关系数据库不同,在关系数据库中,关系通过外键和查询来定义,以便始终存在反向查询。

在 JPA 中,多对一 关系通过 @ManyToOne 注解或 <many-to-one> 元素指定。@ManyToOne 注解通常伴随 @JoinColumn 注解。@JoinColumn 注解指定了关系如何映射到数据库(在数据库中表示)。@JoinColumn 定义了源对象中用于查找(连接)目标对象的外部键列名称(@JoinColumn(name = "..."))。

如果在目标对象中指定了反向 一对多 关系,那么目标对象中的 @OneToMany 注解必须包含 mappedBy 属性来定义这个反向关系。

JPA 还定义了 一对一 关系,它类似于 多对一 关系,除了反向关系(如果定义了的话)是一个 一对一 关系。JPA 中 一对一多对一 关系的主要区别在于,多对一 始终包含从源对象表的外部键到目标对象表的外部键,而 一对一 关系的外部键可能位于源对象表或目标对象表中。

多对一 关系数据库示例

[编辑 | 编辑源代码]

员工(表)

员工 ID 姓名 姓氏 薪资 经理 ID
1 鲍勃 50000 2
2 莎拉 史密斯 75000

电话(表)

ID 类型 区号 电话号码 所有者 ID
1 家庭 613 792-0000 1
2 工作 613 896-1234 1
3 工作 416 123-4444 2

多对一 关系注解示例

[编辑 | 编辑源代码]
@Entity
public class Phone {
  @Id
  private long id;
  ...
  // Specifies the PHONE table does not contain an owner column, but 
  // an OWNER_ID column with a foreign key. And creates a join to
  // lazily fetch the owner
  @ManyToOne(fetch=FetchType.LAZY)
  @JoinColumn(name="OWNER_ID")
  private Employee owner;
  ...
}

// Specification of the reverse OneToMany relationship in Employee
@Entity
public class Employee {
  @Id
  private long emp_id;
  ...
  // The 'mappedBy = "owner"' attribute specifies that
  // the 'private Employee owner;' field in Phone owns the
  // relationship (i.e. contains the foreign key for the query to
  // find all phones for an employee.)
  @OneToMany(mappedBy = "owner")
  private List<Phone> phones;
  ...

多对一 关系 XML 示例

[编辑 | 编辑源代码]
<entity name="Phone" class="org.acme.Phone" access="FIELD">
    <attributes>
        <id name="id"/>
        <many-to-one name="owner" fetch="LAZY">
            <join-column name="OWNER_ID"/>
        </many-to-one>
    </attributes>
</entity>

另请参阅

[编辑 | 编辑源代码]

常见问题

[编辑 | 编辑源代码]
外键也是主键的一部分。
[编辑 | 编辑源代码]
参见 通过一对一关系生成主键.
外键也映射为基本类型。
[编辑 | 编辑源代码]
如果你在两个不同的映射中使用相同的字段,通常需要使用 insertable, updatable = false 使其中一个字段变为只读。
参见 目标外键、主键连接列、级联主键.
插入时的约束错误。
[编辑 | 编辑源代码]
这通常是因为你在 一对一 关系中错误地映射了外键。
参见 目标外键、主键连接列、级联主键.
如果你的 JPA 提供程序不支持引用完整性,或者无法解析双向约束,也会发生这种情况。在这种情况下,你可能需要移除约束,或者使用 EntityManager flush() 来确保对象写入的顺序。
外键值为空
[编辑 | 编辑源代码]
确保你设置了对象的 一对一 值,如果 一对一 是双向 一对多 关系的一部分,确保你在将对象添加到 一对多 中时设置了对象的 一对一,JPA 不会为你维护双向关系。
还要检查你是否正确定义了 JoinColumn,确保你没有设置 insertable, updateable = false 或使用 PrimaryKeyJoinColumn

目标外键、主键连接列、级联主键

[编辑 | 编辑源代码]

在复杂的数据模型中,如果外键/JoinColumn 与其他 多对一Basic 映射共享,则可能需要使用目标外键或只读 JoinColumn 来映射 多对一

参见 目标外键、主键连接列、级联主键

华夏公益教科书