Spring-Data JPA: save new entity referencing existing one

前端 未结 3 1019
谎友^
谎友^ 2020-12-08 04:24

The question is basically the same as below one:

JPA cascade persist and references to detached entities throws PersistentObjectException. Why?

I\'m creating

3条回答
  •  攒了一身酷
    2020-12-08 05:13

    The best I came up with is

    public final T save(T containable) {
        // if entity containable.getCompound already exists, it
        // must first be reattached to the entity manager or else
        // an exception will occur (issue in Spring Data JPA ->
        // save() method internal calls persists instead of merge)
        if (containable.getId() == null
                && containable.getCompound().getId() != null){
            Compound compound = getCompoundService()
                    .getById(containable.getCompound().getId());
            containable.setCompound(compound);   
        }
        containable = getRepository().save(containable);
        return containable; 
    }
    

    We check if we are in the problematic situation and if yes just reload the existing entity from the database by its id and set the field of the new entity to this freshly loaded instance. It then will be attached.

    This requires that the service for new entity holds a reference to the service of the referenced entity. This should not be an issue since you are using spring anyway so that service can just be added as a new @Autowired field.

    Another issue however (in my case this behavior is actually desired) that you can't change the referenced existing entity at the same time while saving the new one. All those changes will be ignored.

    IMPORTANT NOTE:

    In many and probably your cases this can be much simpler. You can add a reference of entity manager to your service:

    @PersistenceContext
    private EntityManager entityManager;
    

    and in above if(){} block use

    containable = entityManager.merge(containable);
    

    instead of my code (untested if it works).

    In my case the classes are abstract and targetEntity in @ManyToOne is hence abstract too. Calling entityManager.merge(containable) directly then leads to an exception. However if your classes are all concrete this should work.

提交回复
热议问题