直接修改中间表
简述
首先,中间表被对象模型 隐藏,没有与之直接对应的实体类型。此问题已在查询中间表一文中被阐述,此处不作重复。
另外,在Save指令章节中,我们介绍了save指令。它能对比数据库现有数据和用户要保存的新数据,如果某个基于中间表的关联属性发生了变化,中间表就会被修改。
诚然,Save指令功能非常强大,对中间表的修改只是其中很小的一个功能点。然而,有时候,我们只需要简单地对中间表进行插入或删除操作,我们不需要Save指令那么强大的功能。
Jimmer允许开发人员用更简单的方式,直接对中间表的数据进行插入和删除。
插入关联
- Java
- Kotlin
sqlClient
.getAssociations(BookProps.AUTHORS)
.save(12L, 3L);
sqlClient
.getAssociations(Book::authors)
.save(12L, 3L)
生成的SQL如下
insert into
BOOK_AUTHOR_MAPPING(
BOOK_ID, AUTHOR_ID
)
values (?, ?)
这个例子演示如何使用关联属性Book.authors操作中间表。
同理我们也可以通过关联属性Authors.books达到相同目的:
- Java
- Kotlin
sqlClient
.getAssociations(AuthorProps.BOOKS)
.save(3L, 12L);
sqlClient
.getAssociations(Author::books)
.save(3L, 12L)
注意,和上一个例子相比,因为关联的方向不同,所以save方法的参数顺序不同。
生成的SQL如下
insert into
BOOK_AUTHOR_MAPPING(
AUTHOR_ID, BOOK_ID
)
values (?, ?)
不难发现,insert语句列的顺序也不同。
逆变换
对于双向关联,可以使用reverse在正反关联之间切换
- Java
- Kotlin
Associations bookToAuthor = sqlClient
.getAssociations(BookProps.AUTHORS);
Associations authorToBook = sqlClient
.getAssociations(AuthorProps.BOOKS);
Associations authorToBook2 =
bookToAuthor.reverse();
Associations bookToAuthor2 =
authorToBook.reverse();
val bookToAuthor =
sqlClient.getAssociations(
Book::authors
)
val authorToBook =
sqlClient.getAssociations(
Author::books
)
val authorToBook2 =
bookToAuthor.reverse()
val bookToAuthor2 =
authorToBook.reverse()
这段代码中:
bookToAuthor和bookToAuthor2完全等价authorToBook和authorToBook2完全等价
批量插入
- Java
- Kotlin
sqlClient
.getAssociations(BookProps.AUTHORS)
.saveAll(
Arrays.asList(
new Tuple2<>(10L, 1L),
new Tuple2<>(11L, 1L),
new Tuple2<>(12L, 1L),
new Tuple2<>(10L, 3L),
new Tuple2<>(11L, 3L),
new Tuple2<>(12L, 3L)
)
);
sqlClient
.getAssociations(
Book::authors
)
.saveAll(
listOf(
Tuple2(10L, 1L),
Tuple2(11L, 1L),
Tuple2(12L, 1L),
Tuple2(10L, 3L),
Tuple2(11L, 3L),
Tuple2(12L, 3L)
)
)
这里有3本书,两个作者,共6种组合方式。saveAll方法把这6种组合全部插入到中间表中,生成的SQL如下
insert into BOOK_AUTHOR_MAPPING(
BOOK_ID, AUTHOR_ID
) values
(?, ?),
(?, ?),
(?, ?),
(?, ?),
(?, ?),
(?, ?)
上面这种写法很繁琐,3 * 2 = 6还可以接受,但7 * 9 = 63呢?难道构建63个元组吗?
jimmer-sql提供一种快捷写法
- Java
- Kotlin
sqlClient
.getAssociations(BookProps.AUTHORS)
// 保存两个id集合的笛卡尔乘积
.saveAll(
Arrays.asList(
10L, 11L, 12L
),
Arrays.asList(
1L, 3L
)
);
sqlClient
.getAssociations(
Book::authors
)
// 保存两个id集合的笛卡尔乘积
.saveAll(
listOf(10L, 11L, 12L),
listOf(1L, 3L)
)
上面的saveAll方法接受两个集合参数,把这两个集合形成的笛卡尔乘积插入中间表,所以,功能和上一个例子的相同。
检查存在性
如果向中间表插入已经存在的id元组,数据库会被报错,因为违背了唯一性约束。
为了解决这个问题,可以进行存在性检查。
- Java
- Kotlin
sqlClient
.getAssociations(BookProps.AUTHORS)
.saveAllCommand(
Arrays.asList(
10L, 11L, 12L
),
Arrays.asList(
1L, 3L
)
)
.checkExistence()
.execute();
sqlClient
.getAssociations(
Book::authors
)
.saveAll(
listOf(10L, 11L, 12L),
listOf(1L, 3L),
checkExistence = true
)