最终使用
Jimmer的两种用法
-
使用Jimmer的Spring Boot Starter
-
直接使用底层的SqlClient
Jimmer具备完善的配套例子项目,关于Jimmer之Spring Boot Starter的用法,请参考例子;本文讨论在不使用Spring的前提下,直接使用底层的sqlClient。
SqlClient
SqlClient
是Jimmer中最底层的API
Java | org.babyfish.jimmer.sql.JSqlClient |
Kotlin | org.babyfish.jimmer.sql.kt.KSqlClient |
需要创建一个该类型的全局对象,这个全局变量是Jimmer所有ORM行为的Api入口。
多数据源需要创建多个全局对象。然而,我们这里讨论的是单数据源这种最常见的情况,一个全局对象足够。
由于采用了Jimmer的Spring Boot Starter,在这种情况下,请在application.yml
(或application.properties
) 指定如下配置
- Java
- Kotlin
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/jimmer_demo
username: root
password: 123456
jimmer:
dialect: org.babyfish.jimmer.sql.dialect.MySqlDialect
show-sql: true
pretty-sql: true
database-validation-mode: ERROR
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/jimmer_demo
username: root
password: 123456
jimmer:
language: kotlin // This is important for kotlin
dialect: org.babyfish.jimmer.sql.dialect.MySqlDialect
show-sql: true
pretty-sql: true
database-validation-mode: ERROR
Jimmer的Spring Boot Starter会自动创建这个全局对象
注意,对于kotlin而言,为了创建
KSqlClient
而非JSqlClient
,需要为application.yml
/application.properties
配置jimmer.language = kotlin
。
因此,你可以在任何地方直接注入JSqlClient
/KSqlClient
类型的对象。
本文的后续代码会假设有一个sqlClient
变量并使用它,但不会给予解释,因为这里已经给出了详细的解释。
查询
- Java
- Kotlin
package com.example.model.repository;
import org.babyfish.jimmer.sql.JSqlClient;
import org.babyfish.jimmer.sql.fetcher.Fetcher;
import org.babyfish.jimmer.Page;
import com.example.model.Book;
import com.example.model.BookTable;
public class BookRepository {
private static final BookTable T = BookTable.$;
public Page<Book> findBooks(
int pageIndex, // 从0开始
int pageSize,
@Nullable Fetcher<Book> fetcher,
// 例如: "name asc, edition desc"
@Nullable String sortCode,
@Nullable String name,
@Nullable BigDecimal minPrice,
@Nullable BigDecimal maxPrice,
@Nullable String storeName,
@Nullable String storeWebsite,
@Nullable String authorName,
@Nullable Gender authorGender
) {
return sqlClient
.createQuery(T)
.where(T.name().ilikeIf(name))
.where(T.price().betweenIf(minPrice, maxPrice))
.where(T.store().name().ilikeIf(storeName))
.where(T.store().website().ilikeIf(storeWebsite))
.where(
T.authors(author ->
Predicate.or(
author.firstName().ilikeIf(authorName),
author.lastName().ilikeIf(authorName)
)
)
)
.where(T.authors(author -> author.gender().eqIf(authorGender)))
.orderBy(
Order.makeOrders(
T,
sortCode != null ?
sortCode :
"name asc, edition desc"
)
)
.select(
T.fetch(fetcher)
)
.fetchPage(pageIndex, pageSize);
}
}
package com.example.model.repository
import org.babyfish.jimmer.sql.kt.KSqlClient
import org.babyfish.jimmer.sql.fetcher.Fetcher
import org.babyfish.jimmer.Page
import com.example.model.*
class BookRepository {
fun findBooks(
pageIndex: Int, // 从0开始
pageSize: Int = 10,
fetcher: Fetcher<Book>? = null,
sortCode: String = "name asc, edition desc",
name: String? = null,
minPrice: BigDecimal? = null,
maxPrice: BigDecimal? = null,
storeName: String? = null,
storeWebsite: String? = null,
authorName: String? = null,
authorGender: Gender? = null
): Page<Book> =
sqlClient
.createQuery(Book::class) {
where(table.name `ilike?` name)
where(table.price.`between?`(minPrice, maxPrice))
where(table.store.name `ilike?` storeName)
where(table.store.website `ilike?` storeWebsite)
where += table.authors {
or(
firstName `ilike?` authorName,
lastName `ilike?` authorName
)
}
where += table.authors { gender `eq?` authorGender }
orderBy(table.makeOrders(sortCode))
select(
table.fetch(fetcher)
)
}
.fetchPage(pageIndex, pageSize)
}
用户可以自行创建BookRepository
类型的对象,利用各种参数的排列组合,验证
- 动态查询 (包括动态表连接,隐式子查询)
- 动态排序
- 分页查询
这里不再赘述。
保存
保存短关联
在src/main/dto
目录下创建任意扩展名为dto
的文件,编辑其代码如下
export com.example.model.Book
-> package com.example.model.dto
input BookInput {
#allScalars(this)
id(store) // as storeId
id(authors) as authorIds
}
编译,生成基于Java/Kotlin定义的DTO类型com.example.model.dto.BookInput
,然后修改BookRepository
- Java
- Kotlin
public class BookRepository {
...省略其他成员...
public long saveBook(BookInput input) {
return sqlClient
.save(input)
.execute()
.getModifiedEntity()
// 如果`input.id`为null,返回自动分配的id
.getId();
}
}
class BookRepository {
...省略其他成员...
fun saveBook(input: BookInput): Long =
sqlClient
.save(input)
.modifiedEntity
// 如果`input.id`为null,返回自动分配的id
.id
}
保存长关联
在src/main/dto
目录下创建任意扩展名为dto
的文件,编辑其代码如下
export com.example.model.BookStore
-> package com.example.model.dto
input CompositeBookStoreInput {
#allScalars(this)
books {
#allScalars(this)
-id
}
}
编译,生成基于Java/Kotlin定义的DTO类型com.example.model.dto.CompositeBookStoreInput
,然后创建BookStoreRepository
- Java
- Kotlin
public class BookStoreRepository {
public long saveBookStore(CompositeBookStoreInput input) {
return sqlClient
.save(input)
.execute()
.getModifiedEntity()
// 如果`input.id`为null,返回自动分配的id
.getId();
}
}
class BookStoreRepository {
fun saveBookStore(input: CompositeBookStoreInput): Long =
sqlClient
.save(input)
.modifiedEntity
// 如果`input.id`为null,返回自动分配的id
.id
}
删除
修改BookRepository
- Java
- Kotlin
public class BookRepository {
...省略其他成员...
public void deleteBook(long id) {
sqlClient.deleteById(Book.class, id);
}
}
class BookRepository {
...省略其他成员...
fun deleteBook(id: Long) {
sqlClient.deleteById(Book::class, id)
}
}