Hibernate - 单向一对多关联关系映射

xiaoxiao2021-07-27  47

上篇博文描述了Hibernate - 单向多对一关联关系映射,本篇博文继续学习单向一对多关系映射。

这里Customer:Order= 1:N,外键保存在Order表中。

【1】修改Customer和Order

Customer修改如下:

public class Customer { private Integer customerId; private String customerName; private Set<Order> orders; //拥有属性orders public Set<Order> getOrders() { return orders; } public void setOrders(Set<Order> orders) { this.orders = orders; } 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; } @Override public String toString() { return "Customer [customerId=" + customerId + ", customerName=" + customerName + ", orders=" + orders + "]"; } }

Customer.hbm.xml修改如下:

<hibernate-mapping package="com.jane.model"> <class name="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" default="null" /> </property> <!-- name="orders"表示一的一端拥有多的那端的属性; key节点中属性column="customer_id"表示外键(数据库多的一端拥有的) --> <set name="orders" table="ORDERS"> <key column="customer_id"></key> <one-to-many class="Order"/> </set> </class> </hibernate-mapping>

<key>元素设定本持久化类在Set对应表中的外键列名。如上值Customer类在ORDERS表中的外键列名–customer_id。

Order修改如下:

public class Order { private Integer orderId; private String orderName; 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; } @Override public String toString() { return "Order [orderId=" + orderId + ", orderName=" + orderName+"]"; } }

Order.hbm.xml如下:

<hibernate-mapping package="com.jane.model"> <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" default="null" /> </property> </class> </hibernate-mapping>

生成的数据库表结构如下所示:

//Customers表 CREATE TABLE `customers` ( `CUSTOMER_ID` int(11) NOT NULL AUTO_INCREMENT, `CUSTOMER_NAME` varchar(255) DEFAULT NULL, PRIMARY KEY (`CUSTOMER_ID`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; //Orders表 CREATE TABLE `orders` ( `ORDER_ID` int(11) NOT NULL AUTO_INCREMENT, `ORDER_NAME` varchar(255) DEFAULT NULL, `customer_id` int(11) DEFAULT NULL, PRIMARY KEY (`ORDER_ID`), KEY `FK1nbewmmir6psft27yfvvmwpfg` (`customer_id`), CONSTRAINT `FK1nbewmmir6psft27yfvvmwpfg` FOREIGN KEY (`customer_id`) REFERENCES `customers` (`CUSTOMER_ID`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;

可以发现,无论是多对一还是一对多,外键都是多的一端数据表所持有。

单向多对一中,以多的一端为主,在多的一端xml中使用<many-to-one/>进行配置。 单向一对多中,以一的一端为主,在一的一端xml中使用<one-to-many/>进行配置。


【2】代码测试

① 单向一对多持久化

和单向多对一持久化不同的是,单向 1-n 关联关系执行保存时, 一定会多出 UPDATE 语句。因为 n 的一端在插入时不会同时插入外键列。

@Test public void testOneToManySave(){ Customer customer = new Customer(); customer.setCustomerName("AAA"); customer.setOrders(new HashSet<>()); Order order1 = new Order(); order1.setOrderName("O-JJ-1"); Order order2 = new Order(); order2.setOrderName("O-JJ-2"); System.out.println(customer); //建立关联关系 customer.getOrders().add(order1); customer.getOrders().add(order2); session.save(customer); session.save(order1); session.save(order2); }

测试结果如下:

Hibernate: insert into CUSTOMERS (CUSTOMER_NAME) values (?) Hibernate: insert into ORDERS (ORDER_NAME) values (?) Hibernate: insert into ORDERS (ORDER_NAME) values (?) Hibernate: update ORDERS set customer_id=? where ORDER_ID=? Hibernate: update ORDERS set customer_id=? where ORDER_ID=?

② 单向一对多获取对象

默认对关联的多的一方使用懒加载的加载策略,只有在使用的时候才会进行查询。

测试代码如下:

@Test public void testOneToManyGet(){ Customer customer = session.get(Customer.class, 1); System.out.println(customer); System.out.println(customer.getOrders().size()); }

测试结果如下:

Hibernate: select customer0_.CUSTOMER_ID as CUSTOMER1_0_0_, customer0_.CUSTOMER_NAME as CUSTOMER2_0_0_ from CUSTOMERS customer0_ where customer0_.CUSTOMER_ID=? Hibernate: select orders0_.customer_id as customer3_2_0_, orders0_.ORDER_ID as ORDER_ID1_2_0_, orders0_.ORDER_ID as ORDER_ID1_2_1_, orders0_.ORDER_NAME as ORDER_NA2_2_1_ from ORDERS orders0_ where orders0_.customer_id=? Customer [customerId=1, customerName=AAA, orders=[Order [orderId=1, orderName=O-JJ-1], Order [orderId=2, orderName=O-JJ-2]]] 2

③ 单向一对多更新操作

代码如下:

@Test public void testUpdate(){ Customer customer = session.get(Customer.class, 1); customer.getOrders().iterator().next().setOrderName("O-XXX-10"); }

测试结果如下:

Hibernate: select customer0_.CUSTOMER_ID as CUSTOMER1_0_0_, customer0_.CUSTOMER_NAME as CUSTOMER2_0_0_ from CUSTOMERS customer0_ where customer0_.CUSTOMER_ID=? Hibernate: select orders0_.customer_id as customer3_2_0_, orders0_.ORDER_ID as ORDER_ID1_2_0_, orders0_.ORDER_ID as ORDER_ID1_2_1_, orders0_.ORDER_NAME as ORDER_NA2_2_1_ from ORDERS orders0_ where orders0_.customer_id=? Hibernate: update ORDERS set ORDER_NAME=? where ORDER_ID=?

单独更新CustomerName如下:

@Test public void testUpdate(){ Customer customer = session.get(Customer.class, 1); customer.setCustomerName("CC"); System.out.println(customer.getCustomerName()); System.out.println(customer); }

测试结果如下:

Hibernate: select customer0_.CUSTOMER_ID as CUSTOMER1_0_0_, customer0_.CUSTOMER_NAME as CUSTOMER2_0_0_ from CUSTOMERS customer0_ where customer0_.CUSTOMER_ID=? CC Hibernate: select orders0_.customer_id as customer3_2_0_, orders0_.ORDER_ID as ORDER_ID1_2_0_, orders0_.ORDER_ID as ORDER_ID1_2_1_, orders0_.ORDER_NAME as ORDER_NA2_2_1_ from ORDERS orders0_ where orders0_.customer_id=? Customer [customerId=1, customerName=CC, orders=[Order [orderId=1, orderName=O-XXX-10], Order [orderId=2, orderName=O-JJ-2]]] Hibernate: update CUSTOMERS set CUSTOMER_NAME=? where CUSTOMER_ID=?

④ 单向一对多删除操作

默认情况下, 若删除 1 的一端, 则会先把关联的 n 的一端的外键置空, 然后进行删除。

测试代码如下:

@Test public void testOneToManyDel(){ Customer customer = session.get(Customer.class,1); session.delete(customer); }

测试结果如下:

//先查询 Hibernate: select customer0_.CUSTOMER_ID as CUSTOMER1_0_0_, customer0_.CUSTOMER_NAME as CUSTOMER2_0_0_ from CUSTOMERS customer0_ where customer0_.CUSTOMER_ID=? //更新Order表的外键Customer_ID 为null Hibernate: update ORDERS set customer_id=null where customer_id=? //删除Customers Hibernate: delete from CUSTOMERS where CUSTOMER_ID=?

综上可知,只有在持久化操作和删除操作时,单向一对多和单向多对一有所不同,在查找和更新时没有什么区别。

博文是基于XML进行讲解,那么注解版的如何使用呢?

参考博文:注解版的单向一对多