Spring Data - 多列搜索

时间:2014-09-16 15:21:22

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

我使用Spring Data进行分页和排序。但是,我想执行多列搜索。

现在,我在我的存储库界面中使用注释 @Query ,如下所示:

public interface MyRepository extends PagingAndSortingRepository<Item,Long> {

    @Query(value="select mt from MY_TABLE mt where mt.field1 = %searchtext% or mt.field2 = %searchtext% or mt.field3 = %searchtext%")    
    Page<Item> findByAllColumns(@Param("searchtext") String searchtext, Pageable pageable);

}

编辑:此解决方案中的问题出在@Query注释的where子句中,因为我们必须为我们要搜索的每一列重复完全相同的searchtext参数(问题的澄清)在布兰登奥克利的评论之后)

我想知道是否还有其他方法可以做,因为表中的列数可能很高。

感谢您的帮助。

5 个答案:

答案 0 :(得分:8)

以下是此类用户规范的示例:

public static Specification<User> containsTextInName(String text) {
    if (!text.contains("%")) {
        text = "%" + text + "%";
    }
    String finalText = text;
    return (root, query, builder) -> builder.or(
            builder.like(root.get("lastname"), finalText),
            builder.like(root.get("firstname"), finalText)
    );
}

或甚至更可定制的实施:

public static Specification<User> containsTextInAttributes(String text, List<String> attributes) {
    if (!text.contains("%")) {
        text = "%" + text + "%";
    }
    String finalText = text;
    return (root, query, builder) -> builder.or(root.getModel().getDeclaredSingularAttributes().stream()
            .filter(a -> attributes.contains(a.getName()))
            .map(a -> builder.like(root.get(a.getName()), finalText))
            .toArray(Predicate[]::new)
    );
}

public static Specification<User> containsTextInName(String text) {
    return containsTextInAttributes(text, Arrays.asList("lastname", "firstname"));
}

用法:

userRepository.findAll(Specifications.where(UserSpecifications.containsTextInName("irs")))

答案 1 :(得分:5)

您可以使用specifications。这也为您提供了更大的灵活性。您可以使用一种方法,但对查询使用多种规范:

Page<Item> findAll(Specification<T> spec, Pageable pageable);

myRepository.findAll(textInAllColumns(searchText), pageable);

答案 2 :(得分:4)

结合前两个答案:如果您不想将API与数据库架构耦合在一起,或者换句话说您不希望用户提供字符串列名称 - 您可以过滤掉那些不是字符串的属性并将like应用于所有那些。在以下示例中,它将尝试在列的值中搜索textnamefield1field2field3

实体示例:

@Entity
public class MyEntity {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    public int id;
    public String name;
    public String field2;
    public String field3;
    public String field4;
}

规范示例:

public class EntitySpecification {

    public static Specification<MyEntity> textInAllColumns(String text) {

        if (!text.contains("%")) {
            text = "%"+text+"%";
        }
        final String finalText = text;

        return new Specification<MyEntity>() {
            @Override
            public Predicate toPredicate(Root<MyEntity> root, CriteriaQuery<?> cq, CriteriaBuilder builder) {
                return builder.or(root.getModel().getDeclaredSingularAttributes().stream().filter(a-> {
                    if (a.getJavaType().getSimpleName().equalsIgnoreCase("string")) {
                        return true;
                    }
                    else {
                        return false;
                }}).map(a -> builder.like(root.get(a.getName()), finalText)
                    ).toArray(Predicate[]::new)
                );
            }
        };
    }

 }

存储库示例:

public interface MyEntityRepository extends PagingAndSortingRepository<MyEntity, Integer> {
    List<MyEntity> findAll(Specification<MyEntity> spec);
}

用法示例:

List<MyEntity> res = failureRepository.findAll(Specifications.where(FailureSpecification.textInAllColumns(text)));

答案 3 :(得分:0)

如果要实现,

1。分页,

2。搜索所有“字符串”列,

3。排序方式,

4。排序顺序

在相同的服务/请求中,这是给您的!

Michail Michailidis的回答给我留下了深刻的印象,并且我确实以自己的方式对其进行了更新,以便可以用于任何实体,并且具有分页功能(页码和页面尺寸是动态的) ,排序依据,排序顺序

首先在您的末尾复制此类:

    public class EntitySpecification {

    public static <T> Specification<T> textInAllColumns(String text) {
        if (!text.contains("%")) {
            text = "%" + text + "%";
        }
        final String finalText = text;

        return (Specification<T>) (root, cq, builder) ->
                builder.or(root.getModel()
                        .getDeclaredSingularAttributes()
                        .stream()
                        .filter(a -> a.getJavaType()
                                .getSimpleName().equalsIgnoreCase("string"))
                        .map(a -> builder.like(root.get(a.getName()), finalText)
                        ).toArray(Predicate[]::new)
                );
    }
}

现在,在服务类中,例如在UserService class中,如果您想通过搜索,排序,分页等在上实现用户列表之类的功能 ,然后仅使用此

Pageable paging;
    if (paginationRequest.getSortOrder().matches("ASC")) {
        paging = PageRequest.of(paginationRequest.getPageNo(),
                paginationRequest.getPageSize(), Sort.by(
                        paginationRequest.getSortBy()).ascending());
    } else {
        paging = PageRequest.of(paginationRequest.getPageNo(),
                paginationRequest.getPageSize(), Sort.by(paginationRequest.getSortBy()).descending());
    }

    List<User> userList = userRepository.findAll(
            EntitySpecification.textInAllColumns(paginationRequest.getSearch())
            , paging).getContent();

现在不要在这里困惑

PaginationRequest是请求 POJO 类,其中getterssetters最初具有关注度,

Integer pageNo = 0;
Integer pageSize = 10;
String sortBy = "createdTimeStamp";
String sortOrder;
String search = "";

答案 4 :(得分:0)

以上所有解决方案都很棒,但是我们也可以使用Example和ExampleMatcher进行多列搜索

  1. 首先使用搜索参数定义搜索对象
  2. 第二,使用ExampleMatcher和Example定义自定义示例匹配器
  3. 第三,在findAll()方法中使用customExampleMatcher
/* Build Search object */
Employee employee=new Employee();
        employee.setFirstName(requestDTO.getFilterText());
        employee.setLastName(requestDTO.getFilterText());
        employee.setEmail(requestDTO.getFilterText());

/* Build Example and ExampleMatcher object */
ExampleMatcher customExampleMatcher = ExampleMatcher.matchingAny()
                .withMatcher("firstName", ExampleMatcher.GenericPropertyMatchers.contains().ignoreCase())
                .withMatcher("lastName", ExampleMatcher.GenericPropertyMatchers.contains().ignoreCase())
                .withMatcher("email", ExampleMatcher.GenericPropertyMatchers.contains().ignoreCase());

Example<Employee> employeeExample= Example.of(employee, customExampleMatcher);

/* Get employees based on search criteria*/
employeetRepository.findAll(employeeExample, PageRequest.of(requestDTO.getCurrentPageNumber(), requestDTO.getPageSize(), Sort.by(requestDTO.getSortingOrderColumnName()).descending()));