From b6de6564481135e5d2a9a23452f772ed372b8b79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=80=E6=BA=90=E6=B5=B7=E5=93=A5?= Date: Sun, 9 Jul 2023 10:49:08 +0800 Subject: [PATCH] =?UTF-8?q?feat=EF=BC=9A=E6=B7=BB=E5=8A=A0=20BaseMapperDoc?= =?UTF-8?q?sGen=20=E7=94=A8=E4=BA=8E=E8=87=AA=E5=8A=A8=E7=94=9F=E6=88=90?= =?UTF-8?q?=20BaseMapper=20=E7=9A=84=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/zh/base/add-delete-update.md | 44 +---- .../base/parts/base-mapper-delete-methods.md | 6 + .../base/parts/base-mapper-insert-methods.md | 11 ++ .../parts/base-mapper-paginate-methods.md | 20 +++ .../base/parts/base-mapper-query-methods.md | 28 +++ .../parts/base-mapper-relation-methods.md | 8 + .../base/parts/base-mapper-update-methods.md | 10 ++ docs/zh/base/query.md | 70 ++------ .../mybatisflex/test/BaseMapperDocsGen.java | 161 ++++++++++++++++++ 9 files changed, 259 insertions(+), 99 deletions(-) create mode 100644 docs/zh/base/parts/base-mapper-delete-methods.md create mode 100644 docs/zh/base/parts/base-mapper-insert-methods.md create mode 100644 docs/zh/base/parts/base-mapper-paginate-methods.md create mode 100644 docs/zh/base/parts/base-mapper-query-methods.md create mode 100644 docs/zh/base/parts/base-mapper-relation-methods.md create mode 100644 docs/zh/base/parts/base-mapper-update-methods.md create mode 100644 mybatis-flex-test/mybatis-flex-native-test/src/main/java/com/mybatisflex/test/BaseMapperDocsGen.java diff --git a/docs/zh/base/add-delete-update.md b/docs/zh/base/add-delete-update.md index efdb2758..90d1b287 100644 --- a/docs/zh/base/add-delete-update.md +++ b/docs/zh/base/add-delete-update.md @@ -8,30 +8,16 @@ MyBatis-Flex 内置了一个名为 `BaseMapper` 的接口,它实现了基本 `BaseMapper` 的接口提供了 insert 和 insertBatch 方法,用于新增数据; -- **insert(entity)**:新增 1 条数据,不忽略 null 值的字段 -- **insertSelective(entity)**:新增 1 条数据,忽略 null 值的字段 -- **insert(entity, ignoreNulls)**:插入实体类数据,并设置是否忽略 null 值字段。 -- **insertWithPk(entity)**:插入带有主键的实体类,不忽略 null 值字段。 -- **insertSelectiveWithPk(entity)**:插入带有主键的实体类,忽略 null 值字段。 -- **insertWithPk(entity, ignoreNulls)**:带有主键的插入,并设置是否忽略 null 值字段。 -- **insertBatch(entities)**:新增多条数据 -- **insertBatch(entities, size)**:批量插入 entity 数据,按 size 切分 -- **insertOrUpdate(entity)**:插入或者更新,若主键有值,则更新,若没有主键值,则插入,插入或者更新都不会忽略 null 值字段。 -- **insertOrUpdateSelective(entity)**:插入或者更新,若主键有值,则更新,若没有主键值,则插入,插入或者更新都会忽略 null 值字段。 -- **insertOrUpdate(entity, ignoreNulls)**:插入或者更新,若主键有值,则更新,若没有主键值,则插入,并设置是否忽略 null 值字段。 + + + ## 删除数据 `BaseMapper` 的接口提供了 deleteById、deleteBatchByIds、deleteByMap、deleteByQuery 方法,用于删除数据; -- **deleteById(id)**:根据主键 id 删除数据,复合主键需要传入一个数组,例如 [1,100] -- **deleteBatchByIds(ids)**:根据主键的 集合,批量删除多条数据 -- **deleteBatchByIds(ids, size)**:根据多个主键批量删除数据,并按 size 切分。 -- **deleteByMap(map)**:根据 `map<字段名,值>` 组成的条件删除数据,字段名和值的关系为相等的关系,同时,防止 "不小心" 全表 - 删除数据,map 的值不允许为 null 或者 空数据。 -- **deleteByCondition(condition)**:根据 QueryCondition 构建的条件来删除数据 -- **deleteByQuery(queryWrapper)**:根据 QueryWrapper 组成的条件删除数据。 + **deleteByQuery(queryWrapper)** 方法示例: @@ -64,27 +50,7 @@ delete from tb_account where id >= 100; `BaseMapper` 的接口提供了 update、updateByMap、updateByQuery 方法,用于更新数据; -- **update(entity)**:根据主键更新到 entity 到数据库,要求主键值不能为空,否则会抛出异常。同时,数据为 null 的字段 **不会** - 更新到数据库。 -- **update(entity, ignoreNulls)**:根据主键更新到 entity 到数据库,要求主键值不能为空。ignoreNulls 为是否忽略 null 字段,如果为 - false,所有 null 字段都会更新到数据库。 -- **updateByMap(entity, map)**:根据 `map<字段名,值>` 组成的条件更新到 entity 到数据库,entity 可以没有主键(如果有也会被忽略), - entity 的 null 属性,会自动被忽略。 -- **updateByCondition(entity, condition)**:根据 condition 构建的条件更新到 entity 到数据库,entity 可以没有主键(如果有也会被忽略), - entity 的 null 属性,会自动被忽略。 -- **updateByCondition(entity, ignoreNulls, condition)**:ignoreNulls 是否忽略 null 值,默认为 true,如果为 false,所有 null - 字段都会更新到数据库。 -- **updateByQuery(entity, queryWrapper)**:根据 queryWrapper 组成的条件更新到 entity 到数据库,entity 可以没有主键(如果有也会被忽略), - entity 的 null 属性,会自动被忽略。 -- **updateByQuery(entity, ignoreNulls, queryWrapper)**:据 queryWrapper 组成的条件更新到 entity 到数据库,entity - 可以没有主键(如果有也会被忽略)。 ignoreNulls 用于是否忽略 entity 的 null 属性 - , 若 ignoreNulls 为 false,entity 的所有 null 属性都会被更新到数据库。 -- **updateNumberAddByQuery(fieldName,value,queryWrapper)**:通过 `update table set field = field + 1 where ... ` - 的这种方向更新数据库某个字段内容。 -- **updateNumberAddByQuery(column,value,queryWrapper)**:通过 `update table set field = field + 1 where ... ` - 的这种方向更新数据库某个字段内容。 -- **updateNumberAddByQuery(fn,value,queryWrapper)**:通过 `update table set field = field + 1 where ... ` - 的这种方向更新数据库某个字段内容。 + ## 部分字段更新 diff --git a/docs/zh/base/parts/base-mapper-delete-methods.md b/docs/zh/base/parts/base-mapper-delete-methods.md new file mode 100644 index 00000000..c9d4182e --- /dev/null +++ b/docs/zh/base/parts/base-mapper-delete-methods.md @@ -0,0 +1,6 @@ +- **`deleteById(id)`**: 根据主键删除数据。如果是多个主键的情况下,需要传入数组,例如:`new Integer[]{100,101``。 +- **`deleteBatchByIds(ids)`**: 根据多个主键批量删除数据。 +- **`deleteBatchByIds(ids, size)`**: 根据多个主键批量删除数据。 +- **`deleteByMap(Map`QueryWrapper.create().select(ACCOUNT.id).where(...);` +- **`selectObjectByQueryAs(queryWrapper, asType)`**: 查询第一列返回的数据,QueryWrapper 执行的结果应该只有 1 列,例如:
`QueryWrapper.create().select(ACCOUNT.id).where(...);` +- **`selectObjectListByQueryAs(queryWrapper, asType)`**: 查询第一列返回的数据集合,QueryWrapper 执行的结果应该只有 1 列,例如:
`QueryWrapper.create().select(ACCOUNT.id).where(...);` +- **`selectCountByQuery(queryWrapper)`**: 查询数据量。 +- **`selectCountByCondition(whereConditions)`**: 根据条件查询数据总量。 diff --git a/docs/zh/base/parts/base-mapper-relation-methods.md b/docs/zh/base/parts/base-mapper-relation-methods.md new file mode 100644 index 00000000..6d386407 --- /dev/null +++ b/docs/zh/base/parts/base-mapper-relation-methods.md @@ -0,0 +1,8 @@ +- **`selectOneWithRelationsByMap(Map` 组成的条件查询 1 条数据,若命中多条数据,则只返回第一条数据。 -- **selectOneByCondition(condition)**:根据 condition 组成的条件查询 1 条数据,若命中多条数据,则只返回第一条数据。 -- **selectOneByQuery(query)**:根据 QueryWrapper 组成的条件查询 1 条数据,若命中多条数据,**则抛出错误!!!**。一般情况下,用户可以主动添加 `limit(1)` 来阻止返回多条的情况。 -- **selectOneByQueryAs(query, asType)**:和 `selectOneByQuery` 方法类似,但是在某些场景下,`query` 可能包含了 `left join` - 等多表查询,返回的数据和 entity 字段不一致时, - 可以通过 `asType` 参数来指定接收的数据类型(通常是 dto、vo 等)。 -- **selectListByIds(idList)**:根据多个 id 查询,返回多条数据 -- **selectListByMap(map)**:根据 `map<字段名,值>` 组成的条件查询数据。 -- **selectListByMap(map, count)**:根据 `map<字段名,值>` 组成的条件查询数据,只取前 count 条。 -- **selectListByCondition(condition)**:根据 condition 组成的条件查询数据。 -- **selectListByCondition(condition, count)**:根据 condition 组成的条件查询数据,只取前 count 条。 -- **selectListByQuery(query)**: 根据 QueryWrapper 组成的条件查询数据。 -- **selectListByQuery(query, consumers)**: 根据 QueryWrapper 组成的条件查询数据。 -- **selectListByQueryAs(query, asType)**: 和 `selectListByQuery` 方法类似,但是在某些场景下,`query` - 可能包含了 `left join` 等多表查询,返回的数据和 entity 字段不一致时, - 可以通过 `asType` 参数来指定接收的数据类型(通常是 dto、vo 等)。 -- **selectListByQueryAs(query, asType, consumers)**: 和 `selectListByQuery` 方法类似,但是在某些场景下,`query` - 可能包含了 `left join` 等多表查询,返回的数据和 entity 字段不一致时, - 可以通过 `asType` 参数来指定接收的数据类型(通常是 dto、vo 等)。 -- **selectAll**:查询所有数据。 -- **selectObjectByQuery(query)**:查询只返回 1 列,并只有 1 条数据的场景。 -- **selectObjectByQueryAs(query)**:查询只返回 1 列,并只有 1 条数据的场景。 -- **selectObjectListByQuery(query)**:查询只返回 1 列场景,比如 `QueryWrapper.create().select(ACCOINT.ID).from(...)`。 -- **selectObjectListByQueryAs(query, asType)**:对 `selectObjectListByQuery` 进行封装,并转换为特定的类型。 -- **selectCountByCondition(condition)**:根据 QueryWrapper 查询数据量。 -- **selectCountByQuery(queryWrapper)**:根据 QueryWrapper 查询数据量。 + + + ## 游标查询 @@ -70,24 +46,10 @@ List selectRowsByQuery(QueryWrapper queryWrapper); ## Relations 注解查询 -- **selectOneWithRelationsByMap(map)** -- **selectOneWithRelationsByCondition(condition)** -- **selectOneWithRelationsByQuery(queryWrapper)** -- **selectOneWithRelationsByQueryAs(queryWrapper, asType)** -- **selectListWithRelationsByQuery(queryWrapper)** -- **selectListWithRelationsByQueryAs(queryWrapper, asType)** -- **selectListWithRelationsByQueryAs(queryWrapper, asType, consumers)** -- **selectAllWithRelations()** -- **paginateWithRelations(pageNumber, pageSize, queryWrapper)** -- **paginateWithRelations(pageNumber, pageSize, condition)** -- **paginateWithRelations(pageNumber, pageSize, totalRow, queryWrapper)** -- **paginateWithRelations(pageNumber, pageSize, totalRow, condition)** -- **paginateWithRelations(page, queryWrapper)** -- **paginateWithRelations(page, queryWrapper, consumers)** -- **paginateWithRelationsAs(pageNumber, pageSize, queryWrapper, asType)** -- **paginateWithRelationsAs(pageNumber, pageSize, totalRow, queryWrapper, asType)** -- **paginateWithRelationsAs(page, queryWrapper, asType)** -- **paginateWithRelationsAs(page, queryWrapper, asType, consumers)** +Relations 注解查询指的是用于查询带有注解 `@RelationOneToOne`,`@RelationOneToMany`,`@RelationManyToOne`,`@RelationManyToMany` 的查询。 + + + ## 多表查询(关联查询) @@ -232,27 +194,15 @@ System.out.println(results); 在 MyBatis-Flex 的 BaseMapper 中,提供了如下的分页查询功能: -```java -default Page paginate(int pageNumber,int pageSize,QueryWrapper queryWrapper); -default Page paginate(int pageNumber,int pageSize,QueryCondition whereConditions); + -default Page paginate(int pageNumber,int pageSize,int totalRow,QueryWrapper queryWrapper); -default Page paginate(int pageNumber,int pageSize,int totalRow,QueryCondition whereConditions); +**参数说明:** -default Page paginate(Page page,QueryWrapper queryWrapper); -default Page paginate(Page page,QueryWrapper queryWrapper,Consumer>...consumers); - -default Page paginateAs(int pageNumber,int pageSize,QueryWrapper queryWrapper,Class asType); -default Page paginateAs(int pageNumber,int pageSize,int totalRow,QueryWrapper queryWrapper,Class asType) - -default Page paginateAs(Page page,QueryWrapper queryWrapper,Class asType) -default Page paginateAs(Page page,QueryWrapper queryWrapper,Class asType,Consumer>...consumers) -``` - pageNumber: 当前页码,从 1 开始 - pageSize: 每 1 页的数据量 - totalRow: 非必须值,若传入该值,mybatis-flex 则不再去查询总数据量(若传入小于 0 的数值,也会去查询总量)。 - queryWrapper: 查询条件 -- QueryCondition: 查询条件 +- queryCondition: 查询条件 ::: tip totalRow 的说明 在一般的分页场景中,只有第一页的时候有必要去查询数据总量,第二页以后是没必要的(因为第一页已经拿到总量了),因此, diff --git a/mybatis-flex-test/mybatis-flex-native-test/src/main/java/com/mybatisflex/test/BaseMapperDocsGen.java b/mybatis-flex-test/mybatis-flex-native-test/src/main/java/com/mybatisflex/test/BaseMapperDocsGen.java new file mode 100644 index 00000000..03ad3c46 --- /dev/null +++ b/mybatis-flex-test/mybatis-flex-native-test/src/main/java/com/mybatisflex/test/BaseMapperDocsGen.java @@ -0,0 +1,161 @@ +package com.mybatisflex.test; + +import com.alibaba.fastjson2.JSON; +import com.mybatisflex.core.util.StringUtil; + +import java.io.*; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; + +public class BaseMapperDocsGen { + + public static void main(String[] args) throws IOException { + + List methodInfos = readBaseMapperMethodsInfo(); + + StringBuilder insertMethods = new StringBuilder(); + StringBuilder deleteMethods = new StringBuilder(); + StringBuilder updateMethods = new StringBuilder(); + StringBuilder selectMethods = new StringBuilder(); + StringBuilder relationMethods = new StringBuilder(); + StringBuilder paginateMethods = new StringBuilder(); + + for (MethodInfo methodInfo : methodInfos) { + if (methodInfo.name.startsWith("insert")) { + insertMethods.append("- **`").append(methodInfo.getName()).append("`**: ").append(methodInfo.desc).append("\n"); + } else if (methodInfo.name.startsWith("delete")) { + deleteMethods.append("- **`").append(methodInfo.getName()).append("`**: ").append(methodInfo.desc).append("\n"); + } else if (methodInfo.name.startsWith("update")) { + updateMethods.append("- **`").append(methodInfo.getName()).append("`**: ").append(methodInfo.desc).append("\n"); + } else if (methodInfo.name.startsWith("select")) { + selectMethods.append("- **`").append(methodInfo.getName()).append("`**: ").append(methodInfo.desc).append("\n"); + if (methodInfo.name.contains("WithRelation")){ + relationMethods.append("- **`").append(methodInfo.getName()).append("`**: ").append(methodInfo.desc).append("\n"); + } + }else if (methodInfo.name.startsWith("paginate")) { + paginateMethods.append("- **`").append(methodInfo.getName()).append("`**: ").append(methodInfo.desc).append("\n"); + } + } + + String mdDir = System.getProperty("user.dir") + "/docs/zh/base/parts/"; + writeString(new File(mdDir, "base-mapper-insert-methods.md"), insertMethods.toString()); + writeString(new File(mdDir, "base-mapper-delete-methods.md"), deleteMethods.toString()); + writeString(new File(mdDir, "base-mapper-update-methods.md"), updateMethods.toString()); + writeString(new File(mdDir, "base-mapper-query-methods.md"), selectMethods.toString()); + writeString(new File(mdDir, "base-mapper-relation-methods.md"), relationMethods.toString()); + writeString(new File(mdDir, "base-mapper-paginate-methods.md"), paginateMethods.toString()); + + + ///Users/michael/work/git/mybatis-flex/docs/zh/base/parts/base-mapper-insert-methods.md + + System.out.println(JSON.toJSON(methodInfos)); + } + + private static List readBaseMapperMethodsInfo() throws IOException { + List methodInfos = new ArrayList<>(); + String path = System.getProperty("user.dir") + "/mybatis-flex-core/src/main/java/com/mybatisflex/core/BaseMapper.java"; + BufferedReader br = new BufferedReader(new FileReader(path)); + String line; + MethodInfo methodInfo = null; + while ((line = br.readLine()) != null) { + line = line.trim(); + if (line.equals("/**")) { + methodInfo = new MethodInfo(); + } else { + if (methodInfo != null && line.length() > 3 && line.startsWith("*") && line.charAt(2) != '@') { + methodInfo.addDesc(line.substring(1)); + } else if (methodInfo != null && !line.contains("=") && (line.startsWith("default") + || line.startsWith("int") + || line.startsWith("T ") + || line.startsWith("List ") + )) { + String[] tokens = line.split(" "); + int methodTokenIndex = 1; + if (line.contains("default")) { + methodTokenIndex++; + } + if (line.contains("")) { + methodTokenIndex++; + } + String methodToken = tokens[methodTokenIndex]; + methodInfo.setName(line.substring(line.indexOf(methodToken))); + methodInfos.add(methodInfo); + } + } + } + + br.close(); + return methodInfos; + } + + + public static void writeString(File file, String content) throws IOException { + FileOutputStream fos = null; + try { + fos = new FileOutputStream(file, false); + fos.write(content.getBytes(StandardCharsets.UTF_8)); + } catch (Exception e) { + e.printStackTrace(); + } finally { + fos.close(); + } + } + + public static class MethodInfo { + private String name; + private String desc; + + public String getName() { + return name; + } + + public void setName(String name) { + if (name.endsWith("{") || name.endsWith(";")) { + name = name.substring(0, name.length() - 1); + } + + name = name.trim(); + String paramsString = name.substring(name.indexOf("(") + 1, name.lastIndexOf(")")); + if (paramsString.length() > 0) { + String[] params = paramsString.split(","); + for (int i = 0; i < params.length; i++) { + String[] paramInfos = params[i].split(" "); + params[i] = paramInfos[paramInfos.length - 1]; + } + paramsString = StringUtil.join(", ", params); + name = name.substring(0, name.indexOf("(") + 1) + paramsString + ")"; + this.name = name; + } else { + this.name = name; + } + } + + public String getDesc() { + return desc; + } + + public void setDesc(String desc) { + this.desc = desc; + } + + public void addDesc(String desc) { + if (this.desc == null) { + this.desc = desc.trim(); + } else { + this.desc += desc.trim(); + } + if (this.desc.contains("{@code")){ + this.desc = this.desc.replace("{@code ","`").replace("}","`"); + } + } + + @Override + public String toString() { + return "MethodInfo{" + + "name='" + name + '\'' + + ", desc='" + desc + '\'' + + '}'; + } + } +}