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

非常对不起,老蝴蝶由于生活和工作上的事情太忙,无法及时更新,造成了将近三个月的停更。以后,会更加努力的。为了IT,加油。

上一章简单介绍了Hibernate的一对一映射(八),如果没有看过,请观看上一章

一.Hibernate的一对多的使用范围

在实际的生活和工作中,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表

在这里插入图片描述

六.二 编写测试查询方法

/*单向的查询测试*/
	@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);
	}

在这里插入图片描述

六.三 扩充

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);

这个时候再运行的话:
在这里插入图片描述
也将部门信息查询了出来。
顺序是:

  1. 先修改user表中的外键

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

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

  4. 将保存部门和员工的顺序进行改变,即先保存员工,后保存部门.
    在这里插入图片描述
    这个时候,员工和部门均可以正常的保存。但是,员工是没有部门的。因为是先插入的员工,此时部门还没有插入。所以,应该先保存部门,然后根据部门的标识符插入员工表。

七. 单向的一对多的缺点

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

八.一对多的双向关联

不但要在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表

在这里插入图片描述

九.二 双向查询的方法

/*双向的查询测试*/
	@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);
	}

在这里插入图片描述
这个时候,查询员工时,员工所在的部门也是可以查询出来的。

九.三 扩充

  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);
		}

也是可以正常查询的。
在这里插入图片描述
2. 如果 部门的toString() 方法中添加输出users呢? 注意:上面的Dept类toString()方法中没有users的输出。另外,一定要注意,User类中toString() 方法中有dept的输出。 此时,输出dept时—>users中输出user---->找到dept2---->输出此时dept2中的users, 这是一个环,即递归调用的死循环。
在这里插入图片描述
运行的结果是:
在这里插入图片描述
栈溢出了。是Errror,不是Exception。 注意,调用的时候,千万不要形成一个环。
3. 按照2的思路继续思考,此时将User中toString()去除掉dept的输出,保留dept中users的输出呢。
在这里插入图片描述
此刻显示的是正常的。 用的时候,一定要注意这一点。

4.一对多中set标签,如果column不一样呢,会造成什么呢?
以前是deptId,现在改成deptId1, 即Dept中的column与User中的column关于外键的列名不一样。
在这里插入图片描述
运行的是bothTest() 方法后,没有报错。但,这是什么啊? 故,切记: Hibernate运行生成表之后,一定要看一下,生成的表是不是自己想要的。并不是生成表,无报错,就是OK了。
在这里插入图片描述
谢谢!!!

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

两个蝴蝶飞

你的鼓励,是老蝴蝶更努力写作的

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值