I’m experiencing the ‘HibernateException: Found shared references to a collection’ error even though there is no apparent shared references to a collection (at least not one that I can identify). I have two entities: Schedule and ScheduleTimeslot. A schedule has a list of timeslots, but a given timeslot can only belong to one schedule.
Here are the entity definitions:
@Getter
@Setter
@Entity
@Table(name = "schedule")
public class Schedule extends BaseModel{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id", nullable = false)
private Long id;
private String scheduleName;
@NotNull
@Column(name = "schedule_type", nullable = false)
private ScheduleType scheduleType;
@OneToMany(mappedBy = "schedule", cascade = CascadeType.ALL, orphanRemoval = true)
private List<ScheduleTimeslot> timeslotList = new ArrayList<>();
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "school", referencedColumnName = "id", nullable = false)
@JsonIgnore
private School school;
public void addTimeslot(ScheduleTimeslot timeslot) {
if (!this.timeslotList.contains(timeslot)) {
this.timeslotList.add(timeslot);
timeslot.setSchedule(this);
}
}
public void removeTimeslot(ScheduleTimeslot timeslot) {
if (this.timeslotList.contains(timeslot)) {
this.timeslotList.remove(timeslot);
timeslot.setSchedule(null); // Break the bidirectional relationship
}
}
}
@Getter
@Setter
@Entity
@Table(name = "schedule_timeslot")
public class ScheduleTimeslot {
@Id
@GeneratedValue
@EqualsAndHashCode.Exclude
private Long id;
private LocalTime startTime;
private LocalTime endTime;
private TimeslotActivity timeslotActivity;
@JoinColumn(name = "schedule", referencedColumnName = "id")
@ManyToOne(optional = false)
private Schedule schedule;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "school", referencedColumnName = "id", nullable = false)
@JsonIgnore
private School school;
@Override
public String toString() {
return "[" + startTime + "-" + endTime + "]";
}
}
The error is being thrown when I try to edit a schedule. It’s a PUT request that executes this method:
//edit schedule details
@Override
public ScheduleDto editScheduleDetails(Long scheduleId, ScheduleDto editScheduleRequest){
UserAuth currentUser = userDetailsService.getCurrentUser();
School school = userDetailsService.getCurrentSchool();
Schedule schedule = scheduleRepository.findById(scheduleId);
if(schedule == null){
throw new NotFoundException("Schedule not found", "SCHEDULE_NOT_FOUND");
}
//edit schedule name
if(editScheduleRequest.getScheduleName() != null){
schedule.setScheduleName(editScheduleRequest.getScheduleName());
}
//edit schedule timeslots
if(editScheduleRequest.getTimeSlots() != null){
List<ScheduleTimeslot> incomingSlots = editScheduleRequest.getTimeSlots().stream().map(timeslot -> convertDtoToEntity(timeslot)).collect(Collectors.toList());
incomingSlots = validateTimeslots(incomingSlots);
//schedule.getTimeslotList().clear();
List<ScheduleTimeslot> oldTimeslotList = scheduleTimeslotRepository.findBySchedule(schedule);
for (ScheduleTimeslot slot : oldTimeslotList ) {
schedule.removeTimeslot(slot);
}
scheduleTimeslotRepository.deleteMultiple(oldTimeslotList);
schedule.setTimeslotList(new ArrayList<>());
for (ScheduleTimeslot requestSlot : incomingSlots) {
requestSlot.setSchool(school);
schedule.addTimeslot(requestSlot);
}
}
schedule.setUpdatedOn(LocalDateTime.now());
//scheduleRepository.save(schedule); TODO
return editScheduleRequest;
}