文前碎言:数据库
其实原本昨天中午就抽时间把思路写好了,结果一直太忙了,到今天如今才忙完,便想着必定要写了,言归正文哈!
当咱们添加或者修改数据的时候,若是操做的数据对象Employee有关联对象,而此时并未添加关联对象的值,也就是如图所示不选择添加部门
也就是为空或者没有设置值进去,那么此时将对象传入后台进行保存的时候,就会同时传入一个没有id的关联对象Department,
而在发送保存的请求到达后台以前,对应的Controller会执行@ModelAttribute(“beforeupdate”)方法,会根据须要修改的对象Employee的id去数据库中查询,app
/\*\* \* 这个方法会在请求到达Controller以前执行,会将要修改(有id)的对象从数据库中查询出来 \* 由于懒加载的缘故,不会将关联对象查询出来。 \* @param id \* @return \*/ @ModelAttribute("beforeupdate") public Employee before(Long id){ Employee employee = null; if (id != null){ employee = employeeService.findById(id); } return employee; }
查询出来以后,这里的employee对象是一个持久化对象咱们别名为EmployeePersist(之因此为持久化对象,是由于和entitymanager发生了关系),而后在进入修改的Controller以后,会自动将EmployeePersist和须要保存的传入的Employee对象进行对比,this
/\*\* \* 这里再把查询出来的对象和前台传入的对象进行比较,不同的,就直接更新了,而后再把新的对象传入到保存的方法中去保存 \* @param employee \* @return \*/ @RequestMapping("/update") @ResponseBody public AjaxResult update(@ModelAttribute("beforeupdate")Employee employee, MultipartFile fileImage, HttpServletRequest req){ return saveOrUpdate(employee,fileImage, req); }
若是前台传来的Employee有和EmployeePersist不同的地方,那么EmployeePersist就会自动进行更新其数据,而此时,也会将没有id的关联对象Department设置进EmployeePersist这个对象中,而后在Controller中调用对应的保存的方法,在service执行保存的时候,就会直接执行保存这一个EmployeePersist,也就是上面的saveOrUpdate(employee,fileImage, req)
中的employee === EmployeePersist,当进入到SimpleJpaRepository Entitymanager对象执行persist方法的时候,spa
public class SimpleJpaRepository<T, ID extends Serializable> implements JpaRepository<T, ID>, JpaSpecificationExecutor<T> { @Transactional public <S extends T> S save(S entity) { if (this.entityInformation.isNew(entity)) { this.em.persist(entity); return entity; } else { return this.em.merge(entity); } } } ... ... ...
此时由于懒加载的缘故,会将EmployeePersist在数据库中相关联的对象Department查询出来,而后进行修改/保存,结果发现,查询出来的关联对象Department的id不为null,而此时由于是作的修改动做,又要将该Department的id设置为null,可是持久化对象的id不能设置为null,因此最后就形成了nTon问题(之因此nTon,是有可能前台作修改的时候选择了部门也会形成这种状况,即修改前的部门id为2,修改后的部门id为3,就会形成2);code
情形一:在没有选择Department而传入的对象id为null的状况,此时咱们能够在Service里面保存以前,判断Employee对象的部门id是否为null,若是是,则直接将部门对象设置为null,orm
// 这里之因此要判断部门对象不为空而部门id为空的状况是由于在新增的时候若是不选择部门会传一个department对象过来, // 而又没有id,于是须要把则个对象设置为null if (employee.getDepartment() != null && employee.getDepartment().getId() == null) { employee.setDepartment(null); }
那么此时咱们再去保存的时候,实际就是保存的部门为null的Employee对象;
情形二:传入的部门对象有id,而咱们在保存的时候,不可以直接更改关联对象Department对象的id,即nTon,此时咱们能够在执行
@ModelAttribute(“beforeupdate”)方法的时候,将查询出来的Employee对象的关联对象Deparmtment设置为null,对象
@ModelAttribute("beforeupdate") public Employee before(Long id){ Employee employee = null; if (id != null){ employee = employeeService.findById(id); employee.setDepartment(null); } return employee; }
这样,咱们在进行到SimpleJpaSpecification内部调用Entitymanager对象执行persist方法的时候,此时的Employee查村出来的关联对象已经为null了,就能够直接进行保存从而完成修改。
注:上面一个是在service里面的保存方法设置关联对象Department为null,这个前提是传入的Department对象id为null的状况,而咱们不能设置一个关联对象id为null,另外一个实在Controller里面设置根据id查询出来的Employee的关联对象Department为null,这一个是为了解决前台传入的关联对象id有值的状况blog