我正在将遗留应用程序转换为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"
}
有没有人遇到这样的问题?或者解决这种情况的正确方法是什么?
非常感谢您的帮助
答案 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[]
作为结果类型,它几乎总是意味着你已经模拟了错误。