Создание запроса CriteriaBuilder для сравнения списков - PullRequest
0 голосов
/ 06 января 2020

Как сравнить список из таблицы базы данных и список из кода программы? В базе данных есть профили пользователей с навыками.

    @ManyToMany(cascade = {CascadeType.MERGE}, fetch = FetchType.EAGER)
    @JoinTable(name = "profile_skills",
            joinColumns = @JoinColumn(name = "profile_id", referencedColumnName="id"),
            inverseJoinColumns = @JoinColumn(name = "skill_id", referencedColumnName="id"))
    private Map<Integer, Skill> skills = new TreeMap<>();

Нужно найти профили пользователей, обладающие нужными навыками. Я сделал запрос, но он выбирает профили, которые имеют хотя бы одно совпадение для любого из навыков в списке. Однако мне нужно выбрать только те, которые имеют все навыки, указанные в списке (совпадение со всеми элементами в списке).

    CriteriaBuilder cb = em.getCriteriaBuilder();
    CriteriaQuery<Profile> cq = cb.createQuery(Profile.class);
    Root<Profile> root  = cq.from(Profile.class);
    MapJoin<Profile, Integer, Skill> skillMapJoin = root.join(Profile_.skills);
    Expression<String> nameSkill = skillMapJoin.get(Skill_.name);

    List<String> skills = Arrays.asList("Java", "JavaScript");

    cq.where(nameSkill.in(skills)).groupBy(root.get(Profile_.id));

    TypedQuery<Profile> q = em.createQuery(cq);
    List<Profile> profiles = q.getResultList();

Например: Profile1.Skills: "Java", "Scala", "Groovy", "JavaScript" Profile2.Skills: "Java", "Scala", "Groovy" Profile3.Skills: "Groovy", "JavaScript"

Мой запрос возвращает результат: Profile1, Profile2, Profile3 Должен быть результат: Profile1

Подскажите, пожалуйста, как реализовать нужный мне запрос? Как сравнить список из таблицы базы данных и список из кода программы? Это возможно не только с помощью CriteriaBuilder, но и с другими параметрами запроса, такими как sql или jpql.

1 Ответ

0 голосов
/ 06 января 2020

Я нашел решение, хотя думаю, что это можно сделать по-другому.

    CriteriaBuilder cb = em.getCriteriaBuilder();
    CriteriaQuery<Profile> cq = cb.createQuery(Profile.class);
    Root<Profile> root  = cq.from(Profile.class);
    MapJoin<Profile, Integer, Skill> skillMapJoin = root.join(Profile_.skills);
    Expression<String> nameSkill = skillMapJoin.get(Skill_.name);

    List<String> skills = Arrays.asList("Java", "JavaScript");
    Integer sizeListValue = skills.size();
    Expression<Long> countSkills = cb.count(exp);

    cq.where(nameSkill.in(skills))
      .groupBy(root.get(Profile_.id))
      .having(cb.equal(countSkills, sizeListValue));

    TypedQuery<Profile> q = em.createQuery(cq);
    List<Profile> profiles = q.getResultList();
...