Spring Data JPA Criteria API-如何在两个实体中按字段搜索?

时间:2018-08-28 01:32:23

标签: spring hibernate jpa hibernate-criteria 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()
    ...
}

因此,我需要按“地点”条件查找所有“要约”。我已经尝试过了:

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)

如何找到其伙伴所在城市的所有优惠?

1 个答案:

答案 0 :(得分:0)

哦,这很简单。

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)
    )
}