比如有2个类:
public class A{ private int id; private B b; //省略构造及getter,setter方法 } public class B{ private int id; //省略构造及getter,setter方法 }
B主A从,那么,在调用save方法保存A前,必须先用A的set方法将b属性对应的对象添加,否则失败。主对象可以单独保存。判断主从的依据是,数据库的设计(主要的,你设计为主表即为主控方);既是主键又是外键,则为从。被参考的主键所在的表对应的则为主。
因为是整理,所以在说映射之前将一对一关系中的有的东西先说清楚。DAO代码不再附上,仅附上sql脚本和映射文件及对应的类,其实SQL中的外键关系在数据库表中都不用体现,因为有Hibernate映射文件约束,但为了清楚和手动插入数据的完整性,还是加上了。
数据库MySQL5.6,脚本:
CREATE TABLE `address1` ( `id` int(11) NOT NULL AUTO_INCREMENT, `city` varchar(40) DEFAULT NULL, `street` varchar(100) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; CREATE TABLE `adress` ( `id` int(11) NOT NULL DEFAULT '0', `city` varchar(40) DEFAULT NULL, `street` varchar(100) DEFAULT NULL, PRIMARY KEY (`id`), CONSTRAINT `fk_a_p` FOREIGN KEY (`id`) REFERENCES `person` (`id`) ON DELETE CASCADE ON UPDATE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8; CREATE TABLE `person` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(16) DEFAULT NULL, `gender` varchar(2) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; CREATE TABLE `person1` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(16) DEFAULT NULL, `gender` varchar(2) DEFAULT NULL, `adress` int(11) DEFAULT NULL, PRIMARY KEY (`id`), KEY `fk_p_ad` (`adress`), CONSTRAINT `fk_p_ad` FOREIGN KEY (`adress`) REFERENCES `address1` (`id`) ON DELETE CASCADE ON UPDATE NO ACTION ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
一对一关系映射,共享主键方式:
类person为主,adress为从
package model; /** * Person entity */ public class Person implements java.io.Serializable { private Integer id; private Adress adress; private String name; private String gender; /** default constructor */ public Person() { } /** full constructor */ public Person(Adress adress, String name, String gender) { this.adress = adress; this.name = name; this.gender = gender; } public Integer getId() { return this.id; } public void setId(Integer id) { this.id = id; } public Adress getAdress() { return this.adress; } public void setAdress(Adress adress) { this.adress = adress; } 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; } } package model; /** * Adress entity */ public class Adress implements java.io.Serializable { private Integer id; private String city; private String street; private Person person; /** default constructor */ public Adress() { } /** full constructor */ public Adress(Integer id, String city, String street, Person person) { this.id = id; this.city = city; this.street = street; this.person = person; } public Integer getId() { return this.id; } public void setId(Integer id) { this.id = id; } public String getCity() { return this.city; } public void setCity(String city) { this.city = city; } public String getStreet() { return this.street; } public void setStreet(String street) { this.street = street; } public Person getPerson() { return this.person; } public void setPerson(Person person) { this.person = person; } }
映射文件
Person.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="model.Person" table="person" catalog="study"> <id name="id" type="java.lang.Integer"> <column name="id" /> <generator class="native" /> </id> <!-- 一对一映射设置,检索策略立即加载 --> <one-to-one name="adress" class="model.Adress" cascade="all" lazy="false"/> <property name="name" type="java.lang.String"> <column name="name" length="16" /> </property> <property name="gender" type="java.lang.String"> <column name="gender" length="2" /> </property> </class> </hibernate-mapping>
Adress.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="model.Adress" table="adress" catalog="study"> <id name="id" type="java.lang.Integer"> <column name="id" /> <!-- 使用外键生成器,直接采用外键的属性值作为主键值 --> <generator class="foreign"> <param name="property">person</param> </generator> </id> <property name="city" type="java.lang.String"> <column name="city" length="40" /> </property> <property name="street" type="java.lang.String"> <column name="street" length="100" /> </property> <!-- 一对一映射, constrained="true"说明主键上存在外键约束 --> <one-to-one name="person" class="model.Person" constrained="true" /> </class> </hibernate-mapping>
一对一关系映射,唯一外键方式:
类一样,映射文件不同,但为了清楚,还是稍作区别,其实只是类名改变了下。
类:
package model; /** * Person1 entity */ public class Person1 implements java.io.Serializable { private Integer id; private Address1 address1; private String name; private String gender; /** default constructor */ public Person1() { } /** full constructor */ public Person1(Address1 address1, String name, String gender) { this.address1 = address1; this.name = name; this.gender = gender; } public Integer getId() { return this.id; } public void setId(Integer id) { this.id = id; } public Address1 getAddress1() { return this.address1; } public void setAddress1(Address1 address1) { this.address1 = address1; } 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; } } package model; /** * Address1 entity */ public class Address1 implements java.io.Serializable { private Integer id; private String city; private String street; private Person1 person1; /** default constructor */ public Address1() { } /** full constructor */ public Address1(String city, String street, Person1 person1) { this.city = city; this.street = street; this.person1 = person1; } public Integer getId() { return this.id; } public void setId(Integer id) { this.id = id; } public String getCity() { return this.city; } public void setCity(String city) { this.city = city; } public String getStreet() { return this.street; } public void setStreet(String street) { this.street = street; } public Person1 getPerson1() { return this.person1; } public void setPerson1s(Person1 person1) { this.person1 = person1; } }
映射文件:
Person1.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="model.Person1" table="person1" catalog="study"> <id name="id" type="java.lang.Integer"> <column name="id" /> <generator class="native" /> </id> <!-- 一般来说采用外键会表现为一对多,参考方为多,被参考方为1,亦即是拥有外键约束的一方为多。但通过在外键上增加唯一性约束,将使得一对多变为一对一 --> <many-to-one name="address1" class="model.Address1" lazy="false" cascade="true" unique="true"> <column name="adress" /> </many-to-one> <property name="name" type="java.lang.String"> <column name="name" length="16" /> </property> <property name="gender" type="java.lang.String"> <column name="gender" length="2" /> </property> </class> </hibernate-mapping>
Address1.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="model.Address1" table="address1" catalog="study"> <id name="id" type="java.lang.Integer"> <column name="id" /> <generator class="native" /> </id> <property name="city" type="java.lang.String"> <column name="city" length="40" /> </property> <property name="street" type="java.lang.String"> <column name="street" length="100" /> </property> <!-- 注意 property-ref属性,是指在person1类中定义address1类作为属性时的属性名称 --> <one-to-one name="person1" class="model.Person1" property-ref="address1" /> </class> </hibernate-mapping>