EclipseLink - 带条件查询的子查询 (JPA)

EclipseLink - Subqueries with Criteria Query (JPA)

将下面两张表作为给定:

  1. ObjectsobjIdobjTaxonId
  2. TaxataxIdtaxValidSynonymIdtaxName(注意 Taxa 是 Taxon 的复数形式)

如果Taxon有效,则其id和validSynonymId相同,否则不同。要找到分类单元的所有同义词,您 'only' 需要找到所有 taxValidSynonymId 填充有效分类单元 taxId 的分类单元

如何获得 Taxon 具有给定名称(包括其同义词?)的所有 Objects 在 SQL 中,这是在几行(和几分钟)内完成的

SELECT * 
FROM Objects
WHERE objTaxonId IN (
    SELECT taxId
    FROM Taxa
    WHERE taxName LIKE 'Test Taxon 1'
        OR taxSynIdTaxon IN(
        SELECT taxId 
        FROM Taxa 
        WHERE taxName LIKE 'Test Taxon 1'
    )
)

我能够计算出内部部分,在那里我获得了分类群及其同义词的列表。现在我需要将此 Query 转换为 Subquery...

String NAME_LIKE = "Test Taxon 1";
EntityManager em = EntityManagerProvider.getEntityManager("TestDB"); // get the EntityManager
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<TaxonImpl> cqObject = cb.createQuery(TaxonImpl.class);//
Root<TaxonImpl> taxonRoot = cqObject.from(TaxonImpl.class);//
Expression<String> taxon_name = taxonRoot.<String> get("taxName");
Predicate where = cb.equal(taxon_name, NAME_LIKE);
// subquery
Subquery<Integer> subQuery = cqObject.subquery(Integer.class);
Root<TaxonImpl> subRoot = subQuery.from(clsImpl);
subQuery.select(subRoot.<Integer> get("taxId"));
subQuery.where(cb.equal(subRoot.<String> get("taxName"), NAME_LIKE));
where = cb.or(where, taxonRoot.get("taxValidSynonymId").in(subQuery));
cqObject.where(where);
Query query = em.createQuery(cqObject);
List<TaxonImpl> result = query.getResultList();

注意:Taxon 被映射为多对一关系(目标实体是 TaxonImpl)

在我的实际应用程序中,代码(来自子查询)将是动态的,因此 Native Query 对我没有帮助。

我想出了如何将 "transform" 的 subquery 变成 query 但是 Eclipselink 给了我两个错误

第一个被禁止通过字段访问,当我在 TaxonImpl 的结果上尝试输入时(我首先尝试了,因为在我的映射文件中 Taxon 被映射为 Entity.

所以在这之后我尝试将 SQL 1:1 组成 JPA。 但是 Eclipselink 产生了一些奇怪的东西:

SELECT t0.objIdObject, t0.objAdminCreated, t0.objAdminCreator, t0.objAdminEdited, t0.objAdminEditor, t0.objAdminImport1, t0.objAdminImport2, t0.objAddBool1, t0.objAddBool2, t0.objAddBool3, t0.objAddBool4, t0.objAddBool5, t0.objAddDateTime1, t0.objAddDateTime2, t0.objCommonComments, t0.objCommonDescription, t0.objCommonKeywords, t0.objCommonName, t0.objCommonPublished, t0.objCommonPublishedAs, t0.objCommonStatus, t0.objCommonType, t0.objCommonTypustype, t0.objDetAccuracy, t0.objDetCf, t0.objDetComments, t0.objDetDate, t0.objDetMethod, t0.objDetResult, t0.objAddFloat1, t0.objAddFloat2, t0.objAddFloat3, t0.objAddFloat4, t0.objAddFloat5, t0.objEventAbundance, t0.objEventCollectionMethod, t0.objEventComments, t0.objEventMoreContacts, t0.objEventDateDay1, t0.objEventDate1, t0.objEventDateMonth1, t0.objEventDate2, t0.objEventDateUncertain, t0.objEventDateYear1, t0.objEventEcosystem, t0.objEventHabitat, t0.objEventNumber, t0.objEventPermission, t0.objEventSubstratum, t0.objEventTime1, t0.objEventTime2, t0.objEventWeekNumber, t0.objFlora, t0.objGuidObject, t0.objIOComments, t0.objIODeAccessed, t0.objAddInt1, t0.objAddInt2, t0.objAddInt3, t0.objAddInt4, t0.objAddInt5, t0.objStorageForeignNumber, t0.objStorageNumber, t0.objStorageNumberInCollection, t0.objStorageNumberOld, t0.objStorageNumberPrefix, t0.objAddLkp1, t0.objAddLkp10, t0.objAddLkp2, t0.objAddLkp3, t0.objAddLkp4, t0.objAddLkp5, t0.objAddLkp6, t0.objAddLkp7, t0.objAddLkp8, t0.objAddLkp9, t0.objAddLkpCs1, t0.objAddLkpCs10, t0.objAddLkpCs11, t0.objAddLkpCs12, t0.objAddLkpCs13, t0.objAddLkpCs14, t0.objAddLkpCs15, t0.objAddLkpCs2, t0.objAddLkpCs3, t0.objAddLkpCs4, t0.objAddLkpCs5, t0.objAddLkpCs6, t0.objAddLkpCs7, t0.objAddLkpCs8, t0.objAddLkpCs9, t0.objOriginAccessionDate, t0.objOriginAccessionNumber, t0.objOriginComments, t0.objOriginMoreContacts, t0.objOriginSource, t0.objOriginType, t0.objPreparationComments, t0.objPreparationDate, t0.objPreparationType, t0.objPropAdults, t0.objPropAge, t0.objPropAgeUnit, t0.objPropEggs, t0.objPropFemale, t0.objPropHeight, t0.objPropHeightUnit, t0.objPropJuveniles, t0.objPropLarvae, t0.objPropLength, t0.objPropLengthUnit, t0.objPropMale, t0.objPropObservation, t0.objPropObservationComments, t0.objPropPupae, t0.objPropSex, t0.objPropStadium, t0.objPropWeight, t0.objPropWeightUnit, t0.objPropWidth, t0.objPropWidthUnit, t0.objSiteComments, t0.objStorageComments, t0.objStorageContainerNumber, t0.objStorageContainerPieces, t0.objStorageContainerType, t0.objStorageLevel1, t0.objStorageLevel2, t0.objStorageLevel3, t0.objStorageLevel4, t0.objStorageLevel5, t0.objStorageNumberInContainer, t0.objstoragePieces, t0.objStorageValue, t0.objStorageValueUnit, t0.objAddText1, t0.objAddText10, t0.objAddText2, t0.objAddText3, t0.objAddText4, t0.objAddText5, t0.objAddText6, t0.objAddText7, t0.objAddText8, t0.objAddText9, t0.objIdCollection, t0.objCommonIdReference, t0.objDetIdContact, t0.objDetIdReference, t0.objEventIdContact, t0.objIdExcursion, t0.objOriginIdContact, t0.objPreparationIdContact, t0.objIdProject, t0.objSiteIdSite, t0.objdetIdTaxon 
FROM tObjects t0 
WHERE t0.objdetIdTaxon IN (
    SELECT t1.taxIdTaxon.t1.taxIdTaxon 
    FROM tTaxa t1 
    WHERE (t1.taxTaxonDisplay LIKE 'Test Taxon 1' 
        OR t1.taxSynIdTaxon IN (
        SELECT t2.taxSynIdTaxon 
        FROM tTaxa t2 
        WHERE t2.taxTaxonDisplay LIKE 'Test Taxon 1')))

排除错误:

SELECT t1.taxIdTaxon.t1.taxIdTaxon 

这完全是废话。您不能对 int 类型执行函数!

解决这个错误(BUG?)引入了一个新的构造(仍然 returns 相同的结果)

SELECT t1.objIdObject, t1.objAdminCreated, t1.objAdminCreator, t1.objAdminEdited, t1.objAdminEditor, t1.objAdminImport1, t1.objAdminImport2, t1.objAddBool1, t1.objAddBool2, t1.objAddBool3, t1.objAddBool4, t1.objAddBool5, t1.objAddDateTime1, t1.objAddDateTime2, t1.objCommonComments, t1.objCommonDescription, t1.objCommonKeywords, t1.objCommonName, t1.objCommonPublished, t1.objCommonPublishedAs, t1.objCommonStatus, t1.objCommonType, t1.objCommonTypustype, t1.objDetAccuracy, t1.objDetCf, t1.objDetComments, t1.objDetDate, t1.objDetMethod, t1.objDetResult, t1.objAddFloat1, t1.objAddFloat2, t1.objAddFloat3, t1.objAddFloat4, t1.objAddFloat5, t1.objEventAbundance, t1.objEventCollectionMethod, t1.objEventComments, t1.objEventMoreContacts, t1.objEventDateDay1, t1.objEventDate1, t1.objEventDateMonth1, t1.objEventDate2, t1.objEventDateUncertain, t1.objEventDateYear1, t1.objEventEcosystem, t1.objEventHabitat, t1.objEventNumber, t1.objEventPermission, t1.objEventSubstratum, t1.objEventTime1, t1.objEventTime2, t1.objEventWeekNumber, t1.objFlora, t1.objGuidObject, t1.objIOComments, t1.objIODeAccessed, t1.objAddInt1, t1.objAddInt2, t1.objAddInt3, t1.objAddInt4, t1.objAddInt5, t1.objStorageForeignNumber, t1.objStorageNumber, t1.objStorageNumberInCollection, t1.objStorageNumberOld, t1.objStorageNumberPrefix, t1.objAddLkp1, t1.objAddLkp10, t1.objAddLkp2, t1.objAddLkp3, t1.objAddLkp4, t1.objAddLkp5, t1.objAddLkp6, t1.objAddLkp7, t1.objAddLkp8, t1.objAddLkp9, t1.objAddLkpCs1, t1.objAddLkpCs10, t1.objAddLkpCs11, t1.objAddLkpCs12, t1.objAddLkpCs13, t1.objAddLkpCs14, t1.objAddLkpCs15, t1.objAddLkpCs2, t1.objAddLkpCs3, t1.objAddLkpCs4, t1.objAddLkpCs5, t1.objAddLkpCs6, t1.objAddLkpCs7, t1.objAddLkpCs8, t1.objAddLkpCs9, t1.objOriginAccessionDate, t1.objOriginAccessionNumber, t1.objOriginComments, t1.objOriginMoreContacts, t1.objOriginSource, t1.objOriginType, t1.objPreparationComments, t1.objPreparationDate, t1.objPreparationType, t1.objPropAdults, t1.objPropAge, t1.objPropAgeUnit, t1.objPropEggs, t1.objPropFemale, t1.objPropHeight, t1.objPropHeightUnit, t1.objPropJuveniles, t1.objPropLarvae, t1.objPropLength, t1.objPropLengthUnit, t1.objPropMale, t1.objPropObservation, t1.objPropObservationComments, t1.objPropPupae, t1.objPropSex, t1.objPropStadium, t1.objPropWeight, t1.objPropWeightUnit, t1.objPropWidth, t1.objPropWidthUnit, t1.objSiteComments, t1.objStorageComments, t1.objStorageContainerNumber, t1.objStorageContainerPieces, t1.objStorageContainerType, t1.objStorageLevel1, t1.objStorageLevel2, t1.objStorageLevel3, t1.objStorageLevel4, t1.objStorageLevel5, t1.objStorageNumberInContainer, t1.objstoragePieces, t1.objStorageValue, t1.objStorageValueUnit, t1.objAddText1, t1.objAddText10, t1.objAddText2, t1.objAddText3, t1.objAddText4, t1.objAddText5, t1.objAddText6, t1.objAddText7, t1.objAddText8, t1.objAddText9, t1.objIdCollection, t1.objCommonIdReference, t1.objDetIdContact, t1.objDetIdReference, t1.objEventIdContact, t1.objIdExcursion, t1.objOriginIdContact, t1.objPreparationIdContact, t1.objIdProject, t1.objSiteIdSite, t1.objdetIdTaxon 
FROM tTaxa t0, tObjects t1 
WHERE (
    t0.taxIdTaxon IN (
        SELECT t2.taxIdTaxon 
        FROM tTaxa t2 
        WHERE (t2.taxTaxonDisplay LIKE 'Test Taxon 1'
            OR t2.taxSynIdTaxon IN (
            SELECT t3.taxSynIdTaxon 
            FROM tTaxa t3 
            WHERE t3.taxTaxonDisplay LIKE 'Test Taxon 1'
            )
        )
    ) AND (t0.taxIdTaxon = t1.objdetIdTaxon)
)

这对我来说似乎很奇怪,但它确实有效 - 而且它比我的替代查询更快,后者包括 inner join

注意:Eclipselink 会忽略 JoinType。不管你传递什么,它都需要 left outer join。 (文档说了别的东西!)

最后我提供了 joinjoinless

的两个例子
private static Predicate addSynonymsWithJoins(Root<BioObjectImpl> r, CriteriaBuilder b, CriteriaQuery cq,
        Attribute attr, Path path, Object value) {
    Join taxJoin = r.join(BioObjectEnum.taxon.name(), JoinType.INNER);

    Path<Object> taxValidSynonymId = taxJoin.get(TaxonEnum.validSynonymId.name());
    Subquery<TaxonImpl> innerSubquery = cq.subquery(TaxonImpl.class);
    Root fromSubTax = innerSubquery.from(TaxonImpl.class);
    innerSubquery.select(fromSubTax.<Integer> get(TaxonEnum.id.name()));
    Predicate dynamic1 = cb.like(fromSubTax.get(TaxonEnum.name.name()),
     NAME_LIKE);
    innerSubquery.where(dynamic1);
    Predicate dynamic2 = resolveComparator(b, attr, taxJoin.get(attr.getPropertyName()), attr.getValue());//
    Predicate p = b.or(taxValidSynonymId.in(innerSubquery), dynamic2);

    return p;
}

private static Predicate addSynonymsWithoutJoins(Root<BioObjectImpl> r, CriteriaBuilder b, CriteriaQuery cq,
        Attribute attr, Path path, Object value) {
    cq.select(r);

    Path<Integer> objTaxonId = r.<Integer> get(BioObjectEnum.taxon.name()).get(TaxonEnum.id.name());

    Subquery<Integer> t2 = cq.subquery(Integer.class);
    Root<TaxonImpl> t2fromTaxon = t2.from(TaxonImpl.class);
    Path<Integer> t2taxId = t2fromTaxon.<Integer> get(TaxonEnum.validSynonymId.name());
    t2.select(t2taxId);
    Predicate t2dynamicWhere = resolveComparator(b, attr, t2fromTaxon.get(attr.getPropertyName()), attr.getValue());
    t2.where(t2dynamicWhere);

    Subquery<Integer> t1 = cq.subquery(Integer.class);
    Root<TaxonImpl> t1fromTaxon = t1.from(TaxonImpl.class);
    Predicate t1dynamicWhere = b.like(fromSubTax.get(TaxonEnum.name.name()),
     NAME_LIKE);
    Path<Integer> t1Select = t1fromTaxon.<Integer> get(TaxonEnum.id.name());

    t1.select(t1Select);
    Path<Integer> t1TaxSynonymId = t1fromTaxon.<Integer> get(TaxonEnum.validSynonymId.name());
    t1dynamicWhere = b.or(t1dynamicWhere, t1TaxSynonymId.in(t2));
    t1.where(t1dynamicWhere);

    Predicate where = objTaxonId.in(t1);
    return where;
}