Reputation: 459
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
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