Весенний ботинок.Композитный ключ и каскады - PullRequest
1 голос
/ 19 апреля 2019

Может кто-нибудь объяснить, как это на самом деле должно быть достигнуто?

У меня есть родительский объект (называемый Executor в трассировке нижнего стека):

class Parent {
   @Id
   private int id;
}

и у меня есть дочерний элемент (Param1CK в трассировке стека, таблица params3), идентификатор которого является составным и зависит от "Parent" и "номера строки":

@IdClass(ChildID.class)
class Child {
   @Id
   @ManyToOne
   @JoinColumn
   private Parent parent;

   @Id
   @Column
   private int id;
}

class ChildID implements Serializable{
  private Parent parent;
  private int id;

  @Override
  public int hashCode() {...}
}

Коллекция Child у родителя описывается как:

   @OneToMany(mappedBy="parent")
   @Cascasde(value = CascadeType.ALL)
   private List<Child> list = ...;

И этот момент, похоже, решен неправильно.

Когда я пытаюсь сделать:

Parent p = new Parent();
p.getList().add(new Child(p)); // with the Parent targeting in the constructor

и выполнить несколько операций «сохранения», Hibernate не может разрешить ключ и выполняет цикл для разрешения родительского ключа, который разрешается в stackOverFlow:

Hibernate: select executor0_.id as id1_3_1_, executor0_.parent_id as parent_i2_3_1_, params3x1_.parent_id as parent_i3_6_3_, params3x1_.prop as prop1_6_3_, params3x1_.prop as prop1_6_0_, params3x1_.parent_id as parent_i3_6_0_, params3x1_.value as value2_6_0_ from executor executor0_ left outer join paraaaamsssck params3x1_ on executor0_.id=params3x1_.parent_id where executor0_.id=?
Hibernate: select executor0_.id as id1_3_1_, executor0_.parent_id as parent_i2_3_1_, params3x1_.parent_id as parent_i3_6_3_, params3x1_.prop as prop1_6_3_, params3x1_.prop as prop1_6_0_, params3x1_.parent_id as parent_i3_6_0_, params3x1_.value as value2_6_0_ from executor executor0_ left outer join paraaaamsssck params3x1_ on executor0_.id=params3x1_.parent_id where executor0_.id=?
Hibernate: select executor0_.id as id1_3_1_, executor0_.parent_id as parent_i2_3_1_, params3x1_.parent_id as parent_i3_6_3_, params3x1_.prop as prop1_6_3_, params3x1_.prop as prop1_6_0_, params3x1_.parent_id as parent_i3_6_0_, params3x1_.value as value2_6_0_ from executor executor0_ left outer join paraaaamsssck params3x1_ on executor0_.id=params3x1_.parent_id where executor0_.id=?
Hibernate: select executor0_.id as id1_3_1_, executor0_.parent_id as parent_i2_3_1_, params3x1_.parent_id as parent_i3_6_3_, params3x1_.prop as prop1_6_3_, params3x1_.prop as prop1_6_0_, params3x1_.parent_id as parent_i3_6_0_, params3x1_.value as value2_6_0_ from executor executor0_ left outer join paraaaamsssck params3x1_ on executor0_.id=params3x1_.parent_id where executor0_.id=?
Hibernate: select executor0_.id as id1_3_1_, executor0_.parent_id as parent_i2_3_1_, params3x1_.parent_id as parent_i3_6_3_, params3x1_.prop as prop1_6_3_, params3x1_.prop as prop1_6_0_, params3x1_.parent_id as parent_i3_6_0_, params3x1_.value as value2_6_0_ from executor executor0_ left outer join paraaaamsssck params3x1_ on executor0_.id=params3x1_.parent_id where executor0_.id=?
Hibernate: select executor0_.id as id1_3_1_, executor0_.parent_id as parent_i2_3_1_, params3x1_.parent_id as parent_i3_6_3_, params3x1_.prop as prop1_6_3_, params3x1_.prop as prop1_6_0_, params3x1_.parent_id as parent_i3_6_0_, params3x1_.value as value2_6_0_ from executor executor0_ left outer join paraaaamsssck params3x1_ on executor0_.id=params3x1_.parent_id where executor0_.id=?
Hibernate: select executor0_.id as id1_3_1_, executor0_.parent_id as parent_i2_3_1_, params3x1_.parent_id as parent_i3_6_3_, params3x1_.prop as prop1_6_3_, params3x1_.prop as prop1_6_0_, params3x1_.parent_id as parent_i3_6_0_, params3x1_.value as value2_6_0_ from executor executor0_ left outer join paraaaamsssck params3x1_ on executor0_.id=params3x1_.parent_id where executor0_.id=?
2019-04-19 11:05:19 WARN  [localhost-startStop-1] AnnotationConfigServletWebServerApplicationContext.refresh: Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'fixingTheSessionCrapService': Invocation of init method failed; nested exception is java.lang.StackOverflowError
2019-04-19 11:05:19 INFO  [localhost-startStop-1] ExecutorService.killRunningSessions: Killing any running sessions
2019-04-19 11:05:19 INFO  [localhost-startStop-1] ExecutorService.killRunningSessions: Done. ATA closed gracefully
2019-04-19 11:05:19 INFO  [localhost-startStop-1] ThreadPoolTaskExecutor.shutdown: Shutting down ExecutorService 'getDaemonThreadPool'
2019-04-19 11:05:19 INFO  [localhost-startStop-1] LocalContainerEntityManagerFactoryBean.destroy: Closing JPA EntityManagerFactory for persistence unit 'default'
2019-04-19 11:05:19 INFO  [localhost-startStop-1] HikariDataSource.close: HikariPool-1 - Shutdown initiated...
2019-04-19 11:05:19 INFO  [localhost-startStop-1] HikariDataSource.close: HikariPool-1 - Shutdown completed.
2019-04-19 11:05:19 INFO  [localhost-startStop-1] ConditionEvaluationReportLoggingListener.logMessage: 

Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2019-04-19 11:05:19 ERROR [localhost-startStop-1] SpringApplication.reportFailure: Application run failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'fixingTheSessionCrapService': Invocation of init method failed; nested exception is java.lang.StackOverflowError
    at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization(InitDestroyAnnotationBeanPostProcessor.java:139)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization(AbstractAutowireCapableBeanFactory.java:414)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1770)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:593)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:515)
    at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:849)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:877)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:549)
    at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:142)
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:775)
    at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:316)
    at org.springframework.boot.web.servlet.support.SpringBootServletInitializer.run(SpringBootServletInitializer.java:157)
    at org.springframework.boot.web.servlet.support.SpringBootServletInitializer.createRootApplicationContext(SpringBootServletInitializer.java:137)
    at org.springframework.boot.web.servlet.support.SpringBootServletInitializer.onStartup(SpringBootServletInitializer.java:91)
    at org.springframework.web.SpringServletContainerInitializer.onStartup(SpringServletContainerInitializer.java:171)
    at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5245)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1420)
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1410)
    at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
    at java.base/java.lang.Thread.run(Thread.java:844)
Caused by: java.lang.StackOverflowError: null
    at java.base/java.nio.charset.CharsetEncoder.encode(CharsetEncoder.java:578)
    at java.base/sun.nio.cs.StreamEncoder.implWrite(StreamEncoder.java:292)
    at java.base/sun.nio.cs.StreamEncoder.implWrite(StreamEncoder.java:281)
    at java.base/sun.nio.cs.StreamEncoder.write(StreamEncoder.java:125)
    at java.base/java.io.OutputStreamWriter.write(OutputStreamWriter.java:211)
    at java.base/java.io.BufferedWriter.flushBuffer(BufferedWriter.java:120)
    at java.base/java.io.PrintStream.write(PrintStream.java:526)
    at java.base/java.io.PrintStream.print(PrintStream.java:666)
    at java.base/java.io.PrintStream.println(PrintStream.java:803)
    at org.apache.tomcat.util.log.SystemLogHandler.println(SystemLogHandler.java:267)
    at org.hibernate.engine.jdbc.spi.SqlStatementLogger.logStatement(SqlStatementLogger.java:96)
    at org.hibernate.engine.jdbc.spi.SqlStatementLogger.logStatement(SqlStatementLogger.java:78)
    at org.hibernate.engine.jdbc.internal.StatementPreparerImpl$StatementPreparationTemplate.prepareStatement(StatementPreparerImpl.java:167)
    at org.hibernate.engine.jdbc.internal.StatementPreparerImpl.prepareQueryStatement(StatementPreparerImpl.java:148)
    at org.hibernate.loader.Loader.prepareQueryStatement(Loader.java:1984)
    at org.hibernate.loader.Loader.executeQueryStatement(Loader.java:1914)
    at org.hibernate.loader.Loader.executeQueryStatement(Loader.java:1892)
    at org.hibernate.loader.Loader.doQuery(Loader.java:937)
    at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:340)
    at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:310)
    at org.hibernate.loader.Loader.loadEntity(Loader.java:2281)
    at org.hibernate.loader.entity.AbstractEntityLoader.load(AbstractEntityLoader.java:64)
    at org.hibernate.loader.entity.AbstractEntityLoader.load(AbstractEntityLoader.java:54)
    at org.hibernate.persister.entity.AbstractEntityPersister.load(AbstractEntityPersister.java:4271)
    at org.hibernate.event.internal.DefaultLoadEventListener.loadFromDatasource(DefaultLoadEventListener.java:511)
    at org.hibernate.event.internal.DefaultLoadEventListener.doLoad(DefaultLoadEventListener.java:481)
    at org.hibernate.event.internal.DefaultLoadEventListener.load(DefaultLoadEventListener.java:222)
    at org.hibernate.event.internal.DefaultLoadEventListener.proxyOrLoad(DefaultLoadEventListener.java:281)
    at org.hibernate.event.internal.DefaultLoadEventListener.doOnLoad(DefaultLoadEventListener.java:124)
    at org.hibernate.event.internal.DefaultLoadEventListener.onLoad(DefaultLoadEventListener.java:92)
    at org.hibernate.internal.SessionImpl.fireLoad(SessionImpl.java:1256)
    at org.hibernate.internal.SessionImpl.internalLoad(SessionImpl.java:1139)
    at org.hibernate.type.EntityType.resolveIdentifier(EntityType.java:682)
    at org.hibernate.type.EntityType.resolve(EntityType.java:464)
    at org.hibernate.type.ManyToOneType.resolve(ManyToOneType.java:239)
    at org.hibernate.type.EntityType.resolve(EntityType.java:457)
    at org.hibernate.type.ComponentType.resolve(ComponentType.java:688)
    at org.hibernate.loader.Loader.extractKeysFromResultSet(Loader.java:862)
    at org.hibernate.loader.Loader.getRowFromResultSet(Loader.java:718)
    at org.hibernate.loader.Loader.processResultSet(Loader.java:990)
    at org.hibernate.loader.Loader.doQuery(Loader.java:948)
    at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:340)
    at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:310)
    at org.hibernate.loader.Loader.loadEntity(Loader.java:2281)
    at org.hibernate.loader.entity.AbstractEntityLoader.load(AbstractEntityLoader.java:64)
    at org.hibernate.loader.entity.AbstractEntityLoader.load(AbstractEntityLoader.java:54)
    at org.hibernate.persister.entity.AbstractEntityPersister.load(AbstractEntityPersister.java:4271)
    at org.hibernate.event.internal.DefaultLoadEventListener.loadFromDatasource(DefaultLoadEventListener.java:511)
    at org.hibernate.event.internal.DefaultLoadEventListener.doLoad(DefaultLoadEventListener.java:481)
    at org.hibernate.event.internal.DefaultLoadEventListener.load(DefaultLoadEventListener.java:222)
    at org.hibernate.event.internal.DefaultLoadEventListener.proxyOrLoad(DefaultLoadEventListener.java:281)
    at org.hibernate.event.internal.DefaultLoadEventListener.doOnLoad(DefaultLoadEventListener.java:124)
    at org.hibernate.event.internal.DefaultLoadEventListener.onLoad(DefaultLoadEventListener.java:92)

И это идет по длинной петле, пока не появится исключение StackOverflow. В конце говорится:

at org.hibernate.internal.SessionImpl.fireLoad(SessionImpl.java:1256)
    at org.hibernate.internal.SessionImpl.internalLoad(SessionImpl.java:1139)
    at org.hibernate.type.EntityType.resolveIdentifier(EntityType.java:682)
    at org.hibernate.type.EntityType.resolve(EntityType.java:464)
    at org.hibernate.type.ManyToOneType.resolve(ManyToOneType.java:239)

Ответы [ 2 ]

1 голос
/ 19 апреля 2019

1) Сделать вас идентификатором класса Embeddable, поскольку у вас есть отношение ManyToOne как часть идентификатора:

@Embeddable
class ChildID implements Serializable{

  @ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
  @JoinColumn(name = "parent_id")
  private Parent parent;
  private int id;

2) Измените класс Child:

@Entity
class Child {

   @EmbeddedId
   private ChildID id;

3) Измените mappedBy на родительском объекте, чтобы учесть встроенное отношение:

   @OneToMany(mappedBy="id.parent")
   @Cascasde(value = CascadeType.ALL)
   private List<Child> list = ...;
0 голосов
/ 19 апреля 2019

Если кто-то наткнется на это (или пока не будет найдено лучшее решение), вот что на самом деле сработало для меня (я приношу свои извинения за утомляющий глаза класс и присвоение имен элементам, пробовал это в течение последних нескольких дней).Взято из @ OneToMany и составных первичных ключей?

@Entity
@Table(name = "paraaaamsssCK")
public class Param1CK {
    @EmbeddedId
    private Param1CKEmbeddable key;

    @Column(name = "value")
    private String value;

    @MapsId("parentId")
    @ManyToOne
    @JoinColumn
    public Executor parent;


    public Param1CK() {
        super();
    }



    public Param1CK(Executor parent, String id, String value) {
        key = new Param1CKEmbeddable(id);
        this.parent = parent;
        this.value = value;
    }
}

Вот определение Embeddable:

@Embeddable
public class Param1CKEmbeddable implements Serializable{
    private int parentId;
    private String id;

public Param1CKEmbeddable () {}

public Param1CKEmbeddable(int parentId, String id) {
    this.parentId = parentId;
    this.id = id;
}

public Param1CKEmbeddable(String id) {
    this.id = id;
}


@Override
public int hashCode() {
    return Objects.hash(parentId, id);
}

}

От «Родителя» связь проста:

@OneToMany(mappedBy="parent")
@Cascade(value = CascadeType.ALL)
private List<Param1CK> params3 = new LinkedList<Param1CK>();

Надеюсь, это поможет следующему человеку, который столкнется с этой проблемой.

...