03. 关联关系映射(一对一)
关联关系映射
一对一关联关系
表结构中关系为一对一,那么类结构中也是一对一的关系。表结构层面上,一对一的关系都是双向的,从任何一侧表都可以访问到对方另一侧表中的内容。而类一对一的关联关系可以分为单向和双向两种。双向表示在两个关联的类中,都存放对方类信息,并提供相应的获取和设置方法;单向表示只在某一侧存放另一方的信息,我们只能从这一方去访问另一方,而不能从另一方访问这一方。
一对一单向关联关系
由于一对一单向关联关系稍微简单些,而且当我们清楚双向关联关系之后,单向的也自然清楚,所以此处省略。
一对一双向关联关系表结构
如Person和Passport
Person类中:id(Long),name(String),gender(String),age(Integer),passport(Passport)。并提供相应的get、set方法。
Passport类中:id(Long),bh(String),person(Person)。并提供相应的get、set方法。
-
基于外键映射
Persion表
CREATE TABLE t_person{ id NUMBER(10) PRIMERY KEY, name VARCHAR2(20) NOT NULL, gender VARCHAE2(10), age NUMBER(3), CHECK (age BETWEEN 1 and 100) };
Passport表
CREATE TABLE t_passport{ id NUMBER(10) PRIMERY KEY, bh VARCHAR2(30) NOT NULL UNIQUE, person_id NUMBER(10) REFERENCES t_person(id) UNIQUE };
-
基于主键映射
Persion表(父表)
CREATE TABLE t_person{ id NUMBER(10) PRIMERY KEY, name VARCHAR2(20) NOT NULL, gender VARCHAE2(10), age NUMBER(3), CHECK (age BETWEEN 1 and 100) };
Passport表(子表)
CREATE TABLE t_passport{ id NUMBER(10) PRIMERY KEY REFERENCES t_person(id), bh VARCHAR2(30) NOT NULL UNIQUE, };
一对一双向关联关系类结构
-
Person类
public class Person{ private Long id; private String name; private String gender; private Integer age; private Passport passport; ...... }
-
Passport类
public class Passport{ private Long id; private String bh; private Person person; ...... }
一对一双向关联关系的映射文件
-
基于外键映射
Person类映射(父表)
前一个one可以认为是Person,后一个one是Passport。name属性值”passport“对应的是property而不是attribute,即此处的passport对应的是Person类中的getPassport和setPassport方法(按照标准的方式来生成的setter和getter方法)。property-ref是指参考引用,在Passport类中应该要有一个属性(此属性为property)为person。cascade表示级联,”all”值是指级联所有CRUD操作。
<class name="Person" table="T_PERSON"> ...... <one-to-one name="passport" class="Passport" property-ref="person" cascade="all"/> </class>
Passport类映射(子表)
many对应的是Passport,one对应的是Person。在Hibernate中不管是一对一还是一对多的关系,都当成一对多的关系来处理,所以我们将子表配置成多对一的关系。此时,我们加unique属性来限定外键是唯一的,建议加上此属性。
column指示处Passport表中的外键列。name的含义依旧如上:Passport类结构中需要有此属性(property)。<class name="Passport" table="T_PASSPORT"> ...... <many-to-one name="person" class="Person" column="PERSON_ID" unique="true"/> </class>
- Person类
package com.li.association.one2one.pojo; import java.io.Serializable; public class Person implements Serializable{ private static final long serialVersionUID = -6152698999047898223L; private Long id; private String name; private String gender; private Integer age; private Passport passport; public Person() { } public Person(Long id, String name, String gender, Integer age, Passport passport) { super(); this.id = id; this.name = name; this.gender = gender; this.age = age; this.passport = passport; } public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getGender() { return gender; } public void setGender(String gender) { this.gender = gender; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public Passport getPassport() { return passport; } public void setPassport(Passport passport) { this.passport = passport; } public static long getSerialversionuid() { return serialVersionUID; } @Override public String toString() { return "Person [id=" + id + ", name=" + name + ", gender=" + gender + ", age=" + age + ", passport=" + passport + "]"; } }
映射文件(Person_FK.hbm.xml)
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="com.li.association.one2one.pojo"> <class name="Person" table="T_PERSON"> <id name="id" type="long" column="ID"></id> <property name="name" type="string" column="NAME"></property> <property name="gender" type="string" column="GENDER"></property> <property name="age" type="integer" column="AGE"></property> <one-to-one name="passport" class="Passport" property-ref="person" cascade="all"></one-to-one> </class> </hibernate-mapping>
- Passport类
package com.li.association.one2one.pojo; import java.io.Serializable; public class Passport implements Serializable { private static final long serialVersionUID = -1819074069116356352L; private Long id; private String bh; private Person person; public Passport() { } public Passport(Long id, String bh, Person person) { super(); this.id = id; this.bh = bh; this.person = person; } public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getBh() { return bh; } public void setBh(String bh) { this.bh = bh; } public Person getPerson() { return person; } public void setPerson(Person person) { this.person = person; } public static long getSerialversionuid() { return serialVersionUID; } @Override public String toString() { return "Passport [id=" + id + ", bh=" + bh + "]"; } }
映射文件(Passport_FK.hbm.xml)
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="com.li.association.one2one.pojo"> <class name="Passport" table="T_PASSPORT"> <id name="id" type="long" column="ID"></id> <property name="bh" type="string" column="BH"></property> <many-to-one name="person" class="Person" column="PERSON_ID" unique="true"></many-to-one> </class> </hibernate-mapping>
- 将映射文件配置的核心配置文件中
<mapping resource="com/li/association/one2one/pojo/Passport_FK.hbm.xml"/> <mapping resource="com/li/association/one2one/pojo/Person_FK.hbm.xml"/>
- 测试
package com.li.test; import org.hibernate.Session; import org.hibernate.Transaction; import com.li.association.one2one.pojo.Passport; import com.li.association.one2one.pojo.Person; import com.li.common.CurrentSession; public class Association1 { public static void main(String[] args) { Person p=new Person(); p.setId(123L); p.setName("jack"); p.setGender("male"); p.setAge(20); Passport pp=new Passport(); pp.setId(456L); pp.setBh("G123456"); /*建立双向关联关系*/ p.setPassport(pp); pp.setPerson(p); Session session=CurrentSession.getSession(); Transaction trans=null; try { trans=session.beginTransaction(); /*保存Person对象的同时会级联保存Passport对象*/ //session.save(p); /*使用反射从数据库中获取数据,级联查询,Passport的信息也被查询出来*/ Person person=(Person) session.get(Person.class, 123L); /*在重写toString方法时,只从Person输出Passport即可,Passport中不要输出Person,不然会出栈溢出异常*/ System.out.println(person); /*级联更新*/ person.setName("Lee"); person.setAge(21); person.getPassport().setBh("G456789"); session.update(person); /*级联删除*/ session.delete(person); trans.commit(); } catch (Exception e) { e.printStackTrace(); trans.rollback(); } } }
-
基于主键的映射
Person类配置
<class name="Person" table="T_PERSON"> ...... <one-to-one name="passport" class="Passport" cascade="all"/> </class>
Passport类配置
其中主键生成策略中,name=”property”表示基于Passport类中person属性来生成主键。基于主键映射后面的对应关系配置应为one-to-one,因为主键不应该重复。
<class name="Passport" table="T_PASSPORT"> <id name="id" column="ID" type="long"> <generator class=foreign> <param name="property">person</param> </generator> ...... <one-to-one name="person" class="Person"/> </id> </class>
其余部分与基于外键部分操作类似
推荐阅读
-
JPA中实现双向一对一的关联关系
-
Mybatis使用注解实现一对一复杂关系映射及延迟加载
-
MyBatis3一对一关系映射
-
Mybatis使用注解实现一对一复杂关系映射及延迟加载
-
Mybatis04—注解开发实现CRUD以及实现一对一、一对多及多对多复杂关系映射
-
Mybatis常用的注解开发CRUD&&复杂关系映射(一对一,一对多)&&mybatis 基于注解的二级缓存
-
Mybatis—— 使用注解实现一对一复杂关系映射及延迟加载
-
JPA中映射关系详细说明(一对多,多对一,一对一、多对多)、@JoinColumn、mappedBy说明
-
MyBatis的一对一关联关系映射
-
Hibernate:对象关联关系映射