Spring JPA OneToOne与常量值的关系

时间:2017-01-10 16:34:52

标签: java spring jpa groovy spring-boot

我正在将遗留应用程序转换为Spring Boot,Groovy,JPA解决方案,并发现自己的查询形式为:

SELECT ...
FROM table1, table2
WHERE table1.field1 = table2.field1 AND
  table1.field2 = table2.field2 and
  table2.field3 = 'ABC'

正如您所看到的,连接是在三个字段上执行的,其中两个字段基于table1中的数据,第三个字段是常量字符串。

所以,对于我用Google搜索的内容(即http://docs.oracle.com/cd/E13189_01/kodo/docs40/full/html/ref_guide_mapping_notes_nonstdjoins.html),我发现解决方案是:

@Entity
@Table(name = "Table1")
class Table1 {

  // other column definitions here

  @OneToOne(cascade = CascadeType.ALL)
  @JoinColumns([
    @JoinColumn(name="field1", referencedColumnName="field1"),
    @JoinColumn(name="field2", referencedColumnName="field2"),
    @JoinColumn(name="table2.field3", referencedColumnName="'ABC'")]
    )
  Table2 table2
}

当我运行这个时,我得到一个"无法找到具有逻辑名称的列:' ABC'在表2和#34;例外:

Caused by: org.hibernate.MappingException: Unable to find column with logical name: 'ABC' in table2
    at org.hibernate.cfg.Ejb3JoinColumn.checkReferencedColumnsType(Ejb3JoinColumn.java:854) ~[hibernate-core-5.0.9.Final.jar:5.0.9.Final]
    at org.hibernate.cfg.BinderHelper.createSyntheticPropertyReference(BinderHelper.java:241) ~[hibernate-core-5.0.9.Final.jar:5.0.9.Final]
    at org.hibernate.cfg.ToOneFkSecondPass.doSecondPass(ToOneFkSecondPass.java:100) ~[hibernate-core-5.0.9.Final.jar:5.0.9.Final]
    at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.processEndOfQueue(InFlightMetadataCollectorImpl.java:1786) ~[hibernate-core-5.0.9.Final.jar:5.0.9.Final]
    at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.processFkSecondPassesInOrder(InFlightMetadataCollectorImpl.java:1730) ~[hibernate-core-5.0.9.Final.jar:5.0.9.Final]
    at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.processSecondPasses(InFlightMetadataCollectorImpl.java:1617) ~[hibernate-core-5.0.9.Final.jar:5.0.9.Final]
    at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.complete(MetadataBuildingProcess.java:278) ~[hibernate-core-5.0.9.Final.jar:5.0.9.Final]
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.metadata(EntityManagerFactoryBuilderImpl.java:847) ~[hibernate-entitymanager-5.0.9.Final.jar:5.0.9.Final]
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:874) ~[hibernate-entitymanager-5.0.9.Final.jar:5.0.9.Final]
    at org.springframework.orm.jpa.vendor.SpringHibernateJpaPersistenceProvider.createContainerEntityManagerFactory(SpringHibernateJpaPersistenceProvider.java:60) ~[spring-orm-4.3.2.RELEASE.jar:4.3.2.RELEASE]

然而,这个解决方案似乎只适用于@OneToMany关系,如引用示例所示。

我正在尝试连接到一个遗留的Informix数据库,对于该数据库来说,更改模式是完全不可能的。 除此之外,我的build.gradle看起来像这样(相关部分):

buildscript {
  repositories {
     // ...
  }
  dependencies { classpath('org.springframework.boot:spring-boot-gradle-plugin:1.4.0.RELEASE') }
}

apply plugin: 'groovy'
apply plugin: 'spring-boot'

defaultTasks 'clean', 'assemble'

sourceCompatibility = 1.8
targetCompatibility = 1.8

repositories {
   // ...
}

dependencies {
  compile "org.springframework.boot:spring-boot-starter-web"
  compile "org.springframework.boot:spring-boot-starter-actuator"
  compile "org.springframework.boot:spring-boot-starter-data-jpa"
  compile "org.springframework:spring-jms"
  compile "org.apache.cxf:cxf-rt-frontend-jaxws:${cxfVersion}"
  compile "org.apache.cxf:cxf-rt-transports-http:${cxfVersion}"

  compile "org.codehaus.groovy:groovy-all:2.4.4"
  compile "informix:informix-jdbc:${informixVersion}"
  compile "informix:informix-jdbcx:${informixVersion}"

  testCompile "org.springframework.boot:spring-boot-starter-test"
  testCompile "org.spockframework:spock-core:${spockVersion}"
  testCompile "org.spockframework:spock-spring:${spockVersion}"
  testCompile "junit:junit:4.12"
  testCompile "org.springframework:spring-test"
}

有没有人遇到这样的问题?或者解决这种情况的正确方法是什么?

非常感谢您的帮助

1 个答案:

答案 0 :(得分:0)

我认为你正在混合一些术语。 JoinColumns与Many-To-Many关系一起使用。您正在尝试将连接构建到实体之间的关系中,这不是JPA的工作原理。

实体是表的映射。在旧版查询table1和table2中,每个都有一个具有相同值的field1,您可以在查询中使用它来创建连接。这并不意味着Table1与Table2具有一对一的关系,这意味着这两个表的列恰好具有相同的值(这可能是第三个实体的PK)。如果两个表具有一对一关系,则其中一个表将包含一个外键列,其中包含相关表的主键。

您仍然可以执行JPA查询,该查询将选择数据,但它不会很漂亮。

List<Object[]> resultList = em.createQuery(
   "select t1, t2 from Table1 t1, Table2 t2 
    where t1.field1 = t2.field1 and t1.field2 = t2.field2 
    and t2.field3='ABC'", Object[].class).getResultList();

正如您所看到的,这看起来几乎完全是您的原生SQL,但结果是Object[]的列表,每个都有两个对象,第一个是t1,第二个是t2。

我已经和JPA合作了很长时间,并且很少看到Object[]作为结果类型,它几乎总是意味着你已经模拟了错误。