Hibernate学习之路(七): 双向一对一映射

基于外键的一对一映射关系(双方互相持有对方的引用)
  • 对于基于外键的1-1关联,其外键可以存放在任意一边,在需要存放外键一端,增加many-to-one元素。为many-to-one元素增加unique=“true” 属性来表示为1-1关联
<!-- 使用many-to-one的方式来映射1-1关联关系,重点是unique属性要设置为true -->
        <many-to-one name="manager" class="Manager" column="MGR_ID" unique="true">
        </many-to-one>
  • 另一端需要使用one-to-one元素,该元素使用 property-ref 属性指定使用被关联实体主键以外的字段作为关联字段
<!-- 映射一对一关系:另外的一已经有了外键,这个一就使用 one-to-one 进行映射
    property-ref="manager"表示指定使用被关联实体主键以外的字段作为关联字段(一般是外键字段)
         -->
        <one-to-one name="dept" class="Dept" property-ref="manager"></one-to-one>
  • 完整代码如下:
    Dept.java
public class Dept {

    private Integer id;
    private String name;
    private Manager manager;

    //getter,setter略
}

Manager.java

public class Manager {
    private Integer id;
    private String name;
    private Dept dept;

    //getter,setter略
}

Dept.hbm.xml

<hibernate-mapping package="com.zc.cris.onetonoe.foreign">
    <class name="Dept" table="DEPTS">
        <id name="id" type="java.lang.Integer">
            <column name="ID" />
            <generator class="native" />
        </id>
        <property name="name" type="java.lang.String">
            <column name="NAME" />
        </property>

        <!-- 使用many-to-one的方式来映射1-1关联关系,重点是unique属性要设置为true -->
        <many-to-one name="manager" class="Manager" column="MGR_ID" unique="true">
        </many-to-one>

    </class>
</hibernate-mapping>

Manager.hbm.xml

<hibernate-mapping package="com.zc.cris.onetonoe.foreign">

    <class name="Manager" table="MANAGERS">
        <id name="id" type="java.lang.Integer">
            <column name="ID" />
            <generator class="native" />
        </id>
        <property name="name" type="java.lang.String">
            <column name="NAME" />
        </property>

        <!-- 
            映射一对一关系:另外的一已经有了外键,这个一就使用 one-to-one 进行映射
            property-ref="manager"表示指定使用被关联实体主键以外的字段作为关联字段(一般是外键字段)
         -->
        <one-to-one name="dept" class="Dept" property-ref="manager"></one-to-one>

    </class>
</hibernate-mapping>

核心配置文件略

TestHibernate2.java

class TestHibernate2 {

    private SessionFactory sessionFactory = null;
    private Session session = null;
    private Transaction transaction = null;

    //init和destroy方法略

    @Test
    void testGet() {

        //默认情况下查询有外键一端同样会出现懒加载
//      Dept dept = this.session.get(Dept.class, 1);
//      System.out.println(dept.getName());
//      this.session.close();
//      
        //默认情况下查询没有外键一端会把对应的另外一端查询出来,因为对于hibernate来说,它并不知道
        //这个没有外键的表的对应关联关系,所以会把关联的数据一并查询出来
//          select
//              manager0_.ID as ID1_1_0_,
//              manager0_.NAME as NAME2_1_0_,
//              dept1_.ID as ID1_0_1_,
//              dept1_.NAME as NAME2_0_1_,
//              dept1_.MGR_ID as MGR_ID3_0_1_ 
//                  from
//                      MANAGERS manager0_ 
//                  left outer join
//                      DEPTS dept1_ 
//                          on manager0_.ID=dept1_.ID 
//                  where
//                      manager0_.ID=?

        //仔细观察,以上sql语句是有问题的,左外连接的条件应该是:manager.id = dept.manager_id
        //而不应该是manager.id = dept.id
        //所以需要在Manager对应的映射文件中的one-to-one节点设置属性property-ref="manager"
        Manager manager = this.session.get(Manager.class, 1);
        System.out.println(manager.getName());
//      System.out.println(manager.getDept().getName());

    }

    @Test
    void testSave() {

        Manager manager = new Manager();
        manager.setName("aa");

        Dept dept = new Dept();
        dept.setName("bb");

        manager.setDept(dept);
        dept.setManager(manager);

        //建议先保存没有外键的一方,防止发送多余的update语句
        this.session.save(manager);
        this.session.save(dept);
    }
为什么不使用两边都使用外键的一对一映射?

如果是两个对象都使用外键来映射一对一关系,是有可能出现逻辑上的问题(类似于两男两女,男A喜欢的对象是女A,但是女A喜欢的对象却不一定是男A,有可能是男B,无法正确显示一一对应的关系)

基于主键的一对一映射
  • 和基于外键的一对一映射差不多,无非就是将某个一的主键设置为另外一个一的主键,并为其添加外键约束即可

  • 代码:
    Dept.hbm.xml

<hibernate-mapping package="com.zc.cris.onetonoe.primary">
    <class name="Dept" table="DEPTS">
        <id name="id" type="java.lang.Integer">
            <column name="ID" />
            <!-- 表示当前一端的主键依赖于manager属性的主键 -->
            <generator class="foreign" >
                <param name="property">manager</param>
            </generator>
        </id>
        <property name="name" type="java.lang.String">
            <column name="NAME" />
        </property>

        <!-- one-to-one的方式来映射1-1关联关系,需要为当前主键设置外键约束 -->
       <one-to-one name="manager" class="Manager" constrained="true"></one-to-one>

    </class>
</hibernate-mapping>

Manager.hbm.xml

<hibernate-mapping package="com.zc.cris.onetonoe.primary">

    <class name="Manager" table="MANAGERS">
        <id name="id" type="java.lang.Integer">
            <column name="ID" />
            <generator class="native" />
        </id>
        <property name="name" type="java.lang.String">
            <column name="NAME" />
        </property>

        <!-- 
            映射一对一关系:另外的一的主键引用当前一的主键作为外键
         -->
        <one-to-one name="dept" class="Dept"></one-to-one>

    </class>
</hibernate-mapping>

TestHibernate2.java

class TestHibernate2 {

    private SessionFactory sessionFactory = null;
    private Session session = null;
    private Transaction transaction = null;

    //init和destroy方法略

    @Test
    void testGet() {

        //默认情况下查询有外键一端同样会出现懒加载
//      Dept dept = this.session.get(Dept.class, 1);
//      System.out.println(dept.getName());
//      this.session.close();
//      
        //默认情况下查询没有外键一端会把对应的另外一端查询出来,因为对于hibernate来说,它并不知道
        //这个没有外键的表的对应关联关系,所以会把关联的数据一并查询出来
//          select
//              manager0_.ID as ID1_1_0_,
//              manager0_.NAME as NAME2_1_0_,
//              dept1_.ID as ID1_0_1_,
//              dept1_.NAME as NAME2_0_1_,
//              dept1_.MGR_ID as MGR_ID3_0_1_ 
//                  from
//                      MANAGERS manager0_ 
//                  left outer join
//                      DEPTS dept1_ 
//                          on manager0_.ID=dept1_.ID 
//                  where
//                      manager0_.ID=?

        Manager manager = this.session.get(Manager.class, 1);
        System.out.println(manager.getName());
//      System.out.println(manager.getDept().getName());

    }

    @Test
    void testSave() {

        Manager manager = new Manager();
        manager.setName("aa");

        Dept dept = new Dept();
        dept.setName("bb");

        manager.setDept(dept);
        dept.setManager(manager);

        //保存顺序无所谓,因为一定会先插入被依赖的一端的数据,即使先保存dept,也会先执行manager的insert语句
        this.session.save(manager);
        this.session.save(dept);
    }
}

点我获取源代码

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值