单向N-1关联

单向N-1关系,比如多个人对应一个地址,只需从人实体端可以找到对应的地址实体,无须关系某个地址的全部住户。              单向N-1关联只需从N的一端可以访问1的一端。

域模型

从Order到Customer的多对一单向关联需要在Order类中定义一个Customer属性,而在Customer类中无需定义存放Order对象的集合属性。即一个顾客可以对应多个订单。

 

关系数据模型       

ORDERS 表中的CUSTOMER_ID 参照CUSTOMER 表的主键。

 

配置关系映射文件(Order.hbm.xml)

many-to-one指明了外键 ,会根据反射机制,找到要和ORDER建立多对一关系的类,该列默认的是可以为空的

<many-to-one name="customer" column="CUSTOMER_ID" class="mypacker.entity.Customer"></many-to-one>

 映射多对一的关联关系,使用many-to-one 来映射多对一的关联关系
  name:多这一端关联的一那一端的属性的名字                                                                                                                        class:一那一端的属性对应的类名
  column:一那一端在多的一端对应的数据表中的外键的名字
  部门的类型

 

配置持久化类:

public class Order {
    private Integer orderId;
    private String orderName;
    private Customer customer;    
    //单向多对一(如果那个类还有一个对此类的一对多,则这个就是双向的多对一)
}

 

save()方法

public void testMany2OneSave(){
    Customer customer = new Customer();
    customer.setCustomerName("AA");    在Customer表中创建一个CustomerName=AA的数据,ID自动生成
    Order order1 = new Order();
    order1.setOrderName("Order-1");//在Order表中建立Order-1、Order-2两条数据,ID也是自动生成,外键Customer_ID等于上面的AA那条数据的ID
    Order order2 = new Order();
    order2.setOrderName("Order-2");
    //设定关联关系
    //为两条Order对象添加一个Customer对象信息
    order1.setCustomer(customer);
    order2.setCustomer(customer);
    //执行save操作:推荐先插入1的一端,再插入n的一端
    //如果先插入Order,再插入Customer,会产生3条INSERT,2条UPDATE
    //因为在插入多的一端时,无法确定1的一端的外键值,所以只能等1的一端插入后,再额外发送UPDATE语句
    session.save(customer);
    session.save(order1);
    session.save(order2);
    transaction.commit();
}
Hibernate: 
    insert 
    into
        CUSTOMERS
        (CUSTOMER_NAME) 
    values
        ('AA')    ##CUSTOMER_ID为1##
Hibernate: 
    insert 
    into
        ORDERS
        (ORDER_NAME, CUSTOMER_ID) 
    values
        (Order-1, 1)
Hibernate: 
    insert 
    into
        ORDERS
        (ORDER_NAME, CUSTOMER_ID) 
    values
        (Order-2, 1)

 

get()方法

public void testMany2OneGet(){
    //1.若查询多的一端的对象,则默认情况下,只查询了多的一端的对象,而没有查询关联的一的一端的对象
    //获取Order对象时,默认情况下,其关联的Customer对象是一个代理对象
    Order order = (Order) session.get(Order.class,5);
    System.out.println(order.getOrderName());
    //session.close();
    //2.当在需要使用到关联对象的属性时,才发送对应的SQL查询语句
    Customer customer = new Customer();
    System.out.println(customer.toString());
    //3.在查询Customer对象时,由多的一端导航一的一端时,若此时session已被关闭,则会发生懒加载异常
}

 

控制台打印出SQL语句:

Hibernate: 
    select
        order0_.ORDER_ID as ORDER1_1_0_,
        order0_.ORDER_NAME as ORDER2_1_0_,
        order0_.CUSTOMER_ID as CUSTOMER3_1_0_ 
    from
        ORDERS order0_ 
    where
        order0_.ORDER_ID=?

 

update()方法

public void testMany2OneUpdate(){
    Order order = (Order) session.get(Order.class,5);
    order.getCustomer().setCustomerName("AAA");
    //通过orderId=5的那条记录获取对应的customer,而数据库中的那条customer的id=3,所以,costumer表中id=3的那条记录的name变更为AAA
    session.update(order);
    transaction.commit();
}

 

控制台打印出SQL语句:

Hibernate: 
    select
        order0_.ORDER_ID as ORDER1_1_0_,
        order0_.ORDER_NAME as ORDER2_1_0_,
        order0_.CUSTOMER_ID as CUSTOMER3_1_0_ 
    from
        ORDERS order0_ 
    where
        order0_.ORDER_ID=5
Hibernate: 
    select
        customer0_.CUSTOMER_ID as CUSTOMER1_0_0_,
        customer0_.CUSTOMER_NAME as CUSTOMER2_0_0_ 
    from
        CUSTOMERS customer0_ 
    where
        customer0_.CUSTOMER_ID=?
Hibernate: 
    update
        CUSTOMERS 
    set
        CUSTOMER_NAME=? 
    where
        CUSTOMER_ID=?

 

delete()方法

public void testMany2OneDelete(){
    Customer customer = (Customer) session.get(Customer.class,3);
    //在不设定关联关系的情况下,且1这一端的对象有n的对象在引用,则不能直接删除1这一端的对象
    //也就是说在CUSTOMER表的主键数据在ORDER表中有与之对应的外键数据,如果删掉了CUSTOMER的主键=1的记录,那ORDER表中的外键=1的记录就没法与主表对应了,所以会出错,得先删掉ORDER表中的外键=1的记录,才能删掉CUSTOMER的主键=1的记录
    //org.hibernate.exception.ConstraintViolationException: Could not execute JDBC batch update
    session.delete(customer);
    transaction.commit();
}

 

双向1-N关联

对于1-N关联,Hibernate推荐使用双向关联,而且不要让1的一端控制关联关系,而使用N的一端控制关联关系。                      双向的N-1关联与1-N关联是完全相同的两种情况。两端都需要增加对关联属性的访问,N的一端增加引用到关联实体的属性,1的一端增加集合属性,集合元素为关联实体。  

域模型 

从Order到Customer的多对一双向关联需要在Order类中定义一个Customer属性,而在Customer类中需定义存放Order对象的集合属性。

关系数据模型

ORDERS表中的CUSTOMER_ID参照CUSTOMER表的主键。     

配置关系映射文件

<set name="orders" inverse="true" cascade="delete" order-by="ORDER_NAME DESC">
    <key column="CUSTOMER_ID"></key>    <!-- key指明了ORDER表中的外键 -->
    <one-to-many class="mypacker.entity.Order"></one-to-many><!-- one-to-many指明了和哪个类进行一对多的映射   -->
</set>

name:多这一端关联的一那一端的属性的名字
column:一那一端在多的一端对应的数据表中的外键的名字
class:一那一端的属性对应的类名

 

Hibernate_set的3个属性

① <set>元素的inverse属性

在Hibernate中通过对inverse属性的设置来决定是由双向关联的哪一方来维护表和表之间的关系,inverse=false的为主动方,inverse=true的为被动方,由主动方负责维护关联关系。在没有设置inverse=true的情况下,父子两边都维护父子关系。    

② <set>、<many-to-one>、<one-to-many>都有一个cascade属性,它用于设定级联操作,开发时不建议设定该属性。常用的取值包括:

save-update:当通过Session的save()、update()、saveOrUpdate()方法来保存或更新当前对象时,级联保存所有关联的新建的临时对象,并且级联更新所有关联的游离对象。

delete:当通过Session的delete()方法删除当前对象时,会级联删除所有关联的对象。

delete-orphan:删除所有和当前对象接触关联关系的对象。      

③ <set>元素的order-by属性,如果设置了该属性,当Hibernate通过selete语句到数据库中检索集合对象时,利用order by子句进行排序。order-by属性中还可以加入SQL函数。order-by 中使用的是表的字段名,而不是持久化类的属性名。

 

配置持久化类

public class Customer {
    private Integer customerId;
    private String customerName;
    //需要把集合进行初始化防止空指针异常
    //声明集合类型时,需使用接口类型,因为Hibernate在获取集合类型时,返回的是Hibernate内置的集合类型,而不是JavaSE一个标准的集合实现
    private Set<Order> orders = new HashSet<Order>(); //双向一对多

 

save()方法

public void testOne2ManySave(){
    Customer customer = new Customer();
    customer.setCustomerName("GG"); //在Customer表中创建一个CustomerName=GG的数据,ID自动生成
    Order order1 = new Order();
    order1.setOrderName("Order-3");    //在Order表中建立Order-3、Order-4两条数据,ID也是自动生成,外键Customer_ID等于上面的GG那条数据的ID
    Order order2 = new Order();
    order2.setOrderName("Order-4");
    //设定关联关系
    order1.setCustomer(customer);
    order2.setCustomer(customer);
    //为当前Customer对象添加两条Order信息
    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);
    transaction.commit();
}

 

get()方法

public void testOne2ManyGet(){
    //对 n 的一端的集合使用延迟加载,在使用集合中的元素时才初始化,所以也会可能抛出懒加载异常
    Customer customer = (Customer) session.get(Customer.class,1);
    //返回的多的一端的集合是Hibernate内置的集合类型,该类型具有延迟加载和存放代理对象功能
    System.out.println(customer.getCustomerName());
}

 

update()方法

public void testOne2ManyUpdate(){
    Customer customer = (Customer) session.get(Customer.class,4);
    customer.getOrders().iterator().next().setOrderName("GGG");    
    //把外键CUSTOMER_ID=4的那条数据对应的ORDER_NAME改为GGG,但只是第一条改了
    session.save(customer);
    transaction.commit();
}

 

delete()方法

public void testOne2ManyDelete(){
    Customer customer = (Customer) session.get(Customer.class,4);
    //与多对一一样,在不设定关联关系的情况下,且1这一端的对象有n的对象在引用,则不能直接删除1这一端的对象
    //也就是说在CUSTOMER表的主键数据在ORDER表中有与之对应的外键数据,
    //如果删掉了CUSTOMER的主键=1的记录,那ORDER表中的外键=1的记录就没法与主表对应了,
    //所以会出错,得先删掉ORDER表中的外键=1的记录,才能删掉CUSTOMER的主键=1的记录
    session.delete(customer);
}

 

HQL: Hibernate查询语言

HQL(Hibernate Query Language)是面向对象的查询语言,它和SQL查询语言有些相似,在Hibernate提供的各种检索方式中,HQL是使用最广的一种检索方式。

HQL查询包含以下步骤:

1、获取Hibernate Session对象。

2、编写HQL语句。

3、以HQL语句作为参数,调用Session的createQuery方法创建查询对象。

4、如果HQL语句包含参数,则调用Query的setXxx方法为参数赋值。

5、调用Query对象的list()或uniqueResult()方法返回查询结果列表。 

public class UserTest {  
    Session session;  
      
    //junit测试,先执行before,后内容,最后执行after,这样减少重复代码量  
    @Before  
    public void before(){  
        Configuration configuration = new Configuration().configure();  
        SessionFactory sessionFactory = configuration.buildSessionFactory(  
                new StandardServiceRegistryBuilder().applySettings(configuration.getProperties()).build());  
        session = sessionFactory.getCurrentSession();  //sessionFactory.openSession()  
        session.beginTransaction();  
    }  
      
    @After  
    public void after(){  
        session.getTransaction().commit();  
    }  
      
    @Test  
    public void testAddUser() {  
        User user = new User(1,"张三","abcd",new Date());  
        session.save(user);  
    }  
      
    @Test  
    public void testSelectUserById(){  
//      User user = (User) session.get(User.class, 1);  
        User user = (User) session.load(User.class, 1);  
        System.out.println(user);  
    }  
    @Test  
    public void testUpdate(){  
//      User user = new User(1,"李四1","123",new Date());  
//      session.update(user);  
          
        User user = (User) session.get(User.class, 1);  
        user.setUserName("王二");  
          
        session.update(user);  
    }  
      
    @Test  
    public void testDelete(){  
//      User user = new User(1,"李四1","123",new Date());  
//      session.delete(user);  
          
        User user = (User)session.get(User.class, 2);  
        session.delete(user);  
    }  
      
    @Test  
    public void testSelectAllUser(){  
        String hql = "FROM User ORDER BY id DESC ";  
          
        Query query = session.createQuery(hql);  
        List<User> userLists = query.list();  
        for(User user:userLists){  
            System.out.println(user);  
        }  
    }  
      
    @Test  
    public void testSelectUserName(){  
        String hql = "SELECT u.userName FROM User AS u";  
          
        Query query = session.createQuery(hql);  
        List<String> userLists = query.list();  
        for(String user:userLists){  
            System.out.println(user);  
        }  
    }  
    @Test  
    public void testSelectdUserByUsername(){  
        String hql = "FROM User WHERE userName = :name AND passWord = :psw";  
        Query query = session.createQuery(hql);  
        query.setParameter("name", "张三");  
        query.setParameter("psw", "abcd");  
        User user = (User) query.uniqueResult();  
        System.out.println(user);  
    }  
      
    @Test  
    public void testUpdateUsers(){  
        String hql = "UPDATE User SET userName=:name WHERE passWord=:psw";  
        Query query = session.createQuery(hql);  
        query.setParameter("name", "麻子");  
        query.setParameter("psw", "123");  
        int order = query.executeUpdate();  
        System.out.println("order :"+order);  
    }  
      
    @Test  
    public void testDeleteUserByUserName(){  
        String hql = "DELETE User WHERE userName = :name";  
        Query query = session.createQuery(hql);  
        query.setParameter("name", "张三");  
        query.executeUpdate();  
          
    }  
      
}

 

posted on 2018-05-06 13:46  FuYingju  阅读(62)  评论(0编辑  收藏  举报