Spring-Data JPA: save new entity referencing existing one

柔情痞子 提交于 2019-11-28 17:51:14

I had a similar issue where I was trying to save an new entity object with an already saved entity object inside.

What I did was implemented Persistable< T > and implemented isNew() accordingly.

public class MyEntity implements Persistable<Long> {

    public boolean isNew() {
        return null == getId() &&
            subEntity.getId() == null;
    }

Or you could use AbstractPersistable and override the isNew there ofcourse.

I don't know if this will be considered a good way of handling this issue but it worked out quite good for me and besides feels very natural to do.

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.

nakkun

I have the same problem with a @EmbeddedId and business data as part of the id.
The only way to know if the entity is new is performing a (em.find(entity)==null)?em.persist(entity):em.merge(entity)

but spring-data only provides save() method and there is no way to fill the Persistable.isNew() method with a find() method.

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