带有JPA子查询的Spring数据规范

时间:2019-07-30 14:18:24

标签: java hibernate jpa spring-data-jpa

我想从Spring Data Specification执行子查询。它必须像这样的SQL语句:

select u from users u where u.name in (select up.username from users_profiles up where up.profile in ('admin'));

我有3个简单的表:

  1. users存储用户数据
  2. profiles存储用户个人资料类型
  3. users_profiles,可以消除用户和多个个人资料之间的关系

因此,有了配置文件列表,我需要找到所有具有这些配置文件的用户。

public List<User> getUsersByProfileType(List<String> profileTypes) {
    return userRepository.findAll(new Specification<User> () {
        @Override
        public Predicate toPredicate(Root<User> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
            final List<Predicate> predicates = new ArrayList<>();

            /*
            userNamesWithMatchedProfiles = select up.username from users_profiles up where up.profile in profileTypes
            */
            List<String> userNamesWithMatchedProfiles = new ArrayList<String>();
            predicates.add(root.get("name").in(userNamesWithMatchedProfiles))
            return cb.and(predicates.toArray(new Predicate[predicates.size()])); 
        }
    });
}

3 个答案:

答案 0 :(得分:0)

您应该使用Java Persistence Query Language (JPQL).

总而言之,指定一个@NamedQuery来执行数据库查询...

@Entity
@NamedQuery(name="User.findAdmins", query="SELECT u FROM User u WHERE u.name IN (SELECT up.username FROM UserProfile up WHERE up.profile IN ('admin')") 
public class User extends Serializable... 

...然后在您的代码中执行它:

List<String> userNamesWithMatchedProfiles = 
                    entityManager.createNamedQuery("User.findAdmins").getResultList();

以上内容应大致提供 您所需的内容。您会注意到,语法类似于SQL,只有很小的区别。将SQL转换为JPQL非常简单。

您当然可以直接将其作为Query执行,而无需将其存储为NamedQuery。我这样做是因为(以我的拙见)这是一种简洁的模式,有助于保持JPA逻辑井井有条。

请注意,您可以将参数注入查询中。例如:

@NamedQuery(name="User.findUser", query="SELECT u FROM User u WHERE u.name = :name") 
...
List results = entityManager
                  .createNamedQuery("Profile.findUser")
                  .setParameter("name", "Daniel")
                  .getResultList();

答案 1 :(得分:0)

我找到了执行子查询的方法:

public List<User> getUsersByProfileType(List<String> profileTypes) {
        return userRepository.findAll(new Specification<User> () {
            @Override
            public Predicate toPredicate(Root<User> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                final List<Predicate> predicates = new ArrayList<>();

                final Subquery<UserProfile> userProfileSubquery = query.subquery(UserProfile.class);
                final Root<UserProfile> userProfile = userProfileSubquery.from(UserProfile.class);

                // select up.username from users_profiles ...
                userProfileSubquery.select(userProfile.get("user").get("name"));
                // ... where up.profile in ('admin')
                userProfileSubquery.where(cb.trim(userProfile.get("profile").get("id")).in(profileTypes));

                // select u from users u where u.name in ...
                predicates.add(root.get("name").in(userProfileSubquery));

                return cb.and(predicates.toArray(new Predicate[predicates.size()])); 
            }
        });
   }

答案 2 :(得分:0)

使用Hibernate查询(本机),如下所示在UserRepository上,您也可以使用自定义参数。

3
objects
found   #or
$counter objects found  #or 
$($counter) objects found