我正在尝试使用单个事务使用实体管理器删除旧的子实体、创建新的子实体、更新祖父母实体。以下是我的代码:
实体类
@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#]
问题 我在这里做错了什么?
问题在于您尝试保留的实体是分离的。在该 @Transactional 方法中,仅引用上述实体。 有多种方法可以处理这个问题。
rungPositions
。请注意,这可能会带来性能损失,具体取决于存储库调用的其他位置。rungPositions
方法中根据 GrandParent
执行另一个查询来获取 saveGrandParent
。我会选择最后一条路。