07.关于解决保存关联对象时产生的nTon问题

文前碎言:

其实本来昨天中午就抽时间把思路写好了,结果一直太忙了,到今天现在才忙完,便想着一定要写了,言归正文哈!

原理介绍:

当我们添加或者修改数据的时候,如果操作的数据对象Employee有关联对象,而此时并未添加关联对象的值,也就是如图所示不选择添加部门
07.关于解决保存关联对象时产生的nTon问题_第1张图片
而在发送保存的请求到达后台之前,对应的Controller会执行@ModelAttribute(“beforeupdate”)方法,会根据需要修改的对象Employee的id去数据库中查询,

/\*\*  
 \* 这个方法会在请求到达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对象进行对比,

/\*\*  
 \* 这里再把查询出来的对象和前台传入的对象进行比较,不一样的,就直接更新了,然后再把新的对象传入到保存的方法中去保存  
  \* @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方法的时候,

public class SimpleJpaRepository implements JpaRepository, JpaSpecificationExecutor {
    @Transactional  
    public  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);
07.关于解决保存关联对象时产生的nTon问题_第2张图片

解决思路:

情形一:在没有选择Department而传入的对象id为null的情况,此时我们可以在Service里面保存之前,判断Employee对象的部门id是否为null,如果是,则直接将部门对象设置为null,

// 这里之所以要判断部门对象不为空而部门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有值的情况

你可能感兴趣的:(javascript,java)