Spring JPA Repository动态查询

新手上路,请多包涵

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

  @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 + "))";
}

原文由 Channa 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 731
1 个回答

根据 JB Nizet 和 spring-data 文档,您应该使用自定义接口 + 存储库实现。

使用以下方法创建接口:

 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
    }
}

在现有的 Repository 接口中扩展新接口:

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

最后,在别处调用该方法:

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

查询实现

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

您要连接的 word 必须是 有效的 JPQL 标识符,即 : 后跟 java 标识符开始,可选地后跟一些 java 标识符部分。这意味着如果您的 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();
}

原文由 beerbajay 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题