【问题标题】:JpaRepository merge() methodJpaRepository 合并()方法
【发布时间】:2020-07-15 13:07:04
【问题描述】:

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

在旧项目(纯ejb)中更新复杂实体时,代码从DTO's构建entity如下:

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
}

重要的部分是与子实体相关的部分!在制作了这样的映射后,旧项目调用:

EntityManager.merge(entity);

我认为通过合并调用,如果在数据库中存在具有指定 id 和 其他已验证的字段的子实体,则其他字段保持有效并且不会设置为 null,因为它们没有在映射。

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

jpaRepository.save(entity);

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

对吗?

我有什么办法解决这个问题?


首先感谢您的回复!

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

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

  @Entity
  public class Car {
     private String name;
     ....
     ....
     private Engine engine; // nested entity
     private Chassis chassis; // nested entity
}

还有:

@Entity
public class Engine {

  private String company;
  private Oil oil; // nested entity
  ....
}

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

update Car c set c.name = "Fiat" where c.id = [id];

现在,如果我使用 Spring JPA,为了确保在我更新我的实体时所有嵌套实体(及其字段)都没有设置为 null,我必须这样做:

Car car = carRepository.findById([id]);
car.setName("Fiat"):
carRepository.save(car);

这样我将更新汽车名称,并且我确信所有其他实体都将保持设置,因为它们是由 findById() 方法加载的。

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

Car car = new Car();
car.setId(1); // id of Ferrari car
car.setName("Fiat");
someRepositoryOrEntityManager.saveOrUpdate(car);

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

【问题讨论】:

    标签: spring-boot jpa merge


    【解决方案1】:

    您是尝试过还是只是猜测?

    首先,您不需要接受 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);
        }
    }
    

    这意味着JpaRepository.save 会调用em.merge 如果它断定实体不是新的。

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

    您从 dto 分配 id。如果它不为 null(或者对于基元来说不为零),则没有理由相信新代码的行为方式会与旧代码不同。

    更新问题的答案

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

    【讨论】:

      猜你喜欢
      • 2021-12-26
      • 2022-07-06
      • 2020-06-24
      • 2022-10-06
      • 1970-01-01
      • 2019-04-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多