spring - Spring Data JPA Criteria API - 如何在两个实体中按字段进行搜索?
问题描述
我有 3 个不同的实体:Partner
是主要实体,Offer
是合作伙伴的报价(多对一),Location
是合作伙伴中的任何位置。
@Entity
class ObjectLocation(@ManyToOne var place: Place, var partnerId: String) {
constructor() : this(Place(), "")
@Id
var id: String = IDGenerator.longId()
// other fields omitted
...
}
@Entity
class Offer(var partnerId: String, ...) {
constructor() : this(...)
@Id
var id: String = IDGenerator.longId()
...
}
@Entity
class Partner(...) {
constructor() : this(...)
@Id
var id: String = IDGenerator.longId()
...
}
因此,我需要按 Place 条件查找所有 Offer。我试过这个:
Specification {
root: Root<Offer>, criteriaQuery: CriteriaQuery<*>, criteriaBuilder: CriteriaBuilder ->
val objectLocationRoot = criteriaQuery.from(ObjectLocation::class.java)
val objectCityId: Expression<String> = objectLocationRoot
.get<Place>("place")
.get<City>("parentCity")
.get<String>("id")
val objectPartnerId: Expression<String> = objectLocationRoot.get<String>("partnerId")
val offerPartnerId: Expression<String> = root.get<String>("partnerId")
val goodLocations: Predicate = criteriaBuilder.equal(objectCityId, cityId)
val objQuery: Subquery<String> = criteriaQuery.subquery(String::class.java)
.select(objectPartnerId)
.where(goodLocations)
return@Specification criteriaBuilder.equal(objQuery, offerPartnerId)
}
但这只给了我以下例外:
antlr.NoViableAltException: unexpected token: where
at org.hibernate.hql.internal.antlr.HqlBaseParser.fromRange(HqlBaseParser.java:1519) [hibernate-core-5.2.17.Final.jar:5.2.17.Final]
at org.hibernate.hql.internal.antlr.HqlBaseParser.fromClause(HqlBaseParser.java:1343) [hibernate-core-5.2.17.Final.jar:5.2.17.Final]
at org.hibernate.hql.internal.antlr.HqlBaseParser.selectFrom(HqlBaseParser.java:1063) [hibernate-core-5.2.17.Final.jar:5.2.17.Final]
at org.hibernate.hql.internal.antlr.HqlBaseParser.queryRule(HqlBaseParser.java:748) [hibernate-core-5.2.17.Final.jar:5.2.17.Final]
at org.hibernate.hql.internal.antlr.HqlBaseParser.subQuery(HqlBaseParser.java:3910) [hibernate-core-5.2.17.Final.jar:5.2.17.Final]
at org.hibernate.hql.internal.antlr.HqlBaseParser.primaryExpression(HqlBaseParser.java:967) [hibernate-core-5.2.17.Final.jar:5.2.17.Final]
at org.hibernate.hql.internal.antlr.HqlBaseParser.atom(HqlBaseParser.java:3549) [hibernate-core-5.2.17.Final.jar:5.2.17.Final]
....
org.springframework.dao.InvalidDataAccessApiUsageException: org.hibernate.hql.internal.ast.QuerySyntaxException: unexpected token: where near line 1, column 175
[select generatedAlias0 from com.arkell.entity.Offer as generatedAlias0, com.arkell.entity.geo.ObjectLocation as generatedAlias1 where
(select generatedAlias1.partnerId from where generatedAlias1.place.parentCity.id=:param0)=generatedAlias0.partnerId]; nested exception is java.lang.IllegalArgumentException:
org.hibernate.hql.internal.ast.QuerySyntaxException: unexpected token: where near line 1, column 175 [select generatedAlias0
from com.arkell.entity.Offer as generatedAlias0, com.arkell.entity.geo.ObjectLocation as generatedAlias1 where
(select generatedAlias1.partnerId from where generatedAlias1.place.parentCity.id=:param0)=generatedAlias0.partnerId]
at org.springframework.orm.jpa.EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(EntityManagerFactoryUtils.java:367)
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:227)
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:527)
at org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:61)
at org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:242)
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:153)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185)
at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:135)
如何通过合作伙伴所在城市找到所有报价?
解决方案
哦,哇,这很容易。
Specification {
root: Root<Offer>, criteriaQuery: CriteriaQuery<*>, criteriaBuilder: CriteriaBuilder ->
val objectLocationRoot: Root<ObjectLocation> = criteriaQuery.distinct(true).from(ObjectLocation::class.java)
return@Specification criteriaBuilder.and(
criteriaBuilder.equal(root.get<String>("partnerId"), objectLocationRoot.get<String>("partnerId")),
criteriaBuilder.equal(objectLocationRoot.get<Place>("place")
.get<City>("parentCity")
.get<String>("id")("streetType"), cityId)
)
}
推荐阅读
- tensorflow - 使用“tf.compat.v1.metrics.auc”的最佳实践?
- android - 模拟器或物理设备的 AOSP Android 12 Beta2 版本构建失败
- python - 使用 seaborn 创建多条曲线
- android - 如何使用 CameraX 录制没有音频的视频
- node.js - 谷歌云上的 NodeJs Docker 部署运行
- regex - vscode 跨文件查找和替换,如果多个匹配在同一行上,则重复反向引用
- vue.js - appvue 需要一个元素 (vue2)
- java - 为什么每个 else 子句都会出现“非法类型开始”错误?
- java - 并行还是并发?Java并发命名问题
- python - 使用变量调用另一个pythonfile中的数据框