【问题标题】:Updating entity with One to One relationship using Spring Data使用 Spring Data 更新具有一对一关系的实体
【发布时间】: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


【解决方案1】:

一般来说,新的 INSERT 而不是 UPDATE 可能是由于:

传递给 save 的任何一个实体都没有设置 ID,因此在后台调用了 persist 或者数据库中不存在具有给定 ID 的实体,因此合并失败(并且可能作为后备保留,不知道) 检查实体是否设置了 ID 字段。

【讨论】:

  • 就像我上面所说的,Id 作为请求的一部分传递,并且该值当前存在于数据库中。顺便说一句,欢迎使用 stackoverflow :)
【解决方案2】:

在您的模型中,覆盖 equal/hash-code 并检查 id 参数 也许它会帮助你:)

【讨论】:

    【解决方案3】:

    问题已经解决,不知何故,copyproperties 逻辑在我也在更新/设置人的意义上是不正确的。

    【讨论】:

      猜你喜欢
      • 2014-07-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-11-13
      • 1970-01-01
      • 2015-02-09
      • 1970-01-01
      • 2019-01-07
      相关资源
      最近更新 更多