单向一对一是单向多对一的一种特殊情况,可以使用单向多对一实现。只要在多的一面,指定unique="true",即可,例如在学生的映射文件中配置:
<many-to-one name="teacher"
column="id"
class="org.shirdrn.entity.Teacher"
insert="false"
update="false"
cascade="all"
unique="true">
</many-to-one>
说明一个学生对应一个教师,这里如果教师的类型是家庭教师,教师对学生也是一对一关联。
下面做个测试的例子:
建立数据库hibernate,表person和card,即人和身份证,表的结构如图所示:
person表:

card表:

第一种方式:使用one-to-many或者many-to-one配置一对一关联
先看一下一对一单向关联(以Person与Card的关联为例,即在Person一方配置与Card的关联):
映射文件及其POJO如下:
Person.hbm.xml和Person.java分别如下:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!--
Mapping file autogenerated by MyEclipse - Hibernate Tools
-->
<hibernate-mapping>
<class name="org.shirdrn.entity.Person" table="person" schema="dbo" catalog="hibernate">
<id name="id" type="java.lang.String">
<column name="id" length="50" />
<generator class="assigned" />
</id>
<many-to-one name="card"
class="org.shirdrn.entity.Card"
update="false"
insert="false"
cascade="save-update">
<column name="id" length="50" not-null="true" unique="true" />
</many-to-one>
<property name="name" type="java.lang.String">
<column name="name" length="50" not-null="true" />
</property>
<property name="gender" type="java.lang.String">
<column name="gender" length="10" />
</property>
<property name="age" type="java.lang.Integer">
<column name="age" />
</property>
<property name="addr" type="java.lang.String">
<column name="addr" length="50" />
</property>
</class>
</hibernate-mapping>
package org.shirdrn.entity;
/**
* Person generated by MyEclipse - Hibernate Tools
*/
public class Person implements java.io.Serializable {
// Fields
private String id;
private Card card;
private String name;
private String gender;
private Integer age;
private String addr;
// Constructors
/** default constructor */
public Person() {
}
/** minimal constructor */
public Person(String id, Card card, String name) {
this.id = id;
this.card = card;
this.name = name;
}
/** full constructor */
public Person(String id, Card card, String name, String gender, Integer age, String addr) {
this.id = id;
this.card = card;
this.name = name;
this.gender = gender;
this.age = age;
this.addr = addr;
}
// Property accessors
public String getId() {
return this.id;
}
public void setId(String id) {
this.id = id;
}
public Card getCard() {
return this.card;
}
public void setCard(Card card) {
this.card = card;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public String getGender() {
return this.gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public Integer getAge() {
return this.age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getAddr() {
return this.addr;
}
public void setAddr(String addr) {
this.addr = addr;
}
}
Card.hbm.xml和Card.java分别如下:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!--
Mapping file autogenerated by MyEclipse - Hibernate Tools
-->
<hibernate-mapping>
<class name="org.shirdrn.entity.Card" table="card" schema="dbo" catalog="hibernate">
<id name="id" type="java.lang.String">
<column name="id" length="50" />
<generator class="assigned" />
</id>
<property name="cardNo" type="java.lang.String">
<column name="cardNo" length="50" not-null="true" />
</property>
<property name="releaseTime" type="java.util.Date">
<column name="releaseTime" length="23" not-null="true" />
</property>
<property name="releaseArea" type="java.lang.String">
<column name="releaseArea" length="10" not-null="true" />
</property>
<property name="effectTime" type="java.lang.Integer">
<column name="effectTime" not-null="true" />
</property>
</class>
</hibernate-mapping>
package org.shirdrn.entity;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
/**
* Card generated by MyEclipse - Hibernate Tools
*/
public class Card implements java.io.Serializable {
// Fields
private String id;
private String cardNo;
private Date releaseTime;
private String releaseArea;
private Integer effectTime;
// Constructors
/** default constructor */
public Card() {
}
/** minimal constructor */
public Card(String id, String cardNo, Date releaseTime, String releaseArea, Integer effectTime) {
this.id = id;
this.cardNo = cardNo;
this.releaseTime = releaseTime;
this.releaseArea = releaseArea;
this.effectTime = effectTime;
}
// Property accessors
public String getId() {
return this.id;
}
public void setId(String id) {
this.id = id;
}
public String getCardNo() {
return this.cardNo;
}
public void setCardNo(String cardNo) {
this.cardNo = cardNo;
}
public Date getReleaseTime() {
return this.releaseTime;
}
public void setReleaseTime(Date releaseTime) {
this.releaseTime = releaseTime;
}
public String getReleaseArea() {
return this.releaseArea;
}
public void setReleaseArea(String releaseArea) {
this.releaseArea = releaseArea;
}
public Integer getEffectTime() {
return this.effectTime;
}
public void setEffectTime(Integer effectTime) {
this.effectTime = effectTime;
}
}
在Person.hbm.xml中配置了many-to-one,unique="true"说明是一对一单向关联,而且 cascade="save-update",级联存储更新。
测试程序如下:
package org.shirdrn.test;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.shirdrn.HibernateSessionFactory;
import org.shirdrn.entity.Card;
import org.shirdrn.entity.Person;
public class MyTest {
public static void main(String[] args){
Session session = HibernateSessionFactory.getSession();
Transaction tx = null;
try{
tx = session.beginTransaction();
Person p = new Person();
p.setId("222403199901011113");
p.setName("刘备");
Card c = new Card();
c.setId("222403199901011113");
c.setCardNo("JL-2008-03-04-0001");
c.setReleaseTime(new Date());
c.setReleaseArea("长春");
c.setEffectTime(new Integer(20));
p.setCard(c);
session.save(p);
tx.commit();
}
catch(Exception e){
tx.rollback();
e.printStackTrace();
}
finally{
HibernateSessionFactory.closeSession();
}
}
}
查看结果如下:
Hibernate: select card_.id, card_.cardNo as cardNo3_, card_.releaseTime as releaseT3_3_, card_.releaseArea as releaseA4_3_, card_.effectTime as effectTime3_ from hibernate.dbo.card card_ where card_.id=?
Hibernate: insert into hibernate.dbo.card (cardNo, releaseTime, releaseArea, effectTime, id) values (?, ?, ?, ?, ?)
Hibernate: insert into hibernate.dbo.person (name, gender, age, addr, id) values (?, ?, ?, ?, ?)
执行了两次insert操作,存储数据成功。
反过来,在Card.hbm.xml中配置与Person的关联,如果使用many-to-one配置一对一单向关联,过程和上面的是一样的。
现在我们使用one-to-many配置一对一单向关联:
其实,在我们指定了“多”的一方的时候(如Card),如果没有限制的话(比如这里要求配置一对一),它对于“一”的一方来说就是一对一或者一对多,无论是在“一”的一方配置一对一或者一对多,对单向关联都没有影响,因为“多”的一方可以单条记录操作(如果是一对一),也可以多条记录操作(如果是一对多),参照的就是另一方。
在上面的基础上,把Person.hbm.xml中的
<many-to-one name="card"
class="org.shirdrn.entity.Card"
update="false"
insert="false"
cascade="save-update">
<column name="id" length="50" not-null="true" unique="true" />
</many-to-one>
去掉,改为在card.hbm.xml中配置one-to-many如下:
<set name="persons"
inverse="true"
cascade="save-update">
<key>
<column name="id" length="50" not-null="true" unique="true" />
</key>
<one-to-many class="org.shirdrn.entity.Person" />
</set>
并且,要在Card的POJO里面添加Field:
private Set persons = new HashSet(0);
以及:
public Set getPersons() {
return this.persons;
}
public void setPersons(Set persons) {
this.persons = persons;
}
测试程序如下:
package org.shirdrn.test;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.shirdrn.HibernateSessionFactory;
import org.shirdrn.entity.Card;
import org.shirdrn.entity.Person;
public class MyTest {
public static void main(String[] args){
Session session = HibernateSessionFactory.getSession();
Transaction tx = null;
try{
tx = session.beginTransaction();
Person p = new Person();
p.setId("222403199901011116");
p.setName("刘备");
Set hs = new HashSet();
hs.add(p);
Card c = new Card();
c.setId("222403199901011116");
c.setCardNo("JL-2008-03-04-0001");
c.setReleaseTime(new Date());
c.setReleaseArea("长春");
c.setEffectTime(new Integer(20));
p.setCard(c);
c.setPersons(hs);
session.save(c);
tx.commit();
}
catch(Exception e){
tx.rollback();
e.printStackTrace();
}
finally{
HibernateSessionFactory.closeSession();
}
}
}
执行结果如下:
Hibernate: select person_.id, person_.name as name2_, person_.gender as gender2_, person_.age as age2_, person_.addr as addr2_ from hibernate.dbo.person person_ where person_.id=?
Hibernate: insert into hibernate.dbo.card (cardNo, releaseTime, releaseArea, effectTime, id) values (?, ?, ?, ?, ?)
Hibernate: insert into hibernate.dbo.person (name, gender, age, addr, id) values (?, ?, ?, ?, ?)
级联保存成功。
这里,是先把要insert的数据set到Person对象中,然后把Person对象放到HashSet中,通过配置的集合映射及其关联,把存有Person对象的HashSet正确地set到Card的对象中,然后可以insert我们处理过的Card对象了,而且级联insert了Card对象。