Как обновить зависимую сущность не потеряв ссылку на родительскую Spring Data Jpa Hibernate
Это мои энтити:
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import javax.persistence.*;
import java.util.List;
@EqualsAndHashCode(callSuper = true)
@Entity
@Table(name = "users")
@Data
@NoArgsConstructor
public class User extends BaseEntity {
@Column(name = "username")
private String username;
@Column(name = "first_name")
private String firstName;
@Column(name = "last_name")
private String lastName;
@Column(name = "password")
private String password;
@Enumerated(value = EnumType.STRING)
@Column(name = "status")
private UserStatus status;
@Enumerated(value = EnumType.STRING)
@Column(name = "role")
private Role role;
@Column(name = "refresh_token")
private String refreshToken;
@OneToMany(mappedBy = "user", fetch = FetchType.EAGER)
private List<Task> tasks;
}
============================
import lombok.Data;
import lombok.EqualsAndHashCode;
import javax.persistence.*;
@EqualsAndHashCode(callSuper = true)
@Entity
@Table(name = "tasks")
@Data
public class Task extends BaseEntity {
@Column(name = "title")
private String title;
@Column(name = "description")
private String description;
@Column(name = "position")
private Long position;
@Column(name = "status")
@Enumerated(EnumType.STRING)
private TaskStatus status;
@ManyToOne
@JoinColumn(name = "user_id")
private User user;
}
Когда я обновляю title в классе Task, ссылка на user становится null. Я пробоваа сделать cascade = CascadeType.ALL и {CascadeType.REFRESH, CascadeType.MERGE} в классе Task и User поочереди, но это не сработало. Что можно сделать чтобы избежать потери задания юзера?
Обновление происходит так:
tasksRepository.save(task);
Ответы (1 шт):
Автор решения: Anastasiya
→ Ссылка
Ошибка (глупая) была вот в чем: таска получалась в контроллере как DTO, и мапилась без юзера:
@RequestMapping(method = {RequestMethod.POST, RequestMethod.PATCH})
@PreAuthorize("hasRole('ADMIN')")
public TaskOutDto createUpdateTask(@RequestBody @Valid TaskInDto task) {
Task taskToSave = mapper.fromDto(task);
taskToSave = taskService.save(taskToSave);
return mapper.toDto(taskToSave);
}
Решение было следующим - проверить, есть ли таск, и если да то не ставить ему юзера как null:
@Override
@CacheEvict(allEntries = true)
public Task save(Task taskToSave) {
AtomicReference<Task> taskToReturn = new AtomicReference<>(taskToSave);
if (taskToSave.getId() != null) {
tasksRepository.findById(taskToSave.getId())
.ifPresent(task -> {
task.setTitle(taskToSave.getTitle());
task.setDescription(taskToSave.getDescription());
task.setPosition(taskToSave.getPosition());
task.setStatus(taskToSave.getStatus());
taskToReturn.set(task);
});
}
return tasksRepository.save(taskToReturn.get());
}