动态筛选
基本用法
-
Java API使用链式方式构建DSL,为了不打断链式代码书写,使用
whereIf
方法按条件添加where条件。 -
Kotlin API使用lambda构建DSL,动态查询无需专用API支持。
- Java
- Kotlin
public List<Book> findBooks(@Nullable String name) {
BookTable table = Tables.BOOK_TABLE;
return sqlClient
.createQuery(table)
.whereIf(
name != null && !name.isEmpty(),
table.name().eq(name)
)
.orderBy(table.name().asc(), table.edition().desc())
.select(table)
.execute();
}
fun findBooks(name: String?): List<Book> =
sqlClient
.createQuery(Book::class) {
name?.takeIf { it.isNotEmpty() }?.let {
where(table.name eq it)
}
orderBy(table.name.asc(), table.edition.desc())
select(table)
}
.execute()
-
调用
findBooks(null)
,生成的SQL为select
tb_1_.ID,
tb_1_.NAME,
tb_1_.EDITION,
tb_1_.PRICE,
tb_1_.STORE_ID
from BOOK tb_1_
order by
tb_1_.NAME asc,
tb_1_.EDITION desc -
调用
findBooks("SQL in Action")
,生成的SQL为select
tb_1_.ID,
tb_1_.NAME,
tb_1_.EDITION,
tb_1_.PRICE,
tb_1_.STORE_ID
from BOOK tb_1_
where
tb_1_.NAME = ? /* SQL in Action */
order by
tb_1_.NAME asc,
tb_1_.EDITION desc
Java开发人员注意事项
Java开发人员请注意,上面的的代码
.whereIf(
name != null && !name.isEmpty(),
table.name().eq(name)
)
即便name为null,whereIf的条件并不成立,第二个参数table.name().eq(name)
也会被执行,这是几乎所有编程语言的特性。
对于这里eq
*(或ne
)*而言,参数为null不会导致问题。因为eq(null)
会被自动改成isNull()
, ne(null)
会被自动改成isNotNull()
。
但是,对于其他大部分条件表达式而言,用null构建会导致异常。
提示
不用担心,如果你不小心犯了错误,异常信息非常完善,足够引导你采用即将介绍的正确的编程方式。
以大于或等于操作而言ge
,可以如此添加动态查询条件
.whereIf(
minPrice != null,
() -> table.price().ge(minPrice)
)
这里,使用lambda表达式延迟表达式的构建时机即可。只有当条件满足时,才会构建表达式。
对于kotlin而言,不存在这个问题,无任何注意事项。
让我们来看一个更完整的例子
- Java
- Kotlin
public List<Book> findBooks(
@Nullable String name,
@Nullable BigDecimal minPrice,
@Nullable BigDecimal maxPrice
) {
BookTable table = Tables.BOOK_TABLE;
return sqlClient
.createQuery(table)
.whereIf(
name != null && !name.isEmpty(),
table.name().eq(name)
)
.whereIf(
minPrice != null,
() -> table.price().ge(minPrice)
)
.whereIf(
maxPrice != null,
() -> table.price().le(maxPrice)
)
.orderBy(table.name().asc(), table.edition().desc())
.select(table)
.execute();
}
fun findBooks(
name: String? = null,
minPrice: BigDecimal? = null,
maxPrice: BigDecimal? = null
): List<Book> =
sqlClient
.createQuery(Book::class) {
name?.takeIf { it.isNotEmpty() }?.let {
where(table.name eq it)
}
minPrice?.let {
where(table.price ge it)
}
maxPrice?.let {
where(table.price le it)
}
orderBy(table.name.asc(), table.edition.desc())
select(table)
}
.execute()
多表操作
到目前为止,动态查询是基于单表的。
考虑一种更复杂的场景,如果某些动态查询条件针对其他表而非当前表 (即,需要先join到其他表,再对join得到的表添加动态where条件),该如何实现呢?
这个问题没有被任何SQL访问的上层方案优雅解决,属于领域空白,而Jimmer完美解决了这个难题*(Jimmer立项的根本原因)*
在下一篇文档中,我们将会系统性讨论这个问题。
提示
在下一篇文档中,你会发现Jimmer SQL DSL的独到之处,获得一 个行业内无任何方案支持的强大能力。