Spring JPA Repository动态查询

目前我一直在使用以下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 findByFilterText(@Param("filterText") String filterText, Sort sort); 

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

我需要构建动态查询,

 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文档 ,您应该使用自定义接口+存储库实现。

使用方法创建接口:

 public interface MyEntityRepositoryCustom { List findByFilterText(Set words); } 

创建一个实现:

 @Repository public class MyEntityRepositoryImpl implements MyEntityRepositoryCustom { @PersistenceContext private EntityManager entityManager; public List findByFilterText(Set words) { // implementation below } } 

在现有Repository界面中扩展新界面:

 public interface MyEntityRepository extends JpaRepository, MyEntityRepositoryCustom { // other query methods } 

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

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

查询实现

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

您连接的word必须是有效的JPQL标识符 ,即:后跟一个java标识符start ,后跟一些java标识符部分 。 这意味着如果您的CSV包含foo bar,baz ,您将尝试使用foo bar作为标识符,并且您将获得exception。

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

 public List findByFilterText(Set words) { CriteriaBuilder cb = entityManager.getCriteriaBuilder(); CriteriaQuery q = cb.createQuery(User.class); Root user = q.from(User.class); Path namePath = user.get("name"); Path userTypeClassTypeDisplayName = user.get("userType").get("classType").get("displayName"); Path userTypeModel = user.get("userType").get("model"); List predicates = new ArrayList<>(); for(String word : words) { Expression 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(); } 

我自己一直在寻找解决方案:“自定义”存储库接口和实现的命名非常严格(如上所述如何向Spring Data JPA添加自定义方法 )

所以,要清楚,整个代码:(但@beerbajay是对的)

自定义方法界面

 public interface MyEntityRepositoryCustom { List findSpecial(); } 

自定义方法实现

 public class MyEntityRepositoryImpl implements MyEntityRepositoryCustom { @PersistenceContext private EntityManager em; //custom method implementation public List findSpecial() { List list = em.createNativeQuery("select name, value from T_MY_ENTITY").getResultList(); return list; } } 

“原始”存储库

 @Repository public interface MyEntityRepository extends JpaRepository, MyEntityRepositoryCustom { //original methods here... do not redefine findSpecial()... } 

您现在可以将“原始”存储库与新的自定义方法一起使用

 @Service public class MyService { @Autowired private DataRepository r; public void doStuff() { List list = r.findSpecial(); } }