mirror of
https://gitee.com/mybatis-flex/mybatis-flex.git
synced 2025-12-07 00:58:24 +08:00
docs: add auto mapper docs
This commit is contained in:
parent
3ecd8c5483
commit
512f8d3891
@ -58,6 +58,7 @@ export default defineConfig({
|
|||||||
items: [
|
items: [
|
||||||
{text: '增、删、改', link: '/zh/base/add-delete-update'},
|
{text: '增、删、改', link: '/zh/base/add-delete-update'},
|
||||||
{text: '基础查询', link: '/zh/base/query'},
|
{text: '基础查询', link: '/zh/base/query'},
|
||||||
|
{text: '自动映射', link: '/zh/base/auto-mapping'},
|
||||||
{text: '关联查询', link: '/zh/base/relations-query'},
|
{text: '关联查询', link: '/zh/base/relations-query'},
|
||||||
{text: '批量操作', link: '/zh/base/batch'},
|
{text: '批量操作', link: '/zh/base/batch'},
|
||||||
{text: '链式操作🔥🔥', link: '/zh/base/chain'},
|
{text: '链式操作🔥🔥', link: '/zh/base/chain'},
|
||||||
|
|||||||
251
docs/zh/base/auto-mapping.md
Normal file
251
docs/zh/base/auto-mapping.md
Normal file
@ -0,0 +1,251 @@
|
|||||||
|
# 自动映射
|
||||||
|
|
||||||
|
在 MyBatis-Flex 中,内置了非常智能的 **自动映射** 功能,能够使得我们在查询数据的时候,从数据结果集绑定到实体类(或者 VO、DTO等)等变得极其简单易用。
|
||||||
|
|
||||||
|
## 数据假设
|
||||||
|
|
||||||
|
假设在我们的项目中,有如下的表结构、和实体类:
|
||||||
|
|
||||||
|
账户表(tb_account):
|
||||||
|
```sql
|
||||||
|
CREATE TABLE IF NOT EXISTS `tb_account`
|
||||||
|
(
|
||||||
|
`id` INTEGER auto_increment,
|
||||||
|
`user_name` VARCHAR(100),
|
||||||
|
`age` Integer
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
图书表(tb_book):
|
||||||
|
|
||||||
|
```sql
|
||||||
|
CREATE TABLE IF NOT EXISTS `tb_book`
|
||||||
|
(
|
||||||
|
`id` INTEGER auto_increment,
|
||||||
|
`account_id` Integer,
|
||||||
|
`title` VARCHAR(100),
|
||||||
|
`content` text
|
||||||
|
);
|
||||||
|
```
|
||||||
|
> 图书和账户的关系是多对一的关系:一个账户可以拥有多本书。
|
||||||
|
|
||||||
|
|
||||||
|
角色表(tb_role):
|
||||||
|
|
||||||
|
```sql
|
||||||
|
CREATE TABLE IF NOT EXISTS `tb_role`
|
||||||
|
(
|
||||||
|
`id` INTEGER auto_increment,
|
||||||
|
`name` VARCHAR(100)
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
账户和角色的 **多对多** 关系映射表(tb_role_mapping):
|
||||||
|
```sql
|
||||||
|
CREATE TABLE IF NOT EXISTS `tb_role_mapping`
|
||||||
|
(
|
||||||
|
`account_id` INTEGER ,
|
||||||
|
`role_id` INTEGER
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
## 基础映射
|
||||||
|
|
||||||
|
基础映射指的是,定义的实体类和表结构是一一对应的关系,例如:
|
||||||
|
|
||||||
|
```java
|
||||||
|
@Table(value = "tb_account")
|
||||||
|
public class Account {
|
||||||
|
|
||||||
|
@Id(keyType = KeyType.Auto)
|
||||||
|
private Long id;
|
||||||
|
private String userName;
|
||||||
|
private int age;
|
||||||
|
|
||||||
|
//getter setter
|
||||||
|
}
|
||||||
|
```
|
||||||
|
`Account.java `与表 `tb_account` 是字段和属性是一一对应关系的。此时,我们在查询数据的时候,可以通过
|
||||||
|
`AccountMapper` 方法直接查询,例如:
|
||||||
|
|
||||||
|
```java
|
||||||
|
QueryWrapper qw = new QeuryWrapper();
|
||||||
|
qw.select(ACCOUNT.ALL_COLUMNS)
|
||||||
|
.where(ACCOUNT.ID.ge(100));
|
||||||
|
|
||||||
|
List<Account> accounts = accountMapper.selectListByQuery(qw);
|
||||||
|
```
|
||||||
|
|
||||||
|
或者使用如下的链式查询,都可以直接得到 `List<Account>` 结果:`accounts`。
|
||||||
|
|
||||||
|
```java
|
||||||
|
QueryChain.of(accountMapper)
|
||||||
|
.select(ACCOUNT.ALL_COLUMNS)
|
||||||
|
.where(ACCOUNT.ID.ge(100))
|
||||||
|
.list();
|
||||||
|
```
|
||||||
|
|
||||||
|
## AS 映射
|
||||||
|
|
||||||
|
|
||||||
|
假设我们在 `Account.java` 中多定义了一些其他属性,如下所示:
|
||||||
|
|
||||||
|
```java
|
||||||
|
@Table(value = "tb_account")
|
||||||
|
public class Account {
|
||||||
|
|
||||||
|
@Id(keyType = KeyType.Auto)
|
||||||
|
private Long id;
|
||||||
|
private String userName;
|
||||||
|
private int age;
|
||||||
|
|
||||||
|
//最大年龄
|
||||||
|
private int maxAge;
|
||||||
|
|
||||||
|
//平均年龄
|
||||||
|
private int svgAge;
|
||||||
|
|
||||||
|
//getter setter
|
||||||
|
}
|
||||||
|
```
|
||||||
|
那么,我们在查询的时候,就可以通过 `as` 进行映射关联,查询代码如下:
|
||||||
|
|
||||||
|
```java 4,5
|
||||||
|
QueryChain.of(accountMapper)
|
||||||
|
.select(
|
||||||
|
ACCOUNT.ALL_COLUMNS,
|
||||||
|
max(ACCOUNT.AGE).as("maxAge"),
|
||||||
|
avg(ACCOUNT.AGE).as("svgAge")
|
||||||
|
).where(ACCOUNT.ID.ge(100))
|
||||||
|
.list();
|
||||||
|
```
|
||||||
|
或者:
|
||||||
|
|
||||||
|
```java 4,5
|
||||||
|
QueryChain.of(accountMapper)
|
||||||
|
.select(
|
||||||
|
ACCOUNT.ALL_COLUMNS,
|
||||||
|
max(ACCOUNT.AGE).as("max_age"),
|
||||||
|
avg(ACCOUNT.AGE).as("svg_age")
|
||||||
|
).where(ACCOUNT.ID.ge(100))
|
||||||
|
.list();
|
||||||
|
```
|
||||||
|
|
||||||
|
或者使用 lambda:
|
||||||
|
|
||||||
|
```java 4,5
|
||||||
|
QueryChain.of(accountMapper)
|
||||||
|
.select(
|
||||||
|
ACCOUNT.ALL_COLUMNS,
|
||||||
|
max(ACCOUNT.AGE).as(Account::getMaxAge),
|
||||||
|
avg(ACCOUNT.AGE).as(Account::getAvgAge)
|
||||||
|
).where(ACCOUNT.ID.ge(100))
|
||||||
|
.list();
|
||||||
|
```
|
||||||
|
|
||||||
|
## 多表映射
|
||||||
|
|
||||||
|
假设我们定义了一个 `BootVo.java`,其中包含了图书的基本信息,也包含了图书归属的用户信息,例如:
|
||||||
|
|
||||||
|
```java
|
||||||
|
public class BookVo {
|
||||||
|
|
||||||
|
//图书的基本字段
|
||||||
|
private Long id;
|
||||||
|
private Long accountId;
|
||||||
|
private String title;
|
||||||
|
private String content;
|
||||||
|
|
||||||
|
//用户表的字段
|
||||||
|
private String userName;
|
||||||
|
private int userAge;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
此时,我们再进行 `left join` 多表查询时,代码如下:
|
||||||
|
|
||||||
|
```java
|
||||||
|
List<BookVo> bookVos = QueryChain.of(bookMapper)
|
||||||
|
.select(
|
||||||
|
BOOK.ALL_COLUMNS, //图书的所有字段
|
||||||
|
ACCOUNT.USER_NAME, //用户表的 user_name 字段
|
||||||
|
ACCOUNT.AGE.as("userAge") //用户表的 age 字段, as "userAge"
|
||||||
|
).form(BOOK)
|
||||||
|
.leftJoin(ACCONT).on(BOOK.ACCOUNT_ID.eq(ACCOUNT.ID))
|
||||||
|
.where(ACCOUNT.ID.ge(100))
|
||||||
|
.listAs(BookVo.java);
|
||||||
|
```
|
||||||
|
|
||||||
|
或者,我们也可以直接在 BookVo 中,定义 `Account` 对象,例如:
|
||||||
|
|
||||||
|
```java
|
||||||
|
public class BookVo {
|
||||||
|
|
||||||
|
//图书的基本字段
|
||||||
|
private Long id;
|
||||||
|
private Long accountId;
|
||||||
|
private String title;
|
||||||
|
private String content;
|
||||||
|
|
||||||
|
//用户
|
||||||
|
private Account account;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
查询代码如下:
|
||||||
|
|
||||||
|
```java
|
||||||
|
List<BookVo> bookVos = QueryChain.of(bookMapper)
|
||||||
|
.select(
|
||||||
|
BOOK.DEFAULT_COLUMNS,
|
||||||
|
ACCOUNT.DEFAULT_COLUMNS,
|
||||||
|
)
|
||||||
|
.form(BOOK)
|
||||||
|
.leftJoin(ACCONT).on(BOOK.ACCOUNT_ID.eq(ACCOUNT.ID))
|
||||||
|
.where(ACCOUNT.ID.ge(100))
|
||||||
|
.listAs(BookVo.java);
|
||||||
|
```
|
||||||
|
|
||||||
|
## 高级映射
|
||||||
|
|
||||||
|
在以上的表结构中,一个账户可以有多本图书,那么我们假设定义的 `AccountVo.java` 的结构如下:
|
||||||
|
|
||||||
|
```java
|
||||||
|
public class AccountVO {
|
||||||
|
|
||||||
|
private Long id;
|
||||||
|
private String userName;
|
||||||
|
private int age;
|
||||||
|
|
||||||
|
//账户拥有的 图书列表
|
||||||
|
private List<Book> books;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
List<AccountVO> bookVos = QueryChain.of(accountMapper)
|
||||||
|
.select() // 不传入参数等同于 SQL 的 select *
|
||||||
|
.form(ACCONT)
|
||||||
|
.leftJoin(BOOK).on(ACCOUNT.ID.eq(BOOK.ACCOUNT_ID))
|
||||||
|
.where(ACCOUNT.ID.ge(100))
|
||||||
|
.listAs(AccountVO.java);
|
||||||
|
```
|
||||||
|
|
||||||
|
亦或者指定查询参数:
|
||||||
|
|
||||||
|
```java
|
||||||
|
List<AccountVO> bookVos = QueryChain.of(accountMapper)
|
||||||
|
.select(
|
||||||
|
ACCOUNT.ID,
|
||||||
|
ACCOUNT.USER_NAME,
|
||||||
|
ACCOUNT.AGE,
|
||||||
|
BOOK.TITLE,
|
||||||
|
BOOK.CONTENT,
|
||||||
|
)
|
||||||
|
.form(ACCONT)
|
||||||
|
.leftJoin(BOOK).on(ACCOUNT.ID.eq(BOOK.ACCOUNT_ID))
|
||||||
|
.where(ACCOUNT.ID.ge(100))
|
||||||
|
.listAs(AccountVO.java);
|
||||||
|
```
|
||||||
|
|
||||||
|
高级映射的场景中,我们还可以通过注解 `@RelationManyToOne` 进行查询,
|
||||||
|
详情请点击 [这里](./relations-query#%E4%B8%80%E5%AF%B9%E5%A4%9A-relationonetomany)。
|
||||||
@ -203,7 +203,7 @@ WHERE account_id IN (1, 2, 3, 4, 5)
|
|||||||
|
|
||||||
**Map 映射**
|
**Map 映射**
|
||||||
|
|
||||||
若 `Account.books` 是一个 `Map`,而非 `List`,那么,我们需要通过配置 `mapKeyField` 来指定使用用个列来充当 `Map` 的 `Key`,
|
若 `Account.books` 是一个 `Map`,而非 `List`,那么,我们需要通过配置 `mapKeyField` 来指定使用 `Book` 的那个列来充当 `Map` 的 `Key`,
|
||||||
如下代码所示:
|
如下代码所示:
|
||||||
|
|
||||||
```java 9
|
```java 9
|
||||||
@ -218,6 +218,11 @@ public class Account implements Serializable {
|
|||||||
, mapKeyField = "id") //使用 Book 的 id 来填充这个 map 的 key
|
, mapKeyField = "id") //使用 Book 的 id 来填充这个 map 的 key
|
||||||
private Map<Long, Book> books;
|
private Map<Long, Book> books;
|
||||||
|
|
||||||
|
|
||||||
|
//注意 map 的 key 的类型,可以和 Book 的 id 类型不一致也是支持的
|
||||||
|
//比如:
|
||||||
|
//private Map<String, Book> books;
|
||||||
|
|
||||||
//getter setter
|
//getter setter
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user