4.4 动态表连接
用法
- Java
- Kotlin
@Nullable String storeName = ...略...;
@Nullable String storeWebsite = ...略...;
BookTable table = BookTable.$;
List<Book> books = sqlClient
.createQuery(table)
.where(table.store().name().eqIf(storeName)) ❶
.where(table.store().website().eqIf(storeWebsite)) ❷
.select(table)
.execute();
val storeName: String? = ...略...
val storeWebsite: String? = ...略...
val books = sqlClient
.createQuery(Book::class) {
where(table.store.name `eq?` storeName) ❶
where(table.store.website `eq?` storeWebsite) ❷
select(table)
}
.execute()
信息
上述代码中, Java的table.store()
和Kotlin的table.store
表示通过多对一关联Book.store
内连接Book
所定义的表和BookStore
所定义的表。
即,表示如下SQL逻辑
from BOOK b
inner join BOOK_STORE s on b.STORE_ID = s.ID
事实上,假如实体模型更加丰富,可以书写更长的路径,比如table.store().city().province()
。
这里,仅仅做入门示范和快速预览,没必要构建更丰富的实体模型以演示更长的路径,最短表链连接路径table.store()足够。
各种情况
所有表连接都不生效
如果storeName
和storeWebsite
都为null,会导致❶和❷两处创建的动态表连接未被使用,未被使用的表连接会被自动忽略,不会渲染任何真实的SQL连接。
这时,生成如下SQL:
select
tb_1_.ID,
tb_1_.NAME,
tb_1_.EDITION,
tb_1_.PRICE,
tb_1_.STORE_ID
from BOOK tb_1_
部分表连接生效
将storeName
指定为非null,而storeWebsite
仍然为null,❶处的动态表连接生效,而❷的动态表连接被忽略。
这时,生成如下SQL:
select
tb_1_.ID,
tb_1_.NAME,
tb_1_.EDITION,
tb_1_.PRICE,
tb_1_.STORE_ID
from BOOK tb_1_
inner join BOOK_STORE tb_2_
on tb_1_.STORE_ID = tb_2_.ID
where
tb_2_.NAME = ? /* MANNING */
所有表连接都生效
如果storeName
和storeWebsite
都被指定为非null,会导致❶和❷两处创建的动态表连接都生效。
提示
Jimmer能自动合并冲突的连接,两个连接会被合并为一个,最终,只有一个SQL连接被渲染
select
tb_1_.ID,
tb_1_.NAME,
tb_1_.EDITION,
tb_1_.PRICE,
tb_1_.STORE_ID
from BOOK tb_1_
inner join BOOK_STORE tb_2_
on tb_1_.STORE_ID = tb_2_.ID
where
tb_2_.NAME = ? /* MANNING */
and
tb_2_.WEBSITE = ? /* https://www.manning.com */
IsNull和外连接
类似Java中table.store()
或Kotlintable.store
这样的连接路径,会被渲染成SQL的内连接,而非外连接,这是因为
信息
内连接比外连接拥有更好的性能!
警告
为此,Jimmer不惜通过异常让默认情况下内连接而得到的表对象不支持isNull
。
如果要对关联对象施加isNull
,必须明确采用外连接操作,例如
- Java
- Kotlin
TreeNodeTable table = TreeNodeTable.$;
List<TreeNode> rootNodes = sqlClient
.createQuery(table)
.where(table.parent(JoinType.LEFT).isNull())
.select(table)
.execute();
val rootNodes = sqlClient
.createQuery(TreeNode::class) {
where(table.`parent?`.isNull())
select(table)
}
.execute()
Java代码中的.parent(JoinType.LEFT)
和Kotlin代码中的.parent?
表示左连接。
其实,这种案例更适合上一文中的关联id条件
- Java
- Kotlin
TreeNodeTable table = TreeNodeTable.$;
List<TreeNode> rootNodes = sqlClient
.createQuery(table)
.where(table.parentId().isNull())
.select(table)
.execute();
val rootNodes = sqlClient
.createQuery(TreeNode::class) {
where(table.parentId.isNull())
select(table)
}
.execute()