From 86525f16e1fd4afacf685ec0c5255a08cdc32ed5 Mon Sep 17 00:00:00 2001 From: jerry_zheng Date: Mon, 24 Jul 2023 23:58:58 +0800 Subject: [PATCH 01/37] =?UTF-8?q?feat:=20add=20=E4=BB=A3=E7=A0=81=E7=94=9F?= =?UTF-8?q?=E6=88=90=E5=99=A8=20ColumnConfig=20=E5=A2=9E=E5=8A=A0=20proper?= =?UTF-8?q?tyType.=20=E5=8F=AF=E4=BB=A5=E7=94=A8=E4=BA=8E=E8=87=AA?= =?UTF-8?q?=E5=AE=9A=E9=80=9A=E7=94=A8=E5=B1=9E=E6=80=A7=E7=9A=84=E7=B1=BB?= =?UTF-8?q?=E5=9E=8B=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/mybatisflex/codegen/config/ColumnConfig.java | 10 ++++++++++ .../java/com/mybatisflex/codegen/entity/Column.java | 10 +++++++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/mybatis-flex-codegen/src/main/java/com/mybatisflex/codegen/config/ColumnConfig.java b/mybatis-flex-codegen/src/main/java/com/mybatisflex/codegen/config/ColumnConfig.java index 04579aae..7be95683 100644 --- a/mybatis-flex-codegen/src/main/java/com/mybatisflex/codegen/config/ColumnConfig.java +++ b/mybatis-flex-codegen/src/main/java/com/mybatisflex/codegen/config/ColumnConfig.java @@ -60,6 +60,10 @@ public class ColumnConfig implements Serializable { * 配置的 jdbcType。 */ private JdbcType jdbcType; + /** + * 属性的类型。 + */ + private Class propertyType; /** * 自定义 TypeHandler。 @@ -207,5 +211,11 @@ public class ColumnConfig implements Serializable { public void setTenantId(Boolean tenantId) { this.tenantId = tenantId; } + public Class getPropertyType() { + return propertyType; + } + public void setPropertyType(Class propertyType) { + this.propertyType = propertyType; + } } diff --git a/mybatis-flex-codegen/src/main/java/com/mybatisflex/codegen/entity/Column.java b/mybatis-flex-codegen/src/main/java/com/mybatisflex/codegen/entity/Column.java index 4f2c9cd1..d1efb73f 100644 --- a/mybatis-flex-codegen/src/main/java/com/mybatisflex/codegen/entity/Column.java +++ b/mybatis-flex-codegen/src/main/java/com/mybatisflex/codegen/entity/Column.java @@ -93,7 +93,12 @@ public class Column { } public String getPropertySimpleType() { - return propertyType.substring(propertyType.lastIndexOf(".") + 1); + if (columnConfig.getPropertyType()!=null){ + return columnConfig.getPropertyType().getSimpleName(); + } + else { + return propertyType.substring(propertyType.lastIndexOf(".") + 1); + } } public void setPropertyType(String propertyType) { @@ -291,6 +296,9 @@ public class Column { } if (columnConfig != null) { + if (columnConfig.getPropertyType() !=null){ + importClasses.add(columnConfig.getPropertyType().getName()); + } if (columnConfig.getMask() != null) { importClasses.add(ColumnMask.class.getName()); } From d641947d4e3e307213c71801605de331152a20b2 Mon Sep 17 00:00:00 2001 From: jerry_zheng Date: Tue, 25 Jul 2023 00:07:06 +0800 Subject: [PATCH 02/37] =?UTF-8?q?feat:=20add=20=E4=BB=A3=E7=A0=81=E7=94=9F?= =?UTF-8?q?=E6=88=90=E5=99=A8=20StrategyConfig=20=E5=A2=9E=E5=8A=A0ignoreC?= =?UTF-8?q?olumns,=20=E7=94=A8=E4=BA=8E=E5=9C=A8Entity=E7=94=9F=E6=88=90?= =?UTF-8?q?=E6=97=B6=EF=BC=8C=E5=8F=AF=E4=BB=A5=E5=BF=BD=E7=95=A5=E9=83=A8?= =?UTF-8?q?=E5=88=86=E5=AD=97=E6=AE=B5.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../codegen/config/StrategyConfig.java | 27 ++++++++++++++++++- .../com/mybatisflex/codegen/entity/Table.java | 6 +++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/mybatis-flex-codegen/src/main/java/com/mybatisflex/codegen/config/StrategyConfig.java b/mybatis-flex-codegen/src/main/java/com/mybatisflex/codegen/config/StrategyConfig.java index 6c86b8f0..105343f8 100644 --- a/mybatis-flex-codegen/src/main/java/com/mybatisflex/codegen/config/StrategyConfig.java +++ b/mybatis-flex-codegen/src/main/java/com/mybatisflex/codegen/config/StrategyConfig.java @@ -76,6 +76,31 @@ public class StrategyConfig { */ private Set unGenerateTables; + /** + * 需要忽略的列 全局配置。 + */ + private Set ignoreColumns; + + /** + * 获取需要忽略的列 全局配置。 + */ + public Set getIgnoreColumns() { + return ignoreColumns; + } + /** + * 设置需要忽略的列 全局配置。 + */ + public StrategyConfig setIgnoreColumns(String... columns) { + if (ignoreColumns == null) { + ignoreColumns = new HashSet<>(); + } + for (String column : columns) { + if (column != null && column.trim().length() > 0) { + ignoreColumns.add(column.trim().toLowerCase()); + } + } + return this; + } /** * 设置要生成的模式 @@ -348,4 +373,4 @@ public class StrategyConfig { return this; } -} \ No newline at end of file +} diff --git a/mybatis-flex-codegen/src/main/java/com/mybatisflex/codegen/entity/Table.java b/mybatis-flex-codegen/src/main/java/com/mybatisflex/codegen/entity/Table.java index af81310d..d8837f0c 100644 --- a/mybatis-flex-codegen/src/main/java/com/mybatisflex/codegen/entity/Table.java +++ b/mybatis-flex-codegen/src/main/java/com/mybatisflex/codegen/entity/Table.java @@ -131,6 +131,12 @@ public class Table { public void addColumn(Column column) { + //排除忽略列 + if (globalConfig.getStrategyConfig().getIgnoreColumns() != null && + globalConfig.getStrategyConfig().getIgnoreColumns().contains(column.getName().toLowerCase())) { + return; + } + //主键 if (primaryKeys != null && primaryKeys.contains(column.getName())) { column.setPrimaryKey(true); From c4a766b54063e05b6def6e929e9b4f2bc74ffd99 Mon Sep 17 00:00:00 2001 From: zhangchungen Date: Tue, 25 Jul 2023 08:32:56 +0800 Subject: [PATCH 03/37] =?UTF-8?q?=E5=BD=93=E9=85=8D=E7=BD=AEcamelToUnderli?= =?UTF-8?q?ne=E5=B1=9E=E6=80=A7=E6=97=B6entity=E7=94=9F=E6=88=90=E5=90=8E?= =?UTF-8?q?=E7=BC=96=E8=AF=91=E9=94=99=E8=AF=AF=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/com/mybatisflex/codegen/entity/Table.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mybatis-flex-codegen/src/main/java/com/mybatisflex/codegen/entity/Table.java b/mybatis-flex-codegen/src/main/java/com/mybatisflex/codegen/entity/Table.java index d8837f0c..306afc57 100644 --- a/mybatis-flex-codegen/src/main/java/com/mybatisflex/codegen/entity/Table.java +++ b/mybatis-flex-codegen/src/main/java/com/mybatisflex/codegen/entity/Table.java @@ -245,7 +245,7 @@ public class Table { tableAnnotation.append(", schema = \"").append(tableConfig.getSchema()).append("\""); } if (tableConfig.getCamelToUnderline() != null) { - tableAnnotation.append(", camelToUnderline = \"").append(tableConfig.getCamelToUnderline()).append("\""); + tableAnnotation.append(", camelToUnderline = ").append(tableConfig.getCamelToUnderline()); } if (tableConfig.getInsertListenerClass() != null) { tableAnnotation.append(", onInsert = ").append(tableConfig.getInsertListenerClass().getSimpleName()).append(".class"); From 46f98e7083f15d89207b7f8ce14147ec29daa4ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B7=A1=E5=AE=9A?= <1062904651@qq.com> Date: Tue, 25 Jul 2023 01:47:26 +0000 Subject: [PATCH 04/37] =?UTF-8?q?update=20docs/zh/others/apt.md.=20?= =?UTF-8?q?=E9=94=99=E5=88=AB=E5=AD=97=204=E7=A7=8D=E5=86=99=E6=88=90?= =?UTF-8?q?=E4=BA=86=204=20=E4=B8=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: 淡定 <1062904651@qq.com> --- docs/zh/others/apt.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/zh/others/apt.md b/docs/zh/others/apt.md index 075306d2..2da9f74b 100644 --- a/docs/zh/others/apt.md +++ b/docs/zh/others/apt.md @@ -88,7 +88,7 @@ public class AccountTableDef extends TableDef { #upperCase, lowerCase, upperCamelCase, lowerCamelCase processor.tableDef.propertiesNameStyle = upperCase ``` -风格支持 4 中配置,默认(未配置时)为 upperCase,支持的配置分别为: +风格支持 4 种配置,默认(未配置时)为 upperCase,支持的配置分别为: - upperCase:大写 + 下划线,例如:USER_NAME - lowerCase:小写 + 下划线,例如:user_name From fb25359c772160c37aff9e6525632a8fae955e64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B7=A1=E5=AE=9A?= <1062904651@qq.com> Date: Tue, 25 Jul 2023 01:50:50 +0000 Subject: [PATCH 05/37] =?UTF-8?q?update=20docs/zh/others/apt.md.=20?= =?UTF-8?q?=E9=94=99=E5=88=AB=E5=AD=97=E4=BF=AE=E6=94=B9=20=E5=85=B6?= =?UTF-8?q?=E8=A6=81=E6=B1=82=E6=88=91=E4=BB=AC=E5=86=8D=20-->=20=E5=85=B6?= =?UTF-8?q?=E8=A6=81=E6=B1=82=E6=88=91=E4=BB=AC=E5=9C=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: 淡定 <1062904651@qq.com> --- docs/zh/others/apt.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/zh/others/apt.md b/docs/zh/others/apt.md index 075306d2..540785a7 100644 --- a/docs/zh/others/apt.md +++ b/docs/zh/others/apt.md @@ -173,7 +173,7 @@ processor.allInTables.package=com.example.entity.table ## 和 Lombok、Mapstruct 整合 -在很多项目中,用到了 Lombok 帮我们减少代码编写,同时用到 Mapstruct 进行 bean 转换。使用到 Lombok 和 Mapstruct 时,其要求我们再 +在很多项目中,用到了 Lombok 帮我们减少代码编写,同时用到 Mapstruct 进行 bean 转换。使用到 Lombok 和 Mapstruct 时,其要求我们在 pom.xml 添加 `annotationProcessorPaths` 配置, 此时,我们也需要把 MyBatis-Flex 的 annotation 添加到 `annotationProcessorPaths` 配置里去,如下图所示: From 2ef78e50a349a48e6ceeb930bc0ca905479cc7f8 Mon Sep 17 00:00:00 2001 From: xiaobao <272378774@qq.com> Date: Tue, 25 Jul 2023 10:48:43 +0800 Subject: [PATCH 06/37] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=20selectOneWithRelatio?= =?UTF-8?q?nsById(=E6=A0=B9=E6=8D=AE=E4=B8=BB=E8=A1=A8=E4=B8=BB=E9=94=AE?= =?UTF-8?q?=E6=9D=A5=E6=9F=A5=E8=AF=A2=201=20=E6=9D=A1=E6=95=B0=E6=8D=AE)?= =?UTF-8?q?=20=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/com/mybatisflex/core/BaseMapper.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/BaseMapper.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/BaseMapper.java index ce840459..25f4627b 100644 --- a/mybatis-flex-core/src/main/java/com/mybatisflex/core/BaseMapper.java +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/BaseMapper.java @@ -490,6 +490,16 @@ public interface BaseMapper { return MapperUtil.queryRelations(this, MapperUtil.getSelectOneResult(selectListByQuery(queryWrapper))); } + /** + * 根据主表主键来查询 1 条数据。 + * + * @param id 主表主键 + * @return 实体类数据 + */ + default T selectOneWithRelationsById(Serializable id) { + return MapperUtil.queryRelations(this, selectOneById(id)); + } + /** * 根据查询条件来查询 1 条数据。 * From 25c2415cf5d6dbb1f4333de820abd6533827f520 Mon Sep 17 00:00:00 2001 From: Suomm <1474983351@qq.com> Date: Tue, 25 Jul 2023 11:29:53 +0800 Subject: [PATCH 07/37] =?UTF-8?q?feat:=20QueryWrapper.groupBy=20=E6=94=AF?= =?UTF-8?q?=E6=8C=81=20Lambda=20=E8=A1=A8=E8=BE=BE=E5=BC=8F=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/mybatisflex/core/query/QueryWrapper.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/query/QueryWrapper.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/query/QueryWrapper.java index 05e02cae..5b2a8f6a 100644 --- a/mybatis-flex-core/src/main/java/com/mybatisflex/core/query/QueryWrapper.java +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/query/QueryWrapper.java @@ -579,6 +579,18 @@ public class QueryWrapper extends BaseQueryWrapper { return this; } + public QueryWrapper groupBy(LambdaGetter column) { + addGroupByColumns(LambdaUtil.getQueryColumn(column)); + return this; + } + + public QueryWrapper groupBy(LambdaGetter... columns) { + for (LambdaGetter column : columns) { + groupBy(LambdaUtil.getQueryColumn(column)); + } + return this; + } + public QueryWrapper having(QueryCondition queryCondition) { addHavingQueryCondition(queryCondition, SqlConnector.AND); return this; From abfd7d8bca40d2f71ea6a8c24db0fdaad67bf1c6 Mon Sep 17 00:00:00 2001 From: Suomm <1474983351@qq.com> Date: Tue, 25 Jul 2023 11:33:28 +0800 Subject: [PATCH 08/37] feat: CPI add addWhereQueryCondition method. --- .../src/main/java/com/mybatisflex/core/query/CPI.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/query/CPI.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/query/CPI.java index a5a45278..7875bb95 100644 --- a/mybatis-flex-core/src/main/java/com/mybatisflex/core/query/CPI.java +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/query/CPI.java @@ -125,6 +125,10 @@ public class CPI { return queryWrapper.getWhereQueryCondition(); } + public static void addWhereQueryCondition(QueryWrapper queryWrapper, QueryCondition queryCondition, SqlConnector connector) { + queryWrapper.addWhereQueryCondition(queryCondition, connector); + } + public static List getGroupByColumns(QueryWrapper queryWrapper) { return queryWrapper.getGroupByColumns(); } From b65175e1facc60df1c21c97e504afe6f1374427a Mon Sep 17 00:00:00 2001 From: Suomm <1474983351@qq.com> Date: Tue, 25 Jul 2023 11:36:11 +0800 Subject: [PATCH 09/37] =?UTF-8?q?feat:=20Active=20Record=20=E5=8A=9F?= =?UTF-8?q?=E8=83=BD=E5=8C=85=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/activerecord/package-info.java | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 mybatis-flex-core/src/main/java/com/mybatisflex/core/activerecord/package-info.java diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/activerecord/package-info.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/activerecord/package-info.java new file mode 100644 index 00000000..e1cd4ffb --- /dev/null +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/activerecord/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2022-2023, Mybatis-Flex (fuhai999@gmail.com). + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Active Record 功能。 + */ +package com.mybatisflex.core.activerecord; From ef06e19857b1ca3558d6cc5a5a5bdac2da51ccda Mon Sep 17 00:00:00 2001 From: Suomm <1474983351@qq.com> Date: Tue, 25 Jul 2023 11:36:37 +0800 Subject: [PATCH 10/37] feat: add MapperModel. --- .../core/activerecord/MapperModel.java | 80 +++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 mybatis-flex-core/src/main/java/com/mybatisflex/core/activerecord/MapperModel.java diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/activerecord/MapperModel.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/activerecord/MapperModel.java new file mode 100644 index 00000000..78b3cab4 --- /dev/null +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/activerecord/MapperModel.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2022-2023, Mybatis-Flex (fuhai999@gmail.com). + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.mybatisflex.core.activerecord; + +import com.mybatisflex.core.BaseMapper; +import com.mybatisflex.core.mybatis.Mappers; +import com.mybatisflex.core.table.TableInfo; +import com.mybatisflex.core.table.TableInfoFactory; +import com.mybatisflex.core.util.SqlUtil; + +import java.util.Optional; + +/** + * @param 实体类类型 + * @author 王帅 + * @since 2023-07-23 + */ +@SuppressWarnings({"unused", "unchecked"}) +public interface MapperModel { + + default BaseMapper baseMapper() { + return Mappers.ofEntityClass((Class) getClass()); + } + + default Object[] getPkValues() { + TableInfo tableInfo = TableInfoFactory.ofEntityClass(getClass()); + return tableInfo.buildPkSqlArgs(this); + } + + default boolean save() { + return save(true); + } + + default boolean save(boolean ignoreNulls) { + return SqlUtil.toBool(baseMapper().insert((T) this, ignoreNulls)); + } + + default boolean saveOrUpdate() { + return saveOrUpdate(true); + } + + default boolean saveOrUpdate(boolean ignoreNulls) { + return SqlUtil.toBool(baseMapper().insertOrUpdate((T) this, ignoreNulls)); + } + + default boolean removeById() { + return SqlUtil.toBool(baseMapper().deleteById(getPkValues())); + } + + default boolean updateById() { + return updateById(true); + } + + default boolean updateById(boolean ignoreNulls) { + return SqlUtil.toBool(baseMapper().update((T) this, ignoreNulls)); + } + + default T oneById() { + return baseMapper().selectOneById(getPkValues()); + } + + default Optional oneByIdOpt() { + return Optional.ofNullable(oneById()); + } + +} From c036a869da4c37ec37277715e99abea7663d3fb0 Mon Sep 17 00:00:00 2001 From: Suomm <1474983351@qq.com> Date: Tue, 25 Jul 2023 11:37:13 +0800 Subject: [PATCH 11/37] =?UTF-8?q?feat:=20=E6=9F=A5=E8=AF=A2=E6=A8=A1?= =?UTF-8?q?=E5=9E=8B=E6=89=A9=E5=B1=95=E5=8C=85=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/activerecord/query/package-info.java | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 mybatis-flex-core/src/main/java/com/mybatisflex/core/activerecord/query/package-info.java diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/activerecord/query/package-info.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/activerecord/query/package-info.java new file mode 100644 index 00000000..ca0a2d88 --- /dev/null +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/activerecord/query/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2022-2023, Mybatis-Flex (fuhai999@gmail.com). + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * 条件查询功能。 + */ +package com.mybatisflex.core.activerecord.query; From a91987c4d3947b3f1cdc15cb223d0ba567d8cde6 Mon Sep 17 00:00:00 2001 From: Suomm <1474983351@qq.com> Date: Tue, 25 Jul 2023 11:37:33 +0800 Subject: [PATCH 12/37] feat: add WhereBuilder. --- .../core/activerecord/query/WhereBuilder.java | 351 ++++++++++++++++++ 1 file changed, 351 insertions(+) create mode 100644 mybatis-flex-core/src/main/java/com/mybatisflex/core/activerecord/query/WhereBuilder.java diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/activerecord/query/WhereBuilder.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/activerecord/query/WhereBuilder.java new file mode 100644 index 00000000..d9693c5b --- /dev/null +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/activerecord/query/WhereBuilder.java @@ -0,0 +1,351 @@ +/* + * Copyright (c) 2022-2023, Mybatis-Flex (fuhai999@gmail.com). + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.mybatisflex.core.activerecord.query; + +import com.mybatisflex.core.query.CPI; +import com.mybatisflex.core.query.QueryColumn; +import com.mybatisflex.core.query.SqlConnector; +import com.mybatisflex.core.util.LambdaGetter; +import com.mybatisflex.core.util.LambdaUtil; + +import java.util.Collection; +import java.util.function.Predicate; + +/** + * @param + * @author 王帅 + * @since 2023-07-24 + */ +public class WhereBuilder> { + + private final R queryModel; + private final QueryColumn queryColumn; + private final SqlConnector connector; + + public WhereBuilder(R queryModel, QueryColumn queryColumn, SqlConnector connector) { + this.queryModel = queryModel; + this.queryColumn = queryColumn; + this.connector = connector; + } + + public R eq(Object value) { + if (value != null) { + CPI.addWhereQueryCondition(queryModel.getQueryWrapper(), queryColumn.eq(value), connector); + } + return queryModel; + } + + public R eq(Object value, Predicate when) { + if (value != null) { + CPI.addWhereQueryCondition(queryModel.getQueryWrapper(), queryColumn.eq(value, when), connector); + } + return queryModel; + } + + public R eq(LambdaGetter value) { + return eq(LambdaUtil.getQueryColumn(value)); + } + + public R eq(LambdaGetter value, Predicate when) { + return eq(LambdaUtil.getQueryColumn(value), when); + } + + public R ne(Object value) { + if (value != null) { + CPI.addWhereQueryCondition(queryModel.getQueryWrapper(), queryColumn.ne(value), connector); + } + return queryModel; + } + + public R ne(Object value, Predicate when) { + if (value != null) { + CPI.addWhereQueryCondition(queryModel.getQueryWrapper(), queryColumn.ne(value, when), connector); + } + return queryModel; + } + + public R ne(LambdaGetter value) { + return ne(LambdaUtil.getQueryColumn(value)); + } + + public R ne(LambdaGetter value, Predicate when) { + return ne(LambdaUtil.getQueryColumn(value), when); + } + + public R like(Object value) { + if (value != null) { + CPI.addWhereQueryCondition(queryModel.getQueryWrapper(), queryColumn.like(value), connector); + } + return queryModel; + } + + public R like(Object value, Predicate when) { + if (value != null) { + CPI.addWhereQueryCondition(queryModel.getQueryWrapper(), queryColumn.like(value, when), connector); + } + return queryModel; + } + + public R likeLeft(Object value) { + if (value != null) { + CPI.addWhereQueryCondition(queryModel.getQueryWrapper(), queryColumn.likeLeft(value), connector); + } + return queryModel; + } + + public R likeLeft(Object value, Predicate when) { + if (value != null) { + CPI.addWhereQueryCondition(queryModel.getQueryWrapper(), queryColumn.likeLeft(value, when), connector); + } + return queryModel; + } + + public R likeRight(Object value) { + if (value != null) { + CPI.addWhereQueryCondition(queryModel.getQueryWrapper(), queryColumn.likeRight(value), connector); + } + return queryModel; + } + + public R likeRight(Object value, Predicate when) { + if (value != null) { + CPI.addWhereQueryCondition(queryModel.getQueryWrapper(), queryColumn.likeRight(value, when), connector); + } + return queryModel; + } + + public R gt(Object value) { + if (value != null) { + CPI.addWhereQueryCondition(queryModel.getQueryWrapper(), queryColumn.gt(value), connector); + } + return queryModel; + } + + public R gt(Object value, Predicate when) { + if (value != null) { + CPI.addWhereQueryCondition(queryModel.getQueryWrapper(), queryColumn.gt(value, when), connector); + } + return queryModel; + } + + public R gt(LambdaGetter value) { + return gt(LambdaUtil.getQueryColumn(value)); + } + + public R gt(LambdaGetter value, Predicate when) { + return gt(LambdaUtil.getQueryColumn(value), when); + } + + public R ge(Object value) { + if (value != null) { + CPI.addWhereQueryCondition(queryModel.getQueryWrapper(), queryColumn.ge(value), connector); + } + return queryModel; + } + + public R ge(Object value, Predicate when) { + if (value != null) { + CPI.addWhereQueryCondition(queryModel.getQueryWrapper(), queryColumn.ge(value, when), connector); + } + return queryModel; + } + + public R ge(LambdaGetter value) { + return ge(LambdaUtil.getQueryColumn(value)); + } + + public R ge(LambdaGetter value, Predicate when) { + return ge(LambdaUtil.getQueryColumn(value), when); + } + + public R lt(Object value) { + if (value != null) { + CPI.addWhereQueryCondition(queryModel.getQueryWrapper(), queryColumn.lt(value), connector); + } + return queryModel; + } + + public R lt(Object value, Predicate when) { + if (value != null) { + CPI.addWhereQueryCondition(queryModel.getQueryWrapper(), queryColumn.lt(value, when), connector); + } + return queryModel; + } + + public R lt(LambdaGetter value) { + return lt(LambdaUtil.getQueryColumn(value)); + } + + public R lt(LambdaGetter value, Predicate when) { + return lt(LambdaUtil.getQueryColumn(value), when); + } + + public R le(Object value) { + if (value != null) { + CPI.addWhereQueryCondition(queryModel.getQueryWrapper(), queryColumn.le(value), connector); + } + return queryModel; + } + + public R le(Object value, Predicate when) { + if (value != null) { + CPI.addWhereQueryCondition(queryModel.getQueryWrapper(), queryColumn.le(value, when), connector); + } + return queryModel; + } + + public R le(LambdaGetter value) { + return le(LambdaUtil.getQueryColumn(value)); + } + + public R le(LambdaGetter value, Predicate when) { + return le(LambdaUtil.getQueryColumn(value), when); + } + + public R isNull() { + CPI.addWhereQueryCondition(queryModel.getQueryWrapper(), queryColumn.isNull(), connector); + return queryModel; + } + + public R isNull(Predicate when) { + CPI.addWhereQueryCondition(queryModel.getQueryWrapper(), queryColumn.isNull(when), connector); + return queryModel; + } + + public R isNotNull() { + CPI.addWhereQueryCondition(queryModel.getQueryWrapper(), queryColumn.isNotNull(), connector); + return queryModel; + } + + public R isNotNull(Predicate when) { + CPI.addWhereQueryCondition(queryModel.getQueryWrapper(), queryColumn.isNotNull(when), connector); + return queryModel; + } + + public R in(Object... arrays) { + if (arrays != null) { + CPI.addWhereQueryCondition(queryModel.getQueryWrapper(), queryColumn.in(arrays), connector); + } + return queryModel; + } + + public R in(Object[] arrays, Predicate when) { + //忽略 QueryWrapper.in("name", null) 的情况 + if (arrays != null) { + CPI.addWhereQueryCondition(queryModel.getQueryWrapper(), queryColumn.in(arrays, when), connector); + } + return queryModel; + } + + public R in(R queryModel) { + if (queryModel != null) { + CPI.addWhereQueryCondition(queryModel.getQueryWrapper(), queryColumn.in(queryModel), connector); + } + return this.queryModel; + } + + public R in(R queryModel, Predicate when) { + if (queryModel != null) { + CPI.addWhereQueryCondition(queryModel.getQueryWrapper(), queryColumn.in(queryModel, when), connector); + } + return this.queryModel; + } + + public R in(Collection collection) { + if (queryModel != null) { + CPI.addWhereQueryCondition(queryModel.getQueryWrapper(), queryColumn.in(collection), connector); + } + return queryModel; + } + + public R in(Collection collection, Predicate when) { + if (queryModel != null) { + CPI.addWhereQueryCondition(queryModel.getQueryWrapper(), queryColumn.in(collection, when), connector); + } + return queryModel; + } + + public R notIn(Object... arrays) { + if (queryModel != null) { + CPI.addWhereQueryCondition(queryModel.getQueryWrapper(), queryColumn.notIn(arrays), connector); + } + return queryModel; + } + + public R notIn(Object[] arrays, Predicate when) { + if (queryModel != null) { + CPI.addWhereQueryCondition(queryModel.getQueryWrapper(), queryColumn.notIn(arrays, when), connector); + } + return queryModel; + } + + public R notIn(Collection collection) { + if (queryModel != null) { + CPI.addWhereQueryCondition(queryModel.getQueryWrapper(), queryColumn.notIn(collection), connector); + } + return queryModel; + } + + public R notIn(Collection collection, Predicate when) { + if (queryModel != null) { + CPI.addWhereQueryCondition(queryModel.getQueryWrapper(), queryColumn.notIn(collection, when), connector); + } + return queryModel; + } + + public R notIn(R queryModel) { + if (queryModel != null) { + CPI.addWhereQueryCondition(queryModel.getQueryWrapper(), queryColumn.notIn(queryModel), connector); + } + return this.queryModel; + } + + public R notIn(R queryModel, Predicate when) { + if (queryModel != null) { + CPI.addWhereQueryCondition(queryModel.getQueryWrapper(), queryColumn.notIn(queryModel, when), connector); + } + return this.queryModel; + } + + public R between(Object start, Object end) { + if (queryModel != null) { + CPI.addWhereQueryCondition(queryModel.getQueryWrapper(), queryColumn.between(start, end), connector); + } + return queryModel; + } + + public R between(Object start, Object end, Predicate when) { + if (queryModel != null) { + CPI.addWhereQueryCondition(queryModel.getQueryWrapper(), queryColumn.between(start, end, when), connector); + } + return queryModel; + } + + public R notBetween(Object start, Object end) { + if (queryModel != null) { + CPI.addWhereQueryCondition(queryModel.getQueryWrapper(), queryColumn.notBetween(start, end), connector); + } + return queryModel; + } + + public R notBetween(Object start, Object end, Predicate when) { + if (queryModel != null) { + CPI.addWhereQueryCondition(queryModel.getQueryWrapper(), queryColumn.notBetween(start, end, when), connector); + } + return queryModel; + } + +} From 7df2e13832d680532ee5e6c675c96c601cb93498 Mon Sep 17 00:00:00 2001 From: Suomm <1474983351@qq.com> Date: Tue, 25 Jul 2023 11:37:47 +0800 Subject: [PATCH 13/37] feat: add OrderByBuilder. --- .../activerecord/query/OrderByBuilder.java | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 mybatis-flex-core/src/main/java/com/mybatisflex/core/activerecord/query/OrderByBuilder.java diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/activerecord/query/OrderByBuilder.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/activerecord/query/OrderByBuilder.java new file mode 100644 index 00000000..32cb301b --- /dev/null +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/activerecord/query/OrderByBuilder.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2022-2023, Mybatis-Flex (fuhai999@gmail.com). + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.mybatisflex.core.activerecord.query; + + +import com.mybatisflex.core.query.QueryColumn; +import com.mybatisflex.core.util.LambdaGetter; +import com.mybatisflex.core.util.LambdaUtil; + +/** + * 排序字段构建器 + * + * @author michael + */ +public class OrderByBuilder> { + + private final R queryModel; + private final QueryColumn queryColumn; + + public OrderByBuilder(R queryModel, LambdaGetter getter) { + this.queryModel = queryModel; + this.queryColumn = LambdaUtil.getQueryColumn(getter); + } + + public R asc() { + return queryModel.orderBy(queryColumn.asc()); + } + + public R desc() { + return queryModel.orderBy(queryColumn.desc()); + } + +} From 8832da5cafa33e42953981d6191217bf46e3f8d1 Mon Sep 17 00:00:00 2001 From: Suomm <1474983351@qq.com> Date: Tue, 25 Jul 2023 11:40:27 +0800 Subject: [PATCH 14/37] feat: add QueryModel. --- .../core/activerecord/query/QueryModel.java | 171 ++++++++++++++++++ 1 file changed, 171 insertions(+) create mode 100644 mybatis-flex-core/src/main/java/com/mybatisflex/core/activerecord/query/QueryModel.java diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/activerecord/query/QueryModel.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/activerecord/query/QueryModel.java new file mode 100644 index 00000000..e1a45b48 --- /dev/null +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/activerecord/query/QueryModel.java @@ -0,0 +1,171 @@ +/* + * Copyright (c) 2022-2023, Mybatis-Flex (fuhai999@gmail.com). + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.mybatisflex.core.activerecord.query; + +import com.mybatisflex.annotation.Column; +import com.mybatisflex.core.query.*; +import com.mybatisflex.core.util.LambdaGetter; +import com.mybatisflex.core.util.LambdaUtil; + +/** + * @author 王帅 + * @since 2023-07-24 + */ +@SuppressWarnings({"unused", "unchecked"}) +public abstract class QueryModel> { + + @Column(ignore = true) + private QueryWrapper queryWrapper; + + protected QueryWrapper getQueryWrapper() { + if (queryWrapper == null) { + queryWrapper = QueryWrapper.create(this); + } + return queryWrapper; + } + + public T select() { + return (T) this; + } + + public T select(String... columns) { + getQueryWrapper().select(columns); + return (T) this; + } + + public T select(QueryColumn... queryColumns) { + getQueryWrapper().select(queryColumns); + return (T) this; + } + + public T select(LambdaGetter... columns) { + getQueryWrapper().select(columns); + return (T) this; + } + + public T select(QueryColumn[]... queryColumns) { + getQueryWrapper().select(queryColumns); + return (T) this; + } + + public T where(QueryCondition queryCondition) { + getQueryWrapper().where(queryCondition); + return (T) this; + } + + public T where(String sql) { + getQueryWrapper().where(sql); + return (T) this; + } + + public T where(String sql, Object... params) { + getQueryWrapper().where(sql, params); + return (T) this; + } + + public WhereBuilder where(LambdaGetter column) { + return new WhereBuilder<>((T) this, LambdaUtil.getQueryColumn(column), SqlConnector.AND); + } + + public T and(QueryCondition queryCondition) { + getQueryWrapper().and(queryCondition); + return (T) this; + } + + public T and(String sql) { + getQueryWrapper().and(sql); + return (T) this; + } + + public T and(String sql, Object... params) { + getQueryWrapper().and(sql, params); + return (T) this; + } + + public WhereBuilder and(LambdaGetter column) { + return new WhereBuilder<>((T) this, LambdaUtil.getQueryColumn(column), SqlConnector.AND); + } + + public T or(QueryCondition queryCondition) { + getQueryWrapper().or(queryCondition); + return (T) this; + } + + public T or(String sql) { + getQueryWrapper().or(sql); + return (T) this; + } + + public T or(String sql, Object... params) { + getQueryWrapper().or(sql, params); + return (T) this; + } + + public WhereBuilder or(LambdaGetter column) { + return new WhereBuilder<>((T) this, LambdaUtil.getQueryColumn(column), SqlConnector.OR); + } + + public T groupBy(String... names) { + getQueryWrapper().groupBy(names); + return (T) this; + } + + public T groupBy(QueryColumn... columns) { + getQueryWrapper().groupBy(columns); + return (T) this; + } + + public T groupBy(LambdaGetter... columns) { + getQueryWrapper().groupBy(columns); + return (T) this; + } + + public T having(QueryCondition queryCondition) { + getQueryWrapper().having(queryCondition); + return (T) this; + } + + public T orderBy(QueryOrderBy... orderBys) { + getQueryWrapper().orderBy(orderBys); + return (T) this; + } + + public T orderBy(String... orderBys) { + getQueryWrapper().orderBy(orderBys); + return (T) this; + } + + public OrderByBuilder orderBy(LambdaGetter column) { + return new OrderByBuilder<>((T) this, column); + } + + public T limit(Integer rows) { + getQueryWrapper().limit(rows); + return (T) this; + } + + public T offset(Integer offset) { + getQueryWrapper().offset(offset); + return (T) this; + } + + public T limit(Integer offset, Integer rows) { + getQueryWrapper().limit(offset, rows); + return (T) this; + } + +} From 1f0e70528facbf850d96f87be112e2b17e9a84e9 Mon Sep 17 00:00:00 2001 From: Suomm <1474983351@qq.com> Date: Tue, 25 Jul 2023 11:40:38 +0800 Subject: [PATCH 15/37] feat: add Model. --- .../mybatisflex/core/activerecord/Model.java | 72 +++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 mybatis-flex-core/src/main/java/com/mybatisflex/core/activerecord/Model.java diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/activerecord/Model.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/activerecord/Model.java new file mode 100644 index 00000000..e9e46eca --- /dev/null +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/activerecord/Model.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2022-2023, Mybatis-Flex (fuhai999@gmail.com). + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.mybatisflex.core.activerecord; + +import com.mybatisflex.core.activerecord.query.QueryModel; +import com.mybatisflex.core.paginate.Page; +import com.mybatisflex.core.util.SqlUtil; + +import java.util.List; +import java.util.Optional; + +/** + * @param 实体类类型 + * @author 王帅 + * @since 2023-07-24 + */ +@SuppressWarnings({"unused", "unchecked"}) +public abstract class Model> + extends QueryModel + implements MapperModel { + + public boolean remove() { + return SqlUtil.toBool(baseMapper().deleteByQuery(getQueryWrapper())); + } + + public boolean update() { + return update(true); + } + + public boolean update(boolean ignoreNulls) { + return SqlUtil.toBool(baseMapper().updateByQuery((T) this, ignoreNulls, getQueryWrapper())); + } + + public long count() { + return baseMapper().selectCountByQuery(getQueryWrapper()); + } + + public boolean exists() { + return SqlUtil.toBool(count()); + } + + public T one() { + return baseMapper().selectOneByQuery(getQueryWrapper()); + } + + public Optional oneOpt() { + return Optional.ofNullable(one()); + } + + public List list() { + return baseMapper().selectListByQuery(getQueryWrapper()); + } + + public Page page(Page page) { + return baseMapper().paginate(page, getQueryWrapper()); + } + +} From ff5d19099773c21707a36cb300042794404af52c Mon Sep 17 00:00:00 2001 From: Suomm <1474983351@qq.com> Date: Tue, 25 Jul 2023 11:44:52 +0800 Subject: [PATCH 16/37] =?UTF-8?q?refactor:=20Active=20Record=20=E9=93=BE?= =?UTF-8?q?=E5=BC=8F=E6=A8=A1=E5=9E=8B=E7=B1=BB=E6=9E=84=E5=BB=BA=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/mybatisflex/test/model/Good.java | 38 +++++++++++-------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/mybatis-flex-test/mybatis-flex-spring-boot-test/src/main/java/com/mybatisflex/test/model/Good.java b/mybatis-flex-test/mybatis-flex-spring-boot-test/src/main/java/com/mybatisflex/test/model/Good.java index 87d9def7..e95742c9 100644 --- a/mybatis-flex-test/mybatis-flex-spring-boot-test/src/main/java/com/mybatisflex/test/model/Good.java +++ b/mybatis-flex-test/mybatis-flex-spring-boot-test/src/main/java/com/mybatisflex/test/model/Good.java @@ -17,7 +17,9 @@ package com.mybatisflex.test.model; import com.mybatisflex.annotation.Id; +import com.mybatisflex.annotation.KeyType; import com.mybatisflex.annotation.Table; +import com.mybatisflex.core.activerecord.Model; import java.util.Objects; @@ -28,35 +30,42 @@ import java.util.Objects; * @since 2023-06-07 */ @Table("tb_good") -public class Good { +public class Good extends Model { - @Id + @Id(keyType = KeyType.Auto) private Integer goodId; private String name; - private double price; + private Double price; + + public static Good create() { + return new Good(); + } public Integer getGoodId() { return goodId; } - public void setGoodId(Integer goodId) { + public Good setGoodId(Integer goodId) { this.goodId = goodId; + return this; } public String getName() { return name; } - public void setName(String name) { + public Good setName(String name) { this.name = name; + return this; } - public double getPrice() { + public Double getPrice() { return price; } - public void setPrice(double price) { + public Good setPrice(Double price) { this.price = price; + return this; } @Override @@ -79,23 +88,20 @@ public class Good { Good good = (Good) o; - if (Double.compare(good.price, price) != 0) { - return false; - } if (!Objects.equals(goodId, good.goodId)) { return false; } - return Objects.equals(name, good.name); + if (!Objects.equals(name, good.name)) { + return false; + } + return Objects.equals(price, good.price); } @Override public int hashCode() { - int result; - long temp; - result = goodId != null ? goodId.hashCode() : 0; + int result = goodId != null ? goodId.hashCode() : 0; result = 31 * result + (name != null ? name.hashCode() : 0); - temp = Double.doubleToLongBits(price); - result = 31 * result + (int) (temp ^ (temp >>> 32)); + result = 31 * result + (price != null ? price.hashCode() : 0); return result; } From 94ba44a1a43a6144f1300cd186f2197c77ffc1c4 Mon Sep 17 00:00:00 2001 From: Suomm <1474983351@qq.com> Date: Tue, 25 Jul 2023 11:45:24 +0800 Subject: [PATCH 17/37] =?UTF-8?q?test:=20Active=20Record=20=E6=B5=8B?= =?UTF-8?q?=E8=AF=95=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../test/mapper/ActiveRecordTest.java | 72 ++++++++++++++++++- 1 file changed, 69 insertions(+), 3 deletions(-) diff --git a/mybatis-flex-test/mybatis-flex-spring-boot-test/src/test/java/com/mybatisflex/test/mapper/ActiveRecordTest.java b/mybatis-flex-test/mybatis-flex-spring-boot-test/src/test/java/com/mybatisflex/test/mapper/ActiveRecordTest.java index 17bd1675..61d45f33 100644 --- a/mybatis-flex-test/mybatis-flex-spring-boot-test/src/test/java/com/mybatisflex/test/mapper/ActiveRecordTest.java +++ b/mybatis-flex-test/mybatis-flex-spring-boot-test/src/test/java/com/mybatisflex/test/mapper/ActiveRecordTest.java @@ -19,9 +19,12 @@ package com.mybatisflex.test.mapper; import com.mybatisflex.core.mybatis.Mappers; import com.mybatisflex.core.query.QueryWrapper; import com.mybatisflex.test.model.Good; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.springframework.boot.test.context.SpringBootTest; +import static com.mybatisflex.test.model.table.GoodTableDef.GOOD; + /** * @author 王帅 * @since 2023-07-23 @@ -31,12 +34,75 @@ class ActiveRecordTest { @Test void testMapper() { - Good good = new Good(); - good.setPrice(28); + Good good = Good.create(); - GoodMapper goodMapper = Mappers.ofMapperClass(GoodMapper.class); + good.setPrice(28.0); + + GoodMapper goodMapper = (GoodMapper) Mappers.ofEntityClass(Good.class); goodMapper.selectListByQuery(QueryWrapper.create(good)); } + @Test + void testInsert() { + boolean saved = Good.create() + .setPrice(28.0) + .setName("摆渡人") + .save(); + + Assertions.assertTrue(saved); + } + + @Test + void testUpdate() { + Good.create() + .setGoodId(11) + .setPrice(38.0) + .updateById(); + } + + @Test + void testDelete() { + boolean removed = Good.create() + .setGoodId(1) + .removeById(); + + Assertions.assertTrue(removed); + } + + @Test + void testSelectById() { + Good good = Good.create() + .setGoodId(11) + .oneById(); + + System.out.println(good); + } + + @Test + void testSelectOne() { + Good good1 = Good.create() + .setName("摆渡人") + .one(); + + Good good2 = Good.create() + .where(GOOD.NAME.eq("摆渡人")) + .one(); + + Good good3 = Good.create() + .where(Good::getName).eq("摆渡人") + .one(); + + Assertions.assertEquals(good1, good2); + Assertions.assertEquals(good1, good3); + } + + @Test + void testSelectList() { + Good.create() + .where(GOOD.PRICE.ge(28.0)) + .list() + .forEach(System.out::println); + } + } From 3a9dbf5d681841e7bbd2272d262acf318437d6da Mon Sep 17 00:00:00 2001 From: Suomm <1474983351@qq.com> Date: Tue, 25 Jul 2023 12:06:44 +0800 Subject: [PATCH 18/37] style: add MapperModel javadoc. --- .../core/activerecord/MapperModel.java | 75 +++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/activerecord/MapperModel.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/activerecord/MapperModel.java index 78b3cab4..c0a6f465 100644 --- a/mybatis-flex-core/src/main/java/com/mybatisflex/core/activerecord/MapperModel.java +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/activerecord/MapperModel.java @@ -25,6 +25,11 @@ import com.mybatisflex.core.util.SqlUtil; import java.util.Optional; /** + *

使用 {@link BaseMapper} 进行 CRUD 操作的实体类的抽象接口。 + * + *

使用接口是为了方便拓展,该接口提供了简单的根据 主键 操作数据的方法, + * 实现类可以进行其他方法的扩展。 + * * @param 实体类类型 * @author 王帅 * @since 2023-07-23 @@ -32,47 +37,117 @@ import java.util.Optional; @SuppressWarnings({"unused", "unchecked"}) public interface MapperModel { + /** + *

获取实体类对应的 {@link BaseMapper} 接口。 + * + *

可以拓展该方法提高效率,例如: + *

{@code
+     * return AccountMapper.class;
+     * }
+ * + * @return {@link BaseMapper} 接口 + */ default BaseMapper baseMapper() { return Mappers.ofEntityClass((Class) getClass()); } + /** + *

获取实体类主键数据。 + * + *

可以拓展该方法提高效率,例如: + *

{@code
+     * return new Object[]{id};
+     * }
+ * + * @return 主键数据数组 + */ default Object[] getPkValues() { TableInfo tableInfo = TableInfoFactory.ofEntityClass(getClass()); return tableInfo.buildPkSqlArgs(this); } + /** + * 保存数据(自动忽略 {@code null} 值)。 + * + * @return {@code true} 保存成功,{@code false} 保存失败 + */ default boolean save() { return save(true); } + /** + * 保存数据,并设置是否忽略 {@code null} 值。 + * + * @param ignoreNulls 是否忽略 {@code null} 值 + * @return {@code true} 保存成功,{@code false} 保存失败 + */ default boolean save(boolean ignoreNulls) { return SqlUtil.toBool(baseMapper().insert((T) this, ignoreNulls)); } + /** + * 保存或者更新数据,如果实体类主键没有值,则 保存 数据;如果实体类主键有值,则 + * 更新 数据(全部自动忽略 {@code null} 值)。 + * + * @return {@code true} 保存或更新成功,{@code false} 保存或更新失败 + */ default boolean saveOrUpdate() { return saveOrUpdate(true); } + /** + * 保存或者更新数据,如果实体类主键没有值,则 保存 数据;如果实体类主键有值,则 + * 更新 数据,并设置是否忽略 {@code null} 值。 + * + * @param ignoreNulls 是否忽略 {@code null} 值 + * @return {@code true} 保存或更新成功,{@code false} 保存或更新失败 + */ default boolean saveOrUpdate(boolean ignoreNulls) { return SqlUtil.toBool(baseMapper().insertOrUpdate((T) this, ignoreNulls)); } + /** + * 根据实体类主键删除数据。 + * + * @return {@code true} 删除成功,{@code false} 删除失败 + */ default boolean removeById() { return SqlUtil.toBool(baseMapper().deleteById(getPkValues())); } + /** + * 根据实体类主键更新数据(自动忽略 {@code null} 值)。 + * + * @return {@code true} 更新成功,{@code false} 更新失败 + */ default boolean updateById() { return updateById(true); } + /** + * 根据实体类主键更新数据,并设置是否忽略 {@code null} 值。 + * + * @param ignoreNulls 是否忽略 {@code null} 值 + * @return {@code true} 更新成功,{@code false} 更新失败 + */ default boolean updateById(boolean ignoreNulls) { return SqlUtil.toBool(baseMapper().update((T) this, ignoreNulls)); } + /** + * 根据实体类主键获取一条数据。 + * + * @return 数据 + */ default T oneById() { return baseMapper().selectOneById(getPkValues()); } + /** + * 根据实体类主键获取一条数据,并封装为 {@link Optional} 返回。 + * + * @return 数据 + */ default Optional oneByIdOpt() { return Optional.ofNullable(oneById()); } From cd8ce808d2a25890e52181e4916956113dafda02 Mon Sep 17 00:00:00 2001 From: Suomm <1474983351@qq.com> Date: Tue, 25 Jul 2023 12:30:15 +0800 Subject: [PATCH 19/37] style: add OrderByBuilder javadoc. --- .../mybatisflex/core/activerecord/query/OrderByBuilder.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/activerecord/query/OrderByBuilder.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/activerecord/query/OrderByBuilder.java index 32cb301b..7287001a 100644 --- a/mybatis-flex-core/src/main/java/com/mybatisflex/core/activerecord/query/OrderByBuilder.java +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/activerecord/query/OrderByBuilder.java @@ -21,9 +21,10 @@ import com.mybatisflex.core.util.LambdaGetter; import com.mybatisflex.core.util.LambdaUtil; /** - * 排序字段构建器 + * Lambda 排序构建器。 * - * @author michael + * @author 王帅 + * @since 2023-07-25 */ public class OrderByBuilder> { From 34e6685ae89a9e3b7e0c7dc7b25dab27eb778e46 Mon Sep 17 00:00:00 2001 From: Suomm <1474983351@qq.com> Date: Tue, 25 Jul 2023 12:30:26 +0800 Subject: [PATCH 20/37] style: add WhereBuilder javadoc. --- .../com/mybatisflex/core/activerecord/query/WhereBuilder.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/activerecord/query/WhereBuilder.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/activerecord/query/WhereBuilder.java index d9693c5b..285429d6 100644 --- a/mybatis-flex-core/src/main/java/com/mybatisflex/core/activerecord/query/WhereBuilder.java +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/activerecord/query/WhereBuilder.java @@ -25,7 +25,8 @@ import java.util.Collection; import java.util.function.Predicate; /** - * @param + * Lambda 条件构建器。 + * * @author 王帅 * @since 2023-07-24 */ From 26efb7cb664e60d990eb44fb8b8831b5f06dfb72 Mon Sep 17 00:00:00 2001 From: Suomm <1474983351@qq.com> Date: Tue, 25 Jul 2023 12:30:35 +0800 Subject: [PATCH 21/37] style: add QueryModel javadoc. --- .../mybatisflex/core/activerecord/query/QueryModel.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/activerecord/query/QueryModel.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/activerecord/query/QueryModel.java index e1a45b48..29fd527e 100644 --- a/mybatis-flex-core/src/main/java/com/mybatisflex/core/activerecord/query/QueryModel.java +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/activerecord/query/QueryModel.java @@ -22,6 +22,13 @@ import com.mybatisflex.core.util.LambdaGetter; import com.mybatisflex.core.util.LambdaUtil; /** + *

实体类条件查询构建模型。 + * + *

该类内部维护了一个 {@link QueryWrapper} 属性,用来构建查询条件。 + * 通过实体类属性构建的查询条件都是值等于,该扩展用于非等于值构建,及一些其他方法。 + * 如果不想通过实体类直接构建查询条件,可以不继承该类。 + * + * @param 实体类类型 * @author 王帅 * @since 2023-07-24 */ From 9e82a0ac12ff5f8319673f3864e7782eb69c803a Mon Sep 17 00:00:00 2001 From: Suomm <1474983351@qq.com> Date: Tue, 25 Jul 2023 12:30:43 +0800 Subject: [PATCH 22/37] style: add Model javadoc. --- .../mybatisflex/core/activerecord/Model.java | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/activerecord/Model.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/activerecord/Model.java index e9e46eca..2887bbc2 100644 --- a/mybatis-flex-core/src/main/java/com/mybatisflex/core/activerecord/Model.java +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/activerecord/Model.java @@ -24,6 +24,8 @@ import java.util.List; import java.util.Optional; /** + * Active Record 模型。 + * * @param 实体类类型 * @author 王帅 * @since 2023-07-24 @@ -33,38 +35,85 @@ public abstract class Model> extends QueryModel implements MapperModel { + /** + * 根据实体类构建的条件删除数据。 + * + * @return {@code true} 删除成功,{@code false} 删除失败 + */ public boolean remove() { return SqlUtil.toBool(baseMapper().deleteByQuery(getQueryWrapper())); } + /** + * 根据实体类构建的条件更新数据(自动忽略 {@code null} 值)。 + * + * @return {@code true} 更新成功,{@code false} 更新失败 + */ public boolean update() { return update(true); } + /** + * 根据实体类构建的条件更新数据,并设置是否忽略 {@code null} 值。 + * + * @param ignoreNulls 是否忽略 {@code null} 值 + * @return {@code true} 更新成功,{@code false} 更新失败 + */ public boolean update(boolean ignoreNulls) { return SqlUtil.toBool(baseMapper().updateByQuery((T) this, ignoreNulls, getQueryWrapper())); } + /** + * 根据实体类构建的条件查询数据数量。 + * + * @return 数据数量 + */ public long count() { return baseMapper().selectCountByQuery(getQueryWrapper()); } + /** + * 根据实体类构建的条件判断数据是否存在。 + * + * @return {@code true} 数据存在,{@code false} 数据不存在 + */ public boolean exists() { return SqlUtil.toBool(count()); } + /** + * 根据实体类构建的条件获取一条数据。 + * + * @return 数据 + */ public T one() { return baseMapper().selectOneByQuery(getQueryWrapper()); } + /** + * 根据实体类构建的条件获取一条数据,并封装为 {@link Optional} 返回。 + * + * @return 数据 + */ public Optional oneOpt() { return Optional.ofNullable(one()); } + /** + * 根据实体类构建的条件获取多条数据。 + * + * @return 数据列表 + */ public List list() { return baseMapper().selectListByQuery(getQueryWrapper()); } + /** + * 根据实体类构建的条件获取分页数据。 + * + * @param page 分页对象 + * @return 分页数据 + */ public Page page(Page page) { return baseMapper().paginate(page, getQueryWrapper()); } From 9633a2866efe44c88244b4816aa65ce912027f21 Mon Sep 17 00:00:00 2001 From: Suomm <1474983351@qq.com> Date: Tue, 25 Jul 2023 12:31:27 +0800 Subject: [PATCH 23/37] =?UTF-8?q?refactor:=20=E6=95=B0=E6=8D=AE=E6=9E=84?= =?UTF-8?q?=E5=BB=BA=E5=92=8C=E6=9F=A5=E8=AF=A2=E9=9C=80=E8=A6=81=E5=88=86?= =?UTF-8?q?=E7=A6=BB=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/mybatisflex/core/activerecord/query/QueryModel.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/activerecord/query/QueryModel.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/activerecord/query/QueryModel.java index 29fd527e..ece914c4 100644 --- a/mybatis-flex-core/src/main/java/com/mybatisflex/core/activerecord/query/QueryModel.java +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/activerecord/query/QueryModel.java @@ -40,7 +40,7 @@ public abstract class QueryModel> { protected QueryWrapper getQueryWrapper() { if (queryWrapper == null) { - queryWrapper = QueryWrapper.create(this); + queryWrapper = QueryWrapper.create(); } return queryWrapper; } From 5555a286f86285be4984e1e67c60909a5016a2f8 Mon Sep 17 00:00:00 2001 From: Suomm <1474983351@qq.com> Date: Tue, 25 Jul 2023 12:32:11 +0800 Subject: [PATCH 24/37] =?UTF-8?q?fix:=20=E6=9F=A5=E8=AF=A2=E4=B8=80?= =?UTF-8?q?=E6=9D=A1=E6=95=B0=E6=8D=AE=E6=95=B0=E6=8D=AE=E9=99=90=E5=88=B6?= =?UTF-8?q?=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/com/mybatisflex/core/activerecord/Model.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/activerecord/Model.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/activerecord/Model.java index 2887bbc2..d0d17efb 100644 --- a/mybatis-flex-core/src/main/java/com/mybatisflex/core/activerecord/Model.java +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/activerecord/Model.java @@ -87,7 +87,7 @@ public abstract class Model> * @return 数据 */ public T one() { - return baseMapper().selectOneByQuery(getQueryWrapper()); + return baseMapper().selectOneByQuery(getQueryWrapper().limit(1)); } /** From bb16835b942c57f93dc6745f639bce685fd8ec20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=80=E6=BA=90=E6=B5=B7=E5=93=A5?= Date: Tue, 25 Jul 2023 12:46:07 +0800 Subject: [PATCH 25/37] refactor: move IService.queryChain() to baseMapper --- .../src/main/java/com/mybatisflex/core/BaseMapper.java | 6 ++++++ .../main/java/com/mybatisflex/core/service/IService.java | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/BaseMapper.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/BaseMapper.java index 25f4627b..6581842b 100644 --- a/mybatis-flex-core/src/main/java/com/mybatisflex/core/BaseMapper.java +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/BaseMapper.java @@ -55,6 +55,12 @@ public interface BaseMapper { */ int DEFAULT_BATCH_SIZE = 1000; + + default QueryWrapperChain queryChain() { + return new QueryWrapperChain<>(this); + } + + // === 增(insert) === /** diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/service/IService.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/service/IService.java index 2eaa999a..dda3c7f4 100644 --- a/mybatis-flex-core/src/main/java/com/mybatisflex/core/service/IService.java +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/service/IService.java @@ -530,7 +530,7 @@ public interface IService { } default QueryWrapperChain queryChain() { - return new QueryWrapperChain<>(getMapper()); + return getMapper().queryChain(); } } From 290335f9580b2e5a693f59d239ff18443562a317 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=80=E6=BA=90=E6=B5=B7=E5=93=A5?= Date: Tue, 25 Jul 2023 12:49:01 +0800 Subject: [PATCH 26/37] feat: QueryWrapperAdapter add groupBy lambda --- .../mybatisflex/core/query/QueryWrapperAdapter.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/query/QueryWrapperAdapter.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/query/QueryWrapperAdapter.java index 20968f57..dfb99736 100644 --- a/mybatis-flex-core/src/main/java/com/mybatisflex/core/query/QueryWrapperAdapter.java +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/query/QueryWrapperAdapter.java @@ -536,6 +536,18 @@ public class QueryWrapperAdapter> extends Query return (R) this; } + @Override + public R groupBy(LambdaGetter column) { + super.groupBy(column); + return (R) this; + } + + @Override + public R groupBy(LambdaGetter... columns) { + super.groupBy(columns); + return (R) this; + } + @Override public R having(QueryCondition queryCondition) { super.having(queryCondition); From 98696adeededab1b06b474181ff307b6e01609fc Mon Sep 17 00:00:00 2001 From: Suomm <1474983351@qq.com> Date: Tue, 25 Jul 2023 13:32:08 +0800 Subject: [PATCH 27/37] =?UTF-8?q?fix:=20Javadoc=20=E6=8F=8F=E8=BF=B0?= =?UTF-8?q?=E9=94=99=E8=AF=AF=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/mybatisflex/core/activerecord/MapperModel.java | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/activerecord/MapperModel.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/activerecord/MapperModel.java index c0a6f465..1b4e7431 100644 --- a/mybatis-flex-core/src/main/java/com/mybatisflex/core/activerecord/MapperModel.java +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/activerecord/MapperModel.java @@ -38,12 +38,7 @@ import java.util.Optional; public interface MapperModel { /** - *

获取实体类对应的 {@link BaseMapper} 接口。 - * - *

可以拓展该方法提高效率,例如: - *

{@code
-     * return AccountMapper.class;
-     * }
+ * 获取实体类对应的 {@link BaseMapper} 接口。 * * @return {@link BaseMapper} 接口 */ From 8c91f9554c27097b3096b2d14980b8155193aa05 Mon Sep 17 00:00:00 2001 From: Suomm <1474983351@qq.com> Date: Tue, 25 Jul 2023 13:34:51 +0800 Subject: [PATCH 28/37] =?UTF-8?q?doc:=20Active=20Record=20=E6=96=87?= =?UTF-8?q?=E6=A1=A3=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/.vitepress/config.ts | 1 + docs/zh/base/active-record.md | 141 ++++++++++++++++++++++++++++++++++ 2 files changed, 142 insertions(+) create mode 100644 docs/zh/base/active-record.md diff --git a/docs/.vitepress/config.ts b/docs/.vitepress/config.ts index 7bb627d8..b0277067 100644 --- a/docs/.vitepress/config.ts +++ b/docs/.vitepress/config.ts @@ -63,6 +63,7 @@ export default defineConfig({ {text: 'QueryWrapper', link: '/zh/base/querywrapper'}, {text: 'QueryWrapperChain', link: '/zh/base/query-wrapper-chain'}, {text: 'Db + Row', link: '/zh/base/db-row'}, + {text: 'Active Record', link: '/zh/base/active-record'}, {text: 'IService', link: '/zh/base/service'}, {text: 'SpringBoot 配置文件', link: '/zh/base/configuration'}, {text: 'MyBatisFlexCustomizer', link: '/zh/base/mybatis-flex-customizer'}, diff --git a/docs/zh/base/active-record.md b/docs/zh/base/active-record.md new file mode 100644 index 00000000..d8148ba7 --- /dev/null +++ b/docs/zh/base/active-record.md @@ -0,0 +1,141 @@ +# Active Record + +[Active Record 模式](http://www.martinfowler.com/eaaCatalog/activeRecord.html)出自 Martin Fowler +写的《[企业应用架构模式](https://book.douban.com/subject/4826290/)》书中。在 Active Record +模式中,对象中既有持久存储的数据,也有针对数据的操作。Active Record 模式把数据存取逻辑作为对象的一部分,处理对象的用户知道如何把数据写入数据库,还知道如何从数据库中读出数据。 + +在 MyBatis-Flex 中实现 Active Record +功能十分简单,只需继承 [Model](https://gitee.com/mybatis-flex/mybatis-flex/blob/main/mybatis-flex-core/src/main/java/com/mybatisflex/core/activerecord/Model.java) +即可。 + +::: tip 注意事项 + +- 使用 Active Record 功能时,项目中必须注入对应实体类的 BaseMapper 对象! +- 如果不想手动创建 Mapper 接口,可以使用 [APT](../others/apt.md#配置文件和选项) 辅助生成。 + ::: + +## 使用示例 + +在以下示例当中,使用了 [Lombok](https://www.projectlombok.org/) 对实体类进行了增强,以便我们全链式调用: + +1. `@Table` 标记了实体类对应的数据表。 +2. `@Data` 为我们生成了 setter/getter、toString、equals、hashCode 等方法, + 其中 `staticConstructor = "create"` 为我们创建了一个 `create()` 静态方法用于链式调用。 +3. `@Accessors(chain = true)` 为我们开启了 `return this;` 这样既可以被序列化,又可以链式调用。 + +```java + +@Table("tb_account") +@Accessors(chain = true) +@Data(staticConstructor = "create") +public class Account extends Model { + + @Id(keyType = KeyType.Auto) + private Long id; + private String userName; + private Integer age; + private Date birthday; + +} +``` + +这样我们就可以流畅的使用 Active Record 功能了: + +```java +@RestController +@RequestMapping("/account") +public class AccountController { + + @PostMapping("save") + public boolean save(@RequestBody Account account) { + return account.save(); + } + +} +``` + +## 保存数据 + +`Model` 提供了 `save` 方法来保存数据,调用该方法前需要将保存数据填充: + +```java +Account.create() + .setUserName("张三") + .setAge(18) + .setBirthday(new Date()) + .save(); +``` + +## 删除数据 + +`Model` 提供了 `remove` 方法来删除数据: + +- 根据主键删除 + +```java +Account.create() + .setId(1L) + .removeById(); +``` + +- 根据条件删除 + +```java +Account.create() + .where(Account::getId).eq(1L) + .remove(); +``` + +## 更新数据 + +`Model` 提供了 `update` 方法来更新数据,调用该方法前需要将更新数据填充: + +- 根据主键更新 + +```java +Account.create() + .setId(1L) + .setAge(100) + .updateById(); +``` + +- 根据条件更新 + +```java +Account.create() + .setAge(100) + .where(Account::getId).eq(1L) + .update(); +``` + +## 查询数据 + +### 查询一条数据 + +`Model` 提供了 `one` 方法来查询一条数据: + +```java +Account.create() + .where(Account::getId).eq(1L) + .one(); +``` + +### 查询多条数据 + +`Model` 提供了 `list` 方法来查询多条数据: + +```java +Account.create() + .where(Account::getAge).ge(18) + .list(); +``` + +### 查询分页数据 + +`Model` 提供了 `page` 方法来查询分页数据: + +```java +Account.create() + .where(Account::getAge).ge(18) + .page(Page.of(1,10)); +``` From fe8b4f5890041724343af4dc5ec513c335a4b1b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=80=E6=BA=90=E6=B5=B7=E5=93=A5?= Date: Tue, 25 Jul 2023 14:38:23 +0800 Subject: [PATCH 29/37] feat: add UpdateChain.java --- .../java/com/mybatisflex/core/BaseMapper.java | 6 - .../com/mybatisflex/core/mybatis/Mappers.java | 6 + .../core/query/QueryWrapperChain.java | 12 -- .../mybatisflex/core/service/IService.java | 2 +- .../mybatisflex/core/update/UpdateChain.java | 111 ++++++++++++++++++ .../com/mybatisflex/test/UpdateChainTest.java | 56 +++++++++ 6 files changed, 174 insertions(+), 19 deletions(-) create mode 100644 mybatis-flex-core/src/main/java/com/mybatisflex/core/update/UpdateChain.java create mode 100644 mybatis-flex-test/mybatis-flex-native-test/src/main/java/com/mybatisflex/test/UpdateChainTest.java diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/BaseMapper.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/BaseMapper.java index 6581842b..25f4627b 100644 --- a/mybatis-flex-core/src/main/java/com/mybatisflex/core/BaseMapper.java +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/BaseMapper.java @@ -55,12 +55,6 @@ public interface BaseMapper { */ int DEFAULT_BATCH_SIZE = 1000; - - default QueryWrapperChain queryChain() { - return new QueryWrapperChain<>(this); - } - - // === 增(insert) === /** diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/mybatis/Mappers.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/mybatis/Mappers.java index 8363465f..dda16903 100644 --- a/mybatis-flex-core/src/main/java/com/mybatisflex/core/mybatis/Mappers.java +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/mybatis/Mappers.java @@ -23,10 +23,14 @@ import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.util.MapUtil; +import java.lang.invoke.MethodHandles; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; +import java.util.Arrays; +import java.util.HashSet; import java.util.Map; +import java.util.Set; import java.util.concurrent.ConcurrentHashMap; /** @@ -77,6 +81,8 @@ public class Mappers { static class MapperHandler implements InvocationHandler { + private static final Set ignoreMethods = new HashSet<>(Arrays.asList("queryChain","updateChain")); + private static final MethodHandles.Lookup lookup = MethodHandles.lookup(); private Class mapperClass; private final SqlSessionFactory sqlSessionFactory = FlexGlobalConfig.getDefaultConfig().getSqlSessionFactory(); private final ExecutorType executorType = FlexGlobalConfig.getDefaultConfig().getConfiguration().getDefaultExecutorType(); diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/query/QueryWrapperChain.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/query/QueryWrapperChain.java index d420c43b..b6838e9a 100644 --- a/mybatis-flex-core/src/main/java/com/mybatisflex/core/query/QueryWrapperChain.java +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/query/QueryWrapperChain.java @@ -41,18 +41,6 @@ public class QueryWrapperChain extends QueryWrapperAdapter(baseMapper); } - public boolean remove() { - return SqlUtil.toBool(baseMapper.deleteByQuery(this)); - } - - public boolean update(T entity) { - return SqlUtil.toBool(baseMapper.updateByQuery(entity, this)); - } - - public boolean update(T entity, boolean ignoreNulls) { - return SqlUtil.toBool(baseMapper.updateByQuery(entity, ignoreNulls, this)); - } - public long count() { return baseMapper.selectCountByQuery(this); } diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/service/IService.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/service/IService.java index dda3c7f4..2eaa999a 100644 --- a/mybatis-flex-core/src/main/java/com/mybatisflex/core/service/IService.java +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/service/IService.java @@ -530,7 +530,7 @@ public interface IService { } default QueryWrapperChain queryChain() { - return getMapper().queryChain(); + return new QueryWrapperChain<>(getMapper()); } } diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/update/UpdateChain.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/update/UpdateChain.java new file mode 100644 index 00000000..92f74779 --- /dev/null +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/update/UpdateChain.java @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2022-2023, Mybatis-Flex (fuhai999@gmail.com). + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.mybatisflex.core.update; + +import com.mybatisflex.core.BaseMapper; +import com.mybatisflex.core.exception.FlexExceptions; +import com.mybatisflex.core.mybatis.Mappers; +import com.mybatisflex.core.query.QueryColumn; +import com.mybatisflex.core.query.QueryWrapperAdapter; +import com.mybatisflex.core.util.ClassUtil; +import com.mybatisflex.core.util.LambdaGetter; +import com.mybatisflex.core.util.SqlUtil; +import com.mybatisflex.core.util.UpdateEntity; + +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; + +/** + * 用于数据更新、删除的链式操作 + * + * @author michale + * @since 2023-07-25 + */ +public class UpdateChain extends QueryWrapperAdapter> { + + private final BaseMapper baseMapper; + private final T entity; + private final UpdateWrapper entityWrapper; + + public static UpdateChain of(Class entityClass) { + BaseMapper baseMapper = Mappers.ofEntityClass(entityClass); + return new UpdateChain<>(baseMapper); + } + + public UpdateChain(BaseMapper baseMapper) { + this.baseMapper = baseMapper; + this.entity = createEntity(ClassUtil.getUsefulClass(baseMapper.getClass())); + this.entityWrapper = (UpdateWrapper) entity; + } + + private T createEntity(Class mapperClass) { + Type type = mapperClass.getGenericInterfaces()[0]; + if (type instanceof ParameterizedType) { + Class modelClass = (Class) ((ParameterizedType) type).getActualTypeArguments()[0]; + return UpdateEntity.of(modelClass); + } + throw FlexExceptions.wrap("Can not get entity class from mapper: " + mapperClass.getName()); + } + + public static UpdateChain create(BaseMapper baseMapper) { + return new UpdateChain<>(baseMapper); + } + + + public UpdateChain set(String property, Object value) { + entityWrapper.set(property, value); + return this; + } + + + public UpdateChain set(LambdaGetter getter, Object value) { + entityWrapper.set(getter, value); + return this; + } + + + public UpdateChain set(QueryColumn queryColumn, Object value) { + entityWrapper.set(queryColumn, value); + return this; + } + + public UpdateChain setRaw(String property, Object value) { + entityWrapper.setRaw(property, value); + return this; + } + + + public UpdateChain setRaw(LambdaGetter getter, Object value) { + entityWrapper.setRaw(getter, value); + return this; + } + + public UpdateChain setRaw(QueryColumn queryColumn, Object value) { + entityWrapper.set(queryColumn, value); + return this; + } + + + public boolean remove() { + return SqlUtil.toBool(baseMapper.deleteByQuery(this)); + } + + public boolean update() { + return SqlUtil.toBool(baseMapper.updateByQuery(entity, this)); + } + +} diff --git a/mybatis-flex-test/mybatis-flex-native-test/src/main/java/com/mybatisflex/test/UpdateChainTest.java b/mybatis-flex-test/mybatis-flex-native-test/src/main/java/com/mybatisflex/test/UpdateChainTest.java new file mode 100644 index 00000000..48502783 --- /dev/null +++ b/mybatis-flex-test/mybatis-flex-native-test/src/main/java/com/mybatisflex/test/UpdateChainTest.java @@ -0,0 +1,56 @@ +package com.mybatisflex.test; + +import com.mybatisflex.core.MybatisFlexBootstrap; +import com.mybatisflex.core.audit.AuditManager; +import com.mybatisflex.core.audit.ConsoleMessageCollector; +import com.mybatisflex.core.audit.MessageCollector; +import com.mybatisflex.core.update.UpdateChain; +import org.apache.ibatis.logging.stdout.StdOutImpl; +import org.junit.BeforeClass; +import org.junit.Test; +import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder; +import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType; + +import javax.sql.DataSource; + +public class UpdateChainTest { + + static AccountMapper accountMapper; + + @BeforeClass + public static void init() { + DataSource dataSource = new EmbeddedDatabaseBuilder() + .setType(EmbeddedDatabaseType.H2) + .addScript("schema.sql") + .addScript("data.sql") + .build(); + + MybatisFlexBootstrap bootstrap = MybatisFlexBootstrap.getInstance() + .setDataSource(dataSource) + .setLogImpl(StdOutImpl.class) + .addMapper(AccountMapper.class) + .start(); + + //开启审计功能 + AuditManager.setAuditEnable(true); + + //设置 SQL 审计收集器 + MessageCollector collector = new ConsoleMessageCollector(); + AuditManager.setMessageCollector(collector); + + accountMapper = bootstrap.getMapper(AccountMapper.class); + + } + + @Test + public void testUpdateChain() { + UpdateChain.of(Account.class) + .set(Account::getUserName,"张三") + .setRaw(Account::getAge,"age + 1") + .where(Account::getId).eq(1) + .update(); + + Account account = accountMapper.selectOneById(1); + System.out.println(account); + } +} From 1946d4549ffc209c30a01a279dd99c468e690096 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=80=E6=BA=90=E6=B5=B7=E5=93=A5?= Date: Tue, 25 Jul 2023 14:45:19 +0800 Subject: [PATCH 30/37] refactor: rename QueryWrapperChain to QueryChain --- .../query/{QueryWrapperChain.java => QueryChain.java} | 8 ++++---- .../main/java/com/mybatisflex/core/service/IService.java | 6 +++--- .../java/com/mybatisflex/core/update/UpdateWrapper.java | 3 +++ 3 files changed, 10 insertions(+), 7 deletions(-) rename mybatis-flex-core/src/main/java/com/mybatisflex/core/query/{QueryWrapperChain.java => QueryChain.java} (93%) diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/query/QueryWrapperChain.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/query/QueryChain.java similarity index 93% rename from mybatis-flex-core/src/main/java/com/mybatisflex/core/query/QueryWrapperChain.java rename to mybatis-flex-core/src/main/java/com/mybatisflex/core/query/QueryChain.java index b6838e9a..14db79d6 100644 --- a/mybatis-flex-core/src/main/java/com/mybatisflex/core/query/QueryWrapperChain.java +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/query/QueryChain.java @@ -29,16 +29,16 @@ import java.util.Optional; * @author 王帅 * @since 2023-07-22 */ -public class QueryWrapperChain extends QueryWrapperAdapter> { +public class QueryChain extends QueryWrapperAdapter> { private final BaseMapper baseMapper; - public QueryWrapperChain(BaseMapper baseMapper) { + public QueryChain(BaseMapper baseMapper) { this.baseMapper = baseMapper; } - public static QueryWrapperChain create(BaseMapper baseMapper) { - return new QueryWrapperChain<>(baseMapper); + public static QueryChain create(BaseMapper baseMapper) { + return new QueryChain<>(baseMapper); } public long count() { diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/service/IService.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/service/IService.java index 2eaa999a..76a3cb39 100644 --- a/mybatis-flex-core/src/main/java/com/mybatisflex/core/service/IService.java +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/service/IService.java @@ -20,7 +20,7 @@ import com.mybatisflex.core.exception.FlexExceptions; import com.mybatisflex.core.paginate.Page; import com.mybatisflex.core.query.QueryCondition; import com.mybatisflex.core.query.QueryWrapper; -import com.mybatisflex.core.query.QueryWrapperChain; +import com.mybatisflex.core.query.QueryChain; import com.mybatisflex.core.row.Db; import com.mybatisflex.core.util.ClassUtil; import com.mybatisflex.core.util.CollectionUtil; @@ -529,8 +529,8 @@ public interface IService { return QueryWrapper.create(); } - default QueryWrapperChain queryChain() { - return new QueryWrapperChain<>(getMapper()); + default QueryChain queryChain() { + return new QueryChain<>(getMapper()); } } diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/update/UpdateWrapper.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/update/UpdateWrapper.java index dda438b6..be600f65 100644 --- a/mybatis-flex-core/src/main/java/com/mybatisflex/core/update/UpdateWrapper.java +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/update/UpdateWrapper.java @@ -26,6 +26,9 @@ import org.apache.ibatis.javassist.util.proxy.ProxyObject; import java.io.Serializable; import java.util.Map; +/** + * @author michael + */ public interface UpdateWrapper extends Serializable { default Map getUpdates() { From 6c4a1f4e62847b2ae2290da7ae0a6775407a530f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=80=E6=BA=90=E6=B5=B7=E5=93=A5?= Date: Tue, 25 Jul 2023 15:02:01 +0800 Subject: [PATCH 31/37] docs: update docs --- docs/.vitepress/config.ts | 2 +- docs/zh/base/active-record.md | 9 ++--- .../base/{query-wrapper-chain.md => chain.md} | 39 ++++++++++++++----- .../mybatisflex/core/query/QueryChain.java | 2 +- 4 files changed, 35 insertions(+), 17 deletions(-) rename docs/zh/base/{query-wrapper-chain.md => chain.md} (82%) diff --git a/docs/.vitepress/config.ts b/docs/.vitepress/config.ts index b0277067..73655728 100644 --- a/docs/.vitepress/config.ts +++ b/docs/.vitepress/config.ts @@ -60,8 +60,8 @@ export default defineConfig({ {text: '基础查询', link: '/zh/base/query'}, {text: '关联查询', link: '/zh/base/relations-query'}, {text: '批量操作', link: '/zh/base/batch'}, + {text: '链式操作', link: '/zh/base/chain'}, {text: 'QueryWrapper', link: '/zh/base/querywrapper'}, - {text: 'QueryWrapperChain', link: '/zh/base/query-wrapper-chain'}, {text: 'Db + Row', link: '/zh/base/db-row'}, {text: 'Active Record', link: '/zh/base/active-record'}, {text: 'IService', link: '/zh/base/service'}, diff --git a/docs/zh/base/active-record.md b/docs/zh/base/active-record.md index d8148ba7..6690a218 100644 --- a/docs/zh/base/active-record.md +++ b/docs/zh/base/active-record.md @@ -5,13 +5,12 @@ 模式中,对象中既有持久存储的数据,也有针对数据的操作。Active Record 模式把数据存取逻辑作为对象的一部分,处理对象的用户知道如何把数据写入数据库,还知道如何从数据库中读出数据。 在 MyBatis-Flex 中实现 Active Record -功能十分简单,只需继承 [Model](https://gitee.com/mybatis-flex/mybatis-flex/blob/main/mybatis-flex-core/src/main/java/com/mybatisflex/core/activerecord/Model.java) +功能十分简单,只需让 Entity 类继承 [Model](https://gitee.com/mybatis-flex/mybatis-flex/blob/main/mybatis-flex-core/src/main/java/com/mybatisflex/core/activerecord/Model.java) 即可。 ::: tip 注意事项 - -- 使用 Active Record 功能时,项目中必须注入对应实体类的 BaseMapper 对象! -- 如果不想手动创建 Mapper 接口,可以使用 [APT](../others/apt.md#配置文件和选项) 辅助生成。 +- 使用 Active Record 功能时,项目中必须注入对应实体类的 BaseMapper 对象。 +- 如果不想手动创建 Mapper 接口,可以使用 [代码生成器](../others/codegen.md) 或 [APT](../others/apt.md#配置文件和选项) 辅助生成。 ::: ## 使用示例 @@ -35,7 +34,6 @@ public class Account extends Model { private String userName; private Integer age; private Date birthday; - } ``` @@ -50,7 +48,6 @@ public class AccountController { public boolean save(@RequestBody Account account) { return account.save(); } - } ``` diff --git a/docs/zh/base/query-wrapper-chain.md b/docs/zh/base/chain.md similarity index 82% rename from docs/zh/base/query-wrapper-chain.md rename to docs/zh/base/chain.md index 2d65bd1d..5e1057c0 100644 --- a/docs/zh/base/query-wrapper-chain.md +++ b/docs/zh/base/chain.md @@ -1,7 +1,9 @@ -# QueryWrapperChain +# 链式操作 -`QueryWrapperChain.java` 是一个对 `QueryWrapper` 进行链式调用封装的一个类,在 Service 中, -我们可以调用 `service.queryChain()` 获得该实例。 +在 MyBatis-Flex 中,内置了 `QueryChain.java` 和 `UpdateChain.java` 用于对数据进行链式查询操作和链式数据操作(修改和删除)。 + + +## QueryChain 示例 例如,查询文章列表代码如下: @@ -24,29 +26,48 @@ class ArticleServiceTest { } ``` -若不是在 Service 中,我们也可以通过 `QueryWrapperChain.create` 方法,自己创建一个 `QueryWrapperChain` 实例,代码如下: +若不是在 Service 中,我们也可以通过 `QueryChain.create` 方法,自己创建一个 `QueryChain` 实例,代码如下: ```java -List

articles = QueryWrapperChain.create(mapper) +List
articles = QueryChain.of(mapper) .select(ARTICLE.ALL_COLUMNS) .from(ARTICLE) .where(ARTICLE.ID.ge(100)) .list(); ``` -## QueryWrapperChain 的方法 +## UpdateChain 示例 + +假设我们要更新 `Account` 的 `userName` 为 "`张三`",更新年龄在之前的基础上加 1,更新代码如下: +```java +@Test +public void testUpdateChain() { + UpdateChain.of(Account.class) + .set(Account::getUserName, "张三") + .setRaw(Account::getAge, "age + 1") + .where(Account::getId).eq(1) + .update(); +} +``` +以上方法调用时,MyBatis-Flex 内部执行的 SQL 如下: + +```sql +UPDATE `tb_account` SET `user_name` = '张三' , `age` = age + 1 +WHERE `id` = 1 +``` + + +## QueryChain 的方法 - one():获取一条数据 - list():获取多条数据 - page():分页查询 - obj():当 SQL 查询只返回 1 列数据的时候,且只有 1 条数据时,可以使用此方法 - objList():当 SQL 查询只返回 1 列数据的时候,可以使用此方法 -- remove():删除数据 -- update(entity):更新数据 - count():查询数据条数 - exists():是否存在,判断 count 是否大于 0 -## 扩展方法 +## UpdateChain 扩展方法 ### `one()` 系列方法 diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/query/QueryChain.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/query/QueryChain.java index 14db79d6..f1d4be83 100644 --- a/mybatis-flex-core/src/main/java/com/mybatisflex/core/query/QueryChain.java +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/query/QueryChain.java @@ -37,7 +37,7 @@ public class QueryChain extends QueryWrapperAdapter> { this.baseMapper = baseMapper; } - public static QueryChain create(BaseMapper baseMapper) { + public static QueryChain of(BaseMapper baseMapper) { return new QueryChain<>(baseMapper); } From 4edb1fbc2fbf22ab775f05d40eb2d398180a0ddd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=80=E6=BA=90=E6=B5=B7=E5=93=A5?= Date: Tue, 25 Jul 2023 16:17:51 +0800 Subject: [PATCH 32/37] docs: update docs --- docs/zh/others/codegen.md | 50 ++++++++++++++++----------------------- 1 file changed, 20 insertions(+), 30 deletions(-) diff --git a/docs/zh/others/codegen.md b/docs/zh/others/codegen.md index 2f66add4..4296cd86 100644 --- a/docs/zh/others/codegen.md +++ b/docs/zh/others/codegen.md @@ -474,40 +474,30 @@ public class EnjoyTemplate implements ITemplate { private Engine engine; public EnjoyTemplate() { - engine = Engine.create("mybatis-flex", engine -> { - engine.setToClassPathSourceFactory(); - engine.addSharedMethod(StringUtil.class); - }); + Engine engine = Engine.use(engineName); + if (engine == null) { + engine = Engine.create(engineName, e -> { + e.addSharedStaticMethod(StringUtil.class); + e.setSourceFactory(new FileAndClassPathSourceFactory()); + }); + } + this.engine = engine; + + // 以下配置将支持 user.girl 表达式去调用 user 对象的 boolean isGirl() 方法 Engine.addFieldGetterToFirst(new FieldGetters.IsMethodFieldGetter()); } - /** - * 生成 entity 的方法实现 - */ @Override - public void generateEntity(GlobalConfig globalConfig, Table table, File entityJavaFile) throws Exception { - Map params = new HashMap<>(); - params.put("globalConfig", globalConfig); - params.put("table", table); - - - FileOutputStream fileOutputStream = new FileOutputStream(entityJavaFile); - engine.getTemplate("/templates/enjoy/entity.tpl").render(params, fileOutputStream); - } - - - /** - * 生成 mapper 的方法实现 - */ - @Override - public void generateMapper(GlobalConfig globalConfig, Table table, File mapperJavaFile) throws Exception { - Map params = new HashMap<>(); - params.put("globalConfig", globalConfig); - params.put("table", table); - - - FileOutputStream fileOutputStream = new FileOutputStream(mapperJavaFile); - engine.getTemplate("/templates/enjoy/mapper.tpl").render(params, fileOutputStream); + public void generate(Map params, String templateFilePath, File generateFile) { + if (!generateFile.getParentFile().exists() && !generateFile.getParentFile().mkdirs()) { + throw new IllegalStateException("Can not mkdirs by dir: " + generateFile.getParentFile()); + } + // 开始生成文件 + try (FileOutputStream fileOutputStream = new FileOutputStream(generateFile)) { + engine.getTemplate(templateFilePath).render(params, fileOutputStream); + } catch (Exception e) { + e.printStackTrace(); + } } } ``` From d24b723a1b5d41c5337e5dfddd75efbe4fe59ee5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=80=E6=BA=90=E6=B5=B7=E5=93=A5?= Date: Tue, 25 Jul 2023 16:24:09 +0800 Subject: [PATCH 33/37] docs: update docs --- docs/zh/base/chain.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/zh/base/chain.md b/docs/zh/base/chain.md index 5e1057c0..27d6a441 100644 --- a/docs/zh/base/chain.md +++ b/docs/zh/base/chain.md @@ -67,7 +67,7 @@ WHERE `id` = 1 - count():查询数据条数 - exists():是否存在,判断 count 是否大于 0 -## UpdateChain 扩展方法 +## QueryChain 扩展方法 ### `one()` 系列方法 From 68f1a7ef99d5f7eff88277c06051e1f9333881da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=80=E6=BA=90=E6=B5=B7=E5=93=A5?= Date: Tue, 25 Jul 2023 18:19:23 +0800 Subject: [PATCH 34/37] docs: update docs --- docs/zh/base/add-delete-update.md | 25 ++++++++++++++ docs/zh/base/chain.md | 33 ++++++++++++++++++- .../com/mybatisflex/test/UpdateChainTest.java | 16 +++++++++ 3 files changed, 73 insertions(+), 1 deletion(-) diff --git a/docs/zh/base/add-delete-update.md b/docs/zh/base/add-delete-update.md index b8bf6332..ada7c459 100644 --- a/docs/zh/base/add-delete-update.md +++ b/docs/zh/base/add-delete-update.md @@ -170,3 +170,28 @@ update tb_account set user_name = "michael", age = (select ... from ... ) where id = 100 ``` + +## UpdateChain + +UpdateChain 是一个对 `UpdateEntity`、`UpdateWrapper` 等进行封装的一个工具类,方便用户用于进行链式操作。 + +假设我们要更新 `Account` 的 `userName` 为 "`张三`",更新年龄在之前的基础上加 1,更新代码如下: + +```java +@Test +public void testUpdateChain() { + UpdateChain.of(Account.class) + .set(Account::getUserName, "张三") + .setRaw(Account::getAge, "age + 1") + .where(Account::getId).eq(1) + .update(); +} +``` +以上方法调用时,MyBatis-Flex 内部执行的 SQL 如下: + +```sql +UPDATE `tb_account` SET `user_name` = '张三' , `age` = age + 1 +WHERE `id` = 1 +``` + +更多关于 **链式操作**,请点击这个 [这里](./chain.html#updatechain-示例)。 diff --git a/docs/zh/base/chain.md b/docs/zh/base/chain.md index 27d6a441..80e4a533 100644 --- a/docs/zh/base/chain.md +++ b/docs/zh/base/chain.md @@ -2,6 +2,9 @@ 在 MyBatis-Flex 中,内置了 `QueryChain.java` 和 `UpdateChain.java` 用于对数据进行链式查询操作和链式数据操作(修改和删除)。 +- **QueryChain**:链式查询 +- **UpdateChain**:链式更新 + ## QueryChain 示例 @@ -39,9 +42,10 @@ List
articles = QueryChain.of(mapper) ## UpdateChain 示例 假设我们要更新 `Account` 的 `userName` 为 "`张三`",更新年龄在之前的基础上加 1,更新代码如下: + ```java @Test -public void testUpdateChain() { +public void testUpdateChain1() { UpdateChain.of(Account.class) .set(Account::getUserName, "张三") .setRaw(Account::getAge, "age + 1") @@ -56,6 +60,33 @@ UPDATE `tb_account` SET `user_name` = '张三' , `age` = age + 1 WHERE `id` = 1 ``` +**另一个示例:** + +```java +@Test +public void testUpdateChain2() { + + //更新数据 + UpdateChain.of(Account.class) + .set(Account::getAge, ACCOUNT.AGE.add(1)) + .where(Account::getId).ge(100) + .and(Account::getAge).eq(18) + .update(); + + //查询所有数据并打印 + QueryChain.of(accountMapper) + .list() + .forEach(System.out::println); +} +``` +通过 `UpdateChain` 进行 `update()`,其执行的 SQL 如下: + +```sql +UPDATE `tb_account` SET `age` = `age` + 1 +WHERE `id` >= 100 AND `age` = 18 +``` + + ## QueryChain 的方法 diff --git a/mybatis-flex-test/mybatis-flex-native-test/src/main/java/com/mybatisflex/test/UpdateChainTest.java b/mybatis-flex-test/mybatis-flex-native-test/src/main/java/com/mybatisflex/test/UpdateChainTest.java index 48502783..50eabe41 100644 --- a/mybatis-flex-test/mybatis-flex-native-test/src/main/java/com/mybatisflex/test/UpdateChainTest.java +++ b/mybatis-flex-test/mybatis-flex-native-test/src/main/java/com/mybatisflex/test/UpdateChainTest.java @@ -4,6 +4,7 @@ import com.mybatisflex.core.MybatisFlexBootstrap; import com.mybatisflex.core.audit.AuditManager; import com.mybatisflex.core.audit.ConsoleMessageCollector; import com.mybatisflex.core.audit.MessageCollector; +import com.mybatisflex.core.query.QueryChain; import com.mybatisflex.core.update.UpdateChain; import org.apache.ibatis.logging.stdout.StdOutImpl; import org.junit.BeforeClass; @@ -13,6 +14,8 @@ import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType; import javax.sql.DataSource; +import static com.mybatisflex.test.table.AccountTableDef.ACCOUNT; + public class UpdateChainTest { static AccountMapper accountMapper; @@ -53,4 +56,17 @@ public class UpdateChainTest { Account account = accountMapper.selectOneById(1); System.out.println(account); } + + @Test + public void testUpdateChain1() { + UpdateChain.of(Account.class) + .set(Account::getAge, ACCOUNT.AGE.add(1)) + .where(Account::getId).ge(100) + .and(Account::getAge).eq(18) + .update(); + + QueryChain.of(accountMapper) + .list() + .forEach(System.out::println); + } } From 69c68c6a538363d77e6c8a6f0866bb204351e454 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=80=E6=BA=90=E6=B5=B7=E5=93=A5?= Date: Tue, 25 Jul 2023 18:33:44 +0800 Subject: [PATCH 35/37] build: v1.5.3 release (^.^)YYa!! --- mybatis-flex-annotation/pom.xml | 2 +- mybatis-flex-codegen/pom.xml | 2 +- mybatis-flex-core/pom.xml | 2 +- .../src/main/java/com/mybatisflex/core/FlexConsts.java | 2 +- mybatis-flex-processor/pom.xml | 2 +- mybatis-flex-solon-plugin/pom.xml | 2 +- mybatis-flex-spring-boot-starter/pom.xml | 2 +- mybatis-flex-spring/pom.xml | 2 +- mybatis-flex-test/mybatis-flex-native-test/pom.xml | 2 +- mybatis-flex-test/mybatis-flex-spring-boot-test/pom.xml | 2 +- mybatis-flex-test/mybatis-flex-spring-cloud-test/pom.xml | 2 +- mybatis-flex-test/mybatis-flex-spring-test/pom.xml | 2 +- mybatis-flex-test/pom.xml | 2 +- 13 files changed, 13 insertions(+), 13 deletions(-) diff --git a/mybatis-flex-annotation/pom.xml b/mybatis-flex-annotation/pom.xml index 4d25719b..de95347e 100644 --- a/mybatis-flex-annotation/pom.xml +++ b/mybatis-flex-annotation/pom.xml @@ -5,7 +5,7 @@ parent com.mybatis-flex - 1.5.2 + 1.5.3 4.0.0 diff --git a/mybatis-flex-codegen/pom.xml b/mybatis-flex-codegen/pom.xml index 49f54cc9..4a18bada 100644 --- a/mybatis-flex-codegen/pom.xml +++ b/mybatis-flex-codegen/pom.xml @@ -5,7 +5,7 @@ parent com.mybatis-flex - 1.5.2 + 1.5.3 4.0.0 diff --git a/mybatis-flex-core/pom.xml b/mybatis-flex-core/pom.xml index d00433d6..0584d4d9 100644 --- a/mybatis-flex-core/pom.xml +++ b/mybatis-flex-core/pom.xml @@ -5,7 +5,7 @@ parent com.mybatis-flex - 1.5.2 + 1.5.3 4.0.0 diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/FlexConsts.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/FlexConsts.java index aaae62c9..764018e2 100644 --- a/mybatis-flex-core/src/main/java/com/mybatisflex/core/FlexConsts.java +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/FlexConsts.java @@ -24,7 +24,7 @@ public class FlexConsts { } public static final String NAME = "MyBatis-Flex"; - public static final String VERSION = "1.5.2"; + public static final String VERSION = "1.5.3"; public static final String DEFAULT_PRIMARY_FIELD = "id"; diff --git a/mybatis-flex-processor/pom.xml b/mybatis-flex-processor/pom.xml index 229f5778..d487542d 100644 --- a/mybatis-flex-processor/pom.xml +++ b/mybatis-flex-processor/pom.xml @@ -5,7 +5,7 @@ parent com.mybatis-flex - 1.5.2 + 1.5.3 4.0.0 diff --git a/mybatis-flex-solon-plugin/pom.xml b/mybatis-flex-solon-plugin/pom.xml index 3eaaa95b..a277a975 100644 --- a/mybatis-flex-solon-plugin/pom.xml +++ b/mybatis-flex-solon-plugin/pom.xml @@ -5,7 +5,7 @@ parent com.mybatis-flex - 1.5.2 + 1.5.3 4.0.0 diff --git a/mybatis-flex-spring-boot-starter/pom.xml b/mybatis-flex-spring-boot-starter/pom.xml index 4faa8b41..8ede3f76 100644 --- a/mybatis-flex-spring-boot-starter/pom.xml +++ b/mybatis-flex-spring-boot-starter/pom.xml @@ -5,7 +5,7 @@ parent com.mybatis-flex - 1.5.2 + 1.5.3 4.0.0 diff --git a/mybatis-flex-spring/pom.xml b/mybatis-flex-spring/pom.xml index 01f41bd3..cbb27378 100644 --- a/mybatis-flex-spring/pom.xml +++ b/mybatis-flex-spring/pom.xml @@ -5,7 +5,7 @@ parent com.mybatis-flex - 1.5.2 + 1.5.3 4.0.0 diff --git a/mybatis-flex-test/mybatis-flex-native-test/pom.xml b/mybatis-flex-test/mybatis-flex-native-test/pom.xml index 845bcbdc..81815f53 100644 --- a/mybatis-flex-test/mybatis-flex-native-test/pom.xml +++ b/mybatis-flex-test/mybatis-flex-native-test/pom.xml @@ -5,7 +5,7 @@ mybatis-flex-test com.mybatis-flex - 1.5.2 + 1.5.3 4.0.0 diff --git a/mybatis-flex-test/mybatis-flex-spring-boot-test/pom.xml b/mybatis-flex-test/mybatis-flex-spring-boot-test/pom.xml index 7a14ce95..b0b5bb63 100644 --- a/mybatis-flex-test/mybatis-flex-spring-boot-test/pom.xml +++ b/mybatis-flex-test/mybatis-flex-spring-boot-test/pom.xml @@ -5,7 +5,7 @@ mybatis-flex-test com.mybatis-flex - 1.5.2 + 1.5.3 4.0.0 diff --git a/mybatis-flex-test/mybatis-flex-spring-cloud-test/pom.xml b/mybatis-flex-test/mybatis-flex-spring-cloud-test/pom.xml index edf61ec1..99ed3816 100644 --- a/mybatis-flex-test/mybatis-flex-spring-cloud-test/pom.xml +++ b/mybatis-flex-test/mybatis-flex-spring-cloud-test/pom.xml @@ -4,7 +4,7 @@ mybatis-flex-test com.mybatis-flex - 1.5.2 + 1.5.3 4.0.0 diff --git a/mybatis-flex-test/mybatis-flex-spring-test/pom.xml b/mybatis-flex-test/mybatis-flex-spring-test/pom.xml index c926cbb8..0e6e510b 100644 --- a/mybatis-flex-test/mybatis-flex-spring-test/pom.xml +++ b/mybatis-flex-test/mybatis-flex-spring-test/pom.xml @@ -5,7 +5,7 @@ mybatis-flex-test com.mybatis-flex - 1.5.2 + 1.5.3 4.0.0 diff --git a/mybatis-flex-test/pom.xml b/mybatis-flex-test/pom.xml index b646e4da..3f943dbf 100644 --- a/mybatis-flex-test/pom.xml +++ b/mybatis-flex-test/pom.xml @@ -5,7 +5,7 @@ parent com.mybatis-flex - 1.5.2 + 1.5.3 4.0.0 From b979778b163c1a1972f2b3c5deb7a5b35939d2f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=80=E6=BA=90=E6=B5=B7=E5=93=A5?= Date: Tue, 25 Jul 2023 18:34:24 +0800 Subject: [PATCH 36/37] build: v1.5.3 release (^.^)YYa!! --- docs/zh/changes.md | 19 +++++++++++++++++++ docs/zh/intro/getting-started.md | 2 +- docs/zh/intro/maven.md | 14 +++++++------- docs/zh/others/apt.md | 2 +- docs/zh/others/codegen.md | 2 +- pom.xml | 4 ++-- 6 files changed, 31 insertions(+), 12 deletions(-) diff --git a/docs/zh/changes.md b/docs/zh/changes.md index 1d75fe26..0a1c9507 100644 --- a/docs/zh/changes.md +++ b/docs/zh/changes.md @@ -1,6 +1,25 @@ # MyBatis-Flex ChangeLog +## v1.5.3 20230725: +- 新增:添加 UpdateChain 方便用于对数据进行更新 +- 新增:添加对 ActiveRecord 设计模式的支持,感谢 @Suomm +- 新增:代码生成器 ColumnConfig 增加 propertyType. 可以用于自定通用属性的类型。感谢 @jerryzhengsz1 +- 新增:添加 selectOneWithRelationsById(根据主表主键来查询 1 条数据) 方法,感谢 @barql +- 新增:QueryWrapper.groupBy 支持 Lambda 表达式的功能,感谢 @Suomm +- 新增:QueryWrapper 添加 `not like` 构建的支持 +- 优化:重命名 QueryWrapperChain 为 QueryChain,保存和 UpdateChain 统一 +- 修复:`@Relation` 关联查询注解,在指定 selectColumns 出错的问题,感谢 @zhy_balck +- 修复:代码生成器配置 `camelToUnderline` 属性时 entity 生成后编译错误的问题,感谢 @genomics_zcg +- 文档:优化 APT 的文档描述有错别字的问题,感谢 @zhangjx1992 +- 文档:添加关于 ActiveRecord 的相关文档,感谢 @Suomm +- 文档:修改代码生成器对 EnjoyTemplate 的描述错误的问题 +- 文档:添加更多关于链式查询的相关文档 +- 文档:重构文档链接,链式操作的相关文档 +- 文档:修改代码生成器对 EnjoyTemplate 的描述错误的问题 + + + ## v1.5.2 20230723: - 新增:添加 QueryWrapperChain 用于链式调用查询或者操作数据,感谢 @Suomm - 新增:添加 DbChain 链式调用 Db + Row 的相关方法和功能,感谢 @Suomm diff --git a/docs/zh/intro/getting-started.md b/docs/zh/intro/getting-started.md index 3b7e8850..223fc56e 100644 --- a/docs/zh/intro/getting-started.md +++ b/docs/zh/intro/getting-started.md @@ -39,7 +39,7 @@ VALUES (1, '张三', 18, '2020-01-11'), com.mybatis-flex mybatis-flex-spring-boot-starter - 1.5.2 + 1.5.3 com.mysql diff --git a/docs/zh/intro/maven.md b/docs/zh/intro/maven.md index 1d254d0c..7f82722f 100644 --- a/docs/zh/intro/maven.md +++ b/docs/zh/intro/maven.md @@ -12,12 +12,12 @@ com.mybatis-flex mybatis-flex-core - 1.5.2 + 1.5.3 com.mybatis-flex mybatis-flex-processor - 1.5.2 + 1.5.3 provided ``` @@ -28,12 +28,12 @@ com.mybatis-flex mybatis-flex-spring - 1.5.2 + 1.5.3 com.mybatis-flex mybatis-flex-processor - 1.5.2 + 1.5.3 provided `````` @@ -44,12 +44,12 @@ com.mybatis-flex mybatis-flex-spring-boot-starter - 1.5.2 + 1.5.3 com.mybatis-flex mybatis-flex-processor - 1.5.2 + 1.5.3 provided ``` @@ -70,7 +70,7 @@ com.mybatis-flex mybatis-flex-processor - 1.5.2 + 1.5.3 diff --git a/docs/zh/others/apt.md b/docs/zh/others/apt.md index 6e238f70..61e12eba 100644 --- a/docs/zh/others/apt.md +++ b/docs/zh/others/apt.md @@ -219,7 +219,7 @@ pom.xml 添加 `annotationProcessorPaths` 配置, ``` dependencies { ... - annotationProcessor 'com.mybatis-flex:mybatis-flex-processor:1.5.2' + annotationProcessor 'com.mybatis-flex:mybatis-flex-processor:1.5.3' } ``` diff --git a/docs/zh/others/codegen.md b/docs/zh/others/codegen.md index 4296cd86..5115848e 100644 --- a/docs/zh/others/codegen.md +++ b/docs/zh/others/codegen.md @@ -10,7 +10,7 @@ com.mybatis-flex mybatis-flex-codegen - 1.5.2 + 1.5.3 ``` diff --git a/pom.xml b/pom.xml index b0b8c49e..3a363d93 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ com.mybatis-flex parent pom - 1.5.2 + 1.5.3 mybatis-flex https://mybatis-flex.com @@ -54,7 +54,7 @@ 8 8 - 1.5.2 + 1.5.3 3.5.13 2.1.0 From 25e5792fa50305f2a272453ed07fb9e4ef2340e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=80=E6=BA=90=E6=B5=B7=E5=93=A5?= Date: Tue, 25 Jul 2023 18:34:28 +0800 Subject: [PATCH 37/37] build: v1.5.3 release (^.^)YYa!! --- changes.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/changes.md b/changes.md index 1d75fe26..0a1c9507 100644 --- a/changes.md +++ b/changes.md @@ -1,6 +1,25 @@ # MyBatis-Flex ChangeLog +## v1.5.3 20230725: +- 新增:添加 UpdateChain 方便用于对数据进行更新 +- 新增:添加对 ActiveRecord 设计模式的支持,感谢 @Suomm +- 新增:代码生成器 ColumnConfig 增加 propertyType. 可以用于自定通用属性的类型。感谢 @jerryzhengsz1 +- 新增:添加 selectOneWithRelationsById(根据主表主键来查询 1 条数据) 方法,感谢 @barql +- 新增:QueryWrapper.groupBy 支持 Lambda 表达式的功能,感谢 @Suomm +- 新增:QueryWrapper 添加 `not like` 构建的支持 +- 优化:重命名 QueryWrapperChain 为 QueryChain,保存和 UpdateChain 统一 +- 修复:`@Relation` 关联查询注解,在指定 selectColumns 出错的问题,感谢 @zhy_balck +- 修复:代码生成器配置 `camelToUnderline` 属性时 entity 生成后编译错误的问题,感谢 @genomics_zcg +- 文档:优化 APT 的文档描述有错别字的问题,感谢 @zhangjx1992 +- 文档:添加关于 ActiveRecord 的相关文档,感谢 @Suomm +- 文档:修改代码生成器对 EnjoyTemplate 的描述错误的问题 +- 文档:添加更多关于链式查询的相关文档 +- 文档:重构文档链接,链式操作的相关文档 +- 文档:修改代码生成器对 EnjoyTemplate 的描述错误的问题 + + + ## v1.5.2 20230723: - 新增:添加 QueryWrapperChain 用于链式调用查询或者操作数据,感谢 @Suomm - 新增:添加 DbChain 链式调用 Db + Row 的相关方法和功能,感谢 @Suomm