欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

【Hibernate】【映射文件】【关系映射】

程序员文章站 2024-03-02 16:04:16
...
关系映射:即需要映射的属性,是一个实例对象.如员工的部门属性.

单向多对一(常用)

  • MySQL的表格
    【Hibernate】【映射文件】【关系映射】

  • 员工类中的属性

    private Department dept;//dept_id
  • 属性的映射
    • 由员工管理,在员工的映射文件设置
<many-to-one name="dept" column="dept_id"/>

案例1

有一个员工A属于部门B,两者都没有存入数据库
情况1:session.save(员工);

  • 结果:报错
  • 原因:保存了员工后,没有找到外键对应的部门

情况2:session.save(先部门,再员工)

  • 结果:正常发送两个insert的SQL

情况3:session.save(先员工,再部门)

  • 结果:1.保存员工;2.保存部门,3.更新员工
  • 原因:保存员工为持久化后,但其dept属性为临时状态,不受保存.保存部门后,dept又变成了持久化状态,导致员工状态变成脏的持久化状态,需要更新.

案例2

        Employee e = (Employee)session.get(Employee.class, 1L);
        Department dept = e.getDept();
        System.out.println("_____________");
        System.out.println(e);  //使用了dept属性

结果:

  1. 查员工的SQL
  2. 横线
  3. 查部门
  4. 输出员工

原因:e.getDept(); 取外键的对象,返回的是代理对象(延迟加载);使用前才会实例化.

外键的代理对比load()的代理

  • load();返回的代理对象绝对不为null,不可以用代理对象==null来判断
  • 外键的代理:返回的代理对象,可能为空,因为查询e时候,如果dept_id为null,就返回null,非null,就返回代理对象.代理对象==null可以用来判断

单向多对多(常用)

  • MySQL的表格(必有中间表)
    【Hibernate】【映射文件】【关系映射】

  • Teacher类中的属性

    • 由teacher管理student
private  Set<Student> stus;//Teacher_Student  Teacher_id/Student_id
  • 属性的映射
        <set name="stus" table="Teacher_Student" order-by="Student_id">
            <key column="Teacher_id"/>
            <many-to-many class="Student" column="Student_id"/>
        </set>
        <set name="属性名" table="中间表名">
            <key column="对应己方的外键列"/>
            <many-to-many class="他方的类" column="对应他方的外键列"/>
        </set>
<!--set换成bag也会按id排序,bag对应的是list-->
        <set name="stus" table="Teacher_Student" >
            <key column="Teacher_id"/>
            <many-to-many class="Student" column="Student_id"/>
        </set>

//扩展按添加顺序排列
1.在Student类中添加记录添加顺序的属性并且声明
    private Integer sequence;
2.在Teacher映射文件中的order-by="sequence"

单向一对多(常用)

外键依然标记在员工表的dept_id,只不过要将部门类中添加一个属性:

private Set<Employee> emps;//dept_id

属性的映射

         <set name="emps">
            <key column="dept_id"/>
            <one-to-many class="Employee"/>
         </set>

案例1

员工A所属部门B,两者都存入db
情况1.session.save(先部门,后员工)

  • 结果:三条SQL;保存部门,保存员工,更新员工;

情况2.session.save(先员工,后部门)

  • 结果:三条SQL;保存员工,保存部门,更新员工;

情况3.session.save(部门) //单独保存部门(部门中有为保存的员工)会失败

  • 结果:2条SQL;保存部门,更新员工因找不到而报错;

案例2

        Department dept=(Department)session.get(Department.class,1L);
        Set<Employee> emps = dept.getEmps();//返回代理对象
        System.out.println("__________");
        System.out.println(dept);//调用
  • 结果:

    1. 查部门的sql
    2. 横线
    3. 查 员工的sql
    4. 输出部门
      原因:dept.getEmps();返回的是代理对象(延迟加载);使用前才会实例化.该代理对象也是决不为空,于load()一样.要用.size()方法来判断是否为空.

级联

可以通过one方来控制many方,<set cascade="XXX">
【Hibernate】【映射文件】【关系映射】

  • save-update:

    • session.save(主对象):同时保存其集合中的从对象
    • session.update(主对象):1.去持久化新增的从对象;2.修改游离的从对象;3.将已经丢出集合的从对象,其对应的外键设为null;
  • delete: 删除主对象,同时删除其集合中的从对象(在表中删除)

  • all:save-update+delete
  • delete-orphan:1.将外键设为null的从对象,从表中删除.2.将从集合中剔除的从对象,从表中删除.3删除主对象,也双光从对象.
  • all-delete-orphan:上面的全部.订单就要用这个.

双向=一对多+多对一(常用)

数据库的表格不用,一样是员工表格有外键dept_id

更改映射文件

    <!--员工-->
    <class name="Employee">
         <many-to-one name="dept" column="dept_id"/>
    </class>

     <!--部门-->
     <class name="Department" inverse="true">
         <set name="emps">
            <key column="dept_id"/>
            <one-to-many class="Employee"/>
         </set>
    </class>

inverse=”true”: 表示部门放弃对关系的管理,一切由员工的映射管理.

true:删除部门,同时会删对应的员工;而且会出现多余的SQL来维护二者关系
false:删除部门,只会将员工的外键为null

一对一(不常用)

QQ号对应QQ空间,可以使用QQ号的主键,作为外键指向QQ空间的主键;
即QQ空间的主键生成,是跟随QQ号的主键

<!--QQ号-->
        <one-to-one name="zone">
<!--QQ空间-->
    <!--声明主键生成方式依赖别的表的主键-->
    <id name="id">
        <generator class="foregn">
            <param name="property">类中的QQ号属性名</param>
        </generator >
    </id>
    <!--constained="true",表示被控制的-->
    <one-to-one name="类中的QQ号属性名" constained="true">

组件关系

多个类,对应一个表,类与类是组件关系
类中的实例对象属性,就是多类中的其他属性进行一次包装,组件对象没有对应的表格

public class 公司{
    private Long id;
    private String name;
    private Address 营业地址;  //组件1
    private Address 注册;      //组件2
}


public class Address {
    private String 省;
    private String 城;
    private String 街;
}

公司类的映射文件

<class name="公司">
    <id></id>
    <property></property>
<!--组件-->
    <component name="营业地址">
        <property name="省" column="表中的列1">
        ` 
        `
    </component>
<!--组件-->
        <component name="注册地址">
        <property name="省" column="表中的列2">
        ` 
        `
    </component>
</class>

继承关系

多个类,对应一个表,类与类是继承关系
【Hibernate】【映射文件】【关系映射】

映射文件(映射的类用父类!)

<class name="商品" discriminator-value="1">
     <id> </id>
     <property name="XX">
<!--声明表中区别的列名-->
     <discriminator column="type" type="int">
<!--添加子类-->
    <subclass name="书" discriminator-value="2"> 
        <property name="作者"/>
    </subclass >     
        <subclass name="衣" discriminator-value="3"> 
        <property name="颜色"/>
    </subclass >     
</class>

此时 session.get(衣服.class,1L);
sql为 wher id=1 and type = 3;

相关标签: hibernate

上一篇: hibernate 映射组成关系

下一篇: