hibernate 一对多关联关系(详细分析)
在领域模型中, 类与类之间最普遍的关系就是关联关系.
- 以 Customer 和 Order 为例: 一个用户能发出多个订单, 而一个订单只能属于一个客户. 从 Order 到 Customer 的关联是多对一关联; 而从 Customer 到 Order 是一对多关联
- 单向关联
- 双向关联
- 域模型: 从 Order 到 Customer 的多对一单向关联需要在Order 类中定义一个 Customer 属性, 而在 Customer 类中无需定义存放 Order 对象的集合属性
- 关系数据模型:ORDERS 表中的 CUSTOMER_ID 参照 CUSTOMER 表的主键
- 显然无法直接用 property 映射 customer 属性
- Hibernate 使用 <many-to-one> 元素来映射多对一关联关系
package com.atguigu.hibernate.entities.n21; public class Order { private Integer orderId; private String orderName; private Customer customer; public Integer getOrderId() { return orderId; } public void setOrderId(Integer orderId) { this.orderId = orderId; } public String getOrderName() { return orderName; } public void setOrderName(String orderName) { this.orderName = orderName; } public Customer getCustomer() { return customer; } public void setCustomer(Customer customer) { this.customer = customer; } }Customer
package com.atguigu.hibernate.entities.n21; public class Customer { private Integer customerId; private String customerName; public Integer getCustomerId() { return customerId; } public void setCustomerId(Integer customerId) { this.customerId = customerId; } public String getCustomerName() { return customerName; } public void setCustomerName(String customerName) { this.customerName = customerName; } }Customer.hbm.xml
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <class name="com.atguigu.hibernate.entities.n21.Customer" table="CUSTOMERS"> <id name="customerId" type="java.lang.Integer"> <column name="CUSTOMER_ID" /> <generator class="native" /> </id> <property name="customerName" type="java.lang.String"> <column name="CUSTOMER_NAME" /> </property> </class> </hibernate-mapping>Order.hbm.xml
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="com.atguigu.hibernate.entities.n21"> <class name="Order" table="ORDERS"> <id name="orderId" type="java.lang.Integer"> <column name="ORDER_ID" /> <generator class="native" /> </id> <property name="orderName" type="java.lang.String"> <column name="ORDER_NAME" /> </property> <!-- 映射多对一的关联关系。 使用 many-to-one 来映射多对一的关联关系 name: 多这一端关联的一那一端的属性的名字 class: 一那一端的属性对应的类名 column: 一那一端在多的一端对应的数据表中的外键的名字 --> <many-to-one name="customer" class="Customer" column="CUSTOMER_ID"></many-to-one> </class> </hibernate-mapping>
测试增删改查
package com.atguigu.hibernate.entities.n21; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.sql.Blob; import java.sql.Connection; import java.sql.SQLException; import java.util.Date; import org.hibernate.Hibernate; import org.hibernate.LazyInitializationException; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; import org.hibernate.jdbc.Work; import org.hibernate.service.ServiceRegistry; import org.hibernate.service.ServiceRegistryBuilder; import org.junit.After; import org.junit.Before; import org.junit.Test; public class HibernateTest { private SessionFactory sessionFactory; private Session session; private Transaction transaction; @Before public void init(){ Configuration configuration = new Configuration().configure(); ServiceRegistry serviceRegistry = new ServiceRegistryBuilder().applySettings(configuration.getProperties()) .buildServiceRegistry(); sessionFactory = configuration.buildSessionFactory(serviceRegistry); session = sessionFactory.openSession(); transaction = session.beginTransaction(); } @After public void destroy(){ transaction.commit(); session.close(); sessionFactory.close(); } @Test public void testDelete(){ //在不设定级联关系的情况下, 且 1 这一端的对象有 n 的对象在引用, 不能直接删除 1 这一端的对象 Customer customer = (Customer) session.get(Customer.class, 1); session.delete(customer); } @Test public void testUpdate(){ Order order = (Order) session.get(Order.class, 1); order.getCustomer().setCustomerName("AAA"); } @Test public void testMany2OneGet(){ //1. 若查询多的一端的一个对象, 则默认情况下, 只查询了多的一端的对象. 而没有查询关联的 //1 的那一端的对象! Order order = (Order) session.get(Order.class, 1); System.out.println(order.getOrderName()); System.out.println(order.getCustomer().getClass().getName()); session.close(); //2. 在需要使用到关联的对象时, 才发送对应的 SQL 语句. Customer customer = order.getCustomer(); System.out.println(customer.getCustomerName()); //3. 在查询 Customer 对象时, 由多的一端导航到 1 的一端时, //若此时 session 已被关闭, 则默认情况下 //会发生 LazyInitializationException 异常 //4. 获取 Order 对象时, 默认情况下, 其关联的 Customer 对象是一个代理对象! } @Test public void testMany2OneSave(){ Customer customer = new Customer(); customer.setCustomerName("BB"); Order order1 = new Order(); order1.setOrderName("ORDER-3"); Order order2 = new Order(); order2.setOrderName("ORDER-4"); //设定关联关系 order1.setCustomer(customer); order2.setCustomer(customer); //执行 save 操作: 先插入 Customer, 再插入 Order, 3 条 INSERT //先插入 1 的一端, 再插入 n 的一端, 只有 INSERT 语句. // session.save(customer); // // session.save(order1); // session.save(order2); //先插入 Order, 再插入 Customer. 3 条 INSERT, 2 条 UPDATE //先插入 n 的一端, 再插入 1 的一端, 会多出 UPDATE 语句! //因为在插入多的一端时, 无法确定 1 的一端的外键值. 所以只能等 1 的一端插入后, 再额外发送 UPDATE 语句. //推荐先插入 1 的一端, 后插入 n 的一端 session.save(order1); session.save(order2); session.save(customer); } }
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。