在Spring MVC + Hibernate应用程序中使用@ManyToOne关系正确修改对象

时间:2014-02-04 10:59:49

标签: hibernate spring-mvc updating many-to-one

经过几天的折磨来解决这个问题并阅读我能找到的所有内容,我决定问一下。我无法理解我在Hibernate site上读到的内容,所以我将解释我的情况。

我的对象student包含对象program

@ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE}, fetch=FetchType.EAGER)
@JoinColumn(name = "PROGRAM_FK", nullable = false)
private Program program;

在我的服务方法中,我想要仅为学生更改/更新程序:

 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);
 }

我想更改学生的程序,而不是程序本身。我怎样才能做到这一点?有人可以告诉我,在这种特殊情况下,谁是父母,谁是孩子?我应该使用CascadeType.MERGE吗?我应该使用merge()方法还是别的什么?我无法从阅读文档中推断出这一点,如果有人在这个特定情况下如此善意地解释它,那么我终于可以理解它了......谢谢。

程序对象:

@OneToMany(mappedBy="program")
private Set<Student> students;

我正在从控制器调用我的编辑方法:

    @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 个答案:

答案 0 :(得分:1)

主要问题是您使用的输入包含太多您想要做的信息。这让一切都让人困惑。

您要做的就是在现有学生上设置现有课程。您完成此任务所需的唯一输入是学生ID和计划ID。如果你只有那些输入,解决方案就会变得很明显:

@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);
}

请注意,我使用load()而非get()来加载程序,因为您不需要程序状态,只需要对现有程序的引用。它也适用于get(),但它会执行一个额外的,无用的seelct查询来加载程序的状态。