普通属性
抓取标量字段
标量字段即数据库表中所有非关联字段。以抓取书籍名称为例:
- Java
- Kotlin
BookTable book = Tables.BOOK_TABLE;
List<Book> books = sqlClient
.createQuery(book)
.select(
book.fetch(
Fetchers.BOOK_FETCHER.name()
)
)
.execute();
val books = sqlClient
.createQuery(Book::class) {
where(table.edition.eq(3))
select(
table.fetchBy {
name()
}
)
}
.execute()
对Java而言,Annotation processor会为每一个实体接口自动生成一个Fetcher类,在这个例子中,就是BookFetcher
生成的SQL如下:
select
tb_1_.ID,
/* highlight-next-line */
tb_1_.NAME
from BOOK as tb_1_
where tb_1_.EDITION = ?
Java代码没有调用BookFetcher的id()
方法,但是,我们看到SQL语句仍然查询了对象的id属性。
id属性被特殊对待,总是会被查询,并不受对象抓取器的控制。
事实上,自动生成BookFetcher类中也没有id()
方法,因为不需要。
打印的结果如 下(原输出是紧凑的,为了方便阅读,这里进行了格式化):
[
{
"id":3,
"name":"Learning GraphQL"
},
...省略其他对象...
]
抓取多个字段
- Java
- Kotlin
BookTable book = Tables.BOOK_TABLE;
List<Book> books = sqlClient
.createQuery(book)
.select(
book.fetch(
Fetchers.BOOK_FETCHER
.name()
.edition()
)
)
.execute();
val books = sqlClient
.createQuery(Book::class) {
where(table.edition.eq(3))
select(
table.fetchBy {
name()
edition()
}
)
}
.execute()
对象抓取器是不可变对象,每一次链式调用都会返回一个新的对象抓取器。
即,上述Java代码中
Fetchers.BOOK_FETCHER
Fetchers.BOOK_FETCHER.name()
Fetchers.BOOK_FETCHER.name().edition()
是三个不同的对象抓取器,每一个都是不可变的。
对象抓取器是不可变对象,所以你可以借助静态变量随意共享对象抓取器。
生成的SQL如下:
select
tb_1_.ID,
/* highlight-next-line */
tb_1_.NAME,
/* highlight-next-line */
tb_1_.EDITION
from BOOK as tb_1_
where tb_1_.EDITION = ?
打印的结果如下(原输出是紧凑的,为了方便阅读,这里进行了格式化):
[
{
"id":3,
"name":"Learning GraphQL",
"edition":1
},
...省略其他对象...
]
抓取 所有标量字段
在一些场景下,抓取所有非关联字段是非常常用的操作,因此提供了allScalarFields()
用于加载所有非关联字段。
- Java
- Kotlin
BookTable book = Tables.BOOK_TABLE;
List<Book> books = sqlClient
.createQuery(book)
.select(
book.fetch(
Fetchers.BOOK_FETCHER.allScalarFields()
)
)
.execute();
val books = sqlClient
.createQuery(Book::class) {
where(table.edition.eq(3))
select(
table.fetchBy {
allScalarFields()
}
)
}
.execute()
生成的SQL如下:
select
tb_1_.ID,
// highlight-start
tb_1_.NAME,
tb_1_.EDITION,
tb_1_.PRICE
// highlight-end
from BOOK as tb_1_
where tb_1_.EDITION = ?
打印的结果如下(原输出是紧凑的,为了方便阅读,这里进行了格式化):
{
"id":3,
"name":"Learning GraphQL",
"edition":3,
"price":51.00
}
// 省略其他对象
allScalarFields()
只会加载非关联字段,示例中可以看到查询了id
, name
, edition
, price
,但是并没有查询store
和authors
这两个关联属性。
抓取关联属性将在下一篇文档中介绍。
负属性(排除不需要的属性)
前面讲过的属性都是正属性,不断新增要查询的字段。但一些场景下,我们只需要排除一些指定字段,其他的字段则都要查询。
这时候就可以用负属性去排除不需要的字段。
- Java
- Kotlin
BookTable book = Tables.BOOK_TABLE;
List<Book> books = sqlClient
.createQuery(book)
.select(
book.fetch(
Fetchers.BOOK_FETCHER
.allScalarFields()
.edition(false)
)
)
.execute();
val books = sqlClient
.createQuery(Book::class) {
where(table.edition.eq(3))
select(
table.fetchBy {
allScalarFields()
edition(false)
}
)
}
.execute()
edition(false)
使用参数false,这就是负属性。
-
allScalarFields()
的属性是id + name + edition + price
-
edition(false)
表示-edition
所以,最终并在一起,最终被抓取的属性是id + name + price
- 对于正属性而言,
edition()
和edition(true)
等价 - 当大部分属性需要抓取,只有少部分属性不需要抓取时,
allScalarFields
和负属性结合使用会非常有用
生成的SQL如下:
select
tb_1_.ID,
tb_1_.NAME,
tb_1_.PRICE
from BOOK as tb_1_
where tb_1_.EDITION = ?
打印的结果如下(原输出是紧凑的,为了方便阅读,这里进行了格式化):
[
{
"id":3,
"name":"Learning GraphQL",
"price":51.00
// 这里没有`edition`
},
...省略其他对象...
]