Criteria API-2条路径和太多JOIN

时间:2019-06-16 22:09:14

标签: hibernate join hibernate-criteria criteria-api

我想使用Criteria API使用2个WHERE条件创建查询。我有一个具有嵌套字段(@OneToMany等)的实体A。我想创建具有以下条件的select:

entity A.fieldB.fieldC.id = X and A.fieldB.fieldD.id = Y



 public <T> List<T> getEntityWithParams(Map<Field, Object> params, Reportable<T> reportable) {
            CriteriaBuilder builder = em.getCriteriaBuilder();
            CriteriaQuery<T> query = builder.createQuery(reportable.getReportEntityClass());
            Root<T> from = query.from(reportable.getReportEntityClass());
            Predicate conditions = builder.conjunction();

            Path<Object> path = from.join("activityCategories")
                    .get("processActivity")
                    .get("personalData")
                    .get("company")
                    .get("id");

            Path<Object> path2 = from.join("activityCategories")
                    .get("processActivity")
                    .get("personalData")
                    .get("administrator")
                    .get("id");

    //      builder.and(conjunction, builder.equal(path, value), builder.equal(path2, 4)))

            conditions = builder.and(builder.equal(path, 1), builder.equal(path2, 4));


            List<T> typedQuery = em.createQuery(query
                            .select(from)
                            .where(conditions)
                            .distinct(true)).getResultList();

当我使用2条路径时,Hibernate会创建JOIN两次:

select
        distinct processing0_.id as id1_51_,
        processing0_.data_wpr as data_wpr2_51_,
        processing0_.opr as opr3_51_,
        processing0_.aktywna as aktywna4_51_,
        processing0_.id_spolka as id_spolk7_51_,
        processing0_.nazwa as nazwa5_51_,
        processing0_.nazwa_kategorii_podpowierzenia_przetwarzania as nazwa_ka6_51_ 
    from
        odo.odo_kategoria_czynnosci_przetwarzania processing0_ 
    inner join
        odo.odo_czynnosc_kategoria activityca1_ 
            on processing0_.id=activityca1_.id_kategoria_czynnosci 
    inner join
        odo.odo_czynnosc_kategoria activityca2_ 
            on processing0_.id=activityca2_.id_kategoria_czynnosci cross 
    join
        odo.odo_czynnosc_przetwarzania processing3_ cross 
    join
        odo.odo_zbior personalda4_ cross 
    join
        odo.odo_czynnosc_przetwarzania processing5_ cross 
    join
        odo.odo_zbior personalda6_ 
    where
        activityca1_.id_czynnosc=processing3_.id 
        and processing3_.id_zbior=personalda4_.id 
        and activityca2_.id_czynnosc=processing5_.id 
        and processing5_.id_zbior=personalda6_.id 
        and personalda4_.id_zbior_spolka=1 
        and personalda6_.id_zbior_administrator=4

因此结果不正确。此外,还有使用的CROSS JOIN。您是否知道如何准备这样的查询:

select
        distinct processing0_.id as id1_51_,
        processing0_.data_wpr as data_wpr2_51_,
        processing0_.opr as opr3_51_,
        processing0_.aktywna as aktywna4_51_,
        processing0_.id_spolka as id_spolk7_51_,
        processing0_.nazwa as nazwa5_51_,
        processing0_.nazwa_kategorii_podpowierzenia_przetwarzania as nazwa_ka6_51_ 
    from
        odo.odo_kategoria_czynnosci_przetwarzania processing0_ 
    inner join
        odo.odo_czynnosc_kategoria activityca1_ 
            on processing0_.id=activityca1_.id_kategoria_czynnosci 
    inner join

    join
        odo.odo_zbior personalda4_ on personalda4_ = processing0_.id_zbior

    where
         personalda4_.id_zbior_spolka=1 
        and personalda4_.id_zbior_administrator=4

1 个答案:

答案 0 :(得分:0)

您应该将gets替换为连接。

Root<T> from = query.from(reportable.getReportEntityClass());
       Join<Type1, Type2> personalData = from.join("activityCategories")
                .join("processActivity")
                .join("personalData")
       Path<Long> path = personalData.get("company").get("id");
       Path<Long> path2 = personalData.get("administrator").get("id");

在上面的代码中,我假设在您的数据库中,您已经将company.idadministrator.id作为FK存储在personalData表中。这是(我认为)仅在值得用get替换join的情况下使用(因此,您有一个join-更好的性能)