Hibernate双向一对多映射关系

双向 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. 需要把集合进行初始化, 可以防止发生空指针异常


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.hbm.xml

<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);
    }
}

 

posted on 2017-07-25 02:56  玉树霖风  阅读(282)  评论(0编辑  收藏  举报