Muhammad Danish Khan
Muhammad Danish Khan

Reputation: 459

Exception: A collection with cascade="all-delete-orphan" was no longer referenced by the owning entity instance

I know it may be duplicated. But I'm stuck.

When I try to update the below entity. I get the below exception

A collection with cascade="all-delete-orphan" was no longer referenced by the owning entity instance: com.sip.nglis.partneruser.entities.UserEntity.userPostNominals;

Below is the information regarding Entities and my logic

@Entity
@Table(name = "user", schema = "user_management")
public class UserEntity extends BaseEntity implements Serializable {
    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "user_id")
    private Integer userId;

    @Column(name = "display_code")
    private String displayCode;

    @ManyToOne(fetch = FetchType.LAZY, cascade = {CascadeType.ALL})
    @JoinColumn(name = "reporting_to", referencedColumnName = "user_id")
    private UserEntity reportingTo;

    @OneToMany(mappedBy = "user", cascade = {CascadeType.ALL}, orphanRemoval = true)
    private Set<UserRoleEntity> userRoles;

    @OneToMany(mappedBy = "user", cascade = {CascadeType.ALL}, orphanRemoval = true)
    private Set<UserPostNominalEntity> userPostNominals;

    getters... setters...
}

UserService:

@Transactional
public void updateUser(UserWithDependenciesDto user){
      modelMapper.addConverter(CommonUtil.BOOLEAN_SHORT_CONVERTER);
    UserEntity updatedUser = modelMapper.map(user.getUser(), UserEntity.class);

    UserEntity userEntity = userDao.findOne(user.getUser().getUserId());

    // Skipping the fields which will be updated accordingly
    modelMapper.typeMap(UserEntity.class, UserEntity.class).addMappings(mapping -> {
        mapping.skip(UserEntity::setUserPostNominals);
        mapping.skip(UserEntity::setUserRoles);
    });

    // replace the entity with updated data
    modelMapper.map(updatedUser, userEntity);

    //Remove Post Nominal
    userEntity.getUserPostNominals().stream().filter(postNominal -> !userDto.getPostNominal().contains(postNominal.getUserPostNominalPK().getPostNominalId())).collect(Collectors.toSet()).forEach(userEntity.getUserPostNominals()::remove);

    // Add Post Nominal
    Set<UserPostNominalEntity> postNominalEntities = new HashSet<>();
    for (Integer postNominal : user.getUser().getPostNominal()) {
        if (!userEntity.getUserPostNominals().stream().anyMatch(postNominalEntity -> postNominalEntity.getUserPostNominalPK().getPostNominalId() == postNominal)) {
            UserPostNominalEntity userPostNominalEntity = new UserPostNominalEntity();
            userPostNominalEntity.setUser(userEntity);
            userPostNominalEntity.getUserPostNominalPK().setPostNominalId(postNominal);
            userPostNominalEntity.getUserPostNominalPK().setUserId(userEntity.getUserId());
            postNominalEntities.add(userPostNominalEntity);
        }
    }
    postNominalEntities.addAll(userEntity.getUserPostNominals());
    if(!postNominalEntities.isEmpty()){
        userEntity.getUserPostNominals().clear();
        userEntity.getUserPostNominals().addAll(postNominalEntities);
    }


    // Remove Roles
    List<Integer> roleIds = userDto.getRoles().stream().map(userRole -> userRole.getRoleUId()).collect(Collectors.toList());
    userEntity.getUserRoles().stream().filter(userRole -> !roleIds.contains(userRole.getRole().getRoleUId())).collect(Collectors.toSet()).forEach(userEntity.getUserRoles()::remove);
    //Add Roles
    Set<UserRoleEntity> userRoles = new HashSet<>();
    for (RoleDto role : user.getUser().getRoles()) {
        if (!userEntity.getUserRoles().stream().anyMatch(userRoleEntity -> userRoleEntity.getRole().getRoleUId() == role.getRoleUId())) {
            UserRoleEntity userRoleEntity = new UserRoleEntity();
            modelMapper.getConfiguration().setSkipNullEnabled(true);
            RoleEntity roleEntity = modelMapper.map(role, RoleEntity.class);
            userRoleEntity.setRole(roleEntity);
            userRoleEntity.setUser(userEntity);
            userRoleEntity.setAddedBy(user.getCreatedBy());
            userRoleEntity.setAddedTimestamp(Timestamp.from(Instant.now()));

            userRoleEntity.getId().setRoleId(roleEntity.getRoleUId());
            userRoleEntity.getId().setUserId(userEntity.getUserId());

            userRoles.add(userRoleEntity);
        }

    }
    userRoles.addAll(userEntity.getUserRoles());
    if(!userRoles.isEmpty()){
        userEntity.getUserRoles().clear();
        userEntity.getUserRoles().addAll(userRoles);
    }

    userDao.update(userEntity);
}

UserRepository:

public UserEntity update(UserEntity user) {
    return entityManager.merge(user);
}

The above exception only occurs When I try to update the reportingTo in UserEntity, If I try to skip it during mapping and don't update the value of reportingTo then the above exception goes away.

If I do like this in the service updateUser method

modelMapper.typeMap(UserEntity.class, 
UserEntity.class).addMappings(mapping -> {
    mapping.skip(UserEntity::setUserPostNominals);
    mapping.skip(UserEntity::setReportingTo);
    mapping.skip(UserEntity::setUserRoles);
});

As the above code totally removes reportingTo From updating it against the user, then the above-mentioned exception goes away.

reportingTo is a detached object so the object has the only ID the remaining fields are empty.

Upvotes: 1

Views: 1556

Answers (1)

francisco neto
francisco neto

Reputation: 809

A CascadeType.ALL is used when one wants that the changes in parents propagate to its children not the other way round...

So, it is a common pattern using cascade = {CascadeType.ALL} in @OneToMany relationships but very unusual to use it on @ManyToOne relationships.

At a first glance I would guess that the CascadeType.ALL in the @ManyToOne reportingTo relationship should not be there in first place...

In that other question you may find usefull information about @ManyToOne and cascading: What is the meaning of the CascadeType.ALL for a @ManyToOne JPA association

Upvotes: 1

Related Questions