跳到主要内容

超级QBE

能否更简单

通过上一篇文章,我们知道Jimmer SQL DSL天生就是为任意复杂的动态查询而设计,和其他框架的SQL DSL仅仅为了带来强类型体验完全不同。

但是有两个问题

  1. 伴随着上一篇文章的讲解,查询方法的参数越来越多。这对Java语言不友好,我们迫切需要将所有查询参数封装成一个对象。

  2. 我真的很懒,我想实现上一篇文章中的所有功能,但我不想写那些代码,我只想写一行代码。

Jimmer自带的DTO语言可以快速解决以上两个问题。

定义Specification DTO

由于在查询任意形状/暴露功能/返回输出DTO一文中,为讲解Output DTO,我们已经对DTO语言有了一定了解,本文不做重复性阐述。

  1. 安装DTO语言Intellij插件:https://github.com/ClearPlume/jimmer-dto (此过程不是必须的,但非常推荐)

  2. 新建目录src/main/dto

  3. src/main/dto下建立一个文件Book.dto,编写代码如下

    Book.dto
    export com.yourcompany.yourproject.model.Book 
    -> package com.yourcompany.yourproject.model.dto

    specification BookSpecification {
    like/i(name)
    ge(price) // Default alias: minPrice
    le(price) // Default alias: maxPrice
    flat(store) {
    as(^ -> store) {
    like/i(name)
    like/i(website)
    }
    }
    flat(authors) {
    like/i(firstName, lastName) as authorName
    gender as authorGender
    }
    }
    ...省略其他DTO类型定义...
    信息

    和之前讨论过的Output/Input DTO不同,这里查询规格DTO采用specification修饰符。

    这个Specification DTO内部使用了大量的QBE函数,其意义不难理解,本文属于快速预览部分,不做过多解释。

生成的代码

编译项目,Jimmer将会自动生成如下代码

BookSpecification.java
@GeneratedBy(
file = "<yourproject>/src/main/dto/Book.dto"
)
public class BookSpecification
implements JSpecification<Book, BookTable> {

@Nullable
private String name;

@Nullable
private BigDecimal minPrice;

@Nullable
private BigDecimal maxPrice;

@Nullable
private String storeName;

@Nullable
private String storeWebsite;

@Nullable
private String authorName;

@Nullable
private Gender authorGender;

@Override
public void applyTo(SpecificationArgs<Book, BookTable> args) {
...Omit complex dynamic query logic...
}

...Omit getters, setters, hashCode, equals, toString...
}
  • ❶ 提醒开发人员这个类是在编译时被Jimmer自动生成的

  • ❷ Specification DTO实现的接口

  • ❸ 这个类知道如何生成SQL条件

使用

BookRepository.java
@Repository
public class BookRepository {

private final JSqlClient sqlClient;

public BookRepository(JSqlClient sqlClient) {
this.sqlClient = sqlClient;
}

List<Book> findBooks(
BookSpecification specification,
@Nullable Fetcher<Book> fetcher
) {
BookTable table = Tables.BOOK_TABLE;

return sqlClient
.createQuery(table)
.where(specification)
.select(table.fetch(fetcher))
.execute();
}
}

我们看到,支持,我们只需一行代码即可实现复杂的动态查询。

其功能和上一篇文章中最后一个例子完全一样,无需重复。