Search code examples
javahibernatehibernate-mapping

NonUniqueObjectException: A different object with the same identifier value was already associated with the session


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?


Solution

  • 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.