问题
After days of torture to resolve this issue and reading everything I could find on SO I decided to ask. I'm having trouble understanding what I read here on Hibernate site, so I'll explain my situation.
I have object student
that contains object program
:
@ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE}, fetch=FetchType.EAGER)
@JoinColumn(name = "PROGRAM_FK", nullable = false)
private Program program;
In my service method I want o change/update only program for a student:
public void edit(Student student) {
Session session = sessionFactory.getCurrentSession();
// Retrieve existing student via id
Student existingStudent = (Student) session.get(Student.class, student.getStudentId());
// Assign updated program to this student
existingStudent.setProgram(student.getProgram()); <-- This is not working as I would want it! -->
session.merge(existingStudent);
}
I want to change the program for the student, but not the program itself. How can I achieve this? And can someone please tell me, in this particular situation, who is parent and who is child? Should I use CascadeType.MERGE at all? Should I use merge() method or something else? I can't deduce this from reading documentation, if someone would be so kind to explain it on this particular case, so I can finally understand it... Thank you.
Program object:
@OneToMany(mappedBy="program")
private Set<Student> students;
I'm calling my edit method from controller:
@RequestMapping(value="/edit", method = RequestMethod.POST, params="edit")
public String postEditStudent(
@Validated({Student.StudentEditChecks.class}) @ModelAttribute("studentAttribute") Student student,
BindingResult result,
Model model) {
logger.debug("Received request to edit student");
if (result.hasErrors()) {
model.addAttribute("programList", programService.getAll());
return "editStudent";
}
else {
studentService.edit(student);
return "redirect:/essays/main/student/list";
}
}
回答1:
The main problem is that you use inputs that contain too much information for what you want to do. And that makes everything confusing.
All you want to do is setting an existing program on an existing student. The only inputs you need for this task are the student ID and the program ID. And if you had only those inputs, the solution would become obvious:
@Transactional
public void setProgramOnStudent(Long studentId, Long programId) {
Student student = (Student) session.get(Student.class, studentId);
Program program = (Program) session.load(Program.class, programId);
student.setProgram(program);
}
Note that I used load()
and not get()
to load the program, because you don't ven need th state of the program, only a reference to the existing program. It would also work with get()
, but it would execute an additional, useless seelct query to load the state of the program.
来源:https://stackoverflow.com/questions/21550585/properly-modify-object-with-manytoone-relationship-in-spring-mvc-hibernate-ap