JpaRepository merge() 方法

Cod*_*mer 0 merge jpa spring-boot

我正在重写一个大项目,SpringBoot 2.2.6但遇到了问题。

在旧的项目(纯ejb)当一个复杂的实体更新,代码生成entity从DTO's如下:

public Entity dtoToEntity(DTO dto) {
  Entity entity = new Entity();
  entity.setId(dto.getID());
  // ecc...
  // ecc...
  entity.setSubEntity(dto.getSubEntity() != null ? new SubEntity(dto.getSubEntity().getId() : null);
  // and so on
}
Run Code Online (Sandbox Code Playgroud)

重要的部分是与子实体相关的部分!在进行了类似旧项目调用的映射之后:

EntityManager.merge(entity);
Run Code Online (Sandbox Code Playgroud)

我认为通过合并调用,如果数据库内部存在具有指定 id 和其他字段valorized 的 SubEntity ,则其他字段保持有效并且不会设置为 null 因为它们没有在映射中声明。

但是SpringBoot我正在使用JpaRepository,如果我打电话,我认为不会发生同样的事情:

jpaRepository.save(entity);
Run Code Online (Sandbox Code Playgroud)

我认为通过此调用,具有指定 id 的 SubEntity 的其他字段将设置为 null!

这是正确的吗?

我能解决什么?


首先感谢您的回复!

你是对的,我不能做这样的事情,也不能用 EntityManager.merge() 方法!比我试图更好地解释我想要做什么:

假设我有一个复杂的实体,它有许多嵌套实体(可能有嵌套实体),如下所示:

  @Entity
  public class Car {
     private String name;
     ....
     ....
     private Engine engine; // nested entity
     private Chassis chassis; // nested entity
}
Run Code Online (Sandbox Code Playgroud)

和:

@Entity
public class Engine {

  private String company;
  private Oil oil; // nested entity
  ....
}
Run Code Online (Sandbox Code Playgroud)

现在假设在数据库中我有一辆汽车,所有关系都已填充(发动机、底盘、油等),并假设我想将汽车名称从法拉利更新为菲亚特,如果我使用纯 SQL,我可以简单地编写:

update Car c set c.name = "Fiat" where c.id = [id];
Run Code Online (Sandbox Code Playgroud)

现在,如果我使用 Spring JPA,为了确保在更新实体时所有嵌套实体(及其字段)不会设置为 null,我必须执行以下操作:

Car car = carRepository.findById([id]);
car.setName("Fiat"):
carRepository.save(car);
Run Code Online (Sandbox Code Playgroud)

通过这种方式,我将更新 Car name,并且我确定所有其他实体将保持设置状态,因为它们是由 findById() 方法加载的。

我的问题和我的目标是知道是否有办法做这样的事情:

Car car = new Car();
car.setId(1); // id of Ferrari car
car.setName("Fiat");
someRepositoryOrEntityManager.saveOrUpdate(car);
Run Code Online (Sandbox Code Playgroud)

并通过 find 方法保留所有其他字段和关系而不加载所有这些(可能是由于性能原因)。

Les*_*iak 6

你试过了还是只是猜测?

首先,您不需要拥抱 spring 数据存储库。如果 EntityManager 有助于迁移过程,您可以注入它。

其次,看执行情况 SimpleJpaRepository.save

@Transactional
public <S extends T> S save(S entity) {

    if (entityInformation.isNew(entity)) {
        em.persist(entity);
        return entity;
    } else {
        return em.merge(entity);
    }
}
Run Code Online (Sandbox Code Playgroud)

这意味着如果得出结论该实体不是新的,则JpaRepository.save调用em.merge。

检查实体是否是新的在AbstractEntityInformation.isNew. 它得出结论,只有当其 id 为空(或原始数字类型为 0)时,实体才是新的。

您从 dto 分配 id。如果它不为空(或原语非零),则没有理由相信新代码的行为方式与旧代码不同。

回答更新的问题

如果您想修改实体而不获取它,我建议使用 JPQL 或标准查询