How to match a list exactly with all values present in JPA Hibernate?

空扰寡人 提交于 2020-08-09 09:07:44

问题


I have a User entity with skills property as a type List. I want to query the User table against a list of skills in such a way that if all the skills are present in skill column then only a match is found unless no.

I have used JPQL for this but it matches each element in the list one by one using the IN clause.

User Class

@Entity(name = "App_User")
//table name "user" is not allowed in postgres
public class User {
    @Id
    @GeneratedValue(generator = "UUID")
    @GenericGenerator(name = "UUID", strategy = "org.hibernate.id.UUIDGenerator")
    @Column(name = "user_id", updatable = false, nullable = false)
    @Setter(AccessLevel.NONE)
    private UUID id;

    @Column(name = "user_name")
    @NotBlank(message = "Name is mandatory")
    private String name;

    @Column(name = "user_email")
    @NotBlank(message = "Email is mandatory")
    private String email;

    //    Current point balance of the user
    @Column(name = "points")
    private int points;

    @ElementCollection(fetch = FetchType.EAGER)
    @Column(name = "skills")
    @NotEmpty
    private List<String> skills = new ArrayList();

}

JPA query that I have used is

SELECT u FROM App_User u JOIN u.skills skill where skill in :skillList

If I want to match a list of skills like this Arrays.asList("skill1","skill2","skill3")then I want only those users in the result who have all of these skills, not one or two. Above used IN clause return the same result.

I have read that it is not possible to compare two lists in JPQL so how can I achieve this using CriteriaBuilder CriteriaQueryAPI?


回答1:


You can do this

@Query(value = "SELECT u FROM User u LEFT JOIN u.skills sk WHERE sk IN :skillList"
           + " GROUP BY u HAVING COUNT( sk) = :skillListSize")
List<User> findBySkills(@Param("skillList") List<String> skills,
                                 @Param("skillListSize") long skillListSize);

Here, group by user and then check group having all skills or not using size. So it will fetch all user having all skills those are given.

Or use this way

@Query(value = "SELECT u FROM User u LEFT JOIN u.skills sk GROUP BY u"
           + " HAVING SUM(CASE WHEN sk IN (:skillList) THEN 1 ELSE 0 END) = :skillListSize")
List<User> findBySkills(@Param("skillList") List<String> skills,
                                 @Param("skillListSize") long skillListSize);

And if you want a solution for user having exact same skill not more than the given list then see this solution.




回答2:


The problem that you want to solve is called Relational Division.

SELECT  u.* FROM App_User u
INNER JOIN
(
SELECT skills FROM App_User WHERE skills IN (list values)
GROUP BY skills
HAVING COUNT(DISTINCT skills) = (size of list)
) w ON u.user_name = w.user_name 


来源:https://stackoverflow.com/questions/62733249/how-to-match-a-list-exactly-with-all-values-present-in-jpa-hibernate

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!