Hibernate @OneToOne在连接子句中使用OR进行自我连接

时间:2019-07-31 07:44:04

标签: java hibernate jpa

我有一个@OneToOne批注,我想在2个可能的列上加入。我知道如何通过普通的SQL查询来做到这一点,但我不知道如何使用休眠注释。

以下实体:

@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;
}

和相应的数据库表:

create table Foo(
    id int identity(1,1) not null primary key, --primary key
    cancelRecord int,
    externalId varchar(100),
    externalCancellationId varchar(100)
)

到目前为止,cancelRecord仅加入该列。现在,我希望它加入cancelRecordexternalCancellationId上。有效的SQL查询为:

SELECT f.* 
FROM Foo f 
        INNER JOIN Foo fo 
        ON (f.cancelRecord = fo.id 
        OR f.externalCancellationId = fo.externalId)

此查询的关键部分是连接子句OR中的 (f.cancelRecord = fo.id **OR** f.externalCancellationId = fo.externalId)

我认为@JoinColumn无法做到这一点,我需要以某种方式依赖@JoinFormula

该假设正确吗?如果是这样,我是否只需要将上述查询复制为@JoinFormula


我尝试使用此@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;

这会在加载spring上下文时导致NullPointerException

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

编辑:

使用this question解决了异常,但遗憾的是,它再次以AND而不是OR结尾。

2 个答案:

答案 0 :(得分:1)

由于@JoinColumn@JoinFormula用于确定外键列值,因此该方法不起作用,因此它们不适用于多个列。

如果定义多个@JoinColumn@JoinFormula,则ON关系将使用AND而不是OR

在您的情况下,由于您可能只想读取此关联,而不是使用Hibernate进行设置,因此最好使用SQL查询。

答案 1 :(得分:-2)

您可以使用多个@JoinColumn注释。请参见下面的示例:

   @OneToOne
   @JoinColumns(
     {
       @JoinColumn(updatable=false,insertable=false, name="cancelRecord", referencedColumnName="cancelRecord"),
       @JoinColumn(updatable=false,insertable=false, name="other", referencedColumnName="other")
     }
   )
   private Foo cancelRecord;