首页 > 解决方案 > 如何限制自加入中的重复记录

问题描述

我在我的 Spring Data JPA 代码中有描述员工和经理关系的自加入关系,并通过 REST 端点公开它。

这是我的员工控制器

@Controller
@RequestMapping(path = "/employee")
public class EmployeeController {
    @Autowired
    private EmployeeRepository employeeRepository;

    @PostMapping

    public Employee addNewUser(@RequestBody Employee employee) {

        return employeeRepository.save(employee);
    }

    @GetMapping
    public @ResponseBody Iterable<Employee> getAllUsers() {
        // This returns a JSON or XML with the users
        return employeeRepository.findAll();
    }
}

这是员工实体

@Entity
@Table(name = "EMPLOYEE")
public class Employee {

    @Id
    @Column(name = "id")
    @GeneratedValue
    private Long id;

    @Column(name = "fname")
    private String fname;

    @Column(name = "lname")
    private String lname;

    @ManyToOne(cascade = { CascadeType.ALL })
    @JoinColumn(name = "manager_id")
    private Employee manager;

    @OneToMany(mappedBy = "manager")
    private Set<Employee> subordinates = new HashSet<Employee>();

        //getters and setters
}

现在,当我通过以下方式向端点提交POST请求时/employee

POST /employee
{
    "fname":"akash",
    "lname":"xavier",
    "manager":{
        "fname":"kiran",
        "lname":"Kumar"
    }
}

它正在数据库中按预期创建行

mysql> select * from employee;
+----+----------+---------+------------+
| id | fname    | lname   | manager_id |
+----+----------+---------+------------+
| 20 | kiran    | Kumar  |       NULL  |
| 19 | akash    | xavier |         20  |
+----+----------+---------+------------+

现在的问题是我想在请求下方提交

POST /employee

{
    "fname":"Vipul",
    "lname":"Kumar",
    "manager":{
        "fname":"kiran",
        "lname":"Kumar"
    }
}

但不希望Kiran Kumar再次创建经理。

标签: javaspring-bootjpaspring-data-jpa

解决方案


对于您提供的用例,没有开箱即用的解决方案。您需要手动测试同名的现有管理器,类似于:

@PostMapping
public Employee addNewUser(@RequestBody Employee employee) {
    return employeeService.create(employee);
}

其中EmployeeService.create()实现如下:

@Transactional
public void create(Employee employee) {
    Employee manager = Optional.ofNullable(employee.getManager()) 
        .flatMap(managerFromRequest -> employeeRepository.findByFnameAndLname(managerFromRequest.getFname(), managerFromRequest.getLname())
        .ifPresent(Employee:setManager);
    employeeRepository.save(employee);
}

public Optional<Employee> findByFnameAndLname(String fname, String lname)在 上声明EmployeeRepository

作为旁注:

  • @ManyToOne(cascade = { CascadeType.ALL })是错的。特别是,对协会CascadeType.REMOVE没有意义@ManyToOne
  • 您确定fname并且lname足以唯一标识一个Employee? 有时,人们只是碰巧有相同的名字

推荐阅读