I'm trying to persist a workout object that has a list of exercises which has a list of exerciseSets. The error i get is when hibernate tries to persist the exerciseSets to the database when i use CascadeType.ALL. When i use MERGE i don't get a error, but the ExerciseSet is not saved to the database. But the Workout and Exercise objects are.
What am i missing here? The only thing i can come up with is that i have to place the exercise object inside the exerciseSet object which kinda ends up in a loop of adding them to each other.
The objects are as follows:
@Entity
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Workout {
@Id
@GeneratedValue(strategy= GenerationType.AUTO)
Long workoutId;
@Column
int day;
@Column
String workoutName;
@OneToMany(cascade = CascadeType.ALL,
orphanRemoval = true)
@JoinColumn
List<Exercise> exercises;
@Column
String createDate;
}
@Entity
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class Exercise {
@Id
@GeneratedValue(strategy= GenerationType.AUTO)
private Long exerciseId;
@ManyToOne(fetch = FetchType.LAZY)
private Workout workout;
@OneToMany(mappedBy = "exercise",
cascade = CascadeType.ALL)
private List<ExerciseSet> exerciseSets;
@OneToOne(cascade = CascadeType.MERGE)
@JoinTable(name = "var_exercise",
joinColumns =
{ @JoinColumn(name = "exercise_id")},
inverseJoinColumns =
{ @JoinColumn(name = "variation_id" )})
private ExerciseVariations exerciseVariations;
}
@Entity
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class ExerciseSet {
@Id
@GeneratedValue(strategy= GenerationType.AUTO)
private Long setId;
@Column
private int setPosition;
@Column
private int reps;
@Column
private int weight;
@ManyToOne
@JoinColumn(name="exerciseId", nullable = false)
private Exercise exercise;
}
I get a WorkoutDto from the frontend and map it to a entity with a mapper as follows
@PostMapping("/save")
public void saveWorkout(@RequestBody WorkoutDto workoutDto) {
workoutService.saveWorkout(workoutMapper.toWorkout(workoutDto));
}
public Workout toWorkout(WorkoutDto workoutDto) {
Workout workout = modelMapper.map(workoutDto, Workout.class);
if (workoutDto.getWorkoutId() != null) {
workout.setWorkoutId(workout.getWorkoutId());
}
workout.setWorkoutName(workoutDto.getWorkoutName());
workout.setDay(workoutDto.getDay());
List<Exercise> exerciseList = new ArrayList<>();
for (ExerciseDto exerciseDto: workoutDto.getExercisesDto()) {
List<ExerciseSet> exerciseSets = new ArrayList<>();
for (ExerciseSetDto exerciseSetDto : exerciseDto.getExerciseSetDtoList()) {
ExerciseSet exerciseSet = new ExerciseSet();
exerciseSet.setSetPosition(exerciseSetDto.getSetPosition());
exerciseSet.setReps(exerciseSetDto.getReps());
exerciseSet.setWeight(exerciseSetDto.getWeight());
exerciseSets.add(exerciseSet);
}
Exercise exercise = exerciseMapper.toExercise(exerciseDto);
exercise.setExerciseSets(exerciseSets);
exerciseList.add(exercise);
}
workout.setExercises(exerciseList);
workout.setCreateDate(workoutDto.getCreateDate());
return workout;
}
CodePudding user response:
You don't set the Exercise
in the ExerciseSet
and this is the side that manages the relationship.
You code should look like this:
public Workout toWorkout(WorkoutDto workoutDto) {
Workout workout = modelMapper.map(workoutDto, Workout.class);
if (workoutDto.getWorkoutId() != null) {
workout.setWorkoutId(workout.getWorkoutId());
}
workout.setWorkoutName(workoutDto.getWorkoutName());
workout.setDay(workoutDto.getDay());
List<Exercise> exerciseList = new ArrayList<>();
for (ExerciseDto exerciseDto: workoutDto.getExercisesDto()) {
Exercise exercise = exerciseMapper.toExercise(exerciseDto);
List<ExerciseSet> exerciseSets = new ArrayList<>();
for (ExerciseSetDto exerciseSetDto : exerciseDto.getExerciseSetDtoList()) {
ExerciseSet exerciseSet = new ExerciseSet();
exerciseSet.setSetPosition(exerciseSetDto.getSetPosition());
exerciseSet.setReps(exerciseSetDto.getReps());
exerciseSet.setWeight(exerciseSetDto.getWeight());
exerciseSet.setExercise(excercise);
exerciseSets.add(exerciseSet);
}
exercise.setExerciseSets(exerciseSets);
exerciseList.add(exercise);
}
workout.setExercises(exerciseList);
workout.setCreateDate(workoutDto.getCreateDate());
return workout;
}
And then you can set the CascadeType
to ALL
.