Hibernate 映射一对一关联关系

本文介绍Hibernate中一对一关联关系的两种映射方式:按照外键映射和按照主键映射,并通过Customer与Address类的关系进行详细说明。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

之前介绍组成关系时,已介绍了Customer类与Address类,Address类是组件类,没有OID,数据库中没有对应的表, Address对象的生命周期依赖于Customer对象的生命周期。Customer类中定义了两个值类型的homeAddress属性和comAddress属性:

private Address homeAddress;

private Address comAddress;
但也可以将Address设计成实体类,此时,数据库中存在ADDRESSES表,Address类有单独的OID,Customer类与Address类之间为一对一的关联关系。

Hibernate提供两种映射一对一关联关系的方法:按照外键映射和按照主键映射。

1.按照外键映射

CUSTOMERS表的两个外键HOME_ADDRESS_ID和COM_ADDRESS_ID都参照ADDRESSES表的主键。

数据库表:

create table CUSTOMERS (
   ID bigint not null,
   NAME varchar(15),
   HOME_ADDRESS_ID bigint unique,
   COM_ADDRESS_ID bigint unique,
   primary key (ID),
   foreign key (HOME_ADDRESS_ID) references ADDRESSES(ID),
   foreign key (COM_ADDRESS_ID) references ADDRESSES(ID)
);

create table ADDRESSES(
  ID bigint not null,
  CITY varchar(128),
  STREET varchar(128),
  PROVINCE varchar(128),
  ZIPCODE varchar(6),
  primary key(ID)
);

Customer.java:

public class Customer implements Serializable {
    private Long id;
    private String name;
    private Address homeAddress;
    private Address comAddress;
    constructor...(); getter()...;setter()...;
}

Customer.hbm.xml:

<hibernate-mapping >
  <class name="mypack.Customer" table="CUSTOMERS" >
    <id name="id" type="long" column="ID">
      <generator class="increment"/>
    </id>

    <property name="name" column="NAME" type="string" />
       
    <many-to-one name="homeAddress"
        class="mypack.Address"
        column="HOME_ADDRESS_ID"
        cascade="all"
        unique="true"
    />

    <many-to-one name="comAddress"
        class="mypack.Address"
        column="COM_ADDRESS_ID"
        cascade="all"
        unique="true"
    />
        
  </class>
</hibernate-mapping>

<many-to-one>元素的unique为true,表明每个Customer对象都有唯一的homeAddresscomAddress对象。

Address.java:

public class Address implements Serializable {
    private Long id;
    private String street;
    private String city;
    private String province;
    private String zipcode;
    private Customer customer;

    constructor...(); getter()...;setter()...;
}
Address.hbm.xml:

<hibernate-mapping >
  <class name="mypack.Address" table="ADDRESSES" >
    <id name="id" type="long" column="ID">
      <generator class="increment"/>
    </id>

    <property name="city" column="CITY" type="string" />
    <property name="province" column="PROVINCE" type="string" />
    <property name="street" column="STREET" type="string" />
    <property name="zipcode" column="ZIPCODE" type="string" />
        
    <one-to-one name="customer"
        class="mypack.Customer"
       property-ref="homeAddress"
    />

  </class>
</hibernate-mapping>

<one-to-one>元素的property-ref属性为"homeAddress",表明建立了从homeAddress对象到Customer对象的关联。

只能用<one-to-one>元素对Address类的customer属性映射一次,已映射homeAddress对象Customer对象的双向关联,不能同时再映射Customer对象与comAddress对象的双向关联。

解决办法:把Address类定义为抽象类,创建HomeAddress和ComAddress子类,在HomeAddress.hbm.xml和ComAddress.hbm.xml中分别用<one-to-one>元素来映射各自的customer属性。

默认情况下,多对一关联采用延迟检索策略,一对一关联采用迫切左连接检索策略。

2.按照主键映射

ADDRESSES表的ID即作为主键,又作为外键参照CUSTOMERS表的主键,即ADDRESSES表与CUSTOMERS表共享主键。

数据库表:

create table CUSTOMERS (
   ID bigint not null,
   NAME varchar(15),
   primary key (ID)
);

create table ADDRESSES(
   ID bigint not null,
   STREET varchar(128),
   CITY varchar(128),
   PROVINCE varchar(128),
   ZIPCODE varchar(6),
   primary key (ID),
   foreign key (ID) references CUSTOMERS(ID)
);

Customer.java:
public class Customer implements Serializable {
    private Long id;
    private String name;
    private Address address;

    constructor...(); getter()...;setter()...;
}
Customer.hbm.xml:

<hibernate-mapping >
  <class name="mypack.Customer" table="CUSTOMERS" >
    <id name="id" type="long" column="ID">
      <generator class="increment"/>
    </id>

    <property name="name" column="NAME" type="string" />
       
    <one-to-one name="address"
        class="mypack.Address"
        cascade="all"
     />
        
  </class>
</hibernate-mapping>

Address.java:
public class Address implements Serializable {
    private Long id;
    private String street;
    private String city;
    private String province;
    private String zipcode;
    private Customer customer;

    constructor...(); getter()...;setter()...;
}
Address.hbm.xml:

<hibernate-mapping >
  <class name="mypack.Address" table="ADDRESSES" >
    <id name="id" type="long" column="ID">
      <generator class="foreign">
        <param name="property">customer</param>
      </generator>
    </id>

    <property name="city" column="CITY" type="string" />
    <property name="province" column="PROVINCE" type="string" />
    <property name="street" column="STREET" type="string" />
    <property name="zipcode" column="ZIPCODE" type="string" />
        
    <one-to-one name="customer"
        class="mypack.Customer"
       constrained="true"
    />

  </class>
</hibernate-mapping>

<one-to-one>元素的constrained属性为true,表明ADDRESSES表的ID主键同时作为外键参照CUSTOMERS表,此时其OID必须使用foreign标识符生成策略。

使用foreign标识符生成策略,Hibernate会保证Address对象与关联的Customer对象共享同一个OID。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值