Hibernate学习⑤:多对多

Hibernate学习⑤:多对多

一、数据库的多对多

1、数据库中不能直接映射多对多
处理:创建一个桥接表(中间表),将一个多对多关系转换成两个一对多
注意:

	①数据库多表联接查询
       永远就是二个表的联接查询
       
    ②交叉连接
    
    ③外连接:left(左)/right(右)/full(左右)
       主从表:连接条件不成立时,主表记录永远保留,与null匹配

说明:

	   在hibernate中,只管查询当前表对象即可,因为hibernate会自动关联桥表			以及关联表查询出关联对象

菜单案例:
entity:TreeNode

package com.zking.five.entity;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class TreeNode {

	  private Integer treeNodeId;
	  private String treeNodename;
	  private Integer treeNodeType;
	  private Integer posotion;
	  private String url;
	  
//	  两种关系:
//	  	①当前节点与子节点的关联关系     一对多
//	  private Set<TreeNode> children = new HashSet<TreeNode>();
	  private List<TreeNode> children = new ArrayList<TreeNode>();
 //	    ②当前节点与父节点的关系   多对一
	  private TreeNode parent;
	  
	  private Integer initChild;

	public Integer getTreeNodeId() {
		return treeNodeId;
	}

	public void setTreeNodeId(Integer treeNodeId) {
		this.treeNodeId = treeNodeId;
	}

	public String getTreeNodename() {
		return treeNodename;
	}

	public void setTreeNodename(String treeNodename) {
		this.treeNodename = treeNodename;
	}

	public Integer getTreeNodeType() {
		return treeNodeType;
	}

	public void setTreeNodeType(Integer treeNodeType) {
		this.treeNodeType = treeNodeType;
	}

	public Integer getPosotion() {
		return posotion;
	}

	public void setPosotion(Integer posotion) {
		this.posotion = posotion;
	}

	public String getUrl() {
		return url;
	}

	public void setUrl(String url) {
		this.url = url;
	}

	public List<TreeNode> getChildren() {
		return children;
	}

	public void setChildren(List<TreeNode> children) {
		this.children = children;
	}

	public TreeNode getParent() {
		return parent;
	}

	public void setParent(TreeNode parent) {
		this.parent = parent;
	}

	public Integer getInitChild() {
		return initChild;
	}

	public void setInitChild(Integer initChild) {
		this.initChild = initChild;
	}

	@Override
	public String toString() {
		return "TreeNode [treeNodeId=" + treeNodeId + ", treeNodename=" + treeNodename + ", children=" + children + "]";
	}
}

*.hbm.xml:TreeNode.hbm.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC 
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
    <hibernate-mapping>
    	<class table = "t_hibernate_sys_tree_node" name = "com.zking.five.entity.TreeNode">
    		<id name = "treeNodeId" type = "java.lang.Integer" column = "tree_node_id">
				<generator class="increment"></generator>
			</id>
    		<property name = "treeNodename" type = "java.lang.String" column = "tree_node_name"></property>
    		<property name = "treeNodeType" type = "java.lang.Integer" column = "tree_node_type"></property>
    		<property name = "posotion" type = "java.lang.Integer" column = "position"></property>
    	    <property name = "url" type = "java.lang.String" column = "url"></property>
    		
    		<!-- <set name = "children" cascade="save-update" inverse="true">
    			<key column = "parent_node_id"></key>
			    <one-to-many class = "com.zking.five.entity.TreeNode"></one-to-many>		
    		</set> -->
    		<!-- order-by数据库中的表字段 -->
    		<bag order-by="position" name = "children" cascade="save-update" inverse="true">
    		<key column = "parent_node_id"></key>
			    <one-to-many class = "com.zking.five.entity.TreeNode"></one-to-many>
    		</bag>
    		<many-to-one name = "parent" class = "com.zking.five.entity.TreeNode" column = "parent_node_id"></many-to-one>
    		
    		
    	</class>
    </hibernate-mapping>

dao : TreeNodeDao

package com.zking.five.dao;

import org.hibernate.Hibernate;
import org.hibernate.Session;
import org.hibernate.Transaction;

import com.zking.five.entity.TreeNode;
import com.zking.two.util.SessionFactoryUtils;

public class TreeNodeDao {
	//查看
	public TreeNode get(TreeNode treeNode) {
		Session session = SessionFactoryUtils.getSession();
		Transaction transaction = session.beginTransaction();
		TreeNode tn = session.get(TreeNode.class, treeNode.getTreeNodeId());
		if(tn != null && new Integer(1).equals(treeNode.getInitChild())) {
			Hibernate.initialize(tn.getChildren());
		}
//		System.out.println(tn);
		transaction.commit();
		session.close();
		return tn;
	}
}

测试 : TreeNodeDaoTest

package com.zking.five.dao;

import static org.junit.Assert.*;

import org.junit.Before;
import org.junit.Test;

import com.zking.five.entity.TreeNode;

public class TreeNodeDaoTest {
	private TreeNodeDao treeNodeDao = new TreeNodeDao();

	@Before
	public void setUp() throws Exception {
	}

	@Test
	public void testGet() {
		TreeNode treeNode = new TreeNode();
		treeNode.setTreeNodeId(1);
		treeNode.setInitChild(1);
		TreeNode tn = this.treeNodeDao.get(treeNode);
		/*根据id直接打印一级节点以及其所有子节点
			System.out.println(tn);
		 * 会报错
		 	failed to lazily initialize a collection of role:
			 com.zking.five.entity.TreeNode.children, 
			 could not initialize proxy - no Session
		
		 *	代码分析:
			System.out.println(tn.getTreeNodeId()+" , "+tn.getTreeNodename());
			for (TreeNode tn2 : tn.getChildren()) {
				System.out.println(tn2.getTreeNodeId()+" , "+tn.getTreeNodename());
			}
		 *
		 *	原理分析:
		 *	当加载以及节点的时候没问题
		 *	加载二级节点的时候,由于设置了强制加载,同样可以加载所有的二级节点。没问题
		 *	加载三级节点,这时session关闭了,并且默认查出来的节点默认采用懒加载
		 *
		 *	权限菜单加载的两种方式:
		 *	1、一次性将数据库表中的数据全部加载往浏览器返回(是用于菜单较少)
		 *	2、菜单表数据较大,当浏览器出现卡顿的情况,第一中情况不再使用
		 *		那么就采用逐级加载。——逐级加载事件(异步)
		 *
		 */
		System.out.println(tn.getTreeNodeId()+" , "+tn.getTreeNodename());
		for (TreeNode tn2 : tn.getChildren()) {
			System.out.println(tn2.getTreeNodeId()+" , "+tn.getTreeNodename());
		}
	}
}

二、hibernate的多对多

1、 hibernate可以直接映射多对多关联关系(看作两个一对多)
2、多对多关系注意事项

	  ①一定要定义一个主控方
	  ② 多对多删除
		    (1)主控方直接删除
			(2)被控方先通过主控方解除多对多关系,再删除被控方
			(3)禁用级联删除

3、 关联关系编辑,不需要直接操作桥接表,hibernate的主控方会自动维护

书籍与其书书籍类型案例

entity:book

package com.zking.five.entity;

import java.util.HashSet;
import java.util.Set;

public class Book {
	private Integer bookId;
	private String bookName;
	private Float price;
	
	private Set<Category> categories = new HashSet<Category>();
	private Integer initCategories = 0;
	public Integer getInitCategories() {
		return initCategories;
	}
	public void setInitCategories(Integer initCategories) {
		this.initCategories = initCategories;
	}
	public Set<Category> getCategories() {
		return categories;
	}
	public void setCategories(Set<Category> categories) {
		this.categories = categories;
	}
	public Integer getBookId() {
		return bookId;
	}
	public void setBookId(Integer bookId) {
		this.bookId = bookId;
	}
	public String getBookName() {
		return bookName;
	}
	public void setBookName(String bookName) {
		this.bookName = bookName;
	}
	public Float getPrice() {
		return price;
	}
	public void setPrice(Float price) {
		this.price = price;
	}
}

entity : Category

package com.zking.five.entity;

import java.util.HashSet;
import java.util.Set;

public class Category {
	private Integer categoryId;
	private String categoryName;
	private Set<Book> books = new HashSet<Book>();
	private Integer initBooks = 0;
	public Integer getInitBooks() {
		return initBooks;
	}
	public void setInitBooks(Integer initBooks) {
		this.initBooks = initBooks;
	}
	public Set<Book> getBooks() {
		return books;
	}
	public void setBooks(Set<Book> books) {
		this.books = books;
	}
	public Integer getCategoryId() {
		return categoryId;
	}
	public void setCategoryId(Integer categoryId) {
		this.categoryId = categoryId;
	}
	public String getCategoryName() {
		return categoryName;
	}
	public void setCategoryName(String categoryName) {
		this.categoryName = categoryName;
	}
}

*.hbm.xml : book.hbm.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC 
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
    <hibernate-mapping>
    	<class table = "t_hibernate_book" name = "com.zking.five.entity.Book">
    		<id name = "bookId" type = "java.lang.Integer" column = "book_id">
				<generator class="increment"></generator>
			</id>
    		<property name = "bookName" type = "java.lang.String" column = "book_name"></property>
    		<property name = "price" type = "java.lang.Float" column = "price"></property>
    		
    		<!--  
    			table:桥接表
    		-->
    		<set table="t_hibernate_book_category" name = "categories" cascade="delete" inverse="false">
    			<!-- 当前类对应的表主键在桥接表的外键 -->
    			<key column = "bid"></key>
    			<many-to-many column = "cid" class = "com.zking.five.entity.Category"></many-to-many>
    		</set>
    	</class>
    </hibernate-mapping>

*.hbm.xml : TreeNode.hbm.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC 
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
    <hibernate-mapping>
    	<class table = "t_hibernate_category" name = "com.zking.five.entity.Category">
    		<id name = "categoryId" type = "java.lang.Integer" column = "category_id">
				<generator class="increment"></generator>
			</id>
    		<property name = "categoryName" type = "java.lang.String" column = "category_name"></property>
    		
    		<set table = "t_hibernate_book_category" name = "books" cascade = "save-update" inverse="true">
    			<key column = "cid"></key>
    			<many-to-many column = "bid" class = "com.zking.five.entity.Book"></many-to-many>
    		</set>
    	</class>
    </hibernate-mapping>

dao : BookDao

package com.zking.five.dao;

import java.io.Serializable;

import org.hibernate.Hibernate;
import org.hibernate.Session;
import org.hibernate.Transaction;

import com.zking.five.entity.Book;
import com.zking.two.util.SessionFactoryUtils;

public class BookDao {
	public Book get(Book book) {
		Session session = SessionFactoryUtils.getSession();
		Transaction transaction = session.beginTransaction();
		Book b = session.get(Book.class, book.getBookId());
		if(b != null && new Integer(1).equals(book.getInitCategories())) {
			Hibernate.initialize(b.getCategories());
		}
		transaction.commit();
		session.close();
		return b;
	}
	
//	*************************six**************************************************//
	 public Integer add(Book book) {
		 Session session = SessionFactoryUtils.getSession();
		 Transaction transaction = session.beginTransaction();
		 Integer bid = (Integer) session.save(book);
		 transaction.commit();
		 session.close();
		 return bid;
	 }
	 public void del(Book book) {
		 Session session = SessionFactoryUtils.getSession();
		 Transaction transaction = session.beginTransaction();
		 session.delete(book);
		 transaction.commit();
		 session.close();
	 }

}

dao: Categorydao

package com.zking.five.dao;

import org.hibernate.Hibernate;
import org.hibernate.Session;
import org.hibernate.Transaction;

import com.zking.five.entity.Book;
import com.zking.five.entity.Category;
import com.zking.two.util.SessionFactoryUtils;

public class Categorydao {
	public Category get(Category category) {
		Session session = SessionFactoryUtils.getSession();
		Transaction transaction = session.beginTransaction();
		Category c = session.get(Category.class, category.getCategoryId());
		if(c != null && new Integer(1).equals(category.getInitBooks())) {
			Hibernate.initialize(c.getBooks());
		}
		transaction.commit();
		session.close();
		return c;
	}
	
	
	
	
//	*************************six**************************************************//
	
	public Integer add(Category category) {
		Session session = SessionFactoryUtils.getSession();
		Transaction transaction = session.beginTransaction();
		Integer cid = (Integer) session.save(category);
		transaction.commit();
		session.close();
		return cid;
	}

	/*
	 * 被控方删除
	 * 1、被控方通过主控关系解除关联关系
	 * 2、在去删除被控方
	 */
	 public void del(Category category) {
		 Session session = SessionFactoryUtils.getSession();
		 Transaction transaction = session.beginTransaction();
		 Category c = session.get(Category.class, category.getCategoryId());
		 for (Book b : c.getBooks()) {
//			c.getBooks().remove(b);
			b.getCategories().remove(c);
		}
		 session.delete(c);
		 transaction.commit();
		 session.close();
	 }
}

测试:BookDaoTest

package com.zking.five.dao;

import static org.junit.Assert.*;

import org.junit.Before;
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();
	@Before
	public void setUp() throws Exception {
	}
	/**
	 * 通过一本能过查询到多个类别
	 * jdbc:三表联差
	 * hibernate:只需要查询单个对象即可,它会自动关联查询,交给映射文件即可
	 */
	@Test
	public void testGet1() {
		Book book = new Book();
		book.setBookId(5);
		book.setInitCategories(1);
		Book b = this.bookDao.get(book);
		System.out.println(b.getBookName());
		for (Category c : b.getCategories()) {
			System.out.println(c.getCategoryName());
		}
		/*
		 * 《悲伤逆流成河》
			情感
			发牢骚
			青春

		 */
	}
	/**
	 * 查询同一类别下的所有书籍
	 */
	@Test
	public void testGet2() {
		Category category = new Category();
		category.setCategoryId(1);
		category.setInitBooks(1);
		Category c = this.categorydao.get(category);
		System.out.println(c.getCategoryName());
		for (Book b : c.getBooks()) {
			System.out.println(b.getBookName());
		}
		/*
		 * 情感
			《悲伤逆流成河》
			《爸爸妈妈》
			《论辈分,论年龄》
		 */
	}
//	*************************six**************************************************//
	/**
	 * 级联新增
	 * book.hbm.xml    :inverse = false
	 * category.hbm.xml:inverse = true
	 * 含义:将级联关系的维护责任交给book对象
	 * 
	 * 
	 * jdbc:
	 * 	this.bookDao.add
	 * 	this.bookCategoryDao.add
	 * 
	 * hibernate:
	 * 	this.bookDao.add
	 * 
	 * 注意:在多对多的关系维护中,hibernate管理的是持久态对象
	 */
		@Test
		public void testAdd1() {
		 Book book = new Book();
		 book.setBookName("《霸道总裁爱上我222》");
		 book.setPrice(123f);
//		 new 一个对象  临时态对象
		 Category category = new Category();
		 category.setCategoryId(6);
		 /**
		  * 会报错
		  */
//		 book.getCategories().add(category)
		 book.getCategories().add(this.categorydao.get(category));
		 this.bookDao.add(book);
	 }
		
		/**
		 * 添加一个新的类别,绑定原有的某个书籍
		 */
		@Test
		public void testAdd2() {
			Category category = new Category();
			category.setCategoryName("惊悚");
			Book book = new Book();
			book.setBookId(6);
			category.getBooks().add(this.bookDao.get(book));
			this.categorydao.add(category);
		}
		
		
		
		/**
		 * book.hbm.xml    :inverse = true
		 * category.hbm.xml:inverse = true
		 * 双方关系各不维护
		 */
		@Test
		public void testAdd3() {
			Category category = new Category();
			category.setCategoryName("惊悚1");
			Book book = new Book();
			book.setBookId(6);
			category.getBooks().add(this.bookDao.get(book));
			this.categorydao.add(category);
		}
		
		/**
		 * 主控方删除
		 * 	需求:删除有关联关系的一本书
		 * 
		 * jdbc:
		 * 	this.bookCategoryDao.delete
		 * 	this.bookDao.delete
		 * 
		 * hibernate:
		 * 	this.bookDao.delete
		 */
		@Test
		public void testDel1(){
			Book book = new Book();
			book.setBookId(8);
			this.bookDao.del(book);
		}
		/**
		 * 被控方删除
		 * 	需求:删除有关联关系的一个类别包括该类别下的所有数据
		 * 
		 */
		@Test
		public void testDel2(){
			Category category = new Category();
			category.setCategoryId(3);
			this.categorydao.del(category);
		}
}

猜你喜欢

转载自blog.csdn.net/weixin_43163062/article/details/83474858