java - Spring JPA Repository动态查询

标签 java spring jpa spring-data spring-data-jpa

目前我一直在使用以下 Spring JPA Repository 基本自定义查询,它工作正常,

 @Query("SELECT usr FROM User usr  WHERE usr.configurable = TRUE "
              + "AND (" +
                        "lower(usr.name) like lower(:filterText) OR lower(usr.userType.classType.displayName) like lower(:filterText) OR lower(usr.userType.model) like lower(:filterText)"
              +      ")"
              + "")
  public List<User> findByFilterText(@Param("filterText") String filterText, Sort sort);

当过滤器文本将是逗号分隔值时,我需要修改此查询。但按照以下方式,它将是一个动态查询,我该如何执行它。

我需要构建动态查询,

String sql = "SELECT usr FROM User usr WHERE usr.configurable = TRUE";

for(String word : filterText.split(",")) {
                sql += " AND (lower(usr.name) like lower(:" + word + ") OR lower(usr.userType.classType.displayName) like lower(:" + word + ") OR lower(usr.userType.model) like lower(:" + word + "))";
}

最佳答案

JB Nizet 和 spring-data documentation ,您应该使用自定义接口(interface)+存储库实现。

使用以下方法创建接口(interface):

public interface MyEntityRepositoryCustom {
    List<User> findByFilterText(Set<String> words);
}

创建一个实现:

@Repository
public class MyEntityRepositoryImpl implements MyEntityRepositoryCustom {
    @PersistenceContext
    private EntityManager entityManager;

    public List<User> findByFilterText(Set<String> words) {
        // implementation below
    }
}

在现有的存储库接口(interface)中扩展新接口(interface):

public interface MyEntityRepository extends JpaRepository<MyEntity, Long>, MyEntityRepositoryCustom {
    // other query methods
}

最后,在其他地方调用该方法:

dao.findByFilterText(new HashSet<String>(Arrays.asList(filterText.split(","))));

查询实现

您生成sql变量的方法,即通过将一些字符串连接到查询中,是不好的。 不要这样做。

您要连接的单词必须是valid JPQL identifier ,即 : 后跟 java identifier start ,可选地后跟一些 java identifier part 。这意味着,如果您的 CSV 包含 foo bar,baz,您将尝试使用 foo bar 作为标识符,并且会出现异常。

您可以使用 CriteriaBuilder以安全的方式构造查询:

public List<User> findByFilterText(Set<String> words) {
    CriteriaBuilder cb = entityManager.getCriteriaBuilder();
    CriteriaQuery<User> q = cb.createQuery(User.class);
    Root<User> user = q.from(User.class);

    Path<String> namePath = user.get("name");
    Path<String> userTypeClassTypeDisplayName = 
                     user.get("userType").get("classType").get("displayName");
    Path<String> userTypeModel = user.get("userType").get("model");
    List<Predicate> predicates = new ArrayList<>();
    for(String word : words) {
        Expression<String> wordLiteral = cb.literal(word);
        predicates.add(
                cb.or(
                    cb.like(cb.lower(namePath), cb.lower(wordLiteral)),
                    cb.like(cb.lower(userTypeClassTypeDisplayName),
                            cb.lower(wordLiteral)),
                    cb.like(cb.lower(userTypeModel), cb.lower(wordLiteral))
                )
        );
    }
    q.select(doc).where(
            cb.and(predicates.toArray(new Predicate[predicates.size()]))
    );

    return entityManager.createQuery(q).getResultList();
}

关于java - Spring JPA Repository动态查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43752080/

相关文章:

java - 如何排除 findbugs 中的构造函数?

java - 为什么多 Kafka Consumer 对象让它总是重新平衡,并且不起作用

java - Spring 接线 - 未找到默认构造函数

java - 将 java javax.inject.Provider 与 Spring @Scope(BeanDefinition.SCOPE_PROTOTYPE) 一起使用

mysql - 在 spring 中,如何在一次迭代发生事务回滚后继续来自 Controller for 循环的请求

java - 在JPA和存储库接口(interface)中获取实体类

java - 覆盖数据库中的资源

java邮件作为pdf文件作为附件

java - 实体 JPA 中的 session 范围属性

java - SSO 在不同的 Tomcat 中具有 2 个 spring 应用程序