获取异常“分离实体传递到持久化”

问题描述 投票:0回答:1

我正在尝试使用单个事务使用实体管理器删除旧的子实体、创建新的子实体、更新祖父母实体。以下是我的代码:

实体类

@Data
@Entity
@NoArgsConstructor
@AllArgsConstructor
@Table(name = "GrandParent", schema = "testDbo")
public class GrandParent implements Serializable {
    @Serial
    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.UUID)
    @Column(name = "LADDER_SEQUENCE_ID", unique = true, nullable = false)
    protected UUID ladderSequenceId;

    @Column(name = "LADDER_ID", unique = true, nullable = false)
    protected String ladderId;
    @Column(name = "LADDER_NAME")
    protected String ladderName;
    @Column(name = "LADDER_ACCOUNT_NBR")
    protected String ladderAccountNumber;
    @Column(name = "UPDATE_TS")
    protected LocalDateTime updateDate;

    @OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "ladder")
    private List<Parent> ladderRungs;
}

@Data
@Entity
@NoArgsConstructor
@AllArgsConstructor
@Table(name = "Parent", schema = "testDbo")
public class Parent implements Serializable{
    @Serial
    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.UUID)
    @Column(name = "LADDER_RUNG_SEQUENCE_ID", unique = true, nullable = false)
    private UUID ladderRungSequenceId;
    @Column(name = "LADDER_ID")
    protected String ladderId;
    @Column(name = "LADDER_RUNG_NBR")
    protected Integer ladderRungNumber;

    @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    @JoinColumn(name = "LADDER_SEQUENCE_ID", nullable = false)
    GrandParent ladder;

    @OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "rung")
    protected List<Child> rungPositions;
}

@Data
@Entity
@Table(name = "Child" , schema = "testDbo")
public class Child implements Serializable{
    @Serial
    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.UUID)
    @Column(name = "LADDER_POSITION_ID", unique = true, nullable = false)
    protected UUID ladderPositionId;

    @Column(name = "LADDER_RUNG_NBR")
    protected Integer ladderRungNumber;
    @Column(name = "POSITION_QTY")
    protected BigDecimal positionQuantity;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name="LADDER_RUNG_SEQUENCE_ID", referencedColumnName = "LADDER_RUNG_SEQUENCE_ID")
    protected Parent rung;
}

数据库服务代码:

@Service
public class EntityManagerDBService {
    @Autowired
    private EntityManagerFactory entityManagerFactory;

    EntityManager em;
    public void ladderDBStartTransaction(){
        em = entityManagerFactory.createEntityManager();
        em.getTransaction().begin();
    }

    public GrandParent getLadderByAccountNumberAndLadderId(String accountNumber, String ladderId){
        Query query = em.createNativeQuery("select * from testDbo.GrandParent ld where ld.LADDER_ACCOUNT_NBR = :accountNum and ld.ladder_id = :ladderId", GrandParent.class);
        query.setParameter("accountNum", accountNumber);
        query.setParameter("ladderId", ladderId);

        if(!query.getResultList().isEmpty()){
            return (GrandParent)query.getSingleResult();
        }
        return null;
    }

    @jakarta.transaction.Transactional
    public void deleteChild(List<Child> childList){
        for(Child child : childList){
            if(!em.contains(child)){
                em.merge(child);
            }
            em.remove(child);
        }
    }

    @jakarta.transaction.Transactional
    public void saveGrandParent(GrandParent grandParent){
        try{
            for(Parent parent : grandParent.getLadderRungs()){
                for(Child child : parent.getRungPositions()){
                    if(!em.contains(child)){
                        //None Worked
                        em.merge(child);
                        //em.persist(child);
                    }
                }
            }
            grandParent.setUpdateDate(LocalDateTime.now());//Updating Grandparent
            em.merge(grandParent); //Want to save updated Grandparent
            em.getTransaction().commit();
        }catch (Exception ex){
            ex.printStackTrace();
            em.getTransaction().rollback();
        }finally {
            em.close();
        }
    }
}

申请代码:

@Autowired
EntityManagerDBService entityManagerDBService;

entityManagerDBService.ladderDBStartTransaction();
        GrandParent grandParent = entityManagerDBService.getLadderByAccountNumberAndLadderId(this.accountNumber, this.ladderId);
        log.info("GrandParent : {}", grandParent);

        try{
            List<Child> childList = new ArrayList<>();
            for(Child child : grandParent.getLadderRungs().get(3).getRungPositions()){
                Child childToSave = child.clone();
                childToSave.setRung(grandParent.getLadderRungs().get(3));
                childToSave.setPositionQuantity(new BigDecimal("10"));
                childList.add(childToSave);
            }
            entityManagerDBService.deleteChild(grandParent.getLadderRungs().get(3).getRungPositions());
            grandParent.getLadderRungs().get(3).getRungPositions().addAll(childList);
            entityManagerDBService.saveGrandParent(grandParent);
        }catch (CloneNotSupportedException ex){
            ex.printStackTrace();
        }

日志和异常

2024-06-19 22:08:16 INFO com.service.cd.CDLUpdateRungService 82 : LOCAL-1 : GrandParent : 
 GrandParent{ladderSequenceId=95a85ab3-fb83-46db-8a8b-530617a05560, ladderId='00276', ladderName='TestLadder', ladderAccountNumber='X04977780', ladderRungs=[
 Parent{ladderRungSequenceId=9b49bb00-a395-4d41-88b9-36df45623335, ladderId='00276', ladderRungNumber=3, rungPositions=[
 Child{ladderPositionId=9874a624-1cd5-49c6-9db0-e1479339f4f7, ladderRungNumber=3}]}, 
 Parent{ladderRungSequenceId=32fc34e3-5d84-4589-a9bd-f01da276b084, ladderId='00276', ladderRungNumber=1, rungPositions=[
 Child{ladderPositionId=92e5cc6e-ab63-48da-a0b0-d2a624919c56, ladderRungNumber=1}]}, 
 Parent{ladderRungSequenceId=f17b5f20-dd53-4469-b382-efabd3a2e0a1, ladderId='00276', ladderRungNumber=4, rungPositions=[
 Child{ladderPositionId=fc5bf7b6-7ca3-4c1a-8511-7806894deff6, ladderRungNumber=4}, 
 Child{ladderPositionId=a8303128-c24c-4d60-9a5b-90215db2bc88, ladderRungNumber=4}, 
 Child{ladderPositionId=693be613-ae00-4949-a253-fb720cb2f241, ladderRungNumber=4}]}, 
 Parent{ladderRungSequenceId=7482ee82-1e3d-41b1-81b3-82fa76e230f0, ladderId='00276', ladderRungNumber=2, rungPositions=[
 Child{ladderPositionId=f276b538-2ec7-4353-aa93-2ddc66dd1741, ladderRungNumber=2}, 
 Child{ladderPositionId=31e49ce5-abea-4bdf-bad0-8ae05a5594d3, ladderRungNumber=2}, 
 Child{ladderPositionId=1952e6ad-1e0c-4cb1-ba7b-31af88a075e2, ladderRungNumber=2}, 
 Child{ladderPositionId=53188e4b-bdcb-4189-88d8-eee7c748414f, ladderRungNumber=2}, 
 Child{ladderPositionId=6009dffc-5179-4174-9efb-a78726e8b78f, ladderRungNumber=2}]}]}
jakarta.persistence.PersistenceException: Converting `org.hibernate.PersistentObjectException` to JPA `PersistenceException` : detached entity passed to persist: com.model.entities.Child
    at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:165)
    at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:175)
    at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:182)
    at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:743)
    at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:721)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:568)
    at org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.invoke(ExtendedEntityManagerCreator.java:360)
    at jdk.proxy2/jdk.proxy2.$Proxy139.persist(Unknown Source)
    at com.fmr.fbt.fi.ladder.service.db.EntityManagerDBService.saveGrandParent(EntityManagerDBService.java:53)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:568)

在这里,我尝试创建新的子实体并保存到数据库。在保存到数据库之前,我想先删除它。所以,调用了remove方法。我调试代码,发现“删除”从未被调用,但甚至没有抛出任何异常,似乎调用被忽略了。在保存过程中,它给出了如上所述的异常。对于新的子实体,我尝试使用“坚持”方法。 得到异常: 将

org.hibernate.PersistentObjectException
转换为 JPA
PersistenceException
:传递给持久化的分离实体:

如果我启用“合并”方法,则会出现以下异常: java.lang.IllegalArgumentException:org.hibernate.ObjectDeletedException:已删除实例传递给合并:[com.model.entities.Child#]

问题 我在这里做错了什么?

spring-boot jpa spring-data-jpa entitymanager
1个回答
0
投票

问题在于您尝试保留的实体是分离的。在该 @Transactional 方法中,仅引用上述实体。 有多种方法可以处理这个问题。

  • 重构代码以便对附加实体进行操作。
  • 要么尝试急切地获取
    rungPositions
    。请注意,这可能会带来性能损失,具体取决于存储库调用的其他位置。
  • 要么直接在
    rungPositions
    方法中根据
    GrandParent
    执行另一个查询来获取
    saveGrandParent

我会选择最后一条路。

© www.soinside.com 2019 - 2024. All rights reserved.