diff --git a/docs/.vitepress/config.ts b/docs/.vitepress/config.ts index 7b203a65..88b7d0c9 100644 --- a/docs/.vitepress/config.ts +++ b/docs/.vitepress/config.ts @@ -58,6 +58,7 @@ export default defineConfig({ items: [ {text: '增、删、改', link: '/zh/base/add-delete-update'}, {text: '基础查询', link: '/zh/base/query'}, + {text: '自动映射', link: '/zh/base/auto-mapping'}, {text: '关联查询', link: '/zh/base/relations-query'}, {text: '批量操作', link: '/zh/base/batch'}, {text: '链式操作🔥🔥', link: '/zh/base/chain'}, diff --git a/docs/zh/base/auto-mapping.md b/docs/zh/base/auto-mapping.md new file mode 100644 index 00000000..66a4cbb4 --- /dev/null +++ b/docs/zh/base/auto-mapping.md @@ -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 accounts = accountMapper.selectListByQuery(qw); +``` + +或者使用如下的链式查询,都可以直接得到 `List` 结果:`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 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 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 books; +} +``` + +```java +List 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 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)。 diff --git a/docs/zh/base/relations-query.md b/docs/zh/base/relations-query.md index 5d79f684..19c8f9a5 100644 --- a/docs/zh/base/relations-query.md +++ b/docs/zh/base/relations-query.md @@ -203,7 +203,7 @@ WHERE account_id IN (1, 2, 3, 4, 5) **Map 映射** -若 `Account.books` 是一个 `Map`,而非 `List`,那么,我们需要通过配置 `mapKeyField` 来指定使用用个列来充当 `Map` 的 `Key`, +若 `Account.books` 是一个 `Map`,而非 `List`,那么,我们需要通过配置 `mapKeyField` 来指定使用 `Book` 的那个列来充当 `Map` 的 `Key`, 如下代码所示: ```java 9 @@ -218,6 +218,11 @@ public class Account implements Serializable { , mapKeyField = "id") //使用 Book 的 id 来填充这个 map 的 key private Map books; + + //注意 map 的 key 的类型,可以和 Book 的 id 类型不一致也是支持的 + //比如: + //private Map books; + //getter setter } ```