四、一对一
一对一分为,基于主键的一对一,和基于外键的一对一。
基于主键的一对一,指的是,idCard表的主键就是外键,它的值参考person表的id,而不需要重新生成一个字段来记录到底这个idCard是指向哪个person的。
而基于外键的一对一,指的是,person的id我们自定,idCard的id我们也自定。我们要根据用户的代码idCard.setPerson(),在idCard表中新增成一个字段person,来记录到底这个idCard是属于哪个person的。
1.基于主键的一对一
基于主键的一对一:
在person表中,person_id是主键,在IdCard表中,card_id不仅是主键,也是外键--它的值是复制Person_id的。
①创建domain
②创建(domain).hbm.xml
<hibernate-mapping package="com.myz.domain"> <class name="Person" table="person"> <id name="id" type="java.lang.Integer"> <!-- 手动分配id号 --> <generator class="assigned"></generator> </id> <property name="name" type="java.lang.String"> <column name="name" length="64"></column> </property> <!-- 配置person和idCard属性是一对一的关系 --> <one-to-one name="idCard"></one-to-one> </class> </hibernate-mapping>
<hibernate-mapping package="com.myz.domain"> <class name="IdCard" table="idCard"> <id name="id" type="java.lang.Integer"> <!-- 因为我们这里是基于主键的一对一,说明Idcard的主键是依赖于Person的id的,所以这个主键既是主键,又是外键 --> <generator class="foreign"> <!-- 这里的person指的是跟哪个属性一对一 --> <param name="property">person</param> </generator> </id> <property name="cardtime" type="java.util.Date"> <column name="cardtime" length="64"></column> </property> <!-- 配置IdCard和person属性是一对一的关系 --> <one-to-one name="person"></one-to-one> </class> </hibernate-mapping>
③关系详解
④创建hibernate.hbm.xml,并让hibernate帮我们创建数据库
<session-factory> <property name="dialect"> org.hibernate.dialect.MySQLDialect </property> <property name="connection.url"> jdbc:mysql://localhost:3306/test1 </property> <property name="connection.username">root</property> <property name="connection.password">123456</property> <property name="connection.driver_class">com.mysql.jdbc.Driver</property> <property name="myeclipse.connection.profile">mysql</property> <property name="show_sql">true</property> <property name="hbm2ddl.auto">update</property> <mapping resource="com/myz/domain/Person.hbm.xml" /> <mapping resource="com/myz/domain/IdCard.hbm.xml" /> </session-factory>
⑤测试
session=HibernateUtil.getCurrentSession(); ts=session.beginTransaction(); Person p1=new Person(); p1.setId(1); p1.setName("孙悟空"); IdCard idCard=new IdCard(); idCard.setCardtime(new Date()); //表示这个idCard这个对象是属于p1这个对象的 //因为先有person再有idCard,后有的对象设置属性值为先有的对象 idCard.setPerson(p1); //先有人再有idcard,保存也是先保存先有的对象 session.save(p1); session.save(idCard); ts.commit();
这时数据库虽然有person表和idCard表,而且idCard表主键确实也根据person主键确定,但是idCard表却没有外键,idCard的id应该既是主键又是外键才对,这是因为我们没有让hibernate帮我们自动生成外键,在Idcard.hbm.xml处修改:
<one-to-one name="person" constrained="true"></one-to-one>
constrained默认为false,表示不生成外键
此时再执行操作,发现idcard表生成了外键。跟person表的主键相对应。
总结:
配置domain.hbm.xml的时候 ,一个属性一个属性往下配,如果是主键就写到<id>里去,如果是普通属性就写到<property>里去,如果是对象属性就写到一对一里去。哪个值需要参考别的表的值,生成策略就是foreign。哪个表需要生成外键,就在一对一里写上constrained="true"。
2.基于外键的一对一
与基于主键的一对一不同的是,虽然domain结构一样,我们想自己给idCard指定id,而让它给我们自动生成一个实实在在的外键person,指向person的id。
①创建domain对象
②创建Person.hbm.xml
③创建idCard.hbm.xml
<class name="IDCard" table="sqlIDCard"> <id name="cardId" type="java.lang.Integer"> <column name="sqlCardId"></column> <generator class="assigned"> </generator> </id> <property name="cardTime" type="java.util.Date"> <column name="sqlCardTime"></column> </property> //由于多个外键可以指向同一个主键,所以是many-to-one //由于一张身份证只能归一人持有,所以需要添加unique,防止多个外键指向同一个主键 //所以即使这个是一对一的关系,我们还是使用many-to-one <many-to-one name="person" unique="true"></many-to-one> </class>
④测试
public static void main(String[] args) { // TODO Auto-generated method stub Session session=null; Transaction ts=null; try { session=HibernateUtil.getCurrentSession(); ts=session.beginTransaction(); Person p1=new Person(); p1.setPersonId(8); p1.setPersonName("jack"); IDCard idCard=new IDCard(); idCard.setCardId(101); idCard.setCardTime(new Date()); idCard.setPerson(p1); session.save(idCard); session.save(p1); ts.commit(); } catch (Exception e) { // TODO: handle exception e.printStackTrace(); ts.rollback(); }finally{ if(ts.isActive()) ts=null; if(session.isOpen()) session.close(); } }
⑤查看mysql
IdCard表总共有三个字段,id,name,person。系统自动生成了一个字段,person。是外键,它指向person表的id。