Kamil
K.
Senior Software
Engineer
Temat: Hibernate, jak zapisać dwa powiązane obiekty
Witajcie,męczę się już ładny szmat czasu nad problemem zapisywania do bazy dwóch połączonych obiektów, tj. jeden posiada referencję @ManyToOne na drugi.
Oto mój applicationContext.xml
1. <?xml version="1.0" encoding="UTF-8"?>
2. <beans xmlns="http://www.springframework.org/schema/beans"
3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
4. xmlns:tx="http://www.springframework.org/schema/tx"
5. xsi:schemaLocation="http://www.springframework.org/schema/beans
6. http://www.springframework.org/schema/beans/spring-bea...
7. http://www.springframework.org/schema/tx
8. http://www.springframework.org/schema/tx/spring-tx.xsd">
9.
10.
11. <tx:annotation-driven transaction-manager="transactionManager" />
12.
13. <bean id="sessionFactory"
14. class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
15. <property name="dataSource" ref="dataSource" />
16.
17. <property name="annotatedClasses">
18. <list>
19. <value>pl.diagno.model.vo.Person</value>
20. <value>pl.diagno.model.vo.OrderGeneral</value>
21. <value>pl.diagno.model.vo.OrderDetails</value>
22. ... and others ...
23. </list>
24. </property>
25. <property name="hibernateProperties">
26. <props>
27. <prop key="show_sql">true</prop>
28. <prop key="dialect">org.hibernate.dialect.Oracle10gDialect</prop>
29. <prop key="hibernate.transaction.flush_before_completion">true</prop>
30. <prop key="hibernate.transaction.auto_close_session">true</prop>
31. <prop key="hibernate.use_sql_comments">true</prop>
32. <prop key="hibernate.connection.release_mode">auto</prop>
33.
34. </props>
35. </property>
36. </bean>
37.
38. <bean id="transactionManager"
39. class="org.springframework.orm.hibernate3.HibernateTransactionManager">
40. <property name="sessionFactory" ref="sessionFactory" />
41. </bean>
42.
43. <!-- DAO BEANS -->
44. <bean id="personDao" class="pl.diagno.dao.impl.PersonDAOImpl">
45. <property name="sessionFactory" ref="sessionFactory" />
46. </bean>
47.
48. <bean id="orderDetailsDao" class="pl.diagno.dao.impl.OrderDetailsDAOImpl">
49. <property name="sessionFactory" ref="sessionFactory" />
50. </bean>
51.
52. <bean id="orderGeneralDao" class="pl.diagno.dao.impl.OrderGeneralDAOImpl">
53. <property name="sessionFactory" ref="sessionFactory" />
54. </bean>
55.
56. <bean id="testDao" class="pl.diagno.dao.impl.TestDAOImpl">
57. <property name="sessionFactory" ref="sessionFactory" />
58. </bean>
59.
60. <!-- BO BEANS -->
61. <bean id="orderBo" class="pl.diagno.bo.impl.OrderBOImpl"> <!-- autowire="byName" -->
62. <property name="personDAO" ref="personDao" />
63. <property name="testDAO" ref="testDao" />
64. <property name="orderGeneralDAO" ref="orderGeneralDao" />
65. <property name="orderDetailsDAO" ref="orderDetailsDao" />
66. </bean>
67. </beans>
W OrderDetails jest odniesienie @ManyToOne do OrderGeneral.
Nie mogę zapisać OrderGeneral i powiązanego OrderDetails ponieważ Oracle rzuca wyjątek o braku parent key. Oto moja metoda:
1. @Transactional(readOnly = false, propagation = Propagation.REQUIRED)
2. public void saveOrder(long personId, long clinicId, long testsId[]){
3.
4. OrderGeneral orderGeneral = new OrderGeneral();
5. orderGeneral.setPerson(personDAO.load(personId));
6. orderGeneralDAO.save(orderGeneral); // save orderGeneral
7.
8. for(int i = 0; i<testsId.length; i++){
9. OrderDetails orderDetails = new OrderDetails();
10. orderDetails.setOrderGeneral(orderGeneral); //set orderGeneral
11. orderDetails.setTest(testDAO.load(testsId[i]));
12. orderDetailsDAO.save(orderDetails); //save orderDetails
13. }
14. }
i wyjątek
java.sql.BatchUpdateException: ORA-02291: integrity constraint (DIAGNO.ORDERDETAILS_ORDERGENERAL_FK) violated - parent key not found
Czyli powinno być tak że najpierw w bazie zapisuje się orederGeneral, później jest on ustawiany jako pole w orderDetails i zapisywany jest również orderDetails. A niestety wszystko się wali na pierwszym kroku.
Miałem taki sam problem wcześniej, to znaczy chciałem zapisać Person razem z jego polem City. I nie dało się to zrobić za jednym razem. Musiałem "obejść" ten problem tak że w jednej formatce dodaję nowe miasto a w drugim dopiero osobę z załadowanym już, istniejącym w bazie miastem.