hibernate07--关联映射

时间:2021-10-19 00:54:17

单向的一对多关联

创建对应的实体类以及映射文件

hibernate07--关联映射
package cn.bdqn.bean;
/**
*
* @author 小豆腐
*街道对应的实体类
*
*单向的多对一关联
*/
public class Street { private Integer id;
private String name;
//多个街道 属于 一个区县
private District district; //对应的区县 public District getDistrict() {
return district;
}
public void setDistrict(District district) {
this.district = district;
}
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 Street(Integer id, String name) {
super();
this.id = id;
this.name = name;
}
public Street() {
super();
}
@Override
public String toString() {
return "Street [id=" + id + ", name=" + name + "]";
} }
hibernate07--关联映射
hibernate07--关联映射
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="cn.bdqn.bean">
<class name="Street">
<id name="id">
<generator class="assigned"/><!-- 手动给主键赋值 -->
</id>
<property name="name"/>
<!-- 配置多对一关联
name:对应的是 本类中 关联关系的属性名
column:对应数据库中 两个表的 外键!
class:关联的实体类-->
<many-to-one name="district" column="districtId" class="District"/>
</class>
</hibernate-mapping>
hibernate07--关联映射
hibernate07--关联映射
package cn.bdqn.bean;
/**
* @author 小豆腐
*
*区县的实体类
*/
public class District { private Integer id;
private String name; 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 District(Integer id, String name) {
super();
this.id = id;
this.name = name;
}
public District() {
super();
}
@Override
public String toString() {
return "Street [id=" + id + ", name=" + name + "]";
} }
hibernate07--关联映射
hibernate07--关联映射
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="cn.bdqn.bean">
<class name="District">
<id name="id">
<generator class="assigned"/><!-- 手动给主键赋值 -->
</id>
<property name="name"/>
</class>
</hibernate-mapping>
hibernate07--关联映射

需要在hibernate.cfg.xml文件中 配置映射文件

测试类

hibernate07--关联映射
        Session session=null;
Transaction transaction=null; //获取session 开启事务
@Before
public void before(){
session=HibernateSessionUtil.getCurrentSession();
transaction= session.beginTransaction();
} /**
* 测试单向的多对一的关联
*
* 创建对应的区县 新增几个区县 以备后续使用
*/
@Test
public void testAdd(){
District district=new District(3, "区县3");
session.save(district); //保存
transaction.commit(); //提交事务
} //新增 街道的同时 给街道对应的区县赋值
@Test
public void test01(){
//创建一个街道
Street street=new Street();
street.setId(1);
street.setName("街道1");
//给对应的区县赋值
District district= (District) session.load(District.class, 1);
street.setDistrict(district);
session.save(street); //保存
transaction.commit(); //提交事务 只会产生一条sql insert
} //修改 街道对应的区县
@Test
public void test02(){
//从数据库中获取一个街道
Street street=(Street) session.load(Street.class, 1); // 对应的区县是1
District district=(District) session.load(District.class, 2); // 区县是2
//修改
street.setDistrict(district); // 不需要 update 因为两个对象都是持久化对象
//提交事务
transaction.commit();
} //删除 街道对应的区县
@Test
public void test03(){
//从数据库中获取一个街道
Street street=(Street) session.load(Street.class, 1); // 对应的区县是2
//修改
street.setDistrict(null);
//提交事务
transaction.commit();
}
hibernate07--关联映射

双向的一对多关联就是在单向多对一的基础上增加一个单向的一对多!

修改District代码 一对多关联

hibernate07--关联映射
package cn.bdqn.bean;

import java.util.ArrayList;
import java.util.List; /**
* @author 小豆腐
*
*区县的实体类
* 一对多的关联关系
*/
public class District { private Integer id;
private String name;
// 一个区县 有 多个街道
private List<Street> streets=new ArrayList<>(); public List<Street> getStreets() {
return streets;
}
public void setStreets(List<Street> streets) {
this.streets = streets;
}
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 District(Integer id, String name) {
super();
this.id = id;
this.name = name;
}
public District() {
super();
}
@Override
public String toString() {
//如果写成streets 会出现 堆栈溢出的异常!
return "District [id=" + id + ", name=" + name + ", streets=" + streets.size()
+ "]";
} }
hibernate07--关联映射

修改District.hbm.xml文件代码

hibernate07--关联映射
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="cn.bdqn.bean">
<class name="District">
<id name="id">
<generator class="assigned"/><!-- 手动给主键赋值 -->
</id>
<property name="name"/>
<!-- 设置一对多
name:本类中的关联属性名 集合的名称
column: 就是数据库表中的外键
order-by="id desc" 按照 街道的id 进行 降序排列
inverse:是由谁来维护表与表之间的关系! 默认是false!(维护) true(不维护)
-->
<bag name="streets" cascade="all" inverse="true">
<key column="districtId"/>
<one-to-many class="Street"/>
</bag>
</class>
</hibernate-mapping>
hibernate07--关联映射

在测试类中增加代码

hibernate07--关联映射
    /**
* 创建几个街道 测试 双向的一对多关联
*/
@Test
public void test04(){
Street street=new Street();
street.setId(4);
street.setName("街道4");
//给对应的区县赋值
District district= (District) session.load(District.class, 1);
street.setDistrict(district);
session.save(street); //保存
//提交事务
transaction.commit();
} //根据区县 获取所管辖的街道
@Test
public void test05(){
District district=(District) session.load(District.class, 1);
List<Street> streets = district.getStreets();
for (Street street : streets) {
System.out.println(street);
}
}
/**
* 根据区县 获取所管辖的街道 根据街道的编号 降序排列
* 01.只需要在 bag节点中 增加 order-by属性 = id desc
*/
@Test
public void test06(){
District district=(District) session.load(District.class, 1);
List<Street> streets = district.getStreets();
for (Street street : streets) {
System.out.println(street);
}
}
/**
* 02.使用hql语句
*/
@Test
public void test07(){
String hql="from Street s where districtId=:id order by s.id desc";
//创建query对象
Query query = session.createQuery(hql);
//给参数赋值
query.setParameter("id", 1); //区县编号是1
//遍历结果集
List<Street> list = query.list();
for (Street street : list) {
System.out.println(street);
}
} /**
* cascade属性:定义的是关系两端 对象到对象的级联关系!
* 必须是 双向的一对多关联!
*
* 常用的属性值:
* 01.none:默认值!当session操作当前对象的时候,忽略关联的属性!
* 02.save-update:当session调用save,saveorUpdate以及update()的时候!
* 会级联的保存和修改当前对象以及对象关联的属性!
* 001.去区县的xml文件中 的 bag节点 增加 cascade属性!
* 002.直接运行以下代码
* 03.delete: 当session调用 delete()的时候,会级联删除所关联的对象 !
* 04.all: 包括了save-update和delete!
*
* 添加区县的同时 添加街道
*/
@Test
public void test08(){
//创建区县
District district=new District(4, "区县4");
//创建街道
Street street1=new Street(5, "街道5");
Street street2=new Street(6, "街道6");
Street street3=new Street(7, "街道7");
//给区县的街道赋值
district.getStreets().add(street1);
district.getStreets().add(street2);
district.getStreets().add(street3);
//保存区县
session.save(district); //发现 保存了 区县 但是 没有保存对应的街道!
transaction.commit();
/**
* 程序执行之后的结果:
* Hibernate: insert into District (name, id) values (?, ?)
Hibernate: update Street set districtId=? where id=?
Hibernate: update Street set districtId=? where id=?
Hibernate: update Street set districtId=? where id=?
*/ /**
* 在xml文件中设置了 cascade="save-update" 之后的结果
*
* 问题:虽然级联保存成功了!
* 但是有多余update语句!
* 为什么会出现多余的? 两个对象都在维护彼此之间的关系!
*
* Hibernate: select street_.id, street_.name as name1_, street_.districtId as districtId1_ from Street street_ where street_.id=?
Hibernate: select street_.id, street_.name as name1_, street_.districtId as districtId1_ from Street street_ where street_.id=?
Hibernate: select street_.id, street_.name as name1_, street_.districtId as districtId1_ from Street street_ where street_.id=?
Hibernate: insert into District (name, id) values (?, ?)
Hibernate: insert into Street (name, districtId, id) values (?, ?, ?)
Hibernate: insert into Street (name, districtId, id) values (?, ?, ?)
Hibernate: insert into Street (name, districtId, id) values (?, ?, ?)
Hibernate: update Street set districtId=? where id=?
Hibernate: update Street set districtId=? where id=?
Hibernate: update Street set districtId=? where id=?
*/
} /**
* cascade="delete" xml中的配置
* 删除 区县 的同时 删除 街道!
*/
@Test
public void test09(){
District district= (District) session.load(District.class, 1);
//获取三个街道
Street street1= (Street) session.load(Street.class, 2);
Street street2= (Street) session.load(Street.class, 3);
Street street3= (Street) session.load(Street.class, 4);
session.delete(district);
transaction.commit();
/**
* Hibernate: update Street set districtId=null where districtId=?
Hibernate: delete from Street where id=?
Hibernate: delete from Street where id=?
Hibernate: delete from Street where id=?
Hibernate: delete from District where id=?
*/
} /**
* 针对于 多余的sql语句 解决办法!
*
* 只需要一方来维护表之间的关系!
* inverse属性:
* 01.默认是false(由我维护!)
* 02.inverse=true:这一方不维护关系!(不与数据库交互)
*
*
* 不能都维护,也不能都 不维护! 这个时候关键是谁来维护这个关系?
* 双向的一对多!
* hibernate:规定多的一端来维护关系,那么必须在一的一方设置 inverse=true:
*/
@Test
public void test10(){
//创建区县
District district=new District(4, "区县4");
//创建街道
Street street1=new Street(5, "街道5");
Street street2=new Street(6, "街道6");
Street street3=new Street(7, "街道7");
//给区县的街道赋值
district.getStreets().add(street1);
district.getStreets().add(street2);
district.getStreets().add(street3);
//保存区县
session.save(district); //发现 保存了 区县 但是 没有保存对应的街道!
transaction.commit();
/**
*
* 发现 没有了 update语句!
* Hibernate: select street_.id, street_.name as name1_, street_.districtId as districtId1_ from Street street_ where street_.id=?
Hibernate: select street_.id, street_.name as name1_, street_.districtId as districtId1_ from Street street_ where street_.id=?
Hibernate: select street_.id, street_.name as name1_, street_.districtId as districtId1_ from Street street_ where street_.id=?
Hibernate: insert into District (name, id) values (?, ?)
Hibernate: insert into Street (name, districtId, id) values (?, ?, ?)
Hibernate: insert into Street (name, districtId, id) values (?, ?, ?)
Hibernate: insert into Street (name, districtId, id) values (?, ?, ?)
*/
}