• 精通Hibernate类与类关联关系:[一]建立多对一的单向关联关系


         在域模型中,类和类之间最普通的关系就是关联关系在UML语言中,关联是有方向的。以客户(Customer)和订单(Order)的关系为例,一个客户可以发出多个订单,而一个订单只能属于一个客户。

         从Order到Customer的关联是多对一关联,这意味着每个Order对象都会引用一个Customer对象,因此在Order类中应该定义一个Customer类型的属性,来引用所关联的Customer对象。

         从Customer到Order的关联是一对多的关联,这意味着每个Customer对象都会引用一组Order对象,因此在Customer类中应该定义一个集合类型的属性,来引用所有关联的Order对象。

          一、建立多对一的单向关联关系

          如上例中,我们只需在Order类中定义一个customer属性,而在Customer类中无需定义存放Order对象的集合属性。[Order 表中有Customer_ID,即Order知道Customer表的信息]

          Order.java

    1. package mypack; 
    2. publicclass Order  implements java.io.Serializable { 
    3.      privatelong id; 
    4.      private String orderNumber; 
    5.      private Customer customer;//定义一个Customer属性
    6.     public Order() { 
    7.     } 
    8.     public Order(Customer customer) { 
    9.         this.customer = customer; 
    10.     } 
    11.     public Order(String orderNumber, Customer customer) { 
    12.        this.orderNumber = orderNumber; 
    13.        this.customer = customer; 
    14.     } 
    15.     
    16.    //省略了id,orderNumber的构造方法
    17.     public Customer getCustomer() { 
    18.         returnthis.customer; 
    19.     } 
    20.      
    21.     publicvoid setCustomer(Customer customer) { 
    22.         this.customer = customer; 
    23.     } 
    24. }

          Customer类的所有属性都是和CUSTOMERS表中的字段一一对应,因此可以直接使用如下的映射代码:[Customer 中没有Order属性信息,即,不知道Order的存在]

    • <class name="mypack.Customer" table="CUSTOMERS"
    •    <id name="id" type="long" column="ID"
    •      <generator class="increment"/> 
    •    </id> 
    • <property name="name" type="string"
    •        <column name="NAME" length="15" /> 
    •    </property> 
    •       
    • </class>

         Order类的orderNumber属性和ORDERS表中ORDER_NUMBER字段对应,映射代码和上面类似,此处省去。我们关注的主要地方是,Order类中的customer属性,因为他是Customer类型的,是与ORDERS表的外键CUSTOMER_ID对应的,它的真实值是存在CUSTOMERS表中而ORDERS表存的只是对它的引用,因此customer的映射方法不能如上面一样。

    1. <many-to-one
    2. name="customer"
    3. column="CUSTOMER_ID"
    4. class="mypack.Customer"
    5. not-null="true"
    6. lazy="false"
    7. />

         使用方法のBussiness.java演示:

    1. package mypack;
    2. import org.hibernate.*;
    3. import org.hibernate.cfg.Configuration;
    4. import java.util.*;
    5. publicclass BusinessService{
    6. publicstatic SessionFactory sessionFactory;
    7. static{
    8. try{
    9. // 初始化
    10. Configuration config = new Configuration();
    11. config.configure();
    12. sessionFactory = config.buildSessionFactory();
    13. }catch(RuntimeException e){e.printStackTrace();throw e;}
    14. }
    15. /*根据参数指定customer的customer_id找出记录*/
    16. public List findOrdersByCustomer(Customer customer){
    17. Session session = sessionFactory.openSession();
    18. Transaction tx = null;
    19. try {
    20. tx = session.beginTransaction();
    21. List orders=session.createQuery("from Order as o where o.customer.id="+customer.getId())
    22. .list();
    23. //Hibernate执行:select * from ORDERS where CUSTOMER_ID=customer.getId();
    24. tx.commit();
    25. return orders;
    26. }catch (RuntimeException e) {
    27. if (tx != null) {
    28. tx.rollback();
    29. }
    30. throw e;
    31. } finally {
    32. session.close();
    33. }
    34. }
    35. /*根据OID找出指定customer_id的记录*/
    36. public Customer findCustomer(long customer_id){
    37. Session session = sessionFactory.openSession();
    38. Transaction tx = null;
    39. try {
    40. tx = session.beginTransaction();
    41. Customer customer=(Customer)session.get(Customer.class,new Long(customer_id));
    42. tx.commit();
    43. return customer;
    44. }catch (RuntimeException e) {
    45. if (tx != null) {
    46. tx.rollback();
    47. }
    48. throw e;
    49. } finally {
    50. session.close();
    51. }
    52. }
    53. /*
    54. public void saveCustomerAndOrderWithCascade(){
    55. Session session = sessionFactory.openSession();
    56. Transaction tx = null;
    57. try {
    58. tx = session.beginTransaction();
    59. Customer customer=new Customer("Jack");//创建一个Customer持久化对象
    60. //不保存customer对象,这样执行的话会出现异常
    61. Order order1=new Order("Jack_Order001",customer);
    62. Order order2=new Order("Jack_Order002",customer);//创建两个Order对象
    63. session.save(order1);
    64. session.save(order2);
    65. tx.commit();
    66. }catch (RuntimeException e) {
    67. if (tx != null) {
    68. tx.rollback();
    69. }
    70. e.printStackTrace();
    71. } finally {
    72. session.close();
    73. }
    74. }
    75. */publicvoid saveCustomerAndOrder(){
    76. Session session = sessionFactory.openSession();
    77. Transaction tx = null;
    78. try {
    79. tx = session.beginTransaction();
    80. Customer customer=new Customer("Tom");//创建一个Customer持久化对象
    81. session.save(customer);
    82. Order order1=new Order("Tom_Order001",customer);
    83. Order order2=new Order("Tom_Order002",customer);//创建两个Order对象
    84. session.save(order1);
    85. session.save(order2);
    86. // 对同一个customerHibernate执行两次插入ORDERS表
    87. tx.commit();
    88. }catch (RuntimeException e) {
    89. if (tx != null) {
    90. tx.rollback();
    91. }
    92. throw e;
    93. } finally {
    94. session.close();
    95. }
    96. }
    97. publicvoid printOrders(List orders){
    98. for (Iterator it = orders.iterator(); it.hasNext();) {
    99. Order order=(Order)it.next();
    100. System.out.println("OrderNumber of "+order.getCustomer().getName()+ " :"+order.getOrderNumber());
    101. }
    102. }
    103. publicvoid test(){
    104. saveCustomerAndOrder();
    105. // saveCustomerAndOrderWithCascade();
    106. Customer customer=findCustomer(1);
    107. List orders=findOrdersByCustomer(customer);
    108. printOrders(orders);
    109. }
    110. publicstaticvoid main(String args[]){
    111. new BusinessService().test();
    112. sessionFactory.close();
    113. }
    114. }
    115. <span style="font-size:16px;color:#cc33cc;"><strong>
    116. </strong></span>

         上述代码中方法 saveCustomerAndOrderWithCascade()如果没有session.save(customer)这一句,

         执行时会抛出PropertyValueException异常,主要原因是:

         在调用session.save(order1)方法之前,order1和customer对象都是临时的,临时对象是由new创建的,都是没有持久化的对象。假设 session.save(order1)被成功执行,order1会被成功持久化,变成持久化对象,但是Hibernate不会自动持久化order1所关联的customer对象。

         在执行session.save(order1)时,插入ORDERS表记录的CUSTOMER_ID字段为null,这违反了数据库完整性约束,即ORDERS表中不允许CUSTOMER_ID为null。   

          疑问假设ORDERS表中CUSTOMER_ID字段允许为null:

    1. <many-to-one
    2. name="customer"
    3. column="CUSTOMER_ID"
    4. class="mypack.Customer"
    5. not-null="false"
    6. lazy="false"
    7. />

          这样执行的话,能够成功的向ORDERS表中插入两条数据;但是当Hibernate自动清理(flush)缓存中所有持久化对象时,又会抛出新的异常

    • org.hibernate.TransientObjectException:object references an unsaved transient instance -save the transient instance before flushing :mypack.Customer

         所谓清理是指Hibernate按照持久化对象的属性变化来同步更新数据库。在清理的时候Hibernate会发现order1和order2都引用临时对象customer,而在ORDERS表中CUSTOMER_ID字段为null,这就意味着内存中持久化对象的属性和数据库中记录不一致。之所以会报错是因为order1中customer属性引用了一个临时对象Customer

          由此可见,Hibernate持久化一个对象时,默认情况下不会自动持久化所关联的其他对象。但是,我们我们希望当Hibernate持久化Order对象时自动持久化所关联的Customer对象,我们可以修改映射文件如下:

    • <many-to-one                   [Ordrer     多方中的映射文件]
    •         name="customer"
    • column="CUSTOMER_ID"
    •         class="mypack.Customer"
    •         cascade="save-update"
    •         not-null="false"  
    •         lazy="false"
    •      />

         当cascade属性为“save-update”,表明保存或更新对象时,会级联保存或更新与它所关联的对象。如上例中,执行saveCustomerAndOrderWithCascade()时,Hibernate会把order1与customer对象一起持久化,此时Hibernate会执行

    1. insert into CUSTOMERS(ID,NAME) values(2,"Jack"); 
    2. insert into ORDERS(ID,ORDER_NUMBER,CUSTOMER_ID) value (3,"Jack_Order001",2);
  • 相关阅读:
    PostgreSQL数据库((数据库类型介绍)
    postgreSQL(SQL语音操作数据库)
    postgreSQL数据库连接注意事项
    数据库
    Excel函数文本变E+显示怎么办
    无糖可乐不好喝
    通过 命令查看 linux桌面使用的是wayland 还是 X11
    Intel CPU的后缀含义
    互联网缩略语
    linux 下为windows交叉编译 ffmpeg库
  • 原文地址:https://www.cnblogs.com/wukong0214/p/2872788.html
Copyright © 2020-2023  润新知