Hibernate映射关系解析(二)--Unidirectional associations--one-to-one

本文详细阐述了一对一关系在数据库中如何通过外键和unique约束实现,以及基于主键的一对一关联的实现方式,并通过代码示例进行演示。

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

8.2.2  一对一(one-to-one)

基于外键的单向一对一(one-to-one)关联与单向多对一关联几乎是一样的。唯一的不同是单向一对一关联中外键字段具有 unique 约束。

<class name="Person">
    <id name="id" column="personId">
        <generator class="native"/>
    </id>
    <many-to-one name="address" 
        column="addressId" 
        unique="true"
        not-null="true"/>
</class>

<class name="Address">
    <id name="id" column="addressId">
        <generator class="native"/>
    </id>
</class>
create table Person ( personId bigint not null primary key, addressId bigint not null unique )
create table Address ( addressId bigint not null primary key )

-----------------------------------

自己具体说明如下,仍然使用上一个例子,本例中一个人只能对应一个地址。

Address类、Person类、Address.hbm.xml文件与上一例子中全部相同,只需要如下修改Person.hbm.xml文件:

<hibernate-mapping package="com.hibernate.domain">
	<class name="Person" table="person">
		<id name="id" column="personid" type="java.lang.Integer">
			<generator class="native"/>
		</id>
		<property name="personName" type="java.lang.String">
			<column name="personName" length="64" not-null="true"/>
		</property>
		<!-- 配置many-to-one属性  -->
		<!-- 其中name为Person类中“private Address address”中的address属性 -->
		<!-- 这里需要增加unique约束   (这里是重点)-->
		<many-to-one name="address" column="addressId" unique="true" not-null="true"/>			
	</class>
</hibernate-mapping>

测试结果如下:

//从数据中取出数据
			Person person = (Person) session.load(Person.class, 2);
	
			//向数据库中添加数据
			Address add = new Address();
			add.setAddressName("beijing");
			
			Person p1 = new Person();
			p1.setPersonName("Hibernate01");
			p1.setAddress(add);
			Person p2 = new Person();
			p2.setPersonName("hibernate02");
			p2.setAddress(add);

			session.save(add);
			session.save(p1);
			session.save(p2);
如果还像上例这样添加数据的话,就会报错:Duplicate entry '1' for key 'UK_ggbkwpl67fgfv0qtwb6cfque8' ,因为现在一个Person只能对应唯一一个Address。

此时两个表已经建立好了,只不过两张表都为空,没有数据,数据已经回滚。


正确的添加数据的情况如下:

//向数据库中添加数据
			Address add1 = new Address();
			add1.setAddressName("beijing");
			Address add2 = new Address();
			add2.setAddressName("天津");
			
			Person p1 = new Person();
			p1.setPersonName("Hibernate01");
			p1.setAddress(add1);
			Person p2 = new Person();
			p2.setPersonName("hibernate02");
			p2.setAddress(add2);

			session.save(add1);
			session.save(add2);
			session.save(p1);
			session.save(p2);
运行成功后,通过查询数据,结果如下:

Person和Address均正确,且一一对应。查询的话此处不再赘述。


----------------------------------------------------------

基于主键的单向一对一关联通常使用一个特定的id generator。然而,在这个例子中,我们翻转了关联的方向。

<class name="Person">
    <id name="id" column="personId">
        <generator class="native"/>
    </id>
</class>

<class name="Address">
    <id name="id" column="personId">
        <generator class="foreign">
            <param name="property">person</param>
        </generator>
    </id>
    <one-to-one name="person" constrained="true"/>
</class>
create table Person ( personId bigint not null primary key )
create table Address ( personId bigint not null primary key )

--------------------------------------------

自己的实践案例如下:

Person类:

public class Person implements Serializable {

	private static final long serialVersionUID = 1L;
	private Integer id;
	private String personName;
	public Person() {
	}
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	public String getPersonName() {
		return personName;
	}
	public void setPersonName(String personName) {
		this.personName = personName;
	}
}

Address类:

public class Address implements Serializable{

	private static final long serialVersionUID = 1L;
	private Integer id;
	private String addressName;
	private Person person; //由于Address的主键要通过Person来映射,因此Address类必须加上该属性(这点重要)
	public Address() {
	}
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	public String getAddressName() {
		return addressName;
	}
	public void setAddressName(String addressName) {
		this.addressName = addressName;
	}
	public Person getPerson() {
		return person;
	}
	public void setPerson(Person person) {
		this.person = person;
	}
}

Person.hbm.xml文件(该文件正常配置即可):

<hibernate-mapping package="com.hibernate.domain">
	<class name="Person" table="person">
		<id name="id" column="personid" type="java.lang.Integer">
			<generator class="native"/>
		</id>
		<property name="personName" type="java.lang.String">
			<column name="personName" length="64" not-null="true"/>
		</property>		
	</class>
</hibernate-mapping>


Address.hbm.xml文件配置:

<hibernate-mapping package="com.hibernate.domain">
	<class name="Address" table="address">
		<id name="id" column="addressId" type="java.lang.Integer">
		<!-- 因为是基于逐渐的one-to-one,所以我们使用外键策略(重要) -->
			<generator class="foreign">
			<!-- 这里的值,是指定要跟哪个属性one-to-one (重要)-->
			<!-- 具体到该例,是与 private Person person属性对应 -->
				<param name="property">person</param>
			</generator>
		</id>
		<property name="addressName" type="java.lang.String">
			<column name="addressName" length="128" not-null="true"/>
		</property>
		<!-- 这里配置Address和person属性是一对一的关系(重要) -->
		<one-to-one name="person" constrained="true"/>
	</class>
</hibernate-mapping>

进行代码测试如下:

<span style="white-space:pre">			</span>Person p1 = new Person();
			p1.setPersonName("Hibernate01");
			
			Address add = new Address();
			add.setAddressName("beijing");
			add.setPerson(p1); //需要放入Person
			
			session.save(p1);
			session.save(add);

通过 show create table address,可以看到 address的主键同时也是外键。




Address添加成功,Person添加成功,两者的id也相同。





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值