【发布时间】:2019-08-15 04:00:50
【问题描述】:
更新具有 OneToOne 关系的实体时遇到问题,它创建记录而不是更新现有记录。以下是示例实体。
@Entity
@Table(schema = "crm", name = "persons")
public class Person {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
public Long getId() {
return id;
}
@OneToOne(mappedBy = "person", fetch = FetchType.LAZY)
public Employee getEmployee() {
return employee;
}
}
@Entity
@Table(schema = "crm", name = "employees")
public class Employee {
@Id
public Long getId() {
return id;
}
@OneToOne
@MapsId //Use the person PK id value as Employee PK id
@JoinColumn(name = "id")
public Person getPerson() {
return person;
}
}
我正在使用 Spring Data 的 PagingAndSortingRepository。下面是更新实体的服务层。
@Override
@Transactional
public EmployeeResponse updateEmployee(Employee aEmployee) {
EmployeeResponse response = new EmployeeResponse();
try {
Optional<Employee> probableEmployee = employeeRepository.findById(aEmployee.getId());
if (!probableEmployee.isPresent()) {
throw new RecordNotFoundException(String.format(MessageConstants.EMPLOYEE_ID_NOT_FOUND, aEmployee.getId()));
}
Employee existingEmployeeToUpdate = probableEmployee.get();
EmployeeEntityHelper.updateExistingEntity(aEmployee, existingEmployeeToUpdate);
existingEmployeeToUpdate = employeeRepository.save(existingEmployeeToUpdate);
response.setSuccessfulResponse(existingEmployeeToUpdate);
} catch (Exception ex) {
LOGGER.error(ex.getLocalizedMessage(), ex);
response.setErrorAttributes(false, ReturnCode.FAILED.getCode(), ex.getLocalizedMessage());
}
return response;
}
EmployeeEntityHelper.updateExistingEntity(source, target) 将简单地将实体的所有属性从源复制到目标。
即使我明确传递数据库中存在的 id,save() 方法也会为 Person 生成插入。但对于员工来说,它会生成预期的更新。
下面是 updateExistingEntity() 方法:
public static void updateExistingEntity(Employee source, Employee target) {
copyProperties(source, target, Arrays,asList("person", "employeeNumber", "hiredDate", "birthDate"));
}
private static void copyProperties(Object aSource, Object aTarget, Iterable<String> aProperties) {
BeanWrapper sourceWrapper = PropertyAccessorFactory.forBeanPropertyAccess(aSource);
BeanWrapper targetWrapper = PropertyAccessorFactory.forBeanPropertyAccess(aTarget);
aProperties.forEach(p ->
targetWrapper.setPropertyValue(p, sourceWrapper.getPropertyValue(p))
);
}
【问题讨论】:
-
post code on updateExistingEntity,可能就是这个问题。
-
@JonathanJohx,请参阅上面的更新
-
保存之前检查的调试时是否包含ID?对吗?
-
我不知道我是否理解正确,但是在创建新记录时,其优秀员工将根据人员 ID 关联。在更新期间,将提供员工和相关人员对象的 ID。
-
好的,所以你需要把@OneToOne(cascade = CascadeType.ALL) 用于合并,包含所有。
标签: spring-boot spring-data-jpa