Проблема Spring Data Jpa с сохранением родителя, ребенка и ребенка в одной транзакции

#postgresql #spring-boot #hibernate #jpa #spring-data-jpa

Вопрос:

У меня есть Сущность 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

}
 

create Entity 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

}
 

create Entity 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

}
 

create Entity 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

}
 

Создайте сущность

 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()<>;
 

Комментарии:

1. Я уже пробовал это, когда добавлял КАСКАД. УПОРСТВОВАТЬ-это значит, что я отсоединяю сущность, переданную для сохранения.

2. Не могли бы вы, пожалуйста, опубликовать трассировку стека?

3. вызвано: org.спящий режим. PersistentObjectException: отделенная сущность, переданная в persist:EntityE в организации. зимовать. внутренний .SessionImpl.firePersist (SessionImpl.Java:744 ) в организации. зимовать. внутренний. SessionImpl.persist(SessionImpl.Java:712) в организации. hibernate.engine.spi.CascadingActions$7.каскад(CascadeActions.java:298)в организации. спящий режим.двигатель.внутренний. Cascade.cascadeToOne(Каскад.java:499) в организации. зимовать. двигатель. внутренний. Каскад.Каскадная ассоциация(Cascade.java:423) в организации. зимовать. двигатель. внутренний. Каскад.Свойство каскада (Каскад. Java:220)

4. Можете ли вы показать код, где вы его сохраняете? Где находятся границы транзакций?

5. Я заставил это работать, похоже, что метод сохранения, встроенный в jpa, не сработал. Я использовал entitymanger.merge, и это сработало нормально.