JPA不保存实体:传递给持久化的分离实体

时间:2018-03-21 15:30:38

标签: java spring hibernate jpa

我遇到了与我的数据库保持一对多,多对一的双向关系的问题,我无法弄清楚我到底做错了什么。希望有人可以帮助我。

我的数据库中有2个实体,声明如下:

class Lot {
    @OneToMany(targetEntity = Request.class, mappedBy = "lot", cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true)
    private Set<Requests> requests;
}

class Request{
    @ManyToOne(optional = true, fetch = FetchType.EAGER)
    @JoinColumn(name = "fk_lot")
    private Lot lot;
}
问题出现在这里:

class RequestManagerImpl{
    // compose Request r object
    requestId = saveRequest(r).getId();

    // check to see if we need to create a parent object
    LotType lot = createRequestInput.getLot();
    if(lot != null){
        addRequestToLot(Lists.newArrayList(r), lot);
    }
}

class LotManagerImpl {
    @Override
    public Lot addRequestsToLot(List<Request> requests, Lot lot) {

        if (lot != null && requests != null && !requests.isEmpty()) {
            for (Request request : requests) {
            lot.addRequest(request);
        }
        Lot lotValue = lotDAO.saveOrUpdate(lot);
        if (lotValue != null) {
            updateLotStatusByRequestsStatus(lotValue);
        }
        return lotValue;
    }
} 
class LotDAO {
    @Override
    public Lot saveOrUpdate(Lot lot) {
        if (em.contains(lot)) {
            em.merge(lot);
        } else {
            em.persist(lot);
        }
        return lot;
    }
}
class RequestDAO {
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    Request saveRequest(Request request);
}

em.persist返回以下stacktrace:

Caused by: javax.persistence.PersistenceException: org.hibernate.PersistentObjectException: detached entity passed to persist: disp.entities.Request
    at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:147)
    at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:155)
    at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:162)
    at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:811)
    at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:771)
    at org.hibernate.jpa.event.internal.core.JpaPersistEventListener$1.cascade(JpaPersistEventListener.java:80)
    at org.hibernate.engine.internal.Cascade.cascadeToOne(Cascade.java:458)
    at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:383)
    at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:193)
    at org.hibernate.engine.internal.Cascade.cascadeCollectionElements(Cascade.java:491)
    at org.hibernate.engine.internal.Cascade.cascadeCollection(Cascade.java:423)
    at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:386)
    at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:193)
    at org.hibernate.engine.internal.Cascade.cascade(Cascade.java:126)
    at org.hibernate.event.internal.AbstractSaveEventListener.cascadeAfterSave(AbstractSaveEventListener.java:445)
    at org.hibernate.event.internal.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:281)
    at org.hibernate.event.internal.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:182)
    at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:125)
    at org.hibernate.jpa.event.internal.core.JpaPersistEventListener.saveWithGeneratedId(JpaPersistEventListener.java:67)
    at org.hibernate.event.internal.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:189)
    at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:132)
    at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:58)
    at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:780)
    at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:765)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at .proxy.$Proxy78.persist(Unknown Source)
    at disp.dao.impl.LotDAOImpl.saveOrUpdate(LotDAOImpl.java:123)

2 个答案:

答案 0 :(得分:1)

你可能会错过这里的oneToMany映射的魔力

这条线 requestId = saveRequest(r).getId();是不可能的,因为它依赖于Lot。

如果您将请求添加到批次并保存批次,则会自动保存请求作为映射的结果。

答案 1 :(得分:0)

我实际上自己发现了这个问题。

问题出在RequestDAO :: saveRequest方法中,事务被声明为Propagation.REQUIRES_NEW。这是在新事务中创建请求(子对象),稍后在保存它时从批(父)分离。

我只需将其更改为Propagation.REQUIRED即可使用现有事务提交父对象和子对象。