简体   繁体   English

Spring Data JPA具有多个联接的多个可选搜索参数

[英]Spring Data JPA Multiple Optional Search Parameters With Multiple Joins

I'm currently using Spring Boot with Spring Data JPA to connect to an oracle database. 我目前正在使用Spring Boot和Spring Data JPA来连接到oracle数据库。 With one parameter I just use the Spring Repository findById(Long id); 通过一个参数,我只使用Spring Repository findById(Long id); and it works great. 而且效果很好。 Search on the other hand is much more complicated for me. 另一方面,搜索对我来说要复杂得多。 In our case, the user provides a nested JSON object with multiple optional search parameters (at this point I can't change the way the way they send their data it has to be through the nested JSON). 在我们的例子中,用户为嵌套的JSON对象提供了多个可选的搜索参数(目前,我无法更改其通过嵌套JSON发送数据的方式)。 Here is what the JSON input object looks like: JSON输入对象如下所示:

{
  "agent_filter": {
    "first_name": "string",
    "last_name": "string",
    "agentNumber": "string",
    "agentCode": "string"
  },
  "account": "string",
  "status": "string",
  "paid": "string",
  "amount": "string",
  "person_filter": {
    "date_of_birth": "string",
    "first_name": "string",
    "last_name": "string",
    "tax_id": "string"
  }
}

All the search criteria are optional (except at least 1 parameter) 所有搜索条件都是可选的(至少1个参数除外)

On the back-end we have the following entities: 在后端,我们具有以下实体:

@Entity
Account{
@OneToMany
List<PersonRole> role;

@OneToMany
List<AgentRole> role;
}

@Entity
PersonRole{
String role;

Person person;
}

@Entity
AgentRole{
String role;

Agent agent;
}

@Entity
Person{...}

@Entity
Agent{...}

So to provide the search functionality I can do multiple joins. 因此,要提供搜索功能,我可以进行多个联接。 I started using JPQL with an @Query notation but I had to do is null or checks with each parameter and it's a big mess. 我开始使用带有@Query表示法的JPQL,但是我必须做的is null or检查每个参数,这很麻烦。 I started looking into other options and I saw stuff about QueryDSL, criteria, specification but I wasn't sure which one I should focus on and learn about. 我开始研究其他选项,并且看到了有关QueryDSL,标准,规范的信息,但是我不确定应该重点关注哪一个。 Unfortunately I don't know a whole lot on this subject and I was hoping someone can point me in the right direction for a good implementation of this search. 不幸的是,我对这个主题并不了解很多,我希望有人可以指出正确的方向,以便更好地实现此搜索。 Thank you! 谢谢!

QueryDSL ftw! QueryDSL ftw!

Let me give you an example from my code when I had a very similar problem to you in that I had a bunch of stuff that I wanted to filter on and a lot of them could be null... 当我遇到一个与您非常相似的问题时,让我给您一个示例代码,因为我有很多东西要过滤,其中很多可能为空。

Btw, if you need fancy joins then you're probably going to use query dsl directly. 顺便说一句,如果您需要精美的连接,那么您可能将直接使用查询dsl。 These example are for QueryDSL 3 so you might have to change for QueryDSL 4. Because you've mentioned how you 'So to provide the search functionality I can do multiple joins' you're probably going to need to use QueryDSL directly. 这些示例是针对QueryDSL 3的,因此您可能不得不为QueryDSL 4进行更改。因为您已经提到了“如何提供搜索功能以便我可以进行多个联接”,您可能需要直接使用QueryDSL。

First you create yourself and BooleanBuilder and then do something like this: 首先,您创建自己和BooleanBuilder,然后执行以下操作:

BooleanBuilder builder = new BooleanBuilder();
QContent content = QContent.content;
if (contentFilter.headlineFilter == null || contentFilter.headlineFilter.trim().length() == 0) {
        // no filtering on headline as headline filter = null or blank
    } else if (contentFilter.headlineFilter.equals(Filter.NULL_STRING)) {
        // special case when you want to filter for specific null headline
        builder.and(content.label.isNull());
    } else {
        try {
            long parseLong = Long.parseLong(contentFilter.headlineFilter);
            builder.and(content.id.eq(parseLong));
        } catch (NumberFormatException e) {
            builder.and(content.label.contains(contentFilter.headlineFilter));
        }
    }
    if (contentFilter.toDate != null) {
        builder.and(content.modifiedDate.loe(contentFilter.toDate));
    }
    if (contentFilter.fromDate != null) {
        builder.and(content.modifiedDate.goe(contentFilter.fromDate));
    }

So based on whether or not you have each field you can add it to the filter. 因此,根据您是否拥有每个字段,可以将其添加到过滤器中。

To get this to work you're going to need to generate the Query DSL meta data - that is done with the com.mysema.query.apt.jpa.JPAAnnotationProcessor annotation processor. 为了使它起作用,您将需要生成Query DSL元数据-使用com.mysema.query.apt.jpa.JPAAnnotationProcessor注释处理器完成。 It generates the QContent.content stuff above. 它生成上面的QContent.content东西。

That BooleanBuilder is a subclass of Predicate. 该BooleanBuilder是谓词的子类。

However going with query dsl, criteria, specification is good approach but it will require to learn them. 但是,使用查询dsl,条件,规范是不错的方法,但需要学习它们。

Your problem can just be solved using JpaRepository only. 仅使用JpaRepository即可解决您的问题。 Your AccountRepository might be extending JpaRepository which again extends QueryByExampleExecutor . 您的AccountRepository可能正在扩展JpaRepository ,后者又扩展了QueryByExampleExecutor

QueryByExampleExecutor provides some method like findOne(Example<S> example) and findAll(Example<S> example) which will give you result back based on the Example object you pass. QueryByExampleExecutor提供了诸如findOne(Example<S> example)findAll(Example<S> example) ,这些方法将根据传递的Example对象返回结果。

Creating Example is simple 创建Example很简单

Person person = new Person();                         
person.setFirstname("Dave");                          

Example<Person> example = Example.of(person); 

This will match all Person which have firstName = Dave 这将匹配所有具有firstName = Dave Person

Read more on Spring Data Query by Example . 通过示例阅读更多关于Spring Data Query的信息

You need to use custom query to create your own search query . 您需要使用自定义查询来创建自己的搜索查询。

@Query("select u from User u where u.firstname = :#{#customer.firstname}")
List<User> findUsersByCustomersFirstname(@Param("customer") Customer customer);

Now you can add as many param as you want 现在您可以根据需要添加任意数量的参数

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM