Hibernate 一对多自关联 多对多
一对多自关联(说白了就是自己关联自己)比如:
商城里面的分类,一级分类:电器,家具等等。
电器下面分二级分类:厨房电器,生活电器等等。
二级分类厨房电器下的三级分类:电压力锅,电磁炉等等。。
数据库:
实体类:(TreeNode)
package com.chenjiahao.four.entity; import java.util.HashSet; import java.util.Set; public class TreeNode { private Integer nodeId; private String nodeName; private Integer treeNodeType; private Integer position; private String url; private TreeNode parent; private Set<TreeNode> children = new HashSet<TreeNode>(); private Integer initChildren = 0; //0懒加载 1、强制加载(子节点)2、强制加载用户 3、强制加载两个 public Integer getNodeId() { return nodeId; } public void setNodeId(Integer nodeId) { this.nodeId = nodeId; } public String getNodeName() { return nodeName; } public void setNodeName(String nodeName) { this.nodeName = nodeName; } public Integer getTreeNodeType() { return treeNodeType; } public void setTreeNodeType(Integer treeNodeType) { this.treeNodeType = treeNodeType; } public Integer getPosition() { return position; } public void setPosition(Integer position) { this.position = position; } public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } public TreeNode getParent() { return parent; } public void setParent(TreeNode parent) { this.parent = parent; } public Set<TreeNode> getChildren() { return children; } public void setChildren(Set<TreeNode> children) { this.children = children; } public Integer getInitChildren() { return initChildren; } public void setInitChildren(Integer initChildren) { this.initChildren = initChildren; } // @Override // public String toString() { // return "TreeNode [nodeId=" + nodeId + ", nodeName=" + nodeName + ", treeNodeType=" + treeNodeType // + ", position=" + position + ", url=" + url + ", children=" + children + "]"; // } @Override public String toString() { return "TreeNode [nodeId=" + nodeId + ", nodeName=" + nodeName + ", treeNodeType=" + treeNodeType + ", position=" + position + ", url=" + url + "]"; } }
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 name="com.chenjiahao.four.entity.TreeNode" table="t_hibernate_sys_tree_node"> <id name="nodeId" type="java.lang.Integer" column="tree_node_id"> <generator class="increment" /> </id> <property name="nodeName" type="java.lang.String" column="tree_node_name"> </property> <property name="treeNodeType" type="java.lang.Integer" column="tree_node_type"> </property> <property name="position" type="java.lang.Integer" column="position"> </property> <property name="url" type="java.lang.String" column="url"> </property> <many-to-one name="parent" class="com.chenjiahao.four.entity.TreeNode" column="parent_node_id"/> <set name="children" cascade="save-update" inverse="true"> <key column="parent_node_id"></key> <one-to-many class="com.chenjiahao.four.entity.TreeNode"/> </set> </class> </hibernate-mapping>
在主配置文件/hibernate.cfg.xml中加:
<!-- 一对多自关联 --> <mapping resource="com/chenjiahao/four/entity/TreeNode.hbm.xml"/>
TreeNodeDao层
package com.chenjiahao.four.dao; import org.hibernate.Hibernate; import org.hibernate.Session; import org.hibernate.Transaction; import com.chenjiahao.four.entity.TreeNode; import com.chenjiahao.two.util.SessionFactoryUtils; public class TreeNodeDao { public TreeNode load(TreeNode treeNode) { Session session = SessionFactoryUtils.openSession(); Transaction transaction = session.beginTransaction(); TreeNode t = session.load(TreeNode.class, treeNode.getNodeId()); if(t != null && new Integer(1).equals(treeNode.getInitChildren())) { Hibernate.initialize(t.getChildren()); Hibernate.initialize(t.getParent()); } transaction.commit(); session.close(); return t; } }
TreeNodeDaoTest测试:
package com.chenjiahao.four.dao; import org.junit.Test; import com.chenjiahao.four.entity.TreeNode; public class TreeNodeDaoTest { private TreeNodeDao treeNodeDao = new TreeNodeDao(); // @Before // public void setUp() throws Exception { // } // // @After // public void tearDown() throws Exception { // } @Test public void testLoad() { TreeNode treeNode = new TreeNode(); treeNode.setNodeId(6); treeNode.setInitChildren(1); TreeNode t = this.treeNodeDao.load(treeNode); //拿到当前节点 System.out.println(t); //拿到当前节点的父节点 System.out.println(t.getParent()); //拿到当前节点的 子节点 System.out.println(t.getChildren()); } }
多对多
数据库的多对多:
数据库中不能直接映射多对多
处理:创建一个桥接表(中间表),将一个多对多关系转换成两个一对多
注:数据库多表联接查询,永远就是二个表的联接查询
hibernate的多对多:
hibernate可以直接映射多对多关联关系(看作两个一对多)
多对多关系注意事项:一定要定义一个主控方
书本表:t_hibernate_book;
书本类别表:t_hibernate_category;
中间表: t_hibernate_book_category;
t_hibernate_book;
t_hibernate_category;
t_hibernate_book_category
实体类和xml配置:
Book:
public class Book implements Serializable{ // book_id int primary key auto_increment, // book_name varchar(50) not null, // price float not null private Integer bookId; private String bookName; private Float price; }
Category:
public class Category implements Serializable{ // category_id int primary key auto_increment, // category_name varchar(50) not null private Integer categoryId; private String categoryName; private Set<Book> books = new HashSet<Book>(); }
incerse在下面book.hbm.xml和Category.hbm.xml里面都体现了,incerse主要是维护中间表。
book.hbm.xml inverse=false
category.hbm.xml inverse=false
数据添加正常
书籍表、书籍类别关联表各新增一条数据
book.hbm.xml inverse=true
category.hbm.xml inverse=true
只增加书籍表数据
书籍类别关联表不加数据
原因:双方都没有去维护关系
Category.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 name="com.chenjiahao.four.entity.Category" table="t_hibernate_category"> <id name="categoryId" type="java.lang.Integer" column="category_id"> <generator class="increment" /> </id> <property name="categoryName" type="java.lang.String" column="category_name"> </property> <set table="t_hibernate_book_category" name="books" cascade="save-update" inverse="false"> <key column="cid"></key> <many-to-many column="bid" class="com.chenjiahao.four.entity.Book"></many-to-many> </set> </class> </hibernate-mapping>
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 name="com.chenjiahao.four.entity.Book" table="t_hibernate_book"> <cache usage="read-only" region="com.zking.five.entity.Book"/> <id name="bookId" type="java.lang.Integer" column="book_id"> <generator class="increment" /> </id> <property name="bookName" type="java.lang.String" column="book_name"> </property> <property name="price" type="java.lang.Float" column="price"> </property> <!-- table:代表的是中间表 name:书籍的关联属性 inverse:中间表交于对方维护 key:当前类对应的表列段在中间表(t_hibernate_book_category)中的外键bid many-to-many: column:对应的是上面key查出来中间表(t_hibernate_book_category)另一个字段cid,当作关联表的主键(category_id)进行查询 class:上述查出来的主键对应的实体类 流程: 以查询book_id=1西游记这本书为例 1、通过建模反射自动生成sql,可以拿到book_id这条记录的基本信息{book_id=1,book_name=西游记,book_price=50} 2、book_id=1->bid=1去查询中间表t_hibernate_book_category,拿到了cid=1,2 3、cid=1,2->t_hibernate_category的category_id=1,2 4、拿到当前book实列对应的categroy的集合 5、最终{book_id=1,book_name=西游记,book_price=50}-> {book_id=1,book_name=西游记,book_price=50,category=[categoryId=2, categoryName=神话], Category [categoryId=1, categoryName=古典]]} --> <set table="t_hibernate_book_category" name="categories" cascade="save-update" inverse="false"> <!-- one --> <key column="bid"></key> <!-- many --> <many-to-many column="cid" class="com.chenjiahao.four.entity.Category"></many-to-many> </set> </class> </hibernate-mapping>
在主配置文件/hibernate.cfg.xml中加:
<!-- 多对多的自关联 --> <mapping resource="com/chenjiahao/four/entity/Book.hbm.xml"/> <mapping resource="com/chenjiahao/four/entity/Category.hbm.xml"/
dao层:
package com.chenjiahao.four.dao; import java.util.HashMap; import java.util.List; import java.util.Map; import org.hibernate.Hibernate; import org.hibernate.Session; import org.hibernate.Transaction; import org.hibernate.query.Query; import com.chenjiahao.four.entity.Book; import com.chenjiahao.four.entity.Category; import com.chenjiahao.two.util.SessionFactoryUtils; import antlr.StringUtils; public class BookDao { public Integer addBook(Book book) { Session session = SessionFactoryUtils.openSession(); Transaction transaction = session.beginTransaction(); Integer bid = (Integer) session.save(book); transaction.commit(); session.close(); return bid; } public Integer addCategory(Category category) { Session session = SessionFactoryUtils.openSession(); Transaction transaction = session.beginTransaction(); Integer cid = (Integer) session.save(category); transaction.commit(); session.close(); return cid; } public Category getCategory(Category category) { Session session = SessionFactoryUtils.openSession(); Transaction transaction = session.beginTransaction(); Category c = session.get(Category.class, category.getCategoryId()); transaction.commit(); session.close(); return c; } public Book getBook(Book book) { Session session = SessionFactoryUtils.openSession(); 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; } public void delBook(Book book) { Session session = SessionFactoryUtils.openSession(); Transaction transaction = session.beginTransaction(); session.delete(book); transaction.commit(); session.close(); } public void delCategory(Category category) { Session session = SessionFactoryUtils.openSession(); Transaction transaction = session.beginTransaction(); Category c = session.get(Category.class, category.getCategoryId()); if(c!=null) { for (Book b : c.getBooks()) { // 通过在被控方通过主控方来解除关联关系,最后被控方再做删除 b.getCategories().remove(c); } } session.delete(c); transaction.commit(); session.close(); } }
测试:
package com.chenjiahao.four.dao; import org.junit.Test; import com.chenjiahao.four.entity.Book; import com.chenjiahao.four.entity.Category; public class BookDaoTest { private BookDao bookDao = new BookDao(); @Test public void testGetBook() { Book book = new Book(); book.setBookId(1); book.setInitCategories(1); Book b = this.bookDao.getBook(book ); System.out.println(b.getBookName()); System.out.println(b.getCategories()); } /** * book.hbm.xml inverse=false * category.hbm.xml inverse=true * 数据添加正常 * 书籍表、桥接表各新增一条数据 */ @Test public void test1() { Book book = new Book(); book.setBookName("00咖啡店说课稿5"); book.setPrice(10f); Category category = new Category(); category.setCategoryId(1); // 直接将category对象加入到新建的book中是错误的,因为此时的category是临时态的,hibernate是不会管理的 // book.getCategories().add(category); //将数据库里面的类别数据查找出来 Category c = this.bookDao.getCategory(category); // c.getBooks().add(book); book.getCategories().add(c); this.bookDao.addBook(book); } /** * book.hbm.xml inverse=true * category.hbm.xml inverse=true * 只增加书籍表数据 * 桥接表不加数据 * 原因:双方都没有去维护关系 */ @Test public void test2() { Book book = new Book(); book.setBookName("斗宗强者"); book.setPrice(10f); Category category = new Category(); category.setCategoryId(5); Category c = this.bookDao.getCategory(category); book.getCategories().add(c); this.bookDao.addBook(book); // c.getBooks().add(book); } }