【问题标题】:Spring Data JPA Multiple Optional Search Parameters With Multiple JoinsSpring Data JPA 具有多个连接的多个可选搜索参数
【发布时间】:2018-01-27 04:40:15
【问题描述】:

我目前正在使用带有 Spring Data JPA 的 Spring Boot 来连接到 Oracle 数据库。使用一个参数,我只使用 Spring Repository findById(Long id); 并且效果很好。另一方面,搜索对我来说要复杂得多。在我们的例子中,用户提供了一个带有多个可选搜索参数的嵌套 JSON 对象(此时我无法更改他们必须通过嵌套 JSON 发送数据的方式)。下面是 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"
  }
}

所有搜索条件都是可选的(至少1个参数除外)

在后端,我们有以下实体:

@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{...}

因此,为了提供搜索功能,我可以进行多个连接。我开始使用带有 @Query 表示法的 JPQL,但我必须对每个参数进行 is null or 检查,这真是一团糟。我开始研究其他选项,并且看到了有关 QueryDSL、标准、规范的内容,但我不确定应该关注和学习哪一个。不幸的是,我对这个主题知之甚少,我希望有人能指出我正确的方向,以便很好地实施这个搜索。谢谢!

【问题讨论】:

    标签: java json spring hibernate jpa


    【解决方案1】:

    查询DSL ftw!

    当我遇到与您非常相似的问题时,让我从我的代码中给您举一个示例,因为我有一堆东西要过滤,其中很多可能为空...

    顺便说一句,如果您需要花哨的连接,那么您可能会直接使用查询 dsl。这些示例适用于 QueryDSL 3,因此您可能必须针对 QueryDSL 4 进行更改。因为您已经提到“所以为了提供搜索功能,我可以进行多个连接”,您可能需要直接使用 QueryDSL。

    首先您创建自己和 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));
        }
    

    因此,根据您是否拥有每个字段,您可以将其添加到过滤器中。

    要使其工作,您需要生成 Query DSL 元数据 - 这是使用 com.mysema.query.apt.jpa.JPAAnnotationProcessor 注释处理器完成的。它生成上面的 QContent.content 内容。

    BooleanBuilder 是 Predicate 的子类。

    【讨论】:

    • 感谢您的回答,我会尽快调查/尝试。我会让你知道情况如何。谢谢!
    • Query DSL 是否可以使用@OneToMany 列表进行过滤?查看我的示例,我可以使用代理名字进行选择吗?即使代理是列表之一?
    • 你可能需要一个连接,所以在构建查询时在父子之间连接,然后在代理上添加一个过滤器。如果您需要这样做,那么您将无法使用 JpaRepository - 您必须直接使用 QueryDSL。
    • 谢谢。当您说直接使用 querydsl 时,您的意思是像使用实体管理器并构造一个 jpaquery 吗?你能举个例子吗?我真的很感谢你的帮助。非常感谢!
    • 我发布了一个新问题,也许您可​​以回答。 link
    【解决方案2】:

    然而,使用查询 dsl、条件、规范是很好的方法,但需要学习它们。

    您的问题只能使用 JpaRepository 来解决。您的 AccountRepository 可能正在扩展 JpaRepository,它再次扩展 QueryByExampleExecutor

    QueryByExampleExecutor 提供了一些方法,例如 findOne(Example&lt;S&gt; example)findAll(Example&lt;S&gt; example),它们会根据您传递的 Example 对象返回结果。

    创建Example 很简单

    Person person = new Person();                         
    person.setFirstname("Dave");                          
    
    Example<Person> example = Example.of(person); 
    

    这将匹配所有具有firstName = Dave的人

    阅读更多关于Spring Data Query by Example

    【讨论】:

    • 感谢您的回答。 Querybyexample 似乎不适用于列表。 IE:新人; person.setFirstName("鲍勃");新的 PersonRole personRole; personRole.add(person);新建 ArrayList () 列表; list.add(PersonRole) 所以这段代码不会搜索人名。
    【解决方案3】:

    您需要使用自定义查询来创建自己的搜索查询。

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

    现在您可以添加任意数量的参数

    【讨论】:

    • 感谢您的回答。这绝对是一种快速而肮脏的方法,也是我目前的实施方式,但由于有这么多可选参数,它变得非常难看。正如我所提到的,我必须开始放置 or is null 语句。
    猜你喜欢
    • 2021-04-20
    • 2020-02-03
    • 1970-01-01
    • 1970-01-01
    • 2014-12-06
    • 1970-01-01
    • 2014-09-22
    • 1970-01-01
    相关资源
    最近更新 更多