Spring Data – 通过仅一个值进行多列搜索

huangapple go评论70阅读模式
英文:

Spring Data - Multi-column search by only one value

问题

我正在使用Spring Data将一系列客户添加到我的网格中。

在我的存储库中,我有以下方法:

public List<CustomerDto> findAllByFirstNameContainingOrLastNameContainingAllIgnoreCase(String firstName, String lastName);

它可以工作,但实际上,firstNamelastName 参数具有相同的值。

是否有可能仅通过使用方法关键字功能(我不想通过使用 @Query 注解并编写自己的查询来增加复杂性)来实现只有一个参数来过滤我的两个列,并避免我在方法中提供相同的参数,就像是:

repository.myNewAwesomeMethodForFilteringTwoColumnsWithOneValue(filterValue);

而不是:

repository.findAllByFirstNameContainingOrLastNameContainingAllIgnoreCase(filterValue, filterValue);

如果您有任何想法或建议,谢谢您的帮助!

英文:

I am using Spring Data for adding into my grid a list of Customer.

In my repository, I have the following method :

public List&lt;CustomerDto&gt; findAllByFirstNameContainingOrLastNameContainingAllIgnoreCase(String firstName, String lastName);

It works, but in reality, firstName and lastName parameters are the same value.

Is there by any chance the possibility to achieve, by only using the method's keyword functionnality (I don't wanna add complexity by using the @Query annotation and writing my own query), to have only one parameter for filtering my two columns and avoiding me to provide the same parameter twice in the method like :

repository.myNewAwesomeMethodForFilteringTwoColumnsWithOneValue(filterValue);

Instead of :

repository.findAllByFirstNameContainingOrLastNameContainingAllIgnoreCase(filterValue, filterValue);

Thanks for your help, if you have any ideas or suggestions !

答案1

得分: 1

一个通用的解决方案是使用JPA规范(Specification)。虽然这可能是一个过度解决方案,但如果您有许多针对多列搜索的用例,我认为这是值得的。

我首先演示一下我是如何使用它的。

List<String> bookColumns = Arrays.asList("title", "genre", "author.name");

// 搜索"Spring":匹配2本书 - 《Spring in Action》和《Spring Integration》
GenericSearchSpecification<Book> searchSpecification = new GenericSearchSpecification<>(bookColumns, "Spring");
List<Book> books = bookRepository.findAll(searchSpecification);
Assert.assertEquals(2, books.size());

GenericSearchSpecification是我创建的一个类,它有一个接受两个参数的构造函数:

  • searchableColumns
  • searchString

现在是类的实现部分

public class GenericSearchSpecification<T> implements Specification<T> {
    
    private List<String> columns;
    private String search;
    
    public GenericSearchSpecification(List<String> columns, String search) {
        this.columns = columns;
        this.search = search;
    }
    
    @Override
    public Predicate toPredicate(Root<T> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
        List<Predicate> predicates = new ArrayList<>();
        for (String column : columns) {
            Path<?> path = buildPath(column, root);
            Predicate predicate = criteriaBuilder.like(criteriaBuilder.upper(path), "%" + search.toUpperCase() + "%");
            predicates.add(predicate);
        }
    
        return criteriaBuilder.or(predicates.stream().toArray(Predicate[]::new));
    }
    
    private Path<?> buildPath(String column, Path<?> path) {
        if (!column.contains(".")) return path.get(column);
    
        String[] parts = column.split("\\.");
        for (String part : parts) {
            path = path.get(part);
        }
    
        return path;
    }
}

如果您感兴趣,欢迎访问我专门为此创建的文章链接:https://medium.com/javarevisited/jpa-specification-a-generic-search-e8695b1d19ec

英文:

A generic solution that I can think of is using JPA Specification. This might be an overkill solution but if you have a lot of use cases for multi-column search then I think it's worth it.

I'll demonstrate it first how I use it.

    List&lt;String&gt; bookColumns = Arrays.asList(&quot;title&quot;, &quot;genre&quot;, &quot;author.name&quot;);

    // Search &quot;Spring&quot;: matches 2 Books - Spring in Action and Spring Integration
    GenericSearchSpecification&lt;Book&gt; searchSpecification =  new GenericSearchSpecification&lt;&gt;(bookColumns, &quot;Spring&quot;);
    List&lt;Book&gt; books = bookRepository.findAll(searchSpecification);
    Assert.assertEquals(2, books.size());

GenericSearchSpecification is a class that I've created which has a constructor accepting 2 parameters

  • searchableColumns
  • searchString

Now for the class implementation

public class GenericSearchSpecification&lt;T&gt; implements Specification&lt;T&gt; {

    private List&lt;String&gt; columns;
    private String search;

    public GenericSearchSpecification(List&lt;String&gt; columns, String search) {
        this.columns = columns;
        this.search = search;
    }

    @Override
    public Predicate toPredicate(Root&lt;T&gt; root, CriteriaQuery&lt;?&gt; criteriaQuery, CriteriaBuilder criteriaBuilder) {
        List&lt;Predicate&gt; predicates = new ArrayList&lt;&gt;();
        for (String column: columns) {
            Path path = buildPath(column, root);
            Predicate predicate = criteriaBuilder.like(criteriaBuilder.upper(path), &quot;%&quot; + search.toUpperCase() + &quot;%&quot;);
            predicates.add(predicate);
        }

        return criteriaBuilder.or(predicates.stream().toArray(Predicate[]::new));
    }

    private Path buildPath(String column, Path path) {

        if (!column.contains(&quot;.&quot;)) return path.get(column);

        String[] parts = column.split(&quot;\\.&quot;);
        for (String part: parts) {
            path = path.get(part);
        }

        return path;
    }

}

If you're interested feel free to visit the article that I created specifically for this: https://medium.com/javarevisited/jpa-specification-a-generic-search-e8695b1d19ec

huangapple
  • 本文由 发表于 2020年9月4日 19:02:56
  • 转载请务必保留本文链接:https://go.coder-hub.com/63739907.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定