超级QBE查询
Super QBE是一个非常强大的功能,利用DTO语言生成复杂查询的参数类型,并自动实现查询逻辑。
创建文件
在任何可以访问实体类型的项目中,创建src/main/dto目录,在这个目录下创建文件Book.dto。
对于Java项目而言,如果当前项目并 非定义实体类型的项目,需要在为当前项目中任何一个类添加@EnableDtoGeneration注解。
在文件头部添加如下代码
export com.yourcompany.yourproject.model.Book
-> package com.yourcompany.yourproject.dto
以上这些步骤,以及如何编译DTO文件,在DTO语言#2. 创建文件中有详细的讨论,本文不作重复性阐述。
定义Specification类型
...省略export语句...
specification BookSpecification {
}
编译后的代码
编译后,将会生成这样的Java/Kotlin代码
- Java
- Kotlin
package com.yourcompany.yourproject.dto;
import org.babyfish.jimmer.sql.ast.query.specification.JSpecification;
import org.babyfish.jimmer.sql.ast.query.specification.SpecificationArgs;
...省略其他import语句...
public class BookSpecification implements JSpecification<Book, BookTable> {
@Override
public void applyTo(SpecificationArgs<Book, BookTable> args) {}
}
package com.yourcompany.yourproject.dto;
import org.babyfish.jimmer.sql.kt.ast.query.specification.KSpecification
import org.babyfish.jimmer.sql.kt.ast.query.specification.KSpecificationArgs
...省略其他import语句...
data class BookSpecification(
// 现在data class暂时没有字段,会导致编译错误
) : KSpecification<Book> {
override fun applyTo(args: KSpecificationArgs<Book>) {}
}
applyTo是specification编译后生成的代码中的特有方法,按照当前对象的信息动态地为Jimmer查询添加where条件。
此方法无需用户调用 (被Jimmer内部行为调用) ,用户也无需关心其内部代码实现。这里只需要知道此方法有什么用即可。
在后续的讨论中,我们会陆续为DTO文件中的BookSpecification添加属性。
相应地,对于自动生成的BookSpecification类而言,一方面属性会同步增加,另外一方面,applyTo方法中的代码也会变多。
用法
-
在查询中使用
- Java
- Kotlin
public List<Book> find(
Specification<Book> specification ❶
) {
BookTable table = Tables.BOOK_TABLE;
return sqlClient
.createQuery(table)
.where(specification) ❷
.select(table)
.execute();
}fun find(
specification: Specification<Book> ❶
): List<Book> =
sqlClient.createQuery(Book::class) {
where(specification) ❷
select(table)
}.execute()-
❶
org.babyfish.jimmer.Specification<Book>类型的参数,用于生产各种动态SQL条件。 -
❷ 无论
specification格式简单还是复杂,只需一个简单的where语句就可以使用。
-
在Spring Data Repository中使用
Jimmer整合了Spring Data,所以能定义Spring Data Repository,请参考SpringData风格以了解更多。
Jimmer的Spring Data Repository有两种查询风格,抽象方法和default 方法。default方法使用specification的代码和上面雷同, 所以,我们看看抽象查询方法使用specification的例子
- Java
- Kotlin
public interface BookRepository : JRepository<Book, Long> {
public List<Book> find(
Specification<Book> specification
)
}interface BookRepository : KRepository<Book, Long> {
fun find(
specification: Specification<Book>
): List<Book>
}
属性映射
映射属性
...省略export语句...
specification BookSpecification {
name
}
这样,就将实体属性映射到了DTO中,生成的代码为
- Java
- Kotlin
public class BookSpecification implements JSpecification<Book, BookTable> {
@Nullable
private String name;
...省略getters和setters...
@Override
public void applyTo(SpecificationArgs<Book, BookTable> args) {
...略...
}
}
package com.yourcompany.yourproject.dto;
import org.babyfish.jimmer.sql.kt.ast.query.specification.KSpecification
import org.babyfish.jimmer.sql.kt.ast.query.specification.KSpecificationArgs
...省略其他import语句...
data class BookSpecification(
val name: String? = null
) : KSpecification<Book> {
override fun applyTo(args: KSpecificationArgs<Book>) {
...略...
}
}