美文网首页
5.hibernate映射(一对一)

5.hibernate映射(一对一)

作者: arkulo | 来源:发表于2017-07-23 21:42 被阅读14次

一对一关系分以下几种:

  • 单向主键一对一
  • 双向主键一对一
  • 单向外键一对一
  • 双向外键一对一

在此先介绍统一用的实体类:

package entity;

import java.util.Date;


/**
 * 单向one to one,User指向Group
 * 主键关联
 * @author arkulo
 *
 */

public class User {
    private int id;
    private String userName;
    private String passWd;
    private Date addtime;
    private IdCard ic;
    



    public IdCard getIc() {
        return ic;
    }

    public void setIc(IdCard ic) {
        this.ic = ic;
    }

    public Date getAddtime() {
        return addtime;
    }

    public void setAddtime(Date addtime) {
        this.addtime = addtime;
    }

    public User(){}



    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getPassWd() {
        return passWd;
    }

    public void setPassWd(String passWd) {
        this.passWd = passWd;
    }

    
}

package entity;

/**
 * 身份证,不需要指向User
 * @author arkulo
 *
 */
public class IdCard {
    private int id;
    private String idCard;
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getIdCard() {
        return idCard;
    }
    public void setIdCard(String idCard) {
        this.idCard = idCard;
    }

}

一、单向主键一对一

User.hbm.xml

    <?xml version="1.0"?>
    <!DOCTYPE hibernate-mapping PUBLIC 
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
    <hibernate-mapping>
        <class name="entity.User" >
            <id name="id">
                <!-- 单向主键关联,class应该设置成foreign -->
                <generator class="foreign">
                    <!-- User类中的ic这个属性 -->
                    <param name="property">ic</param>
                </generator>
            </id>
            <property name="userName" />        
            <property name="passWd" />
            <property name="addtime" type="time" />
            <!-- constrained表示一个外键约束,默认为false,true的时候数据库表会加外键 -->
            <one-to-one name="ic" constrained="true" cascade="delete"></one-to-one>
        </class>    
    </hibernate-mapping>

idcard.hbm.xml

    <?xml version="1.0"?>
    <!DOCTYPE hibernate-mapping PUBLIC 
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
    <hibernate-mapping>
        <class name="entity.IdCard" >
            <id name="id">
                <generator class="native" />
            </id>
            <property name="idCard" />
        </class>    
    </hibernate-mapping>

单元测试:

    package entity;
    
    import java.util.Date;
    
    import org.hibernate.classic.Session;
    
    import junit.framework.TestCase;
    import util.hibernateUtil;
    
    /**
     * 一对一关联分为两大类:主键关联,唯一外键关联 
     * 一对一关联还有方向之分:单向和双向
     * 
     * 本项目是一对一单向主键关联方式
     * 
     * @author arkulo
     *
     */
    
    public class TestOneToOne extends TestCase {
    
        /**
         * 单向主键one to one,添加数据,注意主键是否需要提前生成
         * 因为是一对一,主键外键关联是做在user表上的,因此,要测试是否提前生成idcard的主键
         */
    
        public void test1() {
            Session session = null;
            try {
                session = hibernateUtil.getSession();
                session.beginTransaction();
    
                IdCard idcard = new IdCard();
                idcard.setIdCard("123456789");
                // 这里不用saveidcard,user保存的时候会一起save
    
                User user = new User();
                user.setUserName("王蕊");
                user.setPassWd("123456");
                user.setAddtime(new Date());
                user.setIc(idcard);
    
                session.save(user);
    
                session.getTransaction().commit();
            } catch (Exception e) {
                e.printStackTrace();
                session.getTransaction().rollback();
            } finally {
                hibernateUtil.closeSession(session);
            }
    
            // 读取关联数据,get函数能不能在读取User的时候,把idCard也读取出来,用不同的session,避免一级缓存
            try {
                session = hibernateUtil.getSession();
                session.beginTransaction();
    
                User user = (User) session.get(User.class, 1);
                System.out.println("用户名:" + user.getUserName());
                // 上面user的查询是直接发出一条sql语句,但是并没有关联查询idcard,当执行到下面这句话的时候,因为可以从user中
                // 获得idcard的主键id,因此又发出了一条sql,条件是id的去查询idcard
                System.out.println("身份证:" + user.getIc().getIdCard());
    
                session.getTransaction().commit();
            } catch (Exception e) {
                e.printStackTrace();
                session.getTransaction().rollback();
            } finally {
                hibernateUtil.closeSession(session);
            }
    
        }
    
        /**
         * 如果要删除idcard数据,user数据会怎么样?
         * 请先用test1函数做数据初始化,初始化后运行此函数,请将hibernate.hbm2ddl.auto改为update
         */
        public void test2() {
            // 在这里调用一下初始化数据的test1函数
            test1();
            System.out.println("----------------------------------");
            Session session = null;
    
            try {
                session = hibernateUtil.getSession();
                session.beginTransaction();
    
                // 因为有外键约束存在,如果构造直接构造一个瞬时状态的IdCard对象,然后直接去删除,系统会报错,提示
                // 有外键约束,不能删除
                // IdCard ic = new IdCard();
                // ic.setId(1);
                // session.delete(ic);
    
                // 这里我们模拟构造一个顺势状态的User,看是否能够直接删除
                // 这里没有构造idcard对象,单独删除user成功,idcard记录没有删除
                // User user = new User();
                // user.setId(1);
                // session.delete(user);
    
                // 这里我们再来试一下,构造了idcard,看能不能关联删除
                // 这里也没有删除idcard
                // IdCard ic = new IdCard();
                // ic.setId(1);
                //
                // User user = new User();
                // user.setId(1);
                // user.setIc(ic);
                // session.delete(user);
    
                // 这里我们设置一下映射文件中的级联方式,让他的级联方式变成delete,看看能不能删除idcard
                // 只有user拥有了id,idcard也拥有了id,加上级联关系,然后删除user的时候,才会连锁删除idcard
                IdCard ic = new IdCard();
                ic.setId(1);
    
                User user = new User();
                user.setId(1);
                user.setIc(ic);
                session.delete(user);
    
                session.getTransaction().commit();
            } catch (Exception e) {
                e.printStackTrace();
                session.getTransaction().rollback();
            } finally {
                hibernateUtil.closeSession(session);
            }
    
        }
    
    }

二、双向主键一对一

    <?xml version="1.0"?>
    <!DOCTYPE hibernate-mapping PUBLIC 
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
    <hibernate-mapping>
        <class name="entity.User" >
            <id name="id">
                <!-- 单向主键关联,class应该设置成foreign -->
                <generator class="foreign">
                    <!-- User类中的ic这个属性 -->
                    <param name="property">ic</param>
                </generator>
            </id>
            <property name="userName" />        
            <property name="passWd" />
            <property name="addtime" type="time" />
            <!-- constrained表示一个外键约束,默认为false -->
            <one-to-one name="ic" constrained="true" cascade="delete"></one-to-one>
        </class>    
    </hibernate-mapping>

    <?xml version="1.0"?>
    <!DOCTYPE hibernate-mapping PUBLIC 
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
    <hibernate-mapping>
        <class name="entity.IdCard" >
            <id name="id">
                <generator class="native" />
            </id>
            <property name="idCard" />
            <!-- 这里不需要设置constrained属性?给idcard也加上这个属性,在数据库中就生成了由idcard表到user表的外键约束-->
            <!-- 不能在一对一关系中,两边都加上constrained属性,会报错的 -->
            <!-- 就是今天,就是今天,我有了人生第一个机械键盘,爽的不行不行的! -->
            <one-to-one name="user"></one-to-one>
        </class>    
    </hibernate-mapping>

单元测试:

    package entity;
    
    import java.util.Date;
    
    import org.hibernate.classic.Session;
    
    import junit.framework.TestCase;
    import util.hibernateUtil;
    
    
    /**
     * 一对一关联分为两大类:主键关联,唯一外键关联
     * 一对一关联还有方向之分:单向和双向
     * 
     * 本项目是双向主键一对一关联,测试目的如下:
     * 1. 双向关联插入?如果是在idcard中添加user对象,是不是保存idcard对象,就算是保存了user对象
     * 2. 不管是读取那个对象的数据,都会带出关联的数据,不需要单独去查询
     * 3. 删除,是否可以反向删除,例如删除idcard,然后会不会也删除user
     * @author arkulo
     *
     */
    
    public class TestOneToOne extends TestCase {
    
        // 1. 双向数据插入的测试
        public void test1() {
            Session session = null;
            try {
                session = hibernateUtil.getSession();
                session.beginTransaction();
                IdCard ic = new IdCard();
                ic.setIdCard("123456789");
    
                User user = new User();
                user.setUserName("王蕊");
                user.setAddtime(new Date());
                user.setPassWd("123323");
                user.setIc(ic);
    
                ic.setUser(user);
    
                // 单独保存idcard不会级联保存user数据,只会单独保存idcard的数据
                // session.save(ic);
    
                // 如果单独保存user对象,会连天idcard对象一起保存
                session.save(user);
    
                session.getTransaction().commit();
            } catch (Exception e) {
                e.printStackTrace();
                session.getTransaction().rollback();
            } finally {
                hibernateUtil.closeSession(session);
            }
        }
    
        /**
         * 2. 读取数据,由user是否能关联查处
         */
        public void test2() {
            // 这里需要调用一下数据初始化函数test
            test1();
            System.out.println("-----------------------------------------");
            Session session = null;
            try {
                session = hibernateUtil.getSession();
                session.beginTransaction();
                // 从user角度读取数据,先发出一条sql语句,查询user,然后打印username,查询idcard的sql语句这时候并没有发出
                User user = (User) session.get(User.class, 1);
                System.out.println("用户名:" + user.getUserName());
                // 在这里要用到idcard的数据的时候,才发出了查询idcard的sql语句(left out join)
                System.out.println("身份证号码:" + user.getIc().getIdCard());
    
                session.getTransaction().commit();
            } catch (Exception e) {
                e.printStackTrace();
                session.getTransaction().rollback();
            } finally {
                hibernateUtil.closeSession(session);
            }
    
            // 这里通过查询idcard,看能不能级联查处user数据,在不同的session里面测试,避免一级缓存
            try {
                session = hibernateUtil.getSession();
                session.beginTransaction();
                IdCard ic = (IdCard) session.get(IdCard.class, 1);
                // 这种情况下,一次性采用连表查询left out join将两张表一起取出来了
                System.out.println("用户名:" + ic.getUser().getUserName());
                System.out.println("身份证编号:" + ic.getIdCard());
    
                session.getTransaction().commit();
            } catch (Exception e) {
                e.printStackTrace();
                session.getTransaction().rollback();
            } finally {
                hibernateUtil.closeSession(session);
            }
    
        }
    
        /**
         * 3. 删除的时候会不会有级联效果
         */
        public void test3() {
            test1();
            System.out.println("-----------------------------");
            Session session = null;
            try {
                session = hibernateUtil.getSession();
                session.beginTransaction();
    
                // 构造一个user瞬时对象,然后直接删除
                IdCard ic = new IdCard();
                ic.setId(1);
    
                User user = new User();
                user.setId(1);
                user.setIc(ic);
    
                ic.setUser(user);
    
                // 如果单独删除user,系统会自动级联删除idcard
                session.delete(user);
    
                // 如果单独删除idcard,系统报错,提示有外键约束,不能删除
                // session.delete(ic);
    
                session.getTransaction().commit();
            } catch (Exception e) {
                e.printStackTrace();
                session.getTransaction().rollback();
            } finally {
                hibernateUtil.closeSession(session);
            }
    
        }
    }

三、单向外键一对一

    <?xml version="1.0"?>
    <!DOCTYPE hibernate-mapping PUBLIC 
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
    <hibernate-mapping>
        <class name="entity.User" >
            <id name="id">
                <generator class="native" />
            </id>
            <property name="userName" />        
            <property name="passWd" />
            <property name="addtime" type="time" />
            <!-- 单向一对一外键关联,其实就是多对一关联设置为唯一 -->
            <many-to-one name="ic" unique="true" cascade="delete"></many-to-one>
        </class>    
    </hibernate-mapping>

    <?xml version="1.0"?>
    <!DOCTYPE hibernate-mapping PUBLIC 
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
    <hibernate-mapping>
        <class name="entity.IdCard" >
            <id name="id">
                <generator class="native" />
            </id>
            <property name="idCard" />
        </class>    
    </hibernate-mapping>

单元测试:

    package entity;
    
    import java.util.Date;
    
    import org.hibernate.classic.Session;
    
    import junit.framework.TestCase;
    import util.hibernateUtil;
    
    
    /**
     * 单向外键一对一关联
     * 
     * 1. 添加数据,级联保存,保存user的时候,是否能同时保存idcard
     * 2. 查询数据,查询user的时候,是否能查处idcard
     * 3. 删除数据,删除user,是否能级联删除idcard,如果把级联规则改掉,删除user,是否可以不删除idcard
     * @author arkulo
     *
     */
    
    
    public class TestOneToOne extends TestCase {
        
    //  添加数据
        public void test1()
        {
            Session session = null;
            try {
                session = hibernateUtil.getSession();
                session.beginTransaction();
                
    //          外间单向关联,首先需要保存idcard,如果只是保存user的时候,会提示错误,user中的外间关联字段会没有值
    //          也就是说,单独保存user的时候,不能一并保存idcard对象
                IdCard ic = new IdCard();
                ic.setIdCard("1234567");
                session.save(ic);
                
                User user = new User();
                user.setUserName("王蕊");
                user.setAddtime(new Date());
                user.setIc(ic);
                
                session.save(user);
                
                session.getTransaction().commit();
            } catch (Exception e) {
                e.printStackTrace();
                session.getTransaction().rollback();
            }finally{
                hibernateUtil.closeSession(session);
            }
        }
    
        
    //  查询数据,是否能实现查询user的时候,一次性关联查询出idcard
        public void test2()
        {
    //      初始化数据
            test1();
            System.out.println("-------------------------------------");
            Session session = null;
            try {
                session = hibernateUtil.getSession();
                session.beginTransaction();
                
    //          采用load查询方式
                User user = (User)session.load(User.class, 1);
    //          这里单独的发出一条sql语句,去查询user表,并没有查询idcard
                System.out.println("用户名:"+user.getUserName());
    //          这里单独的发出了一条sql语句,where条件是id,去查询idcard
                System.out.println("身份证编号:"+user.getIc().getIdCard());
                            
                session.getTransaction().commit();
            } catch (Exception e) {
                e.printStackTrace();
                session.getTransaction().rollback();
            }finally{
                hibernateUtil.closeSession(session);
            }
        }
        
    //  删除操作
        public void test3()
        {
            test1();
            System.out.println("-----------------------------");
            Session session = null;
            
            try {
                session = hibernateUtil.getSession();
                session.beginTransaction();
                
    //          自定义一个idcard瞬时对象
                IdCard ic = new IdCard();
                ic.setId(1);
                
    //          自定义一个顺势对象user
                User user = new User();
                user.setId(1);
                user.setIc(ic);
                
    //          在cascade默认情况下,单独删除user,不会级联删除idcard的!!
    //          在cascade设为delete情况下,单独删除user, 会级联删除idcard
                session.delete(user);
                
                session.getTransaction().commit();
            } catch (Exception e) {
                e.printStackTrace();
                session.getTransaction().rollback();
            }finally{
                hibernateUtil.closeSession(session);
            }
        }
        
        
    }

四、双向外键一对一

    <?xml version="1.0"?>
    <!DOCTYPE hibernate-mapping PUBLIC 
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
    <hibernate-mapping>
        <class name="entity.User" >
            <id name="id">
                <generator class="native" />
            </id>
            <property name="userName" />        
            <property name="passWd" />
            <property name="addtime" type="time" />
            <!-- 单向一对一外键关联,其实就是多对一关联设置为唯一 -->
            <many-to-one name="ic" unique="true" cascade="delete"></many-to-one>
        </class>    
    </hibernate-mapping>

    <?xml version="1.0"?>
    <!DOCTYPE hibernate-mapping PUBLIC 
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
    <hibernate-mapping>
        <class name="entity.IdCard" >
            <id name="id">
                <generator class="native" />
            </id>
            <property name="idCard" />
            <!-- 
            先抛出问题:
                one to one默认是两个对象的主键进行关联,而我们现在是要用外键关联,也就是说User的一个属性(非主键)要和idcard进行关联,
            这个如何设置? 
            
            解决办法:
                property-ref这个选项可以设定User对象中哪个属性和idcard表的主键进行关联,实际代码中指定是user对象的ic属性。
            -->
            <one-to-one name="user" property-ref="ic"></one-to-one>
        </class>    
    </hibernate-mapping>

单元测试:

    package entity;
    
    import java.util.Date;
    
    import org.hibernate.classic.Session;
    
    import junit.framework.TestCase;
    import util.hibernateUtil;
    
    /**
     * 双向一对一外键关联
     * 1. 在设置映射的时候,idcard的one to one映射加上property-ref的作用
     * 2. 新增,新增之后查看idcard和user之间的关联关系
     * 3. 查询,双向关联是基于对象之间的,不是数据库表之间的,数据库表里还是user表中加字段,关联idcard
     * 4. 删除,双向关联,删除idcard会删除user吗?
     * @author arkulo
     *
     */
    
    
    public class TestOneToOne extends TestCase {
    //  新增数据
        public void test1(){
            Session session = null;
            try {
                session = hibernateUtil.getSession();
                session.beginTransaction();
                
                IdCard ic = new IdCard();
                ic.setIdCard("12345678");
                
                User user = new User();
                user.setUserName("王蕊");
                user.setPassWd("242424");
                user.setAddtime(new Date());
                user.setIc(ic);
                
                ic.setUser(user);
                
    //          这里我们来尝试一下,如果我们要保存idcard,能否一起保存use对象
    //          单独保存idcard对象,只能保存idcard,不会级联保存user
    //          如果在idcard的映射文件中,设置cascade属性,然后单独保存idcard,系统会报错
    //          session.save(ic);
                
    //          单独保存user对象也是不行的,因为这时候idcard还没有保存,没有主键可以关联
    //          因此需要先保存idcard,然后再保存user
                session.save(ic);
                session.save(user);
                
                session.getTransaction().commit();
            } catch (Exception e) {
                e.printStackTrace();
                session.getTransaction().rollback();
            }finally{
                hibernateUtil.closeSession(session);
            }
        }
        
        /**
         * 读取数据:
         * 1. 是否能从user级联查询出idcard
         * 2. 是否能从idcard级联查询出user
         */
        public void test2(){
            test1();
            System.out.println("-------------------------------------------");
            Session session = null;
    //      第一种情况
            try {
                session = hibernateUtil.getSession();
                session.beginTransaction();
    //          这里也是两条语句,在get函数的时候立即发出一条sql语句,查询user表
    //          在打印身份证编号的时候发出第二条sql语句,关联查询user表和idcard表,得出idcar的数据
                User user = (User)session.get(User.class, 1);
                System.out.println("用户名:"+user.getUserName());
                System.out.println("身份证编号:"+user.getIc().getIdCard());
                            
                session.getTransaction().commit();
            } catch (Exception e) {
                e.printStackTrace();
                session.getTransaction().rollback();
            }finally{
                hibernateUtil.closeSession(session);
            }
            System.out.println("------------------------------");
    //      第二种情况
            try {
                session = hibernateUtil.getSession();
                session.beginTransaction();
    //          这里一条sql语句,把user表和idcard一起查询出来
                IdCard ic = (IdCard)session.get(IdCard.class, 1);
                System.out.println("用户名:"+ic.getUser().getUserName());
                System.out.println("身份证编号:"+ic.getIdCard());
                            
                session.getTransaction().commit();
            } catch (Exception e) {
                e.printStackTrace();
                session.getTransaction().rollback();
            }finally{
                hibernateUtil.closeSession(session);
            }       
        }
        
        /**
         * 删除测试
         * 1. 在不设置cascade的情况下,删除user,会不会级联删除idcard
         * 2. 在设置了级联操作下,阐述idcard,会不会删除user
         */
        public void test3(){
            test1();
            System.out.println("------------------------------");
            Session session = null;
            
            try {
                session = hibernateUtil.getSession();
                session.beginTransaction();
                
                IdCard ic = new IdCard();
                ic.setId(1);
    
                User user = new User();
                user.setId(1);
                user.setIc(ic);
                ic.setUser(user);
                
    //          1. 在默认不设置cascade的情况下,删除user是不会级联删除idcard的
    //          2. 在默认不设置cascade的情况下,删除idcard会报错,提示外键关联,不能随意删除
    //          3. cascade设置为delete情况下,删除user会级联删除idcard
    //          4. cascade设置为delete情况下,删除idcard会报错,提示外键关联,不能随意删除
                session.delete(user);
    //          session.delete(ic);
                
                
                session.getTransaction().commit();
            } catch (Exception e) {
                e.printStackTrace();
                session.getTransaction().rollback();
            }finally{
                hibernateUtil.closeSession(session);
            }
            
        }
        
    
    }

相关文章

  • 5.hibernate映射(一对一)

    一对一关系分以下几种: 单向主键一对一 双向主键一对一 单向外键一对一 双向外键一对一 在此先介绍统一用的实体类:...

  • 初识Hibernate之关联映射(二)

    基于外键的单向一对一关联映射 基于主键的单向一对一关联映射 单向多对多关联映射 一、基于外键的单向一对一关联映射具...

  • Mybatis源码之美:3.5.2.负责一对一映射的associ

    负责一对一映射的association元素和负责一对多映射的collection元素 负责一对一映射的associ...

  • Hibernate One-To-One Mapping

    Hibernate 一对一映射关系(唯一外键映射) 用户基本信息与扩展信息的映射关系 我们先来看看这一对一映射可以...

  • 编程改变世界(10)-- mybatis映射总结

    无论是一对一映射,一对多映射,还是多对多映射,都记住以下几点即可1.association 代表的是一对一的关系 ...

  • Django-关系映射

    关系映射 一对一映射 语法 查询 一对多映射 语法 查询 多对多映射 语法 查询 自定义查询对象

  • spring data jpa

    一对一 一对多 多对多映射

  • MyBatis高级查询

    使用自动映射处理一对一映射 一个用户只能拥有一个角色。 使用自动映射就是通过别名让MyBatis自动将值匹配到相应...

  • Hibernate 映射关系

    0. 关联关系映射 关联关系映射,是映射关系中比较复杂的一种映射关系,总的说来有一对一、一对多和多对多几种关系。细...

  • spring-data-jpa

    Spring Data JPA 之 一对一,一对多,多对多 关系映射

网友评论

      本文标题:5.hibernate映射(一对一)

      本文链接:https://www.haomeiwen.com/subject/hkbvzttx.html