首页 > 解决方案 > Spring Data JPA 实现一对一关系

问题描述

我正在尝试实现 Spring Data JPA 一对一的关系,但我遇到了问题。我有一张员工表和一张员工详细信息表。在员工表中,我有一个列employeeId,在表EmployeeDetail 中我有列employeeId。因此,当我向表中添加员工外键时,员工详细信息会自动增加。

这是我的实体:

Employee:

@OneToOne(mappedBy = "employee", cascade = CascadeType.ALL)
private EmployeeDetail employeeDetail;

EmployeeDetail:

@OneToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "employeeId")
private Employee employee;

这是我EmployeeServiceImpl保存 Employee 的类和方法,也涉及到 EmployeeDetail。

public Employee saveEmployee(Employee employee) {

    EmployeeDetail employeeDetail = employee.getEmployeeDetail();
    employeeDetail.setEmployee(employee);
    employee = employeeRepository.save(employee);
    return employee;

}

在 EmployeeController 中,我有这两种方法来显示添加新员工和存储新员工的表单:

 @GetMapping("/showFormForAdd")
public String showFormForAdd(Model theModel) {

    // create model attribute to bind form data
    Employee theEmployee = new Employee();

    theModel.addAttribute("employee", theEmployee);

    return "addNewEmployeeForm";
}

@RequestMapping(value = "/addNewEmployee",method = RequestMethod.POST)
@ResponseBody
public Employee addNewEmployee(@ModelAttribute("employee") @RequestBody Employee employee) {
    Employee employeeResponse = employeeService.saveEmployee(employee);
    return employeeResponse;
}

这只是.jsp添加新员工表格的一部分:

 <form:form action="addNewEmployee" modelAttribute="employee" method="POST">

如您所见,我的模型属性在我的文件中以表格形式存在employee,但无法识别。.jsp

我可以通过什么方式修复它?那么当我创建新员工时,他的 ID 会自动存储在 EmployeeDetail 中吗?或者我如何将数据添加到我的相关表(EmployeeDetail)?

标签: javaspringjpa

解决方案


我不知道如何在保存员工时将员工 ID 直接存储在详细信息表中,但我会做的是

  1. 创建一个员工表单,通过员工控制器处理它,如下所示
    @GetMapping("/add")
    public String handleEmployeeForm(Model model) {
        model.addAttribute("employee", new Employee());
        return "formEmployee";
    }
    
    @PostMapping("/add")
    public String saveEmployee(@ModelAttribute("employee") Employee employee, Errors errors) {
        if(errors.hasErrors()) {
            return "formEmployee";
        }
        this.employeeService.save(employee);
        return "redirect:/employee/list";
    }

    @GetMapping("/list")
    public String listEmployees(Model model) {
        model.addAttribute("employees", this.employeeService.findAll());
        return "listEmployee";
    }

  1. 提供链接以添加员工的员工详细信息。我通过一个列出所有员工的页面来做到这一点(检查 EmployeeController 的 /employee/list API)。
<a th:href="@{/employeeDetails/add/{employeeId}(employeeId=${employee.id})}" 
    th:each="employee : ${employees}"><span th:text="${employee.employeeEmail}"></span></a>
  1. 创建一个员工详细信息表单,将员工 ID 存储为表单中的隐藏字段,通过员工详细信息控制器进行处理,如下所示。
<input type="hidden"
                    class="form-control" th:field="*{employee.id}"/>

员工详细信息控制器

    @GetMapping("/add/{employeeID}")
    public String handleEmployeeDetailsForm(@PathVariable long employeeID, Model model) {
        //create dummy employee 
        Employee employee = new Employee();
        //set id received from request to this employee object
        employee.setId(employeeID);
        
        EmployeeDetails employeeDetails = new EmployeeDetails();
        //set dummy employee object    
        employeeDetails.setEmployee(employee);
        model.addAttribute("employeeDetails", employeeDetails);
        return "formEmployeeDetails";
    }
    
    @PostMapping("/add")
    public String saveEmployeeDetails(@ModelAttribute EmployeeDetails employeeDetails, Errors errors) {
        if(errors.hasErrors()) {
            return "formEmployeeDetails";
        }

        //fetch actual employee object from database
        Employee employee = this.employeeService.findById(employeeDetails.getEmployee().getId());

        //set to employee details object
        employeeDetails.setEmployee(employee);

        //save employee details object
        this.employeeDetailsService.save(employeeDetails);
        return "redirect:/listEmployeeDetails";
    }

编辑 1
实现预期结果的另一种方法是修改员工和员工详细信息类,如下面的
员工

@OneToOne(mappedBy = "employee", cascade = CascadeType.ALL)
@PrimaryKeyJoinColumn
private EmployeeDetail employeeDetail;

@PrimaryKeyJoinColumn 注释告诉 Employee 的主键将用作 EmployeeDetails 中的外键。
EmployeeDetail
@OneToOne
@MapsId
private Employee employee;

您将在此处保存 EmployeeDetails 作为其拥有方(我们在 Employee 中定义了 mappedBy),它将包含对 Employee 的外键引用。

EmployeeDetailsController

@GetMapping("/add")
    public String handleEmployeeForm(Model model) {
        EmployeeDetails employeeDetails = new EmplyeeDetails();
        employeeDetails .setEmployee(new Employee());
        model.addAttribute("employeeDetails", employeeDetails );
        return "formEmployee";
    }

@PostMapping("/add")
    public String saveEmployee(@ModelAttribute("employeeDetails") EmployeeDetails employeeDetails) {
        this.employeeDetailsService.save(employeeDetails);
        return "redirect:/employee/add";
    }

推荐阅读