Hibernate的一对多映射的单向关联和双向关联(九)
  TEZNKK3IfmPf 2023年11月15日 36 0


在实际的生活和工作中,Hibernate的一对多的使用是最广的。如班级和学生,部门和员工,用户和购买商品,订单和商品等。这里用部门和员工进行举例说明。 运用部门的例子,主要是为下面的自关联做铺垫。一个部门可以有多个员工,但一个员工只能拥有一个部门。

二. 搭建Hibernate环境

跟一对一关联一样,这里就不进行说明了。具体可以参照以前写的博客。

三. 编写具体的实体类

三.一 编写Dept 部门类

package com.yjl.pojo;
/**
 @author: yuejl
 @date: 2019年2月16日 上午10:15:08
 @Description 数据库中一的一方 部门实体
*/
public class Dept {
  /**
   * @param id 部门的编号
   * @param name 部门的名称
   * @param description 部门的描述
   */
  private Integer id;
  private String name;
  private String description;
  public Integer getId() {
    return id;
  }
  public void setId(Integer id) {
    this.id = id;
  }
  public String getName() {
    return name;
  }
  public void setName(String name) {
    this.name = name;
  }
  public String getDescription() {
    return description;
  }
  public void setDescription(String description) {
    this.description = description;
  }
  @Override
  public String toString() {
    return "Dept [id=" + id + ", name=" + name + ", description=" + description + "]";
  }
}

三.二 编写User 员工类

package com.yjl.pojo;
/**
 @author:两个蝴蝶飞
 @date: 2019年2月16日 上午10:20:08
 @Description 多的一方,用户实体
*/
public class User {
  /**
   * @param id 标识符Id
   * @param name 用户的名称
   * @param sex 用户的性别
   * @param age 用户的年龄
   * @param description 描述
   */
  private Integer id;
  private String name;
  private String sex;
  private Integer age;
  private String description;
  /*通过组合的方面,将部门引入到用户实体中*/
  /**
   * @param dept 用户所在的那个部门
   */
  private Dept dept;
  public Integer getId() {
    return id;
  }
  public void setId(Integer id) {
    this.id = id;
  }
  public String getName() {
    return name;
  }
  public void setName(String name) {
    this.name = name;
  }
  public String getSex() {
    return sex;
  }
  public void setSex(String sex) {
    this.sex = sex;
  }
  public Integer getAge() {
    return age;
  }
  public void setAge(Integer age) {
    this.age = age;
  }
  public String getDescription() {
    return description;
  }
  public void setDescription(String description) {
    this.description = description;
  }
  public Dept getDept() {
    return dept;
  }
  public void setDept(Dept dept) {
    this.dept = dept;
  }
  @Override
  public String toString() {
    return "User [id=" + id + ", name=" + name + ", sex=" + sex + ", age=" + age + ", description=" + description+ "]";
  }
}

四 编写具体的Xxx.hbm.xml文件

四.一 Dept.hbm.xml与以前的一样

<hibernate-mapping package="com.yjl.pojo" >
  <!-- 具体的实体类  由于前面指定了package包名。这里只需要写Dept即可。否则写com.yjl.pojo.Dept 全限定名称-->
  <class name="Dept" table="dept">
    <!-- 主键 -->
    <id name="id" column="id">
      <generator class="native"></generator>  
    </id>
    <!-- 其余属性  这里type运用的是java类型,并不是Hibernate和数据库的-->
    <property name="name" length="20" type="java.lang.String"></property>
    <property name="description" length="100" type="java.lang.String"></property>
  </class>
</hibernate-mapping>

四.二 User.hbm.xml 多添加一个标签

普通的属性,如id,name,sex,age,description与以前的方式一样。 但dept这个字段是不一样的。要用 标签。多对一。

<hibernate-mapping package="com.yjl.pojo" >
  <!-- 具体的实体类 -->
  <class name="User" table="user">
    <!-- 主键 -->
    <id name="id" column="id">
      <generator class="native"></generator>  
    </id>
    <!-- 其余属性  这里type运用的是java类型,并不是Hibernate和数据库的-->
    <property name="name" length="20" type="java.lang.String"></property>
    <property name="sex" length="2" type="java.lang.String"></property>
    <property name="age" length="3" type="java.lang.Integer"></property>
    <property name="description" length="100" type="java.lang.String"></property>
    
    <!-- 开始进行多对一的关联。 n对m,其中n指的是自己的一方。 m指的是要关联的一方。用户对部门,是多对一。
    部门对用户,是一对多。实际上Dept与package连用,构成全限定名称 -->
    <many-to-one name="dept" column="deptId" class="Dept"></many-to-one>
  </class>
</hibernate-mapping>

五.修改hibernate.cfg.xml的引用约束文件

<!-- 引入相应的约束文件  ctrl点击时可以正确进入-->
    <mapping resource="com/yjl/pojo/Dept.hbm.xml"/>
    <mapping resource="com/yjl/pojo/User.hbm.xml"/>

六. 编写测试文件

六.一 编写测试保存方法

/*单向测试保存*/
  @Test
  public void singleTest(){
    /*1。通过工具类构建Session*/
    Session session=HibernateUtil.getSession();
    /*2.实例化Dept类*/
    Dept dept=new Dept();
    dept.setName("开发部");
    dept.setDescription("一切为了开发");
    /*3. 实例化User类,并设置与部门的关系*/
    User user=new User();
    user.setName("两个蝴蝶飞");
    user.setSex("男");
    user.setAge(24);
    user.setDescription("一个充满希望的程序员");
    /*设置与部门的关系*/
    user.setDept(dept);
    /*4.进行保存*/
    session.save(dept);
    session.save(user);
  }

控制台依次输出了五个内容:

  1. 创建表dept

  2. 创建表user, 但没有外键引用

  3. 修改表user,引入dept的id字段做为外键

  4. 插入数据表dept表

  5. 插入数据表user表

Hibernate的一对多映射的单向关联和双向关联(九)

六.二 编写测试查询方法

/*单向的查询测试*/
  @Test
  public void singleSearchTest(){
    /*1。通过工具类构建Session*/
    Session session=HibernateUtil.getSession();
    /*2.查询 部门的search*/
    Dept dept=session.get(Dept.class,1);
    System.out.println("部门自己查询的:"+dept);
    /*3.查询员工的*/
    User user=session.get(User.class,1);
    System.out.println("员工自己查询的:"+user);
    /*4.通过员工找到他所在的部门的信息*/
    Dept dept2=user.getDept();
    System.out.println("通过员工找到他所在的部门:"+dept2);
  }

Hibernate的一对多映射的单向关联和双向关联(九)

六.三 扩充

1.能不能通过员工直接找到输出他所在的部门。即 将User类中的toString()方法改成:

@Override
  public String toString() {
    return "User [id=" + id + ", name=" + name + ", sex=" + sex + ", age=" + age + ", description=" + description
        + ", dept=" + dept + "]";
  }
/*2.查询员工的*/
    User user=session.load(User.class,1);
    System.out.println("员工自己查询的:"+user);

这个时候再运行的话:

Hibernate的一对多映射的单向关联和双向关联(九)


也将部门信息查询了出来。

顺序是:

  1. 先修改user表中的外键

  2. 根据传递进去的参数员工编号,从user表中,将员工的信息查询出来。包括部门的编号。

  3. 根据部门的编号,从dept表中,将部门的信息查询出来。


  4. 将保存部门和员工的顺序进行改变,即先保存员工,后保存部门.

  5. Hibernate的一对多映射的单向关联和双向关联(九)

  6. 这个时候,员工和部门均可以正常的保存。但是,员工是没有部门的。因为是先插入的员工,此时部门还没有插入。所以,应该先保存部门,然后根据部门的标识符插入员工表。

七. 单向的一对多的缺点

其实,实际开发中用单向的多一点。 但还是说一下吧。 现在,是只能根据员工去找部门,并不能解决查询部门下有多少个员工的问题。开发中用表连接去查。 如果部门中有一个保存员工的集合就好了,那么直接遍历这个集合就可以了。 这就是多向关联。

八.一对多的双向关联

不但要在User中表存储关于Dept的字段。还要在Dept中存储关于User的字段。 只不过,这个时候是集合。 一般用List,不用Set.

八.一 对Dept实体的改变

  1. 在Dept表中添加一个集合字段,实现setter和getter方法。 需要进行初始化。 添加的是Set集合,并不是List集合。切记

/**
   * @param users 存储员工集合
   */
  private Set<User> users=new HashSet<User>();
  1. 在Dept.hbm.xml中添加set的标签,在description 后面添加即可.

<!-- 添加一对多的关联  采用的是set标签,不是list. 这里面才有one-to-many. class标签里面没有-->
    <set name="users">
      <!-- 这个deptId 要与User.hbm.xml中的dept属性中的column保持一致 -->
      <key column="deptId"></key>
      <one-to-many class="User"/>
    </set>

不用对User.hbm.xml中进行改变。

九. 编写测试的方法

九.一 双向保存测试的方法

/*双向测试保存*/
  /*双向测试保存*/
  @Test
  public void bothTest(){
    /*1。通过工具类构建Session*/
    Session session=HibernateUtil.getSession();
    Dept dept=new Dept();
    dept.setName("开发部");
    dept.setDescription("一切为了开发");
    /*3. 实例化User类,并设置与部门的关系*/
    User user=new User();
    user.setName("两个蝴蝶飞");
    user.setSex("男");
    user.setAge(24);
    user.setDescription("一个有梦想的程序员");
    User user1=new User();
    user1.setName("两个蝴蝶飞1");
    user1.setSex("男");
    user1.setAge(24);
    user1.setDescription("一个有梦想的程序员");
    User user2=new User();
    user2.setName("两个蝴蝶飞2");
    user2.setSex("男");
    user2.setAge(24);
    user2.setDescription("一个有梦想的程序员");
    /*设置与部门的关系*/
    user.setDept(dept);
    user1.setDept(dept);
    user2.setDept(dept);
    session.save(dept);
    /*级联保存后,就不需要多次保存了。但是要用dept的方法,进行设置关系*/
    session.save(user);
    session.save(user1);
    session.save(user2);
  }

步骤与单向的一对多的步骤一样。

  1. 创建表dept

  2. 创建表user, 但没有外键引用

  3. 修改表user,引入dept的id字段做为外键

  4. 插入数据表dept表

  5. 插入数据表user表

Hibernate的一对多映射的单向关联和双向关联(九)

九.二 双向查询的方法

/*双向的查询测试*/
  @Test
  public void bothSearchTest(){
    /*1。通过工具类构建Session*/
    Session session=HibernateUtil.getSession();
    /*2.查询 部门的search*/
    Dept dept=session.get(Dept.class,1);
    System.out.println("部门自己查询的:"+dept);
    /*3.查询员工的*/
    User user=session.get(User.class,1);
    System.out.println("员工自己查询的:"+user);
    /*4.通过部门找到他的员工*/
    Set<User> userList=dept.getUsers();
    System.out.println("通过部门找到他所有的员工:");
    for (User user2 : userList) {
      System.out.println(user2);
    }
    /*5.通过员工找到他所在的部门的信息*/
    Dept dept2=user.getDept();
    System.out.println("通过员工找到他所在的部门:"+dept2);
  }

Hibernate的一对多映射的单向关联和双向关联(九)


这个时候,查询员工时,员工所在的部门也是可以查询出来的。

九.三 扩充

  1. 上面查询的方法, 如果按钮dept2继续查询呢? 即:

/*5.通过员工找到他所在的部门的信息*/
    Dept dept2=user.getDept();
    System.out.println("通过员工找到他所在的部门:"+dept2);
    Set<User> userList2=dept2.getUsers();
    System.out.println("再次通过部门找到他所有的员工:");
    for (User user2 : userList2) {
      System.out.println(user2);
    }

也是可以正常查询的。

Hibernate的一对多映射的单向关联和双向关联(九)


2. 如果 部门的toString() 方法中添加输出users呢? 注意:上面的Dept类toString()方法中没有users的输出。另外,一定要注意,User类中toString() 方法中有dept的输出。 此时,输出dept时—>users中输出user---->找到dept2---->输出此时dept2中的users, 这是一个环,即递归调用的死循环。

Hibernate的一对多映射的单向关联和双向关联(九)


运行的结果是:

Hibernate的一对多映射的单向关联和双向关联(九)


栈溢出了。是Errror,不是Exception。 注意,调用的时候,千万不要形成一个环。

3. 按照2的思路继续思考,此时将User中toString()去除掉dept的输出,保留dept中users的输出呢。

Hibernate的一对多映射的单向关联和双向关联(九)


此刻显示的是正常的。 用的时候,一定要注意这一点。4.一对多中set标签,如果column不一样呢,会造成什么呢?

以前是deptId,现在改成deptId1, 即Dept中的column与User中的column关于外键的列名不一样。

Hibernate的一对多映射的单向关联和双向关联(九)


运行的是bothTest() 方法后,没有报错。但,这是什么啊? 故,切记: Hibernate运行生成表之后,一定要看一下,生成的表是不是自己想要的。并不是生成表,无报错,就是OK了。

Hibernate的一对多映射的单向关联和双向关联(九)


谢谢!!!


【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月15日 0

暂无评论

推荐阅读
  TEZNKK3IfmPf   19天前   43   0   0 java
  TEZNKK3IfmPf   19天前   31   0   0 ajaxxml
  TEZNKK3IfmPf   2024年05月31日   54   0   0 java
TEZNKK3IfmPf