3

Working with existing working Hibernate 3 code that was deployed on Jboss 4 and now I'm trying to deploy it on Wildfly 10 (Hibernate 5). During the validation done at deployment time, the following message is displayed:

org.hibernate.persister.walking.spi.WalkingException: Association has already been visited: AssociationKey(table=pur_DemandDtl_DemandHeader, columns={DemandEventHeaderTRIk})

(i will show the full stack below)

First I'll give a summary: There are 3 classes involved. In 2 classes there is a member set annotated as ManyToMany and it's unidirectional. The Set has members of the 3rd class.

There are 3 tables corresponding to each of the 3 classes. In addition there is a 4th table which represents BOTH associations. This 4th table has 3 columns. Each column corresponds to one of the tables. Obviously in each row one of the two columns associated with the two tables has a null value.

I have almost no experience with Hibernate, but it looks like each relationship is defined exactly as in all the examples I've seen. The only questions in my mind are: 1) do I have to do something else because there are 2 tables in a relationship with the third? 2) is it legitimate to hold both associations in the same association table? 3) is the hierarchy of the first 2 classes problemtic?

OK, now I'll show some code. I'll omit some details and will add later if needed.

The first 2 classes, are PromoDtl and ReserveDtl. They share a common superclass PromoReserveDtl, and each has a unidirectional ManyToMany relationship to the third class DemandEventHeaderTriggerRecord.

@MappedSuperclass
public abstract class PromoReserveDtl implements Serializable,Comparable<PromoReserveDtl>{

    private Integer promoReserveDtlIk;
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
        @Column(name = "PromoReserveDtlIk")
    public Integer getPromoReserveDtlIk() {
        return promoReserveDtlIk;
    }
    protected Set<DemandEventHeaderTriggerRecord> demandEventHeaderTriggerRecord = new HashSet<DemandEventHeaderTriggerRecord>();
    public void setDemandEventHeaderTriggerRecord(Set<DemandEventHeaderTriggerRecord> demandEventHeaderTriggerRecord) {
        this.demandEventHeaderTriggerRecord = demandEventHeaderTriggerRecord;
    }
    // other stuff
}  

@Entity
@Table(name="pur_PromoDtl")
public class PromoDtl extends PromoReserveDtl implements Serializable{
    @ManyToMany(fetch = FetchType.EAGER,cascade = { CascadeType.ALL })
    @JoinTable(name="pur_DemandDtl_DemandHeader",
          joinColumns=@JoinColumn(name="PromoDtlIk"),
          inverseJoinColumns=@JoinColumn(name="DemandEventHeaderTRIk"))
    public Set<DemandEventHeaderTriggerRecord> getDemandEventHeaderTriggerRecord() {
        return demandEventHeaderTriggerRecord;
    }
    // other stuff
}

@Entity
@Table(name="pur_ReserveDtl")
public class ReserveDtl extends PromoReserveDtl implements Serializable {
    @ManyToMany(fetch = FetchType.EAGER,cascade = { CascadeType.ALL })
    @JoinTable(name="pur_DemandDtl_DemandHeader",
          joinColumns=@JoinColumn(name="ReserveDtlIk"),
          inverseJoinColumns=@JoinColumn(name="DemandEventHeaderTRIk"))
    public Set<DemandEventHeaderTriggerRecord> getDemandEventHeaderTriggerRecord() {
        return demandEventHeaderTriggerRecord;
    }
    // other stuff
}

@Entity
@Table(name="pur_DemandEventHeaderTriggerRecord")
public class DemandEventHeaderTriggerRecord  implements Serializable{
    private Integer demandEventHeaderTRIk;
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "DemandEventHeaderTRIk")
    public Integer getDemandEventHeaderTRIk() {
        return demandEventHeaderTRIk;
    }
    public boolean equals(Object other) {
        //...
    }
    public int hashCode() {
        //...
    }
}

The associations table is defined as follows:

CREATE TABLE [dbo].[pur_DemandDtl_DemandHeader](
    [PromoDtlIk] [int] NULL,
    [ReserveDtlIk] [int] NULL,
    [DemandEventHeaderTRIk] [int] NOT NULL
) ON [PRIMARY]

The Full stack trace logged at deployment is the following:

2016-11-22 14:51:07,765 ERROR [org.jboss.msc.service.fail] (ServerService Thread Pool -- 84) MSC000001: Failed to start service jboss.persistenceunit."InSyncEar-11.0.0-SNAPSHOT.ear/PurchasingServices.jar#purchasingpersistence": org.jboss.msc.service.StartException in service jboss.persistenceunit."InSyncEar-11.0.0-SNAPSHOT.ear/PurchasingServices.jar#purchasingpersistence": javax.persistence.PersistenceException: [PersistenceUnit: purchasingpersistence] Unable to build Hibernate SessionFactory
at org.jboss.as.jpa.service.PersistenceUnitServiceImpl$1$1.run(PersistenceUnitServiceImpl.java:179)
at org.jboss.as.jpa.service.PersistenceUnitServiceImpl$1$1.run(PersistenceUnitServiceImpl.java:121)
at org.wildfly.security.manager.WildFlySecurityManager.doChecked(WildFlySecurityManager.java:667)
at org.jboss.as.jpa.service.PersistenceUnitServiceImpl$1.run(PersistenceUnitServiceImpl.java:193)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
at org.jboss.threads.JBossThread.run(JBossThread.java:320)
Caused by: javax.persistence.PersistenceException: [PersistenceUnit: purchasingpersistence] Unable to build Hibernate SessionFactory
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.persistenceException(EntityManagerFactoryBuilderImpl.java:954)
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:882)
at org.jboss.as.jpa.hibernate5.TwoPhaseBootstrapImpl.build(TwoPhaseBootstrapImpl.java:44)
at org.jboss.as.jpa.service.PersistenceUnitServiceImpl$1$1.run(PersistenceUnitServiceImpl.java:161)
... 7 more
Caused by: org.hibernate.persister.walking.spi.WalkingException: Association has already been visited: AssociationKey(table=pur_DemandDtl_DemandHeader, columns={DemandEventHeaderTRIk})
at org.hibernate.persister.walking.spi.MetamodelGraphWalker.addAssociationKey(MetamodelGraphWalker.java:281)
at org.hibernate.persister.walking.spi.MetamodelGraphWalker.visitCollectionElements(MetamodelGraphWalker.java:257)
at org.hibernate.persister.walking.spi.MetamodelGraphWalker.visitCollectionDefinition(MetamodelGraphWalker.java:208)
at org.hibernate.persister.walking.spi.MetamodelGraphWalker.visitAssociation(MetamodelGraphWalker.java:185)
at org.hibernate.persister.walking.spi.MetamodelGraphWalker.visitAttributeDefinition(MetamodelGraphWalker.java:160)
at org.hibernate.persister.walking.spi.MetamodelGraphWalker.visitAttributes(MetamodelGraphWalker.java:131)
at org.hibernate.persister.walking.spi.MetamodelGraphWalker.visitEntityDefinition(MetamodelGraphWalker.java:94)
at org.hibernate.persister.walking.spi.MetamodelGraphWalker.visitCollectionElements(MetamodelGraphWalker.java:264)
at org.hibernate.persister.walking.spi.MetamodelGraphWalker.visitCollectionDefinition(MetamodelGraphWalker.java:208)
at org.hibernate.persister.walking.spi.MetamodelGraphWalker.visitAssociation(MetamodelGraphWalker.java:185)
at org.hibernate.persister.walking.spi.MetamodelGraphWalker.visitAttributeDefinition(MetamodelGraphWalker.java:160)
at org.hibernate.persister.walking.spi.MetamodelGraphWalker.visitAttributes(MetamodelGraphWalker.java:131)
at org.hibernate.persister.walking.spi.MetamodelGraphWalker.visitEntityDefinition(MetamodelGraphWalker.java:94)
at org.hibernate.persister.walking.spi.MetamodelGraphWalker.visitAssociation(MetamodelGraphWalker.java:188)
at org.hibernate.persister.walking.spi.MetamodelGraphWalker.visitAttributeDefinition(MetamodelGraphWalker.java:160)
at org.hibernate.persister.walking.spi.MetamodelGraphWalker.visitAttributes(MetamodelGraphWalker.java:131)
at org.hibernate.persister.walking.spi.MetamodelGraphWalker.visitEntityDefinition(MetamodelGraphWalker.java:94)
at org.hibernate.persister.walking.spi.MetamodelGraphWalker.visitEntity(MetamodelGraphWalker.java:55)
at org.hibernate.loader.plan.build.spi.MetamodelDrivenLoadPlanBuilder.buildRootEntityLoadPlan(MetamodelDrivenLoadPlanBuilder.java:39)
at org.hibernate.loader.entity.plan.AbstractLoadPlanBasedEntityLoader.<init>(AbstractLoadPlanBasedEntityLoader.java:81)
at org.hibernate.loader.entity.plan.EntityLoader.<init>(EntityLoader.java:103)
at org.hibernate.loader.entity.plan.EntityLoader.<init>(EntityLoader.java:38)
at org.hibernate.loader.entity.plan.EntityLoader$Builder.byUniqueKey(EntityLoader.java:83)
at org.hibernate.loader.entity.plan.EntityLoader$Builder.byPrimaryKey(EntityLoader.java:77)
at org.hibernate.loader.entity.plan.AbstractBatchingEntityLoaderBuilder.buildNonBatchingLoader(AbstractBatchingEntityLoaderBuilder.java:30)
at org.hibernate.loader.entity.BatchingEntityLoaderBuilder.buildLoader(BatchingEntityLoaderBuilder.java:59)
at org.hibernate.persister.entity.AbstractEntityPersister.createEntityLoader(AbstractEntityPersister.java:2254)
at org.hibernate.persister.entity.AbstractEntityPersister.createEntityLoader(AbstractEntityPersister.java:2276)
at org.hibernate.persister.entity.AbstractEntityPersister.createLoaders(AbstractEntityPersister.java:3876)
at org.hibernate.persister.entity.AbstractEntityPersister.postInstantiate(AbstractEntityPersister.java:3858)
at org.hibernate.internal.SessionFactoryImpl.<init>(SessionFactoryImpl.java:444)
at org.hibernate.boot.internal.SessionFactoryBuilderImpl.build(SessionFactoryBuilderImpl.java:444)
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:879)
... 9 more

Thanks for your time.

inor
  • 2,781
  • 2
  • 32
  • 42

1 Answers1

1

In addition there is a 4th table which represents BOTH associations. This 4th table has 3 columns. Each column corresponds to one of the tables. Obviously in each row one of the two columns associated with the two tables has a null value.

Obviously you store apples and bananas in the same table. The purpose of a JoinTable is to store exactly one relation. A JoinTable has two colums with the ids of the entities on each side (I don't know if it's possible to use composite keys, then you have correspondingly more columns). How should Hibernate handle the null values? Filter them out? Or add a null to the Set?

1) do I have to do something else because there are 2 tables in a relationship with the third?

You have to split this table in two.

2) is it legitimate to hold both associations in the same association table?

Specification legitimate: don't know. But it makes no sense.

3) is the hierarchy of the first 2 classes problemtic?

No.

  • 2
    Miranda, I checked this as the right answer, as i split the tables and now the issue is gone. However, i find it hard to believe that the relationship between two entities must be in an exclusive table and cannot be implemented just using 2 or 3 columns of a more general table? Yes, I would expect hibernate to filter out null values (since null is not an entity ). That's how it was in JBoss 4.2.3 and Hibernate 3.... This was working code before migrating it to Wildfly 10. Thanks, though, at least i got the issue resolved thanks to your answer. – inor Nov 29 '16 at 11:28