[hibernate-issues] [Hibernate-JIRA] Updated: (HHH-2801) wrong insert/delete order when updating record-set

Gail Badner (JIRA) noreply at atlassian.com
Tue Feb 12 00:02:33 EST 2008


     [ http://opensource.atlassian.com/projects/hibernate/browse/HHH-2801?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]

Gail Badner updated HHH-2801:
-----------------------------

    Attachment: manytomanywithassocclass.tar.gz
                manytomanywithassocclassbug.tar.gz

Section 7.2.3 of "Java Persistence with Hibernate" describes two approaches to modeling using an association entity class that provides a workaround for dealing with an association entity class having two many-to-one associations that form a unique key.

I am attaching two test cases. The test case that reproduces the case where an element is removed and a new one is added with the same unique key, but a different (or generated primary key) is attached as manytomanywithassocclassbug.tar.gz .

The other test case maps the association entity class as suggested in the first approach described in section 7.2.3 of "Java Persistence with Hibernate" under the heading "Mapping the join table to an intermediate entity". It is attached as manytomanywithassocclass.tar.gz . This test case does not run into the same problems. It works because the generated primary ID was removed and the unique constraint columns were changed to a composite key. By doing this, the object that was removed and the newly instantiated object will have the same composite ID, and Hibernate can figure out that persisted and replaced object are the same. If another generated key is required (e.g., a GUID), it can be mapped as a  generated property.

These test cases are written to work as hibernate-annotations unit tests. The can be untarred into test/org/hibernate/test/annotations and run as part of the test suite. By doing a diff between the two untarred directories, you can easily see how the test case with the bug was converted. 

> wrong insert/delete order when updating record-set
> --------------------------------------------------
>
>                 Key: HHH-2801
>                 URL: http://opensource.atlassian.com/projects/hibernate/browse/HHH-2801
>             Project: Hibernate3
>          Issue Type: Bug
>          Components: core
>    Affects Versions: 3.2.4.sp1
>         Environment: hibernate-3.2.4.sp1, hibernate-annotations-3.3.0.GA, hibernate-entitymanager-3.3.1.GA, Oracle 10g Express Edition
>            Reporter: Christoph Mayerhofer
>         Attachments: manytomanywithassocclass.tar.gz, manytomanywithassocclassbug.tar.gz, model.zip, test-pro.tar.gz
>
>
> Overview: I have a record with a OneToMany association. From this associated record-set a record is removed and added again, both records identified with the same key. When doing a merge, I get a Unique constraint violation, because Hibernate first tries to insert the new record. Hibernate should first delete the old record, and after this insert the new record, avoiding the unique constraint violation.
> Detailed description: I have the following entities: Patient, SocialInsurance, PatientSocialInsurance. A patient could have several social insurances assigned to it. A social insurance could be assigned several times to a patient, we have a m:n relation between Patient and SocialInsurance. The relation-table has the name PatientSocialInsurance, with a unique constraint over patient_id and social_insurance_id. Each POJO inherits from a Base-POJO, which holds the id and the insert- and update-timestamps and userstamps.
> Base ---> PatientEntity ---> Patient
> Base ---> SocialInsuranceEntity ---> SocialInsurance
> Base ---> PatientSocialInsuranceEntity ---> PatientSocialInsurance
> Note: All *Entity model objects are generated with Hibernate-Tools from the db-schema, assuming that there are no wrong annotations, no wrong fields or wrong getter-/setter-methods in these model-classes.
> (I have enclosed all model-classes within an zipped attachment.)
> Now I try to delete an existing social insurance from a patient and add the same social insurance to the patient again:
> 	public void deleteSocialInsurance(Patient p, PatientSocialInsurance s) {
> 		if (p == null || s == null) {
> 			throw new IllegalArgumentException();
> 		}
> 		s.setSocialInsurance(null);
> 		s.setPatient(null);
> 		p.getPatientSocialInsurances().remove(s);
> 	}
> 	public void addPatientSocialInsurance(Patient p, PatientSocialInsurance s)
> 		throws DuplicatePatientSocInsException {
> 		if (p == null || s == null) {
> 			throw new IllegalArgumentException();
> 		}
> 		s.setPatient(p);
> 		p.getPatientSocialInsurances().add(s);
> 	}
> After doing a merge on the patient object, I get the following error:
> DEBUG - persisting patient...
> DEBUG - transaction org.hibernate.ejb.TransactionImpl at 44ac6a started
> DEBUG - update timestamp and userstamp for base record set
> DEBUG - update timestamp and userstamp for base record set
> DEBUG - update timestamp and userstamp for base record set
> DEBUG - update timestamp and userstamp for base record set
> DEBUG - update timestamp and userstamp for base record set
> DEBUG - select rawtohex(sys_guid()) from dual
> DEBUG - insert timestamp and userstamp for base record set
> DEBUG - insert into dseas.PATIENT_SOCIAL_INSURANCE (TIME_CRE, TIME_UPD, USER_CRE, USER_UPD, CODE_MEMBERSHIP_NO, CODE_TYPE_DEFAULT, PATIENT_ID, SOC_INS_ID, ID) values (?, ?, ?, ?, ?, ?, ?, ?, ?)
> ERROR - ORA-00001: Unique Constraint (DSEAS.PATIENT_SOCIAL_INSURANCE_UK) verletzt
> ERROR - ORA-00001: Unique Constraint (DSEAS.PATIENT_SOCIAL_INSURANCE_UK) verletzt
> ERROR - Could not synchronize database state with session
> org.hibernate.exception.ConstraintViolationException: Could not execute JDBC batch update
>    at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:71)
>    at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:43)
>    at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:253)
>    at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:237)
>    at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:141)
>    at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:298)
>    at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:27)
>    at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1000)
>    at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:338)
>    at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:106)
>    at org.hibernate.ejb.TransactionImpl.commit(TransactionImpl.java:54)
>    at org.dseas.base.hibernate.EntityManagerFacade.commit(EntityManagerFacade.java:78)
>    at org.dseas.business.service.maindata.PatientEditorService.save(PatientEditorService.java:112)
>    at org.dseas.ui.rcp.editor.patient.PatientEditorPart.doSave(PatientEditorPart.java:1298)
>    at org.eclipse.ui.internal.SaveableHelper$1.run(SaveableHelper.java:143)
>    at org.eclipse.ui.internal.SaveableHelper$4.run(SaveableHelper.java:266)
>    at org.eclipse.jface.operation.ModalContext.runInCurrentThread(ModalContext.java:369)
>    at org.eclipse.jface.operation.ModalContext.run(ModalContext.java:313)
>    at org.eclipse.jface.window.ApplicationWindow$1.run(ApplicationWindow.java:758)
>    at org.eclipse.swt.custom.BusyIndicator.showWhile(BusyIndicator.java:67)
>    at org.eclipse.jface.window.ApplicationWindow.run(ApplicationWindow.java:755)
>    at org.eclipse.ui.internal.WorkbenchWindow.run(WorkbenchWindow.java:2451)
>    at org.eclipse.ui.internal.SaveableHelper.runProgressMonitorOperation(SaveableHelper.java:274)
>    at org.eclipse.ui.internal.SaveableHelper.runProgressMonitorOperation(SaveableHelper.java:253)
>    at org.eclipse.ui.internal.SaveableHelper.savePart(SaveableHelper.java:148)
>    at org.eclipse.ui.internal.EditorManager.savePart(EditorManager.java:1345)
>    at org.eclipse.ui.internal.WorkbenchPage.savePart(WorkbenchPage.java:3184)
>    at org.eclipse.ui.internal.WorkbenchPage.saveEditor(WorkbenchPage.java:3197)
>    at org.eclipse.ui.internal.SaveAction.run(SaveAction.java:73)
>    at org.eclipse.jface.action.Action.runWithEvent(Action.java:498)
>    at org.eclipse.jface.action.ActionContributionItem.handleWidgetSelection(ActionContributionItem.java:545)
>    at org.eclipse.jface.action.ActionContributionItem.access$2(ActionContributionItem.java:490)
>    at org.eclipse.jface.action.ActionContributionItem$6.handleEvent(ActionContributionItem.java:443)
>    at org.eclipse.swt.widgets.EventTable.sendEvent(EventTable.java:66)
>    at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:938)
>    at org.eclipse.swt.widgets.Display.runDeferredEvents(Display.java:3682)
>    at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:3293)
>    at org.eclipse.ui.internal.Workbench.runEventLoop(Workbench.java:2389)
>    at org.eclipse.ui.internal.Workbench.runUI(Workbench.java:2353)
>    at org.eclipse.ui.internal.Workbench.access$4(Workbench.java:2219)
>    at org.eclipse.ui.internal.Workbench$4.run(Workbench.java:466)
>    at org.eclipse.core.databinding.observable.Realm.runWithDefault(Realm.java:289)
>    at org.eclipse.ui.internal.Workbench.createAndRunWorkbench(Workbench.java:461)
>    at org.eclipse.ui.PlatformUI.createAndRunWorkbench(PlatformUI.java:149)
>    at org.dseas.ui.rcp.Application.start(Application.java:22)
>    at org.eclipse.equinox.internal.app.EclipseAppHandle.run(EclipseAppHandle.java:153)
>    at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.runApplication(EclipseAppLauncher.java:106)
>    at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.start(EclipseAppLauncher.java:76)
>    at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:363)
>    at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:176)
>    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
>    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
>    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
>    at java.lang.reflect.Method.invoke(Unknown Source)
>    at org.eclipse.equinox.launcher.Main.invokeFramework(Main.java:504)
>    at org.eclipse.equinox.launcher.Main.basicRun(Main.java:443)
>    at org.eclipse.equinox.launcher.Main.run(Main.java:1169)
>    at org.eclipse.equinox.launcher.Main.main(Main.java:1144)
> Caused by: java.sql.BatchUpdateException: ORA-00001: Unique Constraint (DSEAS.PATIENT_SOCIAL_INSURANCE_UK) verletzt
>    at oracle.jdbc.driver.DatabaseError.throwBatchUpdateException(DatabaseError.java:343)
>    at oracle.jdbc.driver.OraclePreparedStatement.executeBatch(OraclePreparedStatement.java:10657)
>    at org.hibernate.jdbc.BatchingBatcher.doExecuteBatch(BatchingBatcher.java:48)
>    at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:246)
>    ... 55 more
> ERROR - Error while commiting the transaction 

-- 
This message is automatically generated by JIRA.
-
If you think it was sent incorrectly contact one of the administrators: http://opensource.atlassian.com/projects/hibernate/secure/Administrators.jspa
-
For more information on JIRA, see: http://www.atlassian.com/software/jira

        



More information about the hibernate-issues mailing list