跳到主要内容

最终使用

Jimmer的两种用法

  • 使用Jimmer的Spring Boot Starter

  • 直接使用底层的SqlClient

Jimmer具备完善的配套例子项目,关于Jimmer之Spring Boot Starter的用法,请参考例子;本文讨论在不使用Spring的前提下,直接使用底层的sqlClient。

SqlClient

SqlClient是Jimmer中最底层的API

Javaorg.babyfish.jimmer.sql.JSqlClient
Kotlinorg.babyfish.jimmer.sql.kt.KSqlClient

需要创建一个该类型的全局对象,这个全局变量是Jimmer所有ORM行为的Api入口。

多数据源需要创建多个全局对象。然而,我们这里讨论的是单数据源这种最常见的情况,一个全局对象足够。

由于采用了Jimmer的Spring Boot Starter,在这种情况下,请在application.yml (或application.properties) 指定如下配置

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

Jimmer的Spring Boot Starter会自动创建这个全局对象

注意,对于kotlin而言,为了创建KSqlClient而非JSqlClient,需要为application.yml/application.properties配置jimmer.language = kotlin

信息

因此,你可以在任何地方直接注入JSqlClient/KSqlClient类型的对象。

本文的后续代码会假设有一个sqlClient变量并使用它,但不会给予解释,因为这里已经给出了详细的解释。

查询

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, edtion desc"
@Nullable String sortCode,

@Nullable String name,
@Nullable BigDecimal minPrice,
@Nullable BigDecimal maxPrice,
@Nullable String storeName,
@Nullable String storeWebsite,
@Nullable String authorName
) {
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);
}
}

用户可以自行创建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

public class BookRepository {

...省略其他成员...

public long saveBook(BookInput input) {
return sqlClient
.save(input)
.execute()
.getModifiedEntity()
// 如果`input.id`为null,返回自动分配的id
.getId();
}
}

保存长关联

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

public class BookStoreRepository {

public long saveBookStore(CompositeBookStoreInput input) {
return sqlClient
.save(input)
.execute()
.getModifiedEntity()
// 如果`input.id`为null,返回自动分配的id
.getId();
}
}

删除

修改BookRepository

public class BookRepository {

...省略其他成员...

public void deleteBook(long id) {
sqlClient.deleteById(Book.class, id);
}
}