標籤:一對多 -- 節點 nes key setting service 元素 hbm
雙向 1-n 與 雙向 n-1 是完全相同的兩種情形
雙向 1-n 需要在 1 的一端可以訪問 n 的一端, 反之依然.
領域模型:從 Order 到 Customer 的多對一雙向關聯需要在Order 類中定義一個 Customer 屬性, 而在 Customer 類中需定義存放 Order 對象的集合屬性
關係資料模型:ORDERS 表中的 CUSTOMER_ID 參照 CUSTOMER 表的主鍵
Customer.java
private Integer customerId; private String customerName; private Set<Order> orders = new HashSet<>();
1. 聲明集合類型時, 需使用介面類型, 因為 hibernate 在擷取
集合類型時, 返回的是 Hibernate 內建的集合類型, 而不是 JavaSE 一個標準的
集合實現.
2. 需要把集合進行初始化, 可以防止發生null 指標異常
Order.java
private Integer orderId;private String orderName; private Customer customer;
Customer.hbm.xml
<set name="orders" table="ORDERS" inverse="true" order-by="ORDER_NAME DESC"> <!-- 執行多的表中的外鍵列的名字 --> <key column="CUSTOMER_ID"></key> <!-- 指定映射類型 --> <one-to-many class="Order"/> </set>
<!-- 映射 一 對多的那個集合屬性 -->
<!-- set: 映射 set 類型的屬性, table: set 中的元素對應的記錄放在哪一個資料表中. 該值需要和多對一的多的那個表的名字一致 -->
<!-- inverse: 指定由哪一方來維護關聯關係. 通常設定為 true, 以指定由多的一端來維護關聯關係 -->
<!-- cascade 設定級聯操作. 開發時不建議設定該屬性. 建議使用手工的方式來處理 -->
<!-- order-by 在查詢時對集合中的元素進行排序, order-by 中使用的是表的欄位名, 而不是持久化類的屬性名稱 -->
Order.java
<many-to-one name="customer" class="Customer" column="CUSTOMER_ID"></many-to-one>
HibernateTest.java
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 testCascade(){ Customer customer = (Customer) session.get(Customer.class, 3); customer.getOrders().clear(); } @Test public void testDelete(){ //在不設定級聯關係的情況下, 且 1 這一端的對象有 n 的對象在引用, 不能直接刪除 1 這一端的對象 Customer customer = (Customer) session.get(Customer.class, 1); session.delete(customer); } @Test public void testUpdat2(){ Customer customer = (Customer) session.get(Customer.class, 1); customer.getOrders().iterator().next().setOrderName("GGG"); } @Test public void testUpdate(){ Order order = (Order) session.get(Order.class, 1); order.getCustomer().setCustomerName("AAA"); } @Test public void testOne2ManyGet(){ //1. 對 n 的一端的集合使用消極式載入 Customer customer = (Customer) session.get(Customer.class, 7); System.out.println(customer.getCustomerName()); //2. 返回的多的一端的集合時 Hibernate 內建的集合類型. //該類型具有消極式載入和存放代理對象的功能. System.out.println(customer.getOrders().getClass()); //session.close(); //3. 可能會拋出 LazyInitializationException 異常 System.out.println(customer.getOrders().size()); //4. 再需要使用集合中元素的時候進行初始化. } @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("AA"); Order order1 = new Order(); order1.setOrderName("ORDER-1"); Order order2 = new Order(); order2.setOrderName("ORDER-2"); //設定關聯關係 order1.setCustomer(customer); order2.setCustomer(customer); customer.getOrders().add(order1); customer.getOrders().add(order2); //執行 save 操作: 先插入 Customer, 再插入 Order, 3 條 INSERT, 2 條 UPDATE //因為 1 的一端和 n 的一端都維護關聯關係. 所以會多出 UPDATE //可以在 1 的一端的 set 節點指定 inverse=true, 來使 1 的一端放棄維護關聯關係! //建議設定 set 的 inverse=true, 建議先插入 1 的一端, 後插入多的一端 //好處是不會多出 UPDATE 語句 session.save(customer); // session.save(order1);// session.save(order2); //先插入 Order, 再插入 Cusomer, 3 條 INSERT, 4 條 UPDATE// session.save(order1);// session.save(order2);// // session.save(customer); }}
Hibernate雙向一對多映射關係(2)