Home > Blockchain >  JPA Criteria query combined with @Filter
JPA Criteria query combined with @Filter

Time:09-27

I have a scenario in which I want to use the hibernate annotation @Filter (activated only if the condition is satisfied) but the condition needs to use alias (person as in the code snippet, because there is an ambiguous column in personId) from the original one which is written within Criteria. Note that the filter condition is written in sql. Besides the root.alias("person") don't work in this situation.

The model class:

@Entity
@Table(name = "PERSON")
@NoArgsConstructor
@Getter
@Setter
@Inheritance(strategy = InheritanceType.JOINED)
@FilterDef(name = "authorizePerson", parameters = {@ParamDef(name="userCode", type = "string")})
@Filter(name = "authorizePerson", condition = 
        " NOT EXISTS ("
          "                SELECT"
          "                    multilevel1_.id_dossier,"
          "                    multilevel1_.type_dossier"
          "                FROM"
          "                    dossier_multiniv multilevel1_"
          "                WHERE"
          "                    multilevel1_.id_dossier = TO_CHAR(**person**.id_per)"
          "                    AND multilevel1_.type_dossier = 'PERSONNE'"
          "            )"
          "OR EXISTS ("
          "                SELECT"
          "                    multilevel2_.id_dossier,"
          "                    multilevel2_.cd_util"
          "                FROM"
          "                    v_droits_multiniv_allusers multilevel2_"
          "                WHERE"
          "                    multilevel2_.cd_util = :userCode"
          "                    AND multilevel2_.id_dossier = TO_CHAR(**person**.id_per)"
          "                    AND multilevel2_.type_dossier = 'PERSONNE'"
          "            )", deduceAliasInjectionPoints = true)
public class PersonPO implements Serializable {
    private static final long serialVersionUID = 1L;

    @Id
    @Column(name = "ID_PER")
    private Long personId;

    @Column(name = "AFFICH_PER")
    private String archive;

    @Column(name = "AUTH_ERROR")
    private Long numberOfConnectionErrors;

    // bi-directional many-to-one association to Categper
    @OneToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "ID_PER")
    private PersonCategoryPO personCategory;
  ...
 }

Then the service:

@Transactional
    @Override
    public Pageable<IPersonBO> findAllPersons(String stringFilter, Page page, Sort sort, String userCode) {
        try {
            Predicate filterPredicate = null;
            CriteriaQuery<PersonPO> cq;
            Root<PersonPO> root;
            CriteriaBuilder cb = em.getCriteriaBuilder();
            Predicate allPredicates = cb.equal(cb.literal(1), 1);
            if (!stringFilter.isBlank()) {
                SearchCondition<PersonPO> filter = new FiqlParser<PersonPO>(PersonPO.class).parse(stringFilter);
                JPACriteriaQueryVisitor<PersonPO, PersonPO> jpa = new JPACriteriaQueryVisitor<PersonPO, PersonPO>(em,
                        PersonPO.class, PersonPO.class);
                filter.accept(jpa);
                cq = jpa.getQuery();
                root = (Root<PersonPO>) cq.getRoots().iterator().next();
                filterPredicate = jpa.getQuery().getRestriction();
                allPredicates = filterPredicate;
            } else {
                cq = cb.createQuery(PersonPO.class);
                root =cq.from(PersonPO.class);
            }
            cq.select(root.alias("person"));
            Fetch<PersonPO, PersonCategoryPO> pc = root.fetch("personCategory");
            Fetch<PersonCategoryPO, CategoryPO> category = pc.fetch("category");
            CriteriaQuery<Long> cqCount = cb.createQuery(Long.class);
            cqCount.select(cb.count(cqCount.from(PersonPO.class)));
            if (multiLevelIsActif()) {
                if (userCode != null) {
                    Filter filter = session.enableFilter("authorizePerson");
                    filter.setParameter("userCode", userCode);
                }
            }
            cq.where(allPredicates);
            cqCount.where(allPredicates);

            // sort
            JpaUtils.handleSort(sort, cq, cb, root);

            // get results
            TypedQuery<PersonPO> query = em.createQuery(cq);
            if (page != null) {
                query.setFirstResult(page.getFirstResult()).setMaxResults(page.getPageSize());
            }
            List<IPersonBO> items = query.getResultStream().map(c -> getPerson((PersonPO) c))
                    .collect(Collectors.toList());

            // count results
            Long totalSize = 0l;
            totalSize = em.createQuery(cqCount).getSingleResult();

            return new Pageable<IPersonBO>(items, totalSize, page);
        } catch (Exception e) {
            log.error(e.getMessage());
            return null;
        }

Why the sql-show still generates query and never consider the alias (person) like below ?

        select
            personpo0_.ID_PER as id_per1_102_,
        ...
        from
            RKHATERCHI2.PERSONNE personpo0_ 
        ...
        where
            1=1 
        order by
            personpo0_.ID_PER desc

Is there a way how to enforce the alias in JPA/Criteria so that I can use it in the filter condition? Your thoughts are appreciated.

CodePudding user response:

Take a look into the documentation about how to specify table aliases in filter conditions: https://docs.jboss.org/hibernate/orm/5.6/userguide/html_single/Hibernate_User_Guide.html#pc-filter-sql-fragment-alias

  • Related