JpaRepository merge() method

£可爱£侵袭症+ 提交于 2021-01-29 05:30:29

问题


I'm rewriting a big project with SpringBoot 2.2.6 and I'm run into a problem.

In the old project (pure ejb) when a complex entity is updated, the code build entity from DTO's as follows:

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
}

The important section is that related to subentity! After made a mapping like that the old project calls:

EntityManager.merge(entity);

I think that with merge call, if inside the database exists a SubEntity with specified id and other fields valorized, the other fields remain valid and are not set to null because they aren't declared in mapping.

But with SpringBoot I'm using JpaRepository and I don't think the same thing happens if I call:

jpaRepository.save(entity);

I think with this call the other fields of SubEntity with specified id will set to null!

Is it correct?

What can I solve this?


Thanks for your reply first of all!

You are right, I can't do something like that nor with EntityManager.merge() method! Than I try to explain better what I want to do:

Suppose I have a complex Entity, which has many nested Entities (which may have nested entities) as follows:

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

And:

@Entity
public class Engine {

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

Now suppose in the database I have a Car, with all relationship filled (Engine, Chassis, Oil ecc..) and suppose I want to update the Car name from Ferrari to Fiat, if I use pure SQL I can simply write:

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

Now if I use Spring JPA, to ensure that all nested entity (and their field) are not setting to null when I update my entity I have to do:

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

This way I will update Car name and I'm sure that all other entities will remain set because are loaded by findById() method.

My question and my goal is to know if is there a way to do something like that:

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

And preserve all other field and relation without load all of these by the find method (maybe due to a performance reasons).


回答1:


Did you give it a try or it is just guesswork?

First of all, you don't need to embrace spring data repositories. You can inject EntityManager if it helps in the migration process.

Secondly, look at the implementation of 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);
    }
}

This means that JpaRepository.save calls em.merge if it concludes that the entity is not new.

The check if the entity is new is in AbstractEntityInformation.isNew. It concludes that the entity is new only if its id is null (or 0 for primitive numerical types).

You assign the id from the dto. If it is not null (or non-zero for primitives), there is no reason to believe that the new code will behave in a different way than the old one.

Answer for updated question

If you want to modify an entity without fetching it, I would suggest JPQL or criteria query



来源:https://stackoverflow.com/questions/62915602/jparepository-merge-method

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!