Spring Data Jpa问题在一个事务中保存父,子和childofchild

Posted

技术标签:

【中文标题】Spring Data Jpa问题在一个事务中保存父,子和childofchild【英文标题】:Spring Data Jpa problem saving parent, child and childofchild in one transaction 【发布时间】:2021-12-05 15:58:25 【问题描述】:

我有实体 A、B、C、D、E、F 实体 A 是 B、​​C、D 的父实体 实体 D 是 E、F 的父实体。

我有实体 A 的存储库,当我执行 repo.save 时,它​​只保存 A、B、C、D 而不是 E、F。 我正在使用来自 postgres 的预定义序列。

创建实体 A

@Entity
@Table(name="tname", schema="schemaname")
Public Class EntityA implements serializable

  @Id
  @SequenceGenerator()
  @column(name = "id")
  private int id;
   
  private string column1;
  private string column2;

  @OneToMany(cascade = CASCADE.ALL, mappedBy="entityA") 
  private set<EntityB> = new Hashset()<>;

  @OneToMany(cascade = CASCADE.ALL, mappedBy="entityB") 
  private set<EntityB> = new Hashset()<>;

  @OneToMany(cascade = CASCADE.ALL, mappedBy="entityC") 
  private set<EntityB> = new Hashset()<>;

  //getters and setters  


创建实体 B

@Entity
@Table(name="tname", schema="schemaname")
Public Class EntityB implements serializable

  @Id
  @SequenceGenerator()
  @column(name = "id")
  private int id;
   
  private string column1;
  private string column2;

  @ManyToOne
  @joinColumn(name="EntityA.id", referencedColumn="EntityA.id")
  private EnityA entityA


  //getters and setters  ​
  //constructor


创建实体 C

@Entity
@Table(name="tname", schema="schemaname")
Public Class EntityC implements serializable

  @Id
  @SequenceGenerator()
  @column(name = "id")
  private int id;
   
  private string column1;
  private string column2;

  @ManyToOne
  @joinColumn(name="EntityA.id", referencedColumn="EntityA.id")
  private EnityA entityA


  //getters and setters  ​
  //constructor


创建实体 D

@Entity
@Table(name="tname", schema="schemaname")
Public Class EntityD implements serializable

  @Id
  @SequenceGenerator()
  @column(name = "id")
  private int id;


  @ManyToOne
  @joinColumn(name="EntityA.id", referencedColumn="EntityA.id")
  private EnityA entityA
   
  private string column1;
  private string column2;

  @OneToMany(cascade = CASCADE.MERGE, mappedBy="entityD") 
  private set<EntityE> = new Hashset()<>;

  @OneToMany(cascade = CASCADE.MERGE, mappedBy="entityD") 
  private set<EntityF> = new Hashset()<>;
  

  //getters and setters  ​
  //constructor


创建实体 E

@Entity
@Table(name="tname", schema="schemaname")
Public Class EntityE implements serializable

  @Id
  @SequenceGenerator()
  @column(name = "id")
  private int id;
   
  private string column1;
  private string column2;

  @ManyToOne
  @joinColumn(name="EntityD.id", referencedColumn="EntityD.id")
  private EnityD entityD


  //getters and setters  ​
  //constructor


创建实体 F

@Entity
@Table(name="tname", schema="schemaname")
Public Class EntityF implements serializable

  @Id
  @SequenceGenerator()
  @column(name = "id")
  private int id;
   
  private string column1;
  private string column2;

  @ManyToOne
  @joinColumn(name="EntityD.id", referencedColumn="EntityD.id")
  private EnityD entityD


  //getters and setters  ​
  //constructor


构建实体A

Public class EntityABuilder

 EntityA a = new EntityA();
 a.setColumn1("test");

 //build B
 Set<EntityB> bSet = a.getEntityB();
 EnityB b = new EntityB();
 b.setColumn1("btest");
 bSet.add(b);

//for each B setA
for(EntityB bs:bSet)

 bs.setEntityA(a);


//build C
 Set<EntityC> cSet = a.getEntityC();
 EnityC c = new EntityC();
 c.setColumn1("ctest");
 cSet.add(c);

//for each c set A
for(EntityC cs:cSet)

 cs.setEntityA(a);


//build D
Set<EntityD> dSet = a.getEntityD();
 EnityD d = new EntityD();
 d.setColumn1("btest");

 //build EntityE
 Set<EntityE> ESet = D.getEntityE();
 EntityE e = new EntityE();
 e.setCloumn1("eTest")
 eset.add(e);

//for each E set D
  for(EntityE es:eSet)
  
   es.setEntityD(d);
  

  //build EntityF
  Set<EntityF> fSet = D.getEntityE();
 EntityF f = new EntityF();
 f.setCloumn1("eTest")
 fSet.add(f);

  //foe each F set D
  for(EntityF fs:fSet)
  
   fs.setEntityD(d);
  

//add D
 dSet.add(d);

//for each D set A
for(EntityD ds:dSet)

 ds.setEntityA(a);


调用 EntityARepository.save(EntityA) 它保存 A、B、C、D 而不是 E、F。

【问题讨论】:

【参考方案1】:

您只设置了CASCADE.MERGE,但在创建新实体时,您还需要设置CASCADE.PERSIST

@OneToMany(cascade = CASCADE.PERSIST, CASCADE.MERGE, mappedBy="entityD") 
private set<EntityE> = new Hashset()<>;

@OneToMany(cascade = CASCADE.PERSIST, CASCADE.MERGE, mappedBy="entityD") 
private set<EntityF> = new Hashset()<>;

【讨论】:

我已经尝试过了,当我添加 CASCADE.PERSIST 时,它会抛出我传递给持久化的分离实体。 你能发布堆栈跟踪吗? 引起:org.hibernate.PersistentObjectException:分离的实体传递给persist:org的EntityE。冬眠。 org 的内部 .SessionImpl.firePersist (SessionImpl.Java:744)。冬眠。 internal.SessionImpl.persist(SessionImpl.Java:712) 在 org. hibernate.engine.spi.CascadingActions$7.cascade(CascadeActions.java:298) at org. hibernate.engine.internal.Cascade.cascadeToOne(Cascade.java:499) at org.冬眠。引擎。 internal.Cascade.cascadeAssociation(Cascade.java:423) 在 org.冬眠。引擎。 internal.Cascade.cascadeProperty (Cascade.Java:220) 你能显示你保存的代码吗?交易边界在哪里? 我得到了这个工作,看起来 jpa 内置的保存方法不起作用。我使用了 entitymanger.merge 并且效果很好。

以上是关于Spring Data Jpa问题在一个事务中保存父,子和childofchild的主要内容,如果未能解决你的问题,请参考以下文章

spring data jpa使用spring data jpa时,关于service层一个方法中进行删除和插入两种操作在同一个事务内处理

在同一事务中删除后的 Spring Data JPA 计数

Spring Boot + Spring Data JPA + 事务无法正常工作

Spring data jpa嵌套事务回滚不删除插入?

Spring Boot 中的事务同步

Spring data JPA:未提交每条记录的事务