broken column mapping: OneToOne unidirectional with two join columns

2.3k Views Asked by At

I have two given tables (posgres) with the following fields (all big ints):

Transaction:

  • transactionid
  • reader_id
  • readertrxref
  • ...

Reversal:

  • reversalid
  • trxref
  • readerid
  • ...

There is an optional 1:1 relationship between Transaction and Reversal: Transaction exists always; Reversal exists, if the transaction has been reversed. The relationship is done with a composite foreign key in reversal (reader_id, trxref). The tables are given this way and I need to map them in JPA. I need to map Reversal in Transaction that I can navigate in named queries i.e. SELECT FROM Transaction t LEFT JOIN t.reversal rv ....

So what I do is:

@Entity
@Table(
        indexes = {
                @Index(columnList = "readerTrxRef,reader_id", unique = true),
        }
)
public class Transaction
{
    static final Long serialVersionUID = 1L;

    @Id
    @GeneratedValue
    private Long transactionid;

    private Long reader_id;

    private Long readertrxref

    @OneToOne(fetch = FetchType.EAGER, mappedBy = "transaction")
    private Reversal reversal;

    ...
}


@Entity
@Table(
        indexes = {
                @Index(columnList = "readerID,trxRef", unique = true),
        }
)
public class Reversal
{
    static final Long serialVersionUID = 1L;

    @Id
    @GeneratedValue
    private Long id;

    private Integer trxref;

    private Long readerid;

    public Integer getTrxRef()
    {
        return trxRef;
    }

    @OneToOne
    @JoinColumns(
            {
                    @JoinColumn(updatable = false, insertable = false, name = "readerid", referencedColumnName = "reader_id"),
                    @JoinColumn(updatable = false, insertable = false, name = "trxref", referencedColumnName = "readertrxref"),
            }
    )
    private Transaction transaction;

During deployment, I get the following exception:

14:24:12,455 ERROR [org.jboss.msc.service.fail] (ServerService Thread Pool -- 24) MSC000001: Failed to start service jboss.persistenceunit."ROOT.war#primary": org.jboss.msc.service.StartException in service jboss.persistenceunit."ROOT.war#primary": javax.persistence.PersistenceException: [PersistenceUnit: primary] 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: primary] 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.MappingException: broken column mapping for: reversal.transaction of: ch.microtronic.evending.web.model.entities.Transaction
    at org.hibernate.persister.entity.AbstractPropertyMapping.initPropertyPaths(AbstractPropertyMapping.java:165)
    at org.hibernate.persister.entity.AbstractPropertyMapping.initIdentifierPropertyPaths(AbstractPropertyMapping.java:253)
    at org.hibernate.persister.entity.AbstractPropertyMapping.initPropertyPaths(AbstractPropertyMapping.java:219)
    at org.hibernate.persister.entity.AbstractEntityPersister.initOrdinaryPropertyPaths(AbstractEntityPersister.java:2194)
    at org.hibernate.persister.entity.AbstractEntityPersister.initPropertyPaths(AbstractEntityPersister.java:2241)
    at org.hibernate.persister.entity.AbstractEntityPersister.postConstruct(AbstractEntityPersister.java:3790)
    at org.hibernate.persister.entity.SingleTableEntityPersister.<init>(SingleTableEntityPersister.java:437)
    at sun.reflect.GeneratedConstructorAccessor62.newInstance(Unknown Source)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
    at org.hibernate.persister.internal.PersisterFactoryImpl.createEntityPersister(PersisterFactoryImpl.java:96)
    at org.hibernate.persister.internal.PersisterFactoryImpl.createEntityPersister(PersisterFactoryImpl.java:77)
    at org.hibernate.internal.SessionFactoryImpl.<init>(SessionFactoryImpl.java:346)
    at org.hibernate.boot.internal.SessionFactoryBuilderImpl.build(SessionFactoryBuilderImpl.java:444)
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:879)
    ... 9 more

Can anybody point me to the fault? I just tried to remove @JoinColumns and to have just one @JoinColumn. In this case, I can deploy the application - this shows me that it is a strange error and I am not very amazed, if it is a bug in hibernate even though I thougth this is a not very exotic use case. (we use Hibernate 5.2.12 in Wildfly 10.1.0).

Edit Clarified that the mapping is transaction(reader_id, readertrxref)->reversal(readerid, trxref) and that this is given this way. I need to map it this way and I cannot use transactionid as foreign key in reversal because it does (due to technical reason) not exist in this table.

2

There are 2 best solutions below

0
On BEST ANSWER

It is not possible to solve that. As Tom and DN1 pointed out, JoinColumns must be on the PKs. Since they are not the PKs in my use case and I cannot make them to be a composite PK (because the relation Transaction->Reversal is optional and thus, I still need a real PK i.e. transactionID), it seems not to be possible to solve this with JPA.

2
On

Tables are joint by using the primary key. In your case it would be the following:

@OneToOne
@JoinColumn(name = "transactionid")
private Transaction transaction;

The @JoinColumnsannotation is used for composite primary keys.

I recomend reading the wikibooks.