本篇博客主要介绍hibernate的关联关系(一对多,多对多)
1、一对多的配置文件配置介绍
2、一对多如何通过代码进行级联新增
3、一对多的懒加载问题及解决方案
4、一对多的级联删除
5、一对多的自关联
6、多对多的配置文件介绍
7、多对多的查询
8、多对多的新增(inverse属性详解)
9、多对多的级联删除(慎用,会将三张表的数据清空)
1、一对多的配置文件配置介绍
<class name="com.javaxl.three.entity.Order" table="t_hibernate_order"> <id name="orderId" type="java.lang.Integer" column="order_id"> <generator class="increment" /> </id> <property name="orderNo" type="java.lang.String" column="order_no"> </property> <!-- Exception in thread "main" java.lang.ClassCastException: java.util.ArrayList cannot be cast to java.util.Set --> <bag lazy="true" name="orderItems" cascade="save-update" inverse="true"> <key column="oid"></key> <one-to-many class="com.javaxl.three.entity.OrderItem" /> </bag> </class>
<class name="com.javaxl.three.entity.OrderItem" table="t_hibernate_order_item"> <id name="orderItemId" type="java.lang.Integer" column="order_item_id"> <generator class="increment" /> </id> <property name="productId" type="java.lang.Integer" column="product_id"> </property> <property name="quantity" type="java.lang.Integer" column="quantity"> </property> <property name="oid" type="java.lang.Integer" column="oid" insert="false" update="false"> </property> <many-to-one name="order" class="com.javaxl.three.entity.Order" column="oid"></many-to-one> </class>
注意:外键只能被hibernate所管理的对象中的一个属性所维护
2、一对多如何通过代码进行级联新增
/** * 为了测试关系型映射文件配置准确 * 讲解insert=false,update=false的用途 * @param order * @return */ public Integer addOrder(Order order) { Session session = SessionFactoryUtils.openSession(); Transaction transaction = session.beginTransaction(); Integer oid = (Integer)session.save(order); transaction.commit(); session.close(); return oid; } public Integer addOrderItem(OrderItem orderItem) { Session session = SessionFactoryUtils.openSession(); Transaction transaction = session.beginTransaction(); Integer otid = (Integer)session.save(orderItem); transaction.commit(); session.close(); return otid; }
/** * 一方的新增 */ @Test public void testAddOrder() { // Order order = new Order(); // order.setOrderNo("P3"); // System.out.println(orderDao.addOrder(order)); //配置关系的好处 Order order = new Order(); order.setOrderNo("P5"); OrderItem orderItem; for(int i =0; i<6 ;i++) { orderItem = new OrderItem(); orderItem.setOid(i); orderItem.setProductId(i); orderItem.setQuantity(i); orderItem.setOrder(order ); order.getOrderItems().add(orderItem); } this.demoDao.addOrder(order); } /** * 多方的新增 */ @Test public void testAddOrderItem() { OrderItem orderItem; for(int i =0; i<6 ;i++) { orderItem = new OrderItem(); orderItem.setOid(i); orderItem.setProductId(i); orderItem.setQuantity(i); Order order = new Order(); order.setOrderId(3); orderItem.setOrder(order ); Integer otid = demoDao.addOrderItem(orderItem); System.out.println(otid); } // Repeated column in mapping for entity: com.javaxl.four.entity.OrderItem column: // oid (should be mapped with insert="false" update="false") // 原因是同一个表中的字段被映射了两次 // System.out.println(otid); }
3、一对多的懒加载问题及解决方案
/** * 为了讲解懒加载的问题(hibernate3.0后所有查询方式默认采用的是懒加载方式) * 1、查单个时存在问题,代理对象已经关闭 * 2、查多个存在问题,有性能的问题 * @param order * @return */ public Order getOrder(Order order) { Session session = SessionFactoryUtils.openSession(); Transaction transaction = session.beginTransaction(); Order o = session.get(Order.class, order.getOrderId()); if(o != null && new Integer(1).equals(order.getInitChildren())) { Hibernate.initialize(o.getOrderItems()); // System.out.println(o.getOrderItems()); } transaction.commit(); session.close(); return o; } public List<Order> getOrderList() { Session session = SessionFactoryUtils.openSession(); Transaction transaction = session.beginTransaction(); List<Order> list = session.createQuery("from Order").list(); transaction.commit(); session.close(); return list; }
/** * 懒加载测试 */ @Test public void testGetOrder() { Order order = new Order(); order.setOrderId(8); order.setInitChildren(1); Order o = this.demoDao.getOrder(order); System.out.println(o.getOrderNo()); // failed to lazily initialize a collection of role: com.javaxl.four.entity.Order.orderItems, // could not initialize proxy - no Session // 由于查询默认采用的是懒加载的方式,加载主表对应的实体类,拿到了从表对应的实体类的oid, // 并且保留在org.hibernate.collection.internal.PersistentSet这个代理对象中。 // 等要获取从表的对应实体类额确切信息是,这是session已经关闭了。 System.out.println(o.getOrderItems()); // org.hibernate.collection.internal.PersistentSet // System.out.println(o.getOrderItems().getClass().getName()); } /** * 懒加载 lazy设置为false的弊端 */ @Test public void testGetOrderList() { List<Order> orderList = demoDao.getOrderList(); for (Order order : orderList) { System.out.println(order.getOrderNo()); // System.out.println(order.getOrderItems()); } }
注意:hibernate3之后lazy默认为true,lazy=true会引发一个问题,不能加载关联属性,但是将lazy设置为false的话,又会造成查询多条主表数据的时候性能变差,这时我们采取的措施是
在主表对应的实体类中添加一个是否强制加载的控制字段;
4、一对多的级联删除
/** * z主表的数据不能随便删除,得先删除从表中对应信息,才能删除主表的信息。 * @param order */ public void delOrder(Order order) { Session session = SessionFactoryUtils.openSession(); Transaction transaction = session.beginTransaction(); Order order2 = session.get(Order.class, order.getOrderId()); for (OrderItem oi : order2.getOrderItems()) { session.delete(oi); } session.delete(order2); // session.delete(order); transaction.commit(); session.close(); }
/** * 级联删除 */ @Test public void testDelOrder() { Order order = new Order(); order.setOrderId(3); this.demoDao.delOrder(order ); }
5、一对多的自关联
<class name="com.javaxl.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.javaxl.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.javaxl.four.entity.TreeNode"/> </set> </class>
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; }
@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()); }
6、多对多的配置文件介绍
<class name="com.javaxl.four.entity.Book" table="t_hibernate_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> <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.javaxl.four.entity.Category"></many-to-many> </set> </class>
<class name="com.javaxl.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="true"> <key column="cid"></key> <many-to-many column="bid" class="com.javaxl.four.entity.Book"></many-to-many> </set> </class>
注意:key对应的column不要填反,这里填的是当前类所映射的表的主键,所对应的桥接表中的外键
7、多对多的查询
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; }
@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()); }
8、多对多的新增(inverse属性详解)
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; }
/** * book.hbm.xml inverse=fasle * category.hbm.xml inverse=true * 数据添加正常 * 书籍表、桥接表各新增一条数据 */ @Test public void test1() { Book book = new Book(); book.setBookName("b"); book.setPrice(10f); Category category = new Category(); category.setCategoryId(5); // 直接将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("c"); 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); } /** * inverse进一步讲解 */ @Test public void test3() { Category category = new Category(); category.setCategoryName("7"); Book book = new Book(); book.setBookId(6); Book b = bookDao.getBook(book); category.getBooks().add(b); this.bookDao.addCategory(category); }
9、多对多的级联删除(慎用,会将三张表的数据清空)
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(); }
/** * 书籍为主控方 */ @Test public void test4() { Book book = new Book(); book.setBookId(3); this.bookDao.delBook(book); } @Test public void test5() { Category category = new Category(); category.setCategoryId(1); this.bookDao.delCategory(category); }
over......
备案号:湘ICP备19000029号
Copyright © 2018-2019 javaxl晓码阁 版权所有