英文:
Exception: A collection with cascade="all-delete-orphan" was no longer referenced by the owning entity instance
问题
我知道可能会重复。但我被卡住了。
当我尝试更新下面的实体时。我得到了下面的异常
级联关系为 "all-delete-orphan" 的集合不再由拥有它的实体实例引用:com.sip.nglis.partneruser.entities.UserEntity.userPostNominals;
以下是有关实体和我的逻辑的信息
@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());
// 跳过相应将根据需要更新的字段
modelMapper.typeMap(UserEntity.class, UserEntity.class).addMappings(mapping -> {
mapping.skip(UserEntity::setUserPostNominals);
mapping.skip(UserEntity::setUserRoles);
});
// 用更新的数据替换实体
modelMapper.map(updatedUser, userEntity);
//删除后置名
userEntity.getUserPostNominals().stream().filter(postNominal -> !userDto.getPostNominal().contains(postNominal.getUserPostNominalPK().getPostNominalId())).collect(Collectors.toSet()).forEach(userEntity.getUserPostNominals()::remove);
// 添加后置名
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);
}
// 删除角色
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);
// 添加角色
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);
}
只有当我尝试更新UserEntity中的reportingTo时才会出现上述异常,如果在映射过程中跳过它并且不更新reportingTo的值,那么上述异常将消失。
如果我在服务的updateUser方法中这样做
modelMapper.typeMap(UserEntity.class,
UserEntity.class).addMappings(mapping -> {
mapping.skip(UserEntity::setUserPostNominals);
mapping.skip(UserEntity::setReportingTo);
mapping.skip(UserEntity::setUserRoles);
});
由于上述代码完全从更新用户中删除了reportingTo,因此上述异常消失了。
reportingTo是一个游离的对象,所以该对象只有ID,其余字段为空。
英文:
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.
答案1
得分: 1
A CascadeType.ALL
是在一个希望父级的更改传播到其子级而不是反过来时使用的...
因此,在@OneToMany
关系中使用cascade = {CascadeType.ALL}
是一种常见模式,但在@ManyToOne
关系中使用它非常不寻常。
乍一看,我会猜测@ManyToOne
中的reportingTo
关系中不应该有CascadeType.ALL
...
在另一个问题中,您可能会找到有关@ManyToOne
和级联的有用信息:
https://stackoverflow.com/questions/13027214/what-is-the-meaning-of-the-cascadetype-all-for-a-manytoone-jpa-association
英文:
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:
https://stackoverflow.com/questions/13027214/what-is-the-meaning-of-the-cascadetype-all-for-a-manytoone-jpa-association
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论