我有以下问题:
SUPPRESS
还有:
Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Error while committing the transaction
我知道问题出在哪里了。
我尝试更新一个子实体,即与父实体的 ManyToOne 关系。 当我更新孩子时,刷新不好。如果我改变父母,它会保留孩子。这不好。 因此,我正在尝试获取“旧”父级,从其列表中删除子级,然后继续更新。 但是当我删除孩子时,它会触发@Preremove 注释。 我不想那样。
这是孩子:
Caused by: java.util.ConcurrentModificationException: null
服务(@Service,@Transactional):
@Entity
@Table(name = "job", schema = "public")
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class Job implements Serializable {
...
...
@ManyToOne(cascade = CascadeType.REFRESH,fetch = FetchType.LAZY)
@OnDelete(action = OnDeleteAction.CASCADE)
@JsonIgnoreProperties(value = "jobs", allowSetters = true)
private Project project;
..
...
...
public Project getProject() {
return project;
}
public Job project(Project project) {
this.project = project;
return this;
}
public void setProject(Project project) {
this.project = project;
}
...
...
...
@PreRemove
public void removeAppUsers() {
if(this.appUsers.size()>0)
for (AppUser ap : this.appUsers) {
ap.removeJob(this);
}
if(this.performances.size()>0)
for (Performance p : this.performances) {
p.setJob(null);
}
}
你有什么想法吗?
编辑 1:
删除作业:
public JobDTO save(JobDTO jobDTO) {
Optional<Project> projectToRemove;
Project p;
log.debug("Request to save Job : {}", jobDTO);
Job job = jobMapper.toEntity(jobDTO);
projectToRemove=projectRepository.findProjectByJob(jobDTO.getId());
jobRepository.save(job);
if(projectToRemove.isPresent()&&jobDTO.getProjectId()!=projectToRemove.get().getId()) {
projectToRemove.get().removeJob(job);
projectRepository.save(projectToRemove.get());
}
if (jobDTO.getProjectId() != null) {
p = projectRepository.findById(jobDTO.getProjectId()).get();
p.addJob(job);
projectRepository.save(p);
job.setProject(p);
jobRepository.save(job);
}
....
}
编辑 2:
项目:
public Project removeJob(Job job) {
this.jobs.remove(job);
job.setProject(null);
return this;
}
答案 0 :(得分:1)
如 JPA - @PreRemove method behaviour 中所述,@PreRemove 是由移除孤儿作业触发的。
您正确同步了 Projet-Job 双向关联的两端,也许您应该避免使用 @PreRemove
执行其他双向关联同步,而是在 add*
中进行和 remove*
方法,而不是其他地方。
您不需要那么频繁地调用 repository.save
。在事务方法中,对托管实体的更改会自动传播,因此您应该仅在非托管实体上使用它(此处,对于由 MapStruct 创建的 job
仅使用 1 次)。如果你真的需要冲洗,你可以使用repository.saveAndFlush
方法,但乍一看这里没有必要。
顺便说一下,您保留了 JHipster 生成的代码,该代码使用相同的 save
方法创建和更新实体,该方法合并了 DTO 中的所有内容。我建议使用单独的创建和更新方法,以避免在其他问题中出现不需要的更新。
您还可以利用 MapStruct 进行更新:
https://mapstruct.org/documentation/stable/reference/html/#updating-bean-instances
希望这会有所帮助!