I have the following mappings in 2 of my beans
Parent Bean
@OneToMany(fetch = FetchType.LAZY, mappedBy = "application")
@Cascade({CascadeType.SAVE_UPDATE, CascadeType.DELETE})
@JsonIgnore
private Set<ApplicationBuildVO> applicationBuilds = new HashSet<ApplicationBuildVO>(0);
Child Bean
@ManyToOne(fetch = FetchType.LAZY)
@Cascade({CascadeType.SAVE_UPDATE})
@JoinColumn(name = "APPLICATION_ID", nullable = false)
@JsonIgnore
private ApplicationVO application;
In my service method - I perform a find on the Application bean Create a child application bean - which has a reference to the parent application
Then - when I try to update a value on the Parent bean in the same service method I get the following error
Caused by: org.hibernate.NonUniqueObjectException: A different object with the same identifier value was already associated with the session : [com.domain.dao.ApplicationVO#1]
at org.hibernate.engine.internal.StatefulPersistenceContext.checkUniqueness(StatefulPersistenceContext.java:617)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.performUpdate(DefaultSaveOrUpdateEventListener.java:301)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.entityIsDetached(DefaultSaveOrUpdateEventListener.java:244)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.performSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:109)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:90)
My Service code (stripped down) is as follows
public boolean performBuild(Integer applicationId) {
ApplicationVO applicationVO = applicationServices.findAnyApplicationId(applicationId);
ApplicationBuildVO androidApplicationBuildVO = new ApplicationBuildVO();
androidApplicationBuildVO.setIsAndroid(true);
androidApplicationBuildVO.setIsSuccess(appBuildSuccessful);
androidApplicationBuildVO.setApplication(applicationVO);
androidApplicationBuildVO.setSoftwareVersion(androidSoftwareVersionVO);
androidApplicationBuildVO.setS3BucketName(mobileAppsBucketName);
androidApplicationBuildVO.setS3ArtifactKey(androidArtifact);
Integer applicationBuildId = applicationBuildServices.saveApplicationBuild(androidApplicationBuildVO);
applicationVO.setIsCurrentlyBeingBuilt(false);
boolean updateApplicationResult = applicationServices.updateApplication(applicationVO);
}
Any ideas what I can do to resolve this issue?
I think your problem is caused by the fact your are saving androidApplicationBuildVO
the child first and after that you save the parent applicationVO
you could add the child to parent and save the parent like that:
boolean performBuild(Integer applicationId) {
ApplicationVO applicationVO = applicationServices.findAnyApplicationId(applicationId);
ApplicationBuildVO androidApplicationBuildVO = new ApplicationBuildVO();
androidApplicationBuildVO.setIsAndroid(true);
androidApplicationBuildVO.setIsSuccess(appBuildSuccessful);
androidApplicationBuildVO.setApplication(applicationVO);
androidApplicationBuildVO.setSoftwareVersion(androidSoftwareVersionVO);
androidApplicationBuildVO.setS3BucketName(mobileAppsBucketName);
androidApplicationBuildVO.setS3ArtifactKey(androidArtifact);
applicationVO.addBuild(androidApplicationBuildVO);
applicationVO.setIsCurrentlyBeingBuilt(false);
boolean updateApplicationResult = applicationServices.updateApplication(applicationVO);
}
And you should add this method if it does not exist in applicationVO
public void addBuild(ApplicationBuildVO buildVo) {
applicationBuilds.add(buildVo);
}
Beware of equals
and hashcode
implementations in ApplicationBuildVO not to be based on the id to not have surpises when adding not saved elemnts applicationBuilds
Set.