zoukankan      html  css  js  c++  java
  • Hibernate 一对一关联查询

    版权声明:本文为博主原创文章,如需转载请标注转载地址。

    博客地址:http://www.cnblogs.com/caoyc/p/5602418.html 

    一对一关联,可以分为两种。一种是基于外键的关联,另一种是基于主键的关联。如图

    一、基于外键的方式

      

      User.java

     1 package com.proc.one2one;
     2 
     3 public class User {
     4 
     5     private Integer id;
     6     private String name;
     7     private IdCard card;
     8     public User() {
     9     }
    10     public User(String name) {
    11         this.name = name;
    12     }
    13     public Integer getId() {
    14         return id;
    15     }
    16     public void setId(Integer id) {
    17         this.id = id;
    18     }
    19     public String getName() {
    20         return name;
    21     }
    22     public void setName(String name) {
    23         this.name = name;
    24     }
    25     public IdCard getCard() {
    26         return card;
    27     }
    28     public void setCard(IdCard card) {
    29         this.card = card;
    30     }
    31     @Override
    32     public String toString() {
    33         return "User [id=" + id + ", name=" + name + "]";
    34     }
    35 }

      IdCard.java

     1 package com.proc.one2one;
     2 
     3 public class IdCard {
     4 
     5     private Integer id;
     6     private String cardNo;
     7     private User user;
     8     public IdCard(String cardNo) {
     9         this.cardNo = cardNo;
    10     }
    11     public IdCard() {
    12     }
    13     public Integer getId() {
    14         return id;
    15     }
    16     public void setId(Integer id) {
    17         this.id = id;
    18     }
    19     public String getCardNo() {
    20         return cardNo;
    21     }
    22     public void setCardNo(String cardNo) {
    23         this.cardNo = cardNo;
    24     }
    25     public User getUser() {
    26         return user;
    27     }
    28     public void setUser(User user) {
    29         this.user = user;
    30     }
    31     @Override
    32     public String toString() {
    33         return "IdCard [id=" + id + ", cardNo=" + cardNo + "]";
    34     }
    35     
    36 }

      

      User.hbm.xml

     1 <?xml version="1.0" encoding="UTF-8" ?>
     2 <!DOCTYPE hibernate-mapping PUBLIC 
     3     "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
     4     "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
     5 <hibernate-mapping package="com.proc.one2one">
     6     <class name="User" table="t_user">
     7         <id name="id" type="int" column="id" >
     8             <generator class="native"></generator>
     9         </id>
    10         <property name="name" length="20" not-null="true"></property>
    11         <one-to-one name="card" class="IdCard"></one-to-one>
    12     </class>
    13 </hibernate-mapping>

      

      IdCard.hbm.xml

     1 <?xml version="1.0" encoding="UTF-8" ?>
     2 <!DOCTYPE hibernate-mapping PUBLIC 
     3     "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
     4     "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
     5 <hibernate-mapping package="com.proc.one2one">
     6     <class name="IdCard" table="t_idcard">
     7         <id name="id" type="int" column="id" >
     8             <generator class="native"></generator>
     9         </id>
    10         <property name="cardNo" type="string" column="cardNo" length="20" not-null="true"></property>
    11         <many-to-one name="user" column="userid" class="User" unique="true"></many-to-one>
    12     </class>
    13 </hibernate-mapping>

      我们可以看到一个是one-to-one一个是many-to-one的unique。

      分清楚这两个很重要,many-to-one用在保存外键的表,也就是说t_idcard表,one-to-one用在没有保存外键的表,也就是user表.

    测试代码:

    1、添加关联关系

    测试:1:

     1 public class App {
     2 
     3     private static SessionFactory factory=new Configuration()
     4                     .configure()
     5                     .addClass(User.class)
     6                     .addClass(IdCard.class)
     7                     .buildSessionFactory();
     8     
     9     @Test
    10     public void test(){
    11         
    12         Session session=factory.openSession();
    13         Transaction tx=session.beginTransaction();
    14         
    15         User user=new User("caoyc");
    16         IdCard card=new IdCard("510123588413x");
    17         
    18         card.setUser(user);
    19         session.save(user);
    20         session.save(card);
    21         tx.commit();
    22         session.close();
    23         
    24     }
    25 }

      上面我们通过IdCard来维护关联关系,结果正确

      

    测试2:

      下面我们来试一试通过User来维护关联关系,看结果会怎么样?

     1     @Test
     2     public void test(){
     3         
     4         Session session=factory.openSession();
     5         Transaction tx=session.beginTransaction();
     6         
     7         User user=new User("caoyc");
     8         IdCard card=new IdCard("510123588413x");
     9         
    10         user.setCard(card);
    11         
    12         session.save(user);
    13         session.save(card);
    14         tx.commit();
    15         session.close();
    16         
    17     }

      在数据库中我们可以看到,数据库中表的结构完全一致,而且在t_user中也插入了数据,在t_idcard表中也同样有数据,只不过,t_idcard表中的userid列为null,也就是说,通过user无法维护关联关系

      【总结】:在有外键的一方,可以维护关联关系,而在没有外键的一方无法维护关联关系

    测试3:

      我们交换user对象和card对象的保存顺序

    1 session.save(card);
    2 session.save(user);

      结果数据也能够正常插入到数据库中,结果和测试1相同。那么交换保存顺序是否有其他影响呢?答案是肯定的,虽然数据同样插入进去了,但是在具体插入过程却有不同。

      在测试1中:我们先保存的user,通过insert into语句我们将数据正确插入,然后我们在保存card,而此时的user对象由于已经在数据库中存在,那么必然有主键ID存在,我们在插入到IdCard表中,数据全部完全插入。具体sql语句

    1 Hibernate: insert into t_user (name) values (?)
    2 Hibernate: insert into t_idcard (cardNo, userid) values (?, ?)

      在测试3中:我们先将card的数据保存到idcard表中,而此时的user的id值为null,所有在插入到idcard中是,userid会是nul

      l

      然后在插入user到t_user表中,那么此时user的主键值已经生成。为了维护关联关系

      系统会有执行一条语句

      update t_idcard set cardNo=?, userid=? where id=?

      所有在测试3中,我们会看到

    1 Hibernate: insert into t_idcard (cardNo, userid) values (?, ?)
    2 Hibernate: insert into t_user (name) values (?)
    3 Hibernate: update t_idcard set cardNo=?, userid=? where id=?

      【总结】:在保存数据时,我们先保存没有外键的一方,然后在保存有外键的一方,这样执行效率更高

     

    2、解除关联关系

    测试1:通过User来解除关联关系

     1     @Test
     2     public void test(){
     3         
     4         Session session=factory.openSession();
     5         Transaction tx=session.beginTransaction();
     6         
     7         User user=session.get(User.class, 1);
     8         user.setCard(null);
     9 
    10         tx.commit();
    11         session.close();
    12         
    13     }

      执行的SQL语句

    Hibernate: select user0_.id as id1_1_0_, user0_.name as name2_1_0_, idcard1_.id as id1_0_1_, idcard1_.cardNo as cardNo2_0_1_, idcard1_.userid as userid3_0_1_ from t_user user0_ left outer join t_idcard idcard1_ on user0_.id=idcard1_.id where user0_.id=?

      可以看到,此时通过user无法来解除关联关系

    测试2:通过idcard来解除关联关系

     1     @Test
     2     public void test(){
     3         
     4         Session session=factory.openSession();
     5         Transaction tx=session.beginTransaction();
     6         
     7         IdCard card=session.get(IdCard.class, 1);
     8         card.setUser(null);
     9 
    10         tx.commit();
    11         session.close();
    12         
    13     }

      执行的SQL语句

    1 Hibernate: select idcard0_.id as id1_0_0_, idcard0_.cardNo as cardNo2_0_0_, idcard0_.userid as userid3_0_0_ from t_idcard idcard0_ where idcard0_.id=?
    2 Hibernate: update t_idcard set cardNo=?, userid=? where id=?

      在数据库中也可看到通过idcard的确能够解除关联关系

     

    3、删除操作

    测试1:删除user

     1     @Test
     2     public void test(){
     3         
     4         Session session=factory.openSession();
     5         Transaction tx=session.beginTransaction();
     6         
     7         User user=session.get(User.class, 1);
     8         session.delete(user);
     9 
    10         tx.commit();
    11         session.close();
    12         
    13     }

      如果此时将要删除的user数据在t_idcard表中没有对应相应的数据,那么可以删除成功,否则将会抛出异常,意思说有外键约束,该数据无法删除

    测试2:删除idcard

    1     public void test(){
    2         
    3         Session session=factory.openSession();
    4         Transaction tx=session.beginTransaction();
    5         IdCard card=session.get(IdCard.class, 1);
    6         session.delete(card);
    7         tx.commit();
    8         session.close();
    9     }

      结果:删除成功 

    Question:在上面测试2中,我们删除了t_idcard中的数据,如果我需要当删除了t_idcard中的数据后,同样删除t_user中对应的属性,我们该怎么办呢?

    Answer: 那么我们需要设置cascade属性为delete,我们在IdCard.hbm.xml

    <many-to-one name="user" column="userid" class="User" unique="true" cascade="delete"></many-to-one>

    也就是说,我们在删除对象idCard是,同样对其属性user也做删除动作

    外键方式总结:

      1、在有外键的一方,可以维护关联关系,可以建立关联关系,同样也可以解除关联关系,可以任意删除本对象,如果在hbm.xml中设置了cascade="delete",也可以删除关联对象

      2、在没有外键的一方,不可以维护关联关系,所有无法建立关联关系,也无法解除关联关系。在删除过程中,如有没有外键值对应本条数据,可以成功删除,否则会抛出异常

      

    二、基于主键的关联方式

      基于外键方式:一个many-to-one(有外键方)和一个one-to-one(无外键方法)

      基于主键方式:两个都是one-to-one

      还是上面的例子,其它我们都不需要改变,我们只需要改变IdCard.hbm.xml就可以,具体代码如下

     1 <?xml version="1.0" encoding="UTF-8" ?>
     2 <!DOCTYPE hibernate-mapping PUBLIC 
     3     "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
     4     "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
     5 <hibernate-mapping package="com.proc.one2one">
     6     <class name="IdCard" table="t_idcard">
     7         <id name="id" type="int" column="id" >
     8             <generator class="foreign">
     9                 <param name="property">user</param>
    10             </generator>
    11         </id>
    12         <property name="cardNo" type="string" column="cardNo" length="20" not-null="true"></property>
    13         <one-to-one name="user" class="User" constrained="true"></one-to-one>
    14     </class>
    15 </hibernate-mapping>

     

      代码说明:

        1、由于是基于主键方式,所有对应t_idcard表的主键id也是来自于t_user表,所有对应IdCard主键生成策略我们选用foregin,其中还必须指定一个从参数property,表示该主键生成策略基于对象的那个属性,我们这里的属性是user

        2、constrained="true":表示给t_idcard添加一个外键约束,默认为false,不添加外键约束

  • 相关阅读:
    软件工程实践项目课程的自我目标
    个人作业3——个人总结(Alpha阶段)
    结对编程2——单元测试
    个人作业2——英语学习APP案例分析
    结对编程1
    个人作业1——四则运算题目生成程序(基于控制台)
    关于在写5-3路上的一点趣事
    第一次课堂作业
    第四次作业
    面向对象程序设计课-第三次作业(改)
  • 原文地址:https://www.cnblogs.com/caoyc/p/5602418.html
Copyright © 2011-2022 走看看