I have a @OneToOne
annotation which I want to join on 2 possible columns. I know how to do it with a plain SQL query, but I have no idea how this could work with hibernate annotations.
Following entity:
@Entity
public class Foo {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
@OneToOne
@JoinColumn(name = "cancelRecord")
private Foo cancelRecord;
private String externalId;
private String externalCancellationId;
}
and the corresponding database table:
create table Foo(
id int identity(1,1) not null primary key, --primary key
cancelRecord int,
externalId varchar(100),
externalCancellationId varchar(100)
)
So far cancelRecord
is only joined on that column. Now I want it to join on either cancelRecord
or externalCancellationId
. A valid SQL query for that would be:
SELECT f.*
FROM Foo f
INNER JOIN Foo fo
ON (f.cancelRecord = fo.id
OR f.externalCancellationId = fo.externalId)
The crucial part about this query is the OR
in the join clause (f.cancelRecord = fo.id **OR** f.externalCancellationId = fo.externalId)
.
I assume that this is not possible with @JoinColumn
and I'd need to rely on @JoinFormula
in some way.
Is that assumption right? If so, would I simply need to copy the above query as @JoinFormula
?
I tried to use this @JoinFoluma
:
@OneToOne
@JoinFormula(value = "SELECT f.*
FROM Foo f
INNER JOIN Foo fo
ON (f.cancelRecord = fo.id
OR f.externalCancellationId = fo.externalId)")
private Foo cancelRecord;
This causes an NullPointerException
when loading the spring context:
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sessionFactory' defined in class path resource [spring/test-database.xml]: Invocation of init method failed; nested exception is java.lang.NullPointerException
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1589)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:554)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:351)
... 43 common frames omitted
Caused by: java.lang.NullPointerException: null
at org.hibernate.cfg.AnnotationBinder.bindOneToOne(AnnotationBinder.java:3185)
at org.hibernate.cfg.AnnotationBinder.processElementAnnotations(AnnotationBinder.java:1798)
at org.hibernate.cfg.AnnotationBinder.processIdPropertiesIfNotAlready(AnnotationBinder.java:961)
at org.hibernate.cfg.AnnotationBinder.bindClass(AnnotationBinder.java:788)
at org.hibernate.boot.model.source.internal.annotations.AnnotationMetadataSourceProcessorImpl.processEntityHierarchies(AnnotationMetadataSourceProcessorImpl.java:250)
at org.hibernate.boot.model.process.spi.MetadataBuildingProcess$1.processEntityHierarchies(MetadataBuildingProcess.java:231)
at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.complete(MetadataBuildingProcess.java:274)
at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.build(MetadataBuildingProcess.java:84)
at org.hibernate.boot.internal.MetadataBuilderImpl.build(MetadataBuilderImpl.java:474)
at org.hibernate.boot.internal.MetadataBuilderImpl.build(MetadataBuilderImpl.java:85)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:689)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:724)
at org.springframework.orm.hibernate5.LocalSessionFactoryBean.buildSessionFactory(LocalSessionFactoryBean.java:511)
at org.springframework.orm.hibernate5.LocalSessionFactoryBean.afterPropertiesSet(LocalSessionFactoryBean.java:495)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1648)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1585)
... 50 common frames omitted
EDIT:
Exception resolved with this question, but sadly this again ends with an AND
instead of an OR
.