Hibernate Association

1, One to many configuration and lazy loading query 1. One to many 1.1 association refers to the reference relationship...
1, One to many configuration and lazy loading query


1. One to many
1.1 association refers to the reference relationship between classes.
If class A is associated with class B, the referenced class B will be defined as an attribute of class A.

1.2. One to many association:
For example: orders and order items. An order has multiple order items,     However, an order item has only one order;

Database: master table, slave table, associated by foreign key Class: class A{ B b; } class B{ }

1.3. Example: Order and Order_item (multiple Order items corresponding to an Order, but one Order item has only one Order)
Entity class: Order

//Note: variable attributes must be accepted by the interface private Set<OrderItem> orderItems = new HashSet<>(); private Integer initOrderItems = 0;//0 represents lazy loading and 1 represents forced loading
package com.smy.two.entity; import java.util.HashSet; import java.util.Set; public class Order { // create table t_hibernate_order // ( // order_id int primary key auto_increment, // order_no varchar(50) not null // ); private Integer orderId; private String orderNo; //Note: variable attributes must be accepted by the interface private Set<OrderItem> orderItems = new HashSet<>(); private Integer initOrderItems = 0;//0 represents lazy loading and 1 represents forced loading public Integer getInitOrderItems() { return initOrderItems; } public void setInitOrderItems(Integer initOrderItems) { this.initOrderItems = initOrderItems; } public Set<OrderItem> getOrderItems() { return orderItems; } public void setOrderItems(Set<OrderItem> orderItems) { this.orderItems = orderItems; } public Integer getOrderId() { return orderId; } public void setOrderId(Integer orderId) { this.orderId = orderId; } public String getOrderNo() { return orderNo; } public void setOrderNo(String orderNo) { this.orderNo = orderNo; } }

Entity class: OrderItem

package com.smy.two.entity; public class OrderItem { // create table t_hibernate_order_item // ( // order_item_id int primary key auto_increment, // product_id int not null, // quantity int not null, // oid int not null, // foreign key(oid) references t_hibernate_order(order_id) // ); private Integer orderItemId; private Integer productId; private Integer quantity; private Integer oid; private Order order; public Order getOrder() { return order; } public void setOrder(Order order) { this.order = order; } public Integer getOrderItemId() { return orderItemId; } public void setOrderItemId(Integer orderItemId) { this.orderItemId = orderItemId; } public Integer getProductId() { return productId; } public void setProductId(Integer productId) { this.productId = productId; } public Integer getQuantity() { return quantity; } public void setQuantity(Integer quantity) { this.quantity = quantity; } public Integer getOid() { return oid; } public void setOid(Integer oid) { this.oid = oid; } }

Mapping file Order.hbm.xml
For an order, it belongs to the one to many tag   class is the fully qualified name of the order item

  The name attribute is the attribute name   Key indicates the foreign key column;

<?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.smy.two.entity.Order" table="t_hibernate_order"> <id name="orderId" type="java.lang.Integer" column="order_id"> <generator></generator> </id> <property name="orderNo" type="java.lang.String" column="order_no"/> <!-- cascade:Cascade attribute configuration inverse: Is the relationship maintained by the other party? --> <set name="orderItems" cascade="save-update" inverse="true"> <key column="oid"></key> <one-to-many/> </set> </class> </hibernate-mapping>

2. Lazy loading
Tool class: sessionFactory

package com.zking.util; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.cfg.Configuration; /** * 1,Used to produce session * 2,Used to test whether your hibernate configuration is correct * @author Administrator * */ public class SessionFactoryUtil { static SessionFactory sessionFactory; static { Configuration configure = new Configuration().configure("hibernate.cfg.xml"); sessionFactory = configure.buildSessionFactory(); } public static Session getSession() { Session session = sessionFactory.getCurrentSession(); if(session == null) { session = sessionFactory.openSession(); } return session; } public static void main(String[] args) { Session session = SessionFactoryUtil.getSession(); // Calling method 'isConnected' is not valid without an active transaction (Current status: NOT_ACTIVE) session.beginTransaction(); System.out.println(session.isConnected()); session.close(); System.out.println(session.isConnected()); } }


Dao method: OrderDao

package com.smy.two.Dao; import java.util.Iterator; import java.util.List; import org.hibernate.Hibernate; import org.hibernate.Session; import org.hibernate.Transaction; import com.smy.two.entity.Order; import com.smy.two.entity.OrderItem; import com.zking.util.SessionFactoryUtil; public class OrderDao { public Order get(Order order) { Session session = SessionFactoryUtil.getSession(); Transaction transaction = session.beginTransaction(); Order o = session.get(Order.class, order.getOrderId()); // In addition, if you want to query the data of associated order items, you can use forced loading if(o != null && new Integer(1).equals(order.getInitOrderItems())) { Hibernate.initialize(o.getOrderItems()); // Force loading of order item data associated with the order Hibernate.initialize(o.getInitOrderItems()); } transaction.commit(); session.close(); return o; } public List<Order> list() { Session session = SessionFactoryUtil.getSession(); Transaction transaction = session.beginTransaction(); List<Order> list = session.createQuery("from Order").list(); for (Order o: list) { Hibernate.initialize(o.getOrderItems()); } transaction.commit(); session.close(); return list; } public void delete(Order order) { Session session = SessionFactoryUtil.getSession(); Transaction transaction = session.beginTransaction(); Order o = session.get(Order.class, order.getOrderId()); for(OrderItem oi:o.getOrderItems()) { session.delete(oi); } session.delete(o); transaction.commit(); session.close(); } }

Dao method: OrderItemDao

package com.smy.two.Dao; import org.hibernate.Session; import org.hibernate.Transaction; import com.xhy.two.entity.OrderItem; import com.zking.util.SessionFactoryUtil; public class OrderItemDao { public OrderItem get(OrderItem orderItem) { Session session = SessionFactoryUtil.getSession(); Transaction transaction = session.beginTransaction(); OrderItem oi = session.get(OrderItem.class, orderItem.getOrderItemId()); transaction.commit(); session.close(); return oi; } }


Configure hibernate.cfg.xml

<!-- One to many --> <mapping resource="com/smy/two/entity/Order.hbm.xml" /> <mapping resource="com/smy/two/entity/OrderItem.hbm.xml" />


Test: OrderDaoTest

package com.smy.two.Dao; import java.util.List; import org.junit.Test; import com.smy.two.entity.Order; public class OrderDaoTest { private OrderDao orderDao = new OrderDao(); /** * org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.zking.two.entity.Order.orderItems, could not initialize proxy - no Session * 1.Normal query * 2.Lazy load exception error * 3.performance tuning */ @Test public void testGet() { Order order = new Order(); order.setOrderId(7); // order.setInitOrderItems(1); Order o = this.orderDao.get(order); System.out.println(o.getOrderNo()); // System.out.println(o.getOrderItems()); } @Test public void testList() { List<Order> list = this.orderDao.list(); for (Order o : list) { System.out.println(o.getOrderNo()); // System.out.println(o.getOrderItems().size()); } } @Test public void testDelete() { Order order = new Order(); order.setOrderId(6); this.orderDao.delete(order); } }

  When you run testGet(), you will get the order normally. When you need to get the order item together with the annotation, an error will be reported

Reason for error reporting: lazy loading is used by default. The session is closed when the above output is executed, so an error will be reported. This error requires forced loading, that is, forced loading of order item data associated with the order

Solution: uncomment and set to   one  , Forced loading, all the order item data associated with the order will be presented:

order.setInitOrderItems(1);

Performance tuning (explains why hibernate uses lazy loading by default)

Actual scenario:

        1. Only use the data of the order table - you want to load it lazily

        2. You need to use both the order and the individual table data at the same time - you don't want to load them lazily

2, One to many Subassociation


Analysis (simulation environment: tree menu):

One to many self association means that you can have multiple child nodes, but the parent node has only one and is in your own table

Entity class: TreeNode  
The first is the parent node (there is only one parent node)

The second is a child node (there may be multiple child nodes, so it is wrapped in a collection)

The third is lazy loading (0 is lazy loading and 1 is forced loading)

private TreeNode parent; private Set<TreeNode> children = new HashSet<TreeNode>(); private Integer initChildren = 0;
package com.zking.two.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; 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 + "]"; } }

Dao: TreeNodeDao

package com.zking.two.dao; import org.hibernate.Hibernate; import org.hibernate.Session; import org.hibernate.Transaction; import com.zking.two.entity.TreeNode; import com.zking.util.SessionFactoryUtil; public class TreeNodeDao { public TreeNode load(TreeNode treeNode) { Session session = SessionFactoryUtil.getSession(); 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; } }

Map 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.smy.two.entity.TreeNode" table="t_hibernate_sys_tree_node"> <id name="nodeId" type="java.lang.Integer" column="tree_node_id"> <generator /> </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" column="parent_node_id"/> <set name="children" cascade="save-update" inverse="true"> <key column="parent_node_id"></key> <one-to-many/> </set> </class> </hibernate-mapping>

Configuration: hibernate.cfg.xml

<!-- One to many autocorrelation --> <mapping resource="com/smy/two/entity/TreeNode.hbm.xml" />

Test:  

public void testLoad() { TreeNode treeNode = new TreeNode(); treeNode.setNodeId(6); treeNode.setInitChildren(1); TreeNode t = this.treeNodeDao.load(treeNode); System.out.println(t);//Current node System.out.println(t.getParent());//Parent node System.out.println(t.getChildren());//Child of parent node }

3, Many to many


It is equivalent to two one to many. There are foreign keys of two tables in the middle table. Both tables and the middle table are one to many

  Table: intermediate table. The data of the intermediate table is maintained by the framework
        name: association attribute
        Reverse: (true) reverse, that is, the data of the intermediate table is maintained by another table.

        (false) that is, the data of the intermediate table is maintained by itself
                        When both tables are false, two data will be generated
                        When both tables are true, the data will not be generated
                        If one table is false and the other is true, the data can be maintained normally

        Key: the primary key of the current table is the foreign key of the intermediate table

        Many to many: the primary key of the current table finds the foreign key of another table in the intermediate table

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.smy.two.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 /> </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"></many-to-many> </set> </class> </hibernate-mapping>


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.smy.two.entity.TreeNode" table="t_hibernate_sys_tree_node"> <id name="nodeId" type="java.lang.Integer" column="tree_node_id"> <generator /> </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" column="parent_node_id"/> <set name="children" cascade="save-update" inverse="true"> <key column="parent_node_id"></key> <one-to-many/> </set> </class> </hibernate-mapping>

8 November 2021, 07:49 | Views: 4563

Add new comment

For adding a comment, please log in
or create account

0 comments