Hibernate -- 一对一映射
一对一关联指两个表之间的记录是一一对应的关系。分为两种:外键关联和主键关联。
(1)外键关联
比如一家公司(Company)和它所在的地址(Address)。在业务逻辑中要求一家公司只有唯一的地址,一个地址也只有一家公司。下图表现为外键关联关系。
对于基于外键的1-1关联,其外键可以存放在任意一边,在需要存放外键一端,增加many-to-one
元素。为many-to-one元素增加unique=“true”属性来表示为1-1关联,并用name属性来指定关联属性的属性名
另一端需要使用one-to-one元素,该元素使用property-ref(可以不加)属性指定使用被关联实体主键以外的字段作为关联字段
示例代码:
Company.java bean对象
public class Company implements java.io.Serializable { private Integer id; private String name; //一家公司对应一个地址 private Address address; 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 Address getAddress() { return address; } public void setAddress(Address address) { this.address = address; } }
Address.java
public class Address implements java.io.Serializable{ private Integer id; private String city; private String country; //一个地址含有一家公司 private Company company; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getCity() { return city; } public void setCity(String city) { this.city = city; } public String getCountry() { return country; } public void setCountry(String country) { this.country = country; } public Company getCompany() { return company; } public void setCompany(Company company) { this.company = company; } }
Company.hbm.xml 映射配置文件
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <class name="cn.itcast.one2onefk.Company" table="companyfk"> <id name="id" type="integer"> <column name="id"/> <generator class="increment"/> </id> <property name="name" type="string"> <column name="name"/> </property> <!-- 一对一外键关联 many-to-one:使用many-to-one unique="true":设置companyfk表的外键唯一 addressid integer unique, --> <many-to-one name="address" column="addressid" unique="true"/> </class> </hibernate-mapping>
Address.hbm.xml 映射配置文件
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <class name="cn.itcast.one2onefk.Address" table="addressfk"> <id name="id" type="integer"> <column name="id"/> <generator class="increment"/> </id> <property name="city" type="string"> <column name="city"/> </property> <property name="country" type="string"> <column name="country"/> </property> <!-- 映射一对一 property-ref(互相引用):company属性管理的address这个属性 property-ref的值为Company这个类中的address属性(可以不加) --> <one-to-one name="company" property-ref="address"/> </class> </hibernate-mapping>
App.java 测试代码
public class App { private static SessionFactory sf=null; static{ Configuration config=new Configuration(); config.configure("cn/itcast/one2onefk/hibernate.cfg.xml"); config.addClass(Company.class); config.addClass(Address.class); sf=config.buildSessionFactory(); } /* * 知识点1:测试保存 */ @Test public void saveCompanyAndAddress(){ Session session=sf.openSession(); Transaction tx=session.beginTransaction(); Company c=new Company(); c.setName("长城"); Address address=new Address(); address.setCity("上海"); address.setCountry("中国"); //建立关联 c.setAddress(address); address.setCompany(c); //保存 session.save(address); session.save(c); tx.commit(); session.close(); } //知识点2:测试唯一性 @Test public void testUnique(){ Session session=sf.openSession(); Transaction tx=session.beginTransaction(); Company c=new Company(); c.setName("天空网"); //获取一号地址 Address address=(Address)session.get(Address.class, 1); //建立关联 c.setAddress(address); address.setCompany(c); //不能保存 session.save(c); tx.commit(); session.close(); } }
(2)主键关联
一对一的另一种解决方式就是主键关联,在这种关联关系中,要求两个对象的主键必须保持一致,一方既是主键又是外键,通过两个表的主键建立关联关系,无须外键参与。
基于主键的映射策略:指一端的主键生成器使用
foreign 策略,表明根据”对方”的主键来生成自己的主键,自己并不能独立生成主键.
<param> 子元素指定使用当前持久化类的哪个属性作为 “对方”
采用foreign主键生成器策略的一端增加
one-to-one 元素映射关联属性,其
one-to-one 属性还应增加
constrained=“true”属性;另一端(company)增加one-to-one元素映射关联属性。
constrained(约束):指定为当前持久化类对应的数据库表的主键添加一个外键约束,引用被关联的对象(“对方”)所对应的数据库表主键
示例代码, java bean类 和 测试代码与(1)中一样, 不同的只有映射配置文件。
Address.hbm.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <class name="cn.itcast.one2onepk.Address" table="addresspk"> <id name="id" type="integer"> <column name="id"/> <!-- foreign:表示addresspk表的主键的生成参照另一个表(companypk的)主键 这里addresspk表的主键值来源于companypk表的主键,不是该addresspk表自己生成 --> <generator class="foreign"> <!-- property:该Address类对应表主键的生成,参照该类中的属性company --> <param name="property">company</param> </generator> </id> <property name="city" type="string"> <column name="city"/> </property> <property name="country" type="string"> <column name="country"/> </property> <!--one-to-one配置Address和Company的一对一关联 constrained="true":为addresspk增加外键约束 --> <one-to-one name="company" constrained="true"/> </class> </hibernate-mapping>
Company.hbm.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <class name="cn.itcast.one2onepk.Company" table="companypk"> <id name="id" type="integer"> <column name="id"/> <generator class="increment"/> </id> <property name="name" type="string"> <column name="name"/> </property> <!-- 配置Company和地址的一对一关联 --> <one-to-one name="address"/> </class> </hibernate-mapping>