现在的位置: 首页 > 综合 > 正文

Hibernate一对一主键关联映射(双向)

2018年06月05日 ⁄ 综合 ⁄ 共 4076字 ⁄ 字号 评论关闭

Hibernate一对一主键关联映射(双向关联Person<——>IDCard)。

类图:

映射的数据库表:

原理:在两端都要加上对象的引用。

Person.java:

public class Person {

	private Integer id;
	private String name;

	/*定义Person和IDCard的关系((双向一对一主键关联映射))*/
	private IDCard idCard;
	
	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public IDCard getIdCard() {
		return idCard;
	}

	public void setIdCard(IDCard idCard) {
		this.idCard = idCard;
	}

	
}

注:因为是双向关联,所以在Person的一端要加上IDCard的引用,在IDCard一端也要加上Person的引用。

IDCard.java:

public class IDCard {

	private Integer id;
	private String cardNo;
	/*IDCard和Person的关系(双向一对一主键关联映射)*/
	private Person person;
	
	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	public String getCardNo() {
		return cardNo;
	}

	public void setCardNo(String cardNo) {
		this.cardNo = cardNo;
	}

	public Person getPerson() {
		return person;
	}

	public void setPerson(Person person) {
		this.person = person;
	}

}

注:因为是双向关联,所以在IDCard一端要加上Person的引用,在Person一端要加上IDCard的引用。

Person.hbm.xml:

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC 
	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.lixue.bean">
	<class name="Person" table="t_person">
		<id name="id">
		<!-- 采用foreign生成策略,foreign回去的关联对象的标识 -->
			<generator class="foreign">
			<!-- 通过property来表示要关联的对象 -->
			<param name="property">idCard</param>
			</generator>
		</id>
		<property name="name"/>
		<!-- 
			one-to-one指示Hibernate如何加载其关联对象,默认根据主键加载
			也就是拿到关系字段值,根据对端的主键来加载关联对象
			
			constrained="true"标识当前主键(person的主键)还是一个外键
			参照对端的主键(IdCard的主键),也就是会生成外键约束的语句
		 -->
		 <one-to-one name="idCard" constrained="true"/>
	</class>
</hibernate-mapping>

IDCard.hbm.xml:

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC 
	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.lixue.bean">
	<class name="IDCard" table="t_idCard">
		<id name="id">
			<generator class="native"/>
		</id>
		<property name="cardNo"/>
		
		<!-- 声明IDCard和Person的关系 -->
		<one-to-one name="person"/>
	</class>
</hibernate-mapping>

注:在IDCard一端也要加上<one-to-one>

测试通过Person添加IDCard:

public void testSave1(){
		/*定义Session和事物*/
		Session session = null;
		Transaction transaction = null;
		
		try {
			/*获取Session并开启事物*/
			session = HibernateUtils.getSession();
			transaction = session.beginTransaction();
			
			/*创建身份证并设置属性*/
			IDCard idCard = new IDCard();
			idCard.setCardNo("367578677545348879");
			
			/*创建人并设置属性*/
			Person person = new Person();
			person.setName("习近平");
			/*建立关联*/
			person.setIdCard(idCard);
			
			/*我们可以发现没有抛出TransientObjectException
			 * 这不科学啊,我们并没有保存IDCard对象,它还是Transient状态啊,
			 * 怎么可能不保存呢?其实这是由一对一关联映射的特性决定的,它必须先
			 * 保存关联对象Idcard,这样它采用foreign映射策略才能取得对象的标识
			 * 也就默认了cascade属性所导致的
			 */
			session.save(person);
			/*提交事物*/
			transaction.commit();
		} catch (Exception e) {
			e.printStackTrace();
			transaction.rollback();
		} finally{
			HibernateUtils.closeSession(session);
		}
	}

注:这样是可以实现级联保存的,因为Person是维护关系的一端。

测试通过IDCard添加Person:

public void testSave2(){
		/*定义Session和事物*/
		Session session = null;
		Transaction transaction = null;
		
		try {
			/*获取Session并开启事物*/
			session = HibernateUtils.getSession();
			transaction = session.beginTransaction();
			
			/*创建人并设置属性*/
			Person person = new Person();
			person.setName("李克强");
			
			/*创建身份证并设置属性*/
			IDCard idCard = new IDCard();
			idCard.setCardNo("123578677545348879");
			/*建立关联*/
			idCard.setPerson(person);
			
			/*我们可以发现没有抛出TransientObjectException
			 *但是也不会保存Person的对象,因为IDCard端的one-to-one不影响存储,只影响加载
			 */
			session.save(idCard);
			/*提交事物*/
			transaction.commit();
		} catch (Exception e) {
			e.printStackTrace();
			transaction.rollback();
		} finally{
			HibernateUtils.closeSession(session);
		}
	}

注:通过IDCard是不能级联保存Person的,因为IDCard是关系的被维护端。

测试通过Person加载IDCard:

public void testFind(){
		
		/*获取Person对象*/
		Person person = (Person) HibernateUtils.getSession().get(Person.class, 1);
		/*获取Person的name属性*/
		System.out.println("person.name=" + person.getName());
		/*获取Person关联的IDCard的idcardNo*/
		System.out.println("person.idCard.idCardNo=" + person.getIdCard().getCardNo());
	}

注:通过Person可以加载IDCard对象,因为是双向关联(发出两条sql语句)。

测试通过IDCard添加Person:

public void testFind2(){
		
		/*获取Person对象*/
		IDCard idCard = (IDCard) HibernateUtils.getSession().get(IDCard.class, 1);
		/*获取Person的name属性*/
		System.out.println("idCard.name=" + idCard.getCardNo());
		/*获取Person关联的IDCard的idcardNo*/
		System.out.println("idCard.person.name=" + idCard.getPerson().getName());
	}

注:通过IDCard可以加载Person对象,因为是双向关联(只发出一条语句,这涉及到抓取策略,以后会详解)

抱歉!评论已关闭.