hibernate的多对多
hibernate可以直接映射多对多关联关系(看作两个一对多)
. 多对多关系注意事项
1 一定要定义一个主控方
2 多对多删除
.1 主控方直接删除
.2 被控方先通过主控方解除多对多关系,再删除被控方
.3 禁用级联删除
3 关联关系编辑,不需要直接操作桥接表,hibernate的主控方会自动维护
讲解inverse属性;
* 总共四种 (false 是控制方 ,true 是被控制方),其中有两种正确,两种错误
* 1、book:false category:true ✓(代表意思是:将关系维护的责任交给book book为主控方)
* 2、book: true category:false ✓
* 3、book:true category:true ✗
* 4、book:false category:false ✗
案例:
级联新增 inverse属性值的设置
级联删除
(遇到的问题都在案例里)
dao方法 (book差不多) ,
package com.zking.five.dao;
import org.hibernate.Hibernate;
import org.hibernate.Session;
import com.zking.five.entity.Book;
import com.zking.five.entity.Category;
import com.zking.two.util.SessionFactoryUtil;
public class CategoryDao {
/**
* -----------------------------------six-----------------------------------------------------
* @param category
* @return
*/
//新增
public Integer save(Category category) {
Session session = SessionFactoryUtil.openSession();
Integer cid = (Integer) session.save(category);
SessionFactoryUtil.closeSession();
return cid;
}
//删除 直接删除主控方
// public void del(Category category) {
// Session session = SessionFactoryUtil.openSession();
//
// session.delete(category);
// SessionFactoryUtil.closeSession();
// }
//
//
/** 2.被控方先通过主控方解除多对多关系,再删除被控方
*
* 因为被控方被中间表所引用
* 1、接触关联关系(主控方解除多对多关系 先删除中间表引用数据)
* 2、再删除主控方的相关数据
*
* @param category
*/
//删除
public void del(Category category) {
Session session = SessionFactoryUtil.openSession();
Category c = session.get(Category.class, category.getCategoryId());
//c 里面保存着与某一些书籍相关联的关系
for (Book b : c.getBooks()) {
//注意:关系交于book维护
// c.getBooks().remove(b); 这是错误的 主控方是book 要从书里删除c类型 而不是从类型里删除书
b.getCategories().remove(c);
}
session.delete(c);
SessionFactoryUtil.closeSession();
}
}
测试(book,category都一起)
package com.zking.five.dao;
import org.junit.Test;
import com.zking.five.entity.Book;
import com.zking.five.entity.Category;
public class BookDaoTest {
private BookDao bookDao= new BookDao();
private CategoryDao categoryDao = new CategoryDao();
/**----------------------------------six---------------------------
*- 提交书本信息,勾选复选框类别, 提交
* jdbc: bookDao.add,bookCategoryDao.add(中间表)
* hibernate : bookDao.add
*
* 讲解inverse属性;
* 总共四种 (false 是控制方 ,true 是被控制方),其中有两种正确,两种错误
* 1、book:false category:true ✓(代表意思是:将关系维护的责任交给book book为主控方)
* 2、book: true category:false ✓
* 3、book:true category:true ✗
* 4、book:false category:false ✗
*/
/**错误1:
* Caused by: com.mysql.jdbc.exceptions.
* jdbc4.MySQLIntegrityConstraintViolationException:
* Column 'category_name' cannot be null
*
* 解决方法:这个错误是没有把对象持久态,所以才会出现这个问题把对象通过get方法获取对象持久态就没问题了
*
* */
/**
* 注意:
* hibernate 通过管理持久态对象来操作数据库
*/
@Test
public void testAdd() {
/**
* 1、book:false category:true ✓(代表意思是:将维护的责任交给book book为主控方)
*/
Book book = new Book();
book.setBookName("雨季不再来aaa");
book.setPrice(30f);
//这是错误的示范
// Category category = new Category();//临时态对象 错误1
// category.setCategoryId(4);
// book.getCategories().add(category);
//要通过get获取持久态对象
Category category = new Category();
category.setCategoryId(4);
book.getCategories().add(this.categoryDao.get(category));
this.bookDao.add(book);
}
/**
* 在新增类别的时候不能用第一种维护关系,因为book是主控方,关系的维护是靠book ,
* 新增类别 的时候是需要通过category去维护关系(中间表) 所以要用第二种
* 2、book: true category:false ✓
* 主控方是 category
*
* 总之 新增什么就设置什么是主控方 (inverse="false")
*
*
*/
@Test
public void testAdd2() {
Category category = new Category();
category.setCategoryName("穿越");
Book book = new Book();
book.setBookId(4);
category.getBooks().add(this.bookDao.get(book));
this.categoryDao.save(category);
}
/**
* 3、book:true category:true ✗
* 出现错误:中间表无对象维护(新增类别或书籍时 书籍或类别新增了 但是中间表没有数据)
*/
@Test
public void testAdd3() {
Category category = new Category();
category.setCategoryName("言情");
Book book = new Book();
book.setBookId(5);
category.getBooks().add(this.bookDao.get(book));
this.categoryDao.save(category);
}
/**
* 4、book:false category:false ✗
* 相同的数据加入就会在中间表中有重复的数据,
* 到时候在查询的时候会重复的数据
*
*/
/**------------------del----------------------
* 多对多删除
* 1 、主控方直接删除
* 2、 被控方先通过主控方解除多对多关系,再删除被控方
* 3、 禁用级联删除 (会把三张表的数据都删掉)
*/
/**
* 1.主控方直接删除
*
* 结果: 一并将表关联的中间表信息删除
*/
@Test
public void testDel() {
Book book = new Book();
book.setBookId(6);
this.bookDao.del(book);
}
/**
* 2.被控方先通过主控方解除多对多关系,再删除被控方
*/
/**
* 错误2:
* Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException:
* Cannot delete or update a parent row: a foreign key constraint fails
* (`mybatis_ssm`.`t_hibernate_book_category`, CONSTRAINT `t_hibernate_book_category_ibfk_2`
* FOREIGN KEY (`cid`) REFERENCES `t_hibernate_category` (`category_id`))
*
* 解决方法:
* 这是报数据库的主外键连接的错误,如果你有删除的外键表的数据就要先删除主键表的数据
* 1.接触关联关系(先删除中间表所引用数据)
* 2.再去删除主表信息
*/
@Test
public void testDel2() {
Category category = new Category();
category.setCategoryId(4);
this.categoryDao.del(category);
}
}