[英]detached entity issue when updating entity spring jpa
我查看了一堆類似問題的答案,但沒有找到一個可以為我解決問題的答案。 我現在感覺完全迷失了。
我正在開發一個 Spring Boot Web 應用程序,使用 Spring Data JPA 進行持久性。 當我嘗試對現有實體進行更新時收到以下錯誤:
org.hibernate.PersistentObjectException:分離的實體傳遞給堅持:com.project.timefit.model.WeeklyRoutinePlan
我正在嘗試使用 crudRepository 編輯實體 WeeklyRoutinePlan(get、create 和 delete 方法工作正常)。
這是我服務中的方法
@Override
@Transactional
public void editRoutinePlan(WeeklyRoutinePlan routinePlan, String username) {
WeeklyRoutinePlan oldRoutinePlan = weeklyRoutinePlanRepository.findById(routinePlan.getId()).get();
oldRoutinePlan.setWeekDay(routinePlan.getWeekDay());
weeklyRoutinePlanRepository.save(oldRoutinePlan);
}
為了調試,我已經對其進行了簡化,通常我會進行用戶名驗證並映射其他字段。 我仍然得到這個簡化版本的錯誤。 如果我不改變工作日,我什至會得到它。
我的實體本身看起來像這樣
@Entity
@Data
@SuperBuilder
@NoArgsConstructor
public class WeeklyRoutinePlan{
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@ManyToOne
private Routine routine;
private LocalTime startTime;
private LocalTime endTime;
private Integer weekDay;
@ManyToOne
private Program program;
public void setRoutine(Routine routine) {
if(routine == this.routine){
return;
}
if(this.routine != null){
this.routine.getWeeklyRoutinePlans().remove(this);
}
if(!routine.getWeeklyRoutinePlans().contains(this)){
routine.getWeeklyRoutinePlans().add(this);
}
this.routine = routine;
}
public void setProgram(Program program) {
if(program == this.program){
return;
}
if(this.program != null){
this.program.getWeeklyRoutines().remove(this);
}
if(!program.getWeeklyRoutines().contains(this)){
program.getWeeklyRoutines().add(this);
}
this.program = program;
}
}
這里是相關實體(雖然我不確定這是否相關,因為我什至沒有更新關系)
常規
@Entity
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Routine {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@ManyToOne
private User user;
private String name;
private Integer numberOfCycles;
private Color color;
@ManyToMany(mappedBy = "routines")
private List<Exercise> exercises;
@OneToMany(mappedBy = "routine", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
private List<WeeklyRoutinePlan> weeklyRoutinePlans = new ArrayList<>();
@OneToMany(mappedBy = "routine", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
private List<FrequencyRoutinePlan> frequencyRoutinePlans = new ArrayList<>();
@OneToMany(mappedBy = "routine", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
private List<IndividualRoutinePlan> individualRoutinePlans = new ArrayList<>();
public void remove(){
exercises.forEach(exercise -> exercise.getRoutines().remove(this));
exercises = new ArrayList();
}
public void setExercises(List<Exercise> exercises){
exercises.forEach(e -> {
if(e.getRoutines().stream().noneMatch(r -> Objects.equals(r.getId(), this.getId())))
e.getRoutines().add(this);
});
this.exercises = exercises;
}
public void setWeeklyRoutinePlans(List<WeeklyRoutinePlan> weeklyRoutinePlans) {
if(weeklyRoutinePlans == this.weeklyRoutinePlans){
return;
}
this.weeklyRoutinePlans.forEach(r -> {if(!weeklyRoutinePlans.contains(r))r.setRoutine(null);});
weeklyRoutinePlans.forEach(r -> {if(weeklyRoutinePlans.contains(r))r.setRoutine(this);});
this.weeklyRoutinePlans = weeklyRoutinePlans;
}
public void setFrequencyRoutinePlans(List<FrequencyRoutinePlan> frequencyRoutinePlans) {
if(frequencyRoutinePlans == this.frequencyRoutinePlans){
return;
}
this.frequencyRoutinePlans.forEach(r -> {if(!frequencyRoutinePlans.contains(r))r.setRoutine(null);});
frequencyRoutinePlans.forEach(r -> {if(frequencyRoutinePlans.contains(r))r.setRoutine(this);});
this.frequencyRoutinePlans = frequencyRoutinePlans;
}
public void setIndividualRoutinePlans(List<IndividualRoutinePlan> individualRoutinePlans) {
if(individualRoutinePlans == this.individualRoutinePlans){
return;
}
this.individualRoutinePlans.forEach(r -> {if(!individualRoutinePlans.contains(r))r.setRoutine(null);});
individualRoutinePlans.forEach(r -> {if(individualRoutinePlans.contains(r))r.setRoutine(this);});
this.individualRoutinePlans = individualRoutinePlans;
}
@Override
public String toString() {
return "Routine{" +
"id=" + id +
", user=" + user.getUsername() +
", name='" + name + '\'' +
", numberOfCycles=" + numberOfCycles +
", color=" + color +
'}';
}
}
程序
@Entity
@Data
@AllArgsConstructor
@NoArgsConstructor
@SuperBuilder
public class Program {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
private ProgramSetting programSetting = ProgramSetting.WEEKLY;
private Integer frequency = 1;
@OneToMany(mappedBy = "program", cascade = CascadeType.ALL, orphanRemoval = true)
private List<WeeklyRoutinePlan> weeklyRoutines = new ArrayList<>();
@OneToMany(mappedBy = "program", cascade = CascadeType.ALL, orphanRemoval = true)
private List<FrequencyRoutinePlan> frequencyRoutines = new ArrayList<>();
@OneToMany(mappedBy = "program", cascade = CascadeType.ALL, orphanRemoval = true)
private List<IndividualRoutinePlan> individualRoutines = new ArrayList<>();
@ManyToOne
private User user;
public void setWeeklyRoutines(List<WeeklyRoutinePlan> weeklyRoutines) {
if(weeklyRoutines == this.weeklyRoutines){
return;
}
this.weeklyRoutines.forEach(r -> {if(!weeklyRoutines.contains(r))r.setProgram(null);});
weeklyRoutines.forEach(r -> {if(weeklyRoutines.contains(r))r.setProgram(this);});
this.weeklyRoutines = weeklyRoutines;
}
public void setFrequencyRoutines(List<FrequencyRoutinePlan> frequencyRoutines) {
if(frequencyRoutines == this.frequencyRoutines){
return;
}
this.frequencyRoutines.forEach(r -> {if(!frequencyRoutines.contains(r))r.setProgram(null);});
frequencyRoutines.forEach(r -> {if(frequencyRoutines.contains(r))r.setProgram(this);});
this.frequencyRoutines = frequencyRoutines;
}
public void setIndividualRoutines(List<IndividualRoutinePlan> individualRoutines) {
if(individualRoutines == this.individualRoutines){
return;
}
this.individualRoutines.forEach(r -> {if(!individualRoutines.contains(r))r.setProgram(null);});
individualRoutines.forEach(r -> {if(individualRoutines.contains(r))r.setProgram(this);});
this.individualRoutines = individualRoutines;
}
public void setUser(User user) {
this.user = user;
}
@Override
public String toString() {
return "Program{" +
"id=" + id +
", name='" + name + '\'' +
", programSetting=" + programSetting +
", frequency=" + frequency +
", user=" + user.getUsername() +
'}';
}
}
在這一點上我有點絕望,因為我的其他實體工作正常,我只是不明白我做錯了什么。 該方法是事務性的,因此當我進行保存時不應分離實體。
如果我沒有明確調用 save ,我會遇到同樣的問題,因為無論如何這是由框架完成的。
我已經嘗試將關系上的獲取設置為 LAZY,我也嘗試過 EAGER,我嘗試讓 Program 上的級聯僅 REMOVE,即使最佳實踐是全部但我讀到有些人對 PERSIST 有問題.
我已經確保我的設置器正確更新了關系,盡管正如我所說我已經簡化了更新,所以我什至沒有使用它們。
我不知所措
評論中的回答:
您將實例WeeklyRoutinePlan
(routinePlan) 傳遞給該方法。 我猜這是分離的,因為它是在其他地方加載的。 您能否嘗試將 id 直接作為 Long ( routinePlan.getId()
)傳遞。 或者嘗試合並routinePlan
並再次將合並的實體分配給routinePlan
。
-> 所以問題是我從 DTO 創建的實體有一個 ID,因此即使我沒有嘗試保存那個實體,它也算作一個分離的實體。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.