一对多:
一个部门对应多个员工,一个员工只能属于某一个部门。
一个客户对应多个联系人,一个联系人只能属于某一个客户。
建表原则:
在多的一方创建外键指向一的一方的主键。
客户为一,联系人为多
创建实体类时:
/**
* Customer(一)中放LinkMan(多)的集合
*/
// 通过ORM方式表示,一个客户对应多个联系人
// 放置的是多的一方的集合,hibernate默认使用的Set集合
private Set<LinkMan> linkMans = new HashSet<LinkMan>();
/**
* LinkMan(多)中放Customer(一)的对象
*/
// 通过ORM,一个联系人只能属于某一个客户
private Customer customer;
配置映射文件时:
多的一方的中的配置文件中添加配置(在calss标签中添加):
<!-- 配置一对多的关系 -->
<!--
set标签:
name:多的一方的对象的集合的属性名称
-->
<set name="linkMans" >
<!--
key标签
column:多的一方的外键名称
-->
<key column="lkm_cust_id"></key>
<!--
one-to-many标签
class:多的一方的全路径
-->
<one-to-many class="domain.LinkMan"/>
</set>
一的一方的中的配置文件中添加配置(在calss标签中添加):
<!--配置一对多的关系 -->
<!--
many-to-one标签:
name :一的一方在多的一方类中的属性名称
class :一的一方的类的全路径
column :在多的一方的表中的外键的名称
-->
<many-to-one name="customer" class="domain.Customer" column="lkm_cust_id"></many-to-one>
操作:
一对多关系保存一边不行,会报错,解决方法:级联操作
//一对多关系只保存一边
public void test(){
Session session = HibernateUtils.getCurrentSession();
Transaction transaction = session.beginTransaction();
//一个客户
Customer customer1 = new Customer();
customer1.setCust_name("东");
//一个联系人
LinkMan linkMan1 = new LinkMan();
linkMan1.setLkm_name("甲");
//设置关系
linkMan1.setCustomer(customer1);
customer1.getLinkMans().add(linkMan1);
//保存一边:不可以,报瞬时对象异常,持久态对象关联一个瞬时态对象
session.save(customer1);
transaction.commit();
}
级联:
级联保存或更新:
在一的一方的配置文件中添加配置:
在set标签中添加 cascade=“save-update”
/**
* 级联保存或更新操作
* 保存客户级联联系人,操作主题是客户对象,需要在客户映射文件中配置
*/
public void test(){
Session session = HibernateUtils.getCurrentSession();
Transaction transaction = session.beginTransaction();
//一个客户
Customer customer1 = new Customer();
customer1.setCust_name("东");
//一个联系人
LinkMan linkMan1 = new LinkMan();
linkMan1.setLkm_name("甲");
//设置关系
linkMan1.setCustomer(customer1);
customer1.getLinkMans().add(linkMan1);
//保存一边:不可以,配置级联后可以
session.save(customer1);
transaction.commit();
}
在多的一方的配置文件中添加配置:
在many-to-one标签中添加 cascade=“save-update”
/**
* 级联保存或更新操作
* 保存联系人,操作主题是联系人对象,需要在联系人映射文件中配置
*/
public void test(){
Session session = HibernateUtils.getCurrentSession();
Transaction transaction = session.beginTransaction();
//一个客户
Customer customer1 = new Customer();
customer1.setCust_name("1");
//一个联系人
LinkMan linkMan1 = new LinkMan();
linkMan1.setLkm_name("2");
//设置关系
linkMan1.setCustomer(customer1);
customer1.getLinkMans().add(linkMan1);
//保存一边:不可以,配置级联后可以
session.save(linkMan1);
transaction.commit();
}
级联删除:
在一的一方的配置文件中添加配置:
在set标签中添加 cascade=“delete”,delete和save-update可以同时存在
/**
* 级联删除:
* 删除客户级联联系人
* 删除客户,同时删除联系人,在客户配置文件中配置级联删除:cascade=delete
*/
public void test(){
Session session = HibernateUtils.getCurrentSession();
Transaction transaction = session.beginTransaction();
//没有设置级联删除,默认情况:修改了联系人的外键,删除客户
// Customer customer = session.get(Customer.class, 1l);
// session.delete(customer);
//删除客户,同时删除联系人,在客户配置文件中配置级联删除:cascade=delete
Customer customer = session.get(Customer.class, 1l);
session.delete(customer);
transaction.commit();
}
在多的一方的配置文件中添加配置:
在many-to-one标签中添加 cascade=“save-update”,delete和save-update可以同时存在
/**
* 级联删除:
* 删除联系人级联客户
* 删除联系人,同时删除客户,在联系人配置文件中配置级联删除:cascade=delete
*/
public void test(){
Session session = HibernateUtils.getCurrentSession();
Transaction transaction = session.beginTransaction();
//删除联系人,同时删除客户,在联系人配置文件中配置级联删除:cascade=delete
LinkMan linkMan = session.get(LinkMan.class, 1l);
session.delete(linkMan);
transaction.commit();
}
对象导航:
前提是双方都设置了cascade="save-update"
/**
* 测试对象导航
* 前提:一对多的双方都设置cascade="sava-update"
*/
public void test5(){
Session session = HibernateUtils.getCurrentSession();
Transaction transaction = session.beginTransaction();
//一个客户
Customer customer1 = new Customer();
customer1.setCust_name("1");
//三个联系人
LinkMan linkMan1 = new LinkMan();
linkMan1.setLkm_name("张三");
LinkMan linkMan2 = new LinkMan();
linkMan2.setLkm_name("李四");
LinkMan linkMan3 = new LinkMan();
linkMan3.setLkm_name("王如花");
//设置关系
linkMan1.setCustomer(customer1);
customer1.getLinkMans().add(linkMan2);
customer1.getLinkMans().add(linkMan3);
//双方都设置了cascade
//session.save(linkMan1);//4条insert语句
//session.save(linkMan2);//1条insert语句
session.save(customer1);//3条insert语句
transaction.commit();
}
inverse:
比如将2号联系人从1号客户改为2号客户,原来会发三个select语句,两个update语句,在Customer配置文件中配置inverse="true",放弃外键维护权,用来解决多余的sql语句,这样会只发送一条update语句,
/**
* 将2号联系人原来归1号客户,现在在改为2号客户
*
*/
public void test(){
Session session = HibernateUtils.getCurrentSession();
Transaction transaction = session.beginTransaction();
//查询2号联系人
LinkMan linkMan = session.get(LinkMan.class, 2l);
//查询2号客户
Customer customer = session.get(Customer.class, 2l);
//双向关联
linkMan.setCustomer(customer);
customer.getLinkMans().add(linkMan);
transaction.commit();
}
区别:
cascade管的是关联对象,而inverse管的是一的一方控不控制外键
多对多:
一个学生可以选择多门课程,一门课程也可以被多个学生选择。
一个用户可以选择多个角色,一个角色也可以被多个用户选择。
建表原则:
创建一个中间表,中间表至少有两个字段分别作为外键指向多对多双方的主键。
用户和角色都是多
创建实体类时:
User类中有Role对象集合的属性
Role类中有USer对象集合的属性
private Set<User> users = new HashSet<User>();
private Set<Role> roles = new HashSet<Role>();
配置映射文件时:
这是Role的配置文件,User的类似。
<!--
set标签
name:对方的集合的属性名称
table:多对多的关系需要使用中间表,放的是中间表的名称
-->
<set name="users" table="sys_user_role" >
<!--
key标签:
column:当前对象所对应的外键名称
-->
<key column="role_id"></key>
<!--
many-to-many标签
class:对方的类的全路径
column:对方的对象在中间表中的外键名称
-->
<many-to-many class="domain.User" column="user_id"></many-to-many>
</set>
多对多关系中如果进行了双向维护关系(比如角色中添加用户,用户中添加角色),就必须有一方放弃外键维护权,一般由被动方放弃
如下:
如果不放弃外键维护全,中间表中两个字段共同作为主键就会重复,报错。
所以在set中添加inverse=true
public void test(){
Session session = HibernateUtils.getCurrentSession();
Transaction transaction = session.beginTransaction();
//两个用户
User user1 = new User();
user1.setUser_name("u1");
User user2 = new User();
user2.setUser_name("u2");
//三个角色
Role role1 = new Role();
role1.setRole_name("r1");
Role role2 = new Role();
role2.setRole_name("r2");
Role role3 = new Role();
role3.setRole_name("r3");
//设置双向关联关系
user1.getRoles().add(role1);
user1.getRoles().add(role2);
user2.getRoles().add(role3);
user2.getRoles().add(role1);
role1.getUsers().add(user1);
role1.getUsers().add(user1);
role2.getUsers().add(user2);
role3.getUsers().add(user2);
//保存操作,多对多建立双向关系时,必须有一方放弃外键维护
//一般是被动方放弃
session.save(user1);
session.save(user2);
session.save(role1);
session.save(role2);
session.save(role3);
transaction.commit();
}
多对多级联保存(删除类似):
/**
* 多对多只保存一边,会报瞬时对象异常
* 多对多的级联,保存用户级联角色,在用户映射文件中设置
* 保存角色级联用户,在角色映射文件中设置
*/
public void test(){
Session session = HibernateUtils.getCurrentSession();
Transaction transaction = session.beginTransaction();
//一个用户
User user1 = new User();
user1.setUser_name("u1");
//一个角色
Role role1 = new Role();
role1.setRole_name("r1");
//设置双向关联关系
user1.getRoles().add(role1);
role1.getUsers().add(user1);
session.save(user1);
transaction.commit();
}
多对多关系更多的是对集合的操作