• Hibernate(七)__多对一 、一对多、 一对一、多对多


    1.many-to-one

    以学生和部门之间的关系为例:

    Department.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 package="com.xidian.domain">
    <class name="Department" lazy="false">
    <!-- 配置主键属性 -->
    <id name="id" type="java.lang.Integer">
    <!-- 生成策略 -->
    <generator class="identity">
    </generator>
    </id>
    <property name="name" type="java.lang.String">
    <column name="name" length="64" not-null="true"/>
    </property>
    </class>
    </hibernate-mapping>

    student.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 package="com.xidian.domain">
    <class name="Student">
    <id name="id" type="java.lang.Integer"> 
    <generator class="identity">
    </generator>
    </id>
    <property name="name" type="java.lang.String">
    <column name="name" length="64"/>
    </property>
    <!-- 对于private Department dept;就不能使用property 
      column="dept_id" 表示将来自动生成的表的外键名-->
    <many-to-one name="dept" column="dept_id"/>
    </class>
    </hibernate-mapping>

    应用:

    Student stu1=new Student();
    stu.setName("宋江");

    Student stu2=new Student();
    stu.setName("宋江");

    Department d=new Department();
    d.setName("财务部");

    stu1.setDept(d);//指定该学生是哪个部门

    stu2.setDept(d);

    s.save(d);
    s.save(stu1);
    s.save(stu2);
    如果先保存学生再保存部门,也是可以的。在保存学生的时候部门还不存在,外键会设置为空,然后再保存部门,当commit提交事务的

    时候发现它们具有映射关系,就会再来设置学生的外键引用(这种情况下hibernate会多一条update语句)。

     

    在应用多对一的情况时会发现,只做了many到one单方向的映射,只是能将多个学生通过外键关系添加到一个部门中

    问题:反过来如果需要通过一个部门号(1),来获取该部门的所有学生?如果用上面的many to one形式需要hql语句进行查询

    String hql=”from Student where dept.id=1”

    这时就需要one-to-many的反方向查询

     

    在这里引入懒加载的概念:

    简述: 多表查询时,当我们查询一个对象的时候,在默认情况下,返回的只是该对象的普通属性,当用户去使用对象属性时,

    才会向数据库发出再一次的查询.这种现象我们称为 lazy现象.

    student=(Student) s.get(Student.class, 3);

    System.out.println(student1.getName()+" 所在部门="
          +student1.getDept().getName());//当session还在,依然可以向数据库发sql语句。可是假若我们只是获取到student对象,

                       //没有对对象属性进行查询,当session关闭后就不可以再向数据库发sql语句,无法查询。

    解决方法

    1.显示初始化代理对象 Hibernate.initized( student.getdept()) 

    2.修改对象关系文件 class属性 lazy  改写 lazy=false

    3.通过过滤器(web项目) openSessionInView     (从上面的例子可以看出,当session关闭后,就不能向数据库发sql语句,那么就扩大session的范围

                        这个后面会详细介绍)

     

    2.one-to-many

    在one那一方配置<set ></set>

    在many一方必须要一个外键指向one这方的属性,所以配置<many-to-one>是必须的。

    one这方是否配置<one-to-many>看是否需要指定一个集合属性指向回many一方,这样从主表一方获取从表的属性是非常方便的。

    在这里再看通过获取到部门查看学生信息

    Department department1=(Department) s.get(Department.class, 3);
    //取出该部门的学生
    Set<Student> stus= department1.getStus();
    for(Student ss: stus){
    System.out.println(ss.getName());

    }

     

    添加学生
    Department department=new Department();
    department.setName("业务部门");

    Student stu1=new Student();
    stu1.setName("顺平");
    Student stu2=new Student();
    stu2.setName("小明");

    Set<Student> sets=new HashSet<Student>();
    sets.add(stu1);
    sets.add(stu2);
    department.setStus(sets);

    s.save(department);              //这里涉及到级联操作,需要在Department.hbml.xml中配置

                   //<set name="stus" cascade="save-update">这样将在保存department的时候将

                   //部门中的学生一并保存。

     

    3.one-to-one

    一对一有有两种方式  区别是基于主键的情况是会在主键之间形成映射关系

    (从表的某一属性既是自身表的主键也是引用到其他表的外键,主键充当外键),基于外键是以非主键的外键形成映射关系。

    (1) 基于主键的一对一

    一定要设置constrained=true 才能形成外键约束关系

    一对一关系中典型的问题是人与身份证的关系。

    Person p1=new Person();
    p1.setId(1224);
    p1.setName("xkj");

    IdCard idCard=new IdCard();
    idCard.setValidateDte(new Date());

    idCard.setPerson(p1);//表示idCard对象是属于p1这个对象.
               //p1.setIdCard(idCard);错误方式
    s.save(p1);     //先保存人
    s.save(idCard);

    数据库中结果:

    idCard表

    person表

    这里有两个注意问题

    1.如果我使用p1.setIdCard(idCard)来指定person和idCard之间的关系会出错:

    只能使用idCard.setPerson(p1)方式。关系应该是在idCard上有一个外键指向person,而不是相反。报错行在

    说明在保存idCard的时候,外键person属性是空而导致错误。

    2.如果调换保存顺序:

    s.save(idCard); //先保存卡

    s.save(p1);  

    报出错误:

     java.sql.SQLException: [Microsoft][SQLServer 2000 Driver for JDBC][SQLServer]

    INSERT 语句与 FOREIGN KEY 约束"FKB8CDF6CB2A59F864"冲突。该冲突发生于数据库"test",表"dbo.person", column 'id'。  
    解析理论:外键约束,比如B表存在一个字段b,有外键约束,引用于A表的主键a,那么在向B表插入数据时,

    字段b必须为A表中a已经存在的值,如过向b中存放一个a中没有的值,则会报违反外键约束。

    可是如果回头看one-to-many那个例子中却发现学生表中有外键指向部门的主键,先保存学生再保存部门也是可以的,

    只是会多一个update语句,这是hibernate的优化机制。可是放在这个地方却不可以,why?

    希望大家指点填坑!

     

    (二)基于外键的一对一

    只改动上面的IdCard.hbm.xml映射文件

    <id name=”id” type=”java.lang.Integer”>

    <generator class=”assigned” />  

    </id>

    <property ame=”VaidateDate” type=”java.util.Date”>

    <column name=”validateDate” />

    </property>

    <many-to-one  name=”person”  unique=”true” />   //person是外键 在idCard表中会生成这个外键,它指向的是主表的主id

    在idCard这边,可看成是many-to-one的一个特例,加unique保证唯一。

    Person p1=new Person();
    p1.setId(122);
    p1.setName("xkj");

    IdCard idCard=new IdCard();
    idCard.setId(1905);
    idCard.setValidateDte(new Date());

    idCard.setPerson(p1);//表示idCard对象是属于p1这个对象.

    s.save(p1); //先保存人
    s.save(idCard);

    数据库结果:

    在这里我依然测试了前面出现的两个问题:

    第一个问题没有报错,只是idCard的person外键为空。

    第二个问题hibernate又给解决了,同样是多一句update语句。

     

    4.many-to-many

    学生和课程是经典的多对多的案例。

    在实际开发中,如果出现了many-to-many关系,我们应该将其转换成两个one-to-many 或者 many-to-on, 这个程序好控制,同时不会有冗余。

    在stucourse中有两个外键分别指向student和course

    //添加一个学生,一门课程,选课
    Student stu1=new Student();
    stu1.setName("小明");

    Course course=new Course();
    course.setName("java");

    StuCourse sc=new StuCourse();

    sc.setCourse(course);
    sc.setStudent(stu1);

    //顺序保存.
    s.save(stu1);
    s.save(course);
    s.save(sc);

    数据库结果:

  • 相关阅读:
    java快速排序代码
    java操作redis实现和mysql数据库的交互
    python 操作mysql数据库存
    JAVA 操作远程mysql数据库实现单表增删改查操作
    URI和URL及URN的区别
    day06_字符集设置
    day6_oracle手工建库
    day08_SGA后半部分
    day08_存储
    day05_sqlloader基础
  • 原文地址:https://www.cnblogs.com/xiangkejin/p/6002467.html
Copyright © 2020-2023  润新知