From bebbc0ad1a63cb7d240bcb1958a11ebd414e2fa1 Mon Sep 17 00:00:00 2001 From: Suomm <1474983351@qq.com> Date: Tue, 8 Aug 2023 16:26:16 +0800 Subject: [PATCH 01/15] =?UTF-8?q?feat:=20=E6=8F=90=E5=8F=96=E9=93=BE?= =?UTF-8?q?=E5=BC=8F=E8=B0=83=E7=94=A8=E9=80=9A=E7=94=A8=E6=8A=BD=E8=B1=A1?= =?UTF-8?q?=E6=96=B9=E6=B3=95=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mybatisflex/core/query/ChainQuery.java | 110 ++++++++++++++++++ 1 file changed, 110 insertions(+) create mode 100644 mybatis-flex-core/src/main/java/com/mybatisflex/core/query/ChainQuery.java diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/query/ChainQuery.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/query/ChainQuery.java new file mode 100644 index 00000000..35e367e8 --- /dev/null +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/query/ChainQuery.java @@ -0,0 +1,110 @@ +/* + * 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.query; + +import com.mybatisflex.core.paginate.Page; + +import java.util.List; +import java.util.Optional; + +/** + *

链式查询接口。 + * + *

该接口定义了通用的链式查询方法: + *

+ * + * @param 实体类类型 + * @author 王帅 + * @since 2023-08-08 + */ +public interface ChainQuery { + + /** + * 获取一条数据。 + * + * @return 一条数据 + */ + T one(); + + /** + * 获取一条数据,返回的数据为 asType 类型。 + * + * @param asType 接收数据类型 + * @param 接收数据类型 + * @return 一条数据 + */ + R oneAs(Class asType); + + /** + * 获取一条数据,并封装为 {@link Optional} 返回。 + * + * @return 一条数据 + */ + default Optional oneOpt() { + return Optional.ofNullable(one()); + } + + /** + * 获取一条数据,返回的数据为 asType 类型,并封装为 {@link Optional} 返回。 + * + * @param asType 接收数据类型 + * @param 接收数据类型 + * @return 一条数据 + */ + default Optional oneAsOpt(Class asType) { + return Optional.ofNullable(oneAs(asType)); + } + + /** + * 获取多条数据。 + * + * @return 数据列表 + */ + List list(); + + /** + * 获取多条数据,返回的数据为 asType 类型。 + * + * @param asType 接收数据类型 + * @param 接收数据类型 + * @return 数据列表 + */ + List listAs(Class asType); + + /** + * 获取分页数据。 + * + * @param page 分页对象 + * @return 分页数据 + */ + Page page(Page page); + + /** + * 获取分页数据,返回的数据为 asType 类型。 + * + * @param page 分页对象 + * @param asType 接收数据类型 + * @param 接收数据类型 + * @return 分页数据 + */ + Page pageAs(Page page, Class asType); + +} From b04bd6379f3937a962d298d45a03612727979323 Mon Sep 17 00:00:00 2001 From: Suomm <1474983351@qq.com> Date: Tue, 8 Aug 2023 16:26:42 +0800 Subject: [PATCH 02/15] =?UTF-8?q?feat:=20=E9=93=BE=E5=BC=8F=E8=B0=83?= =?UTF-8?q?=E7=94=A8=20BaseMapper=20=E6=8E=A5=E5=8F=A3=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/query/MapperQueryChain.java | 195 ++++++++++++++++++ 1 file changed, 195 insertions(+) create mode 100644 mybatis-flex-core/src/main/java/com/mybatisflex/core/query/MapperQueryChain.java diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/query/MapperQueryChain.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/query/MapperQueryChain.java new file mode 100644 index 00000000..31886606 --- /dev/null +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/query/MapperQueryChain.java @@ -0,0 +1,195 @@ +/* + * 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.query; + +import com.mybatisflex.core.BaseMapper; +import com.mybatisflex.core.paginate.Page; +import com.mybatisflex.core.util.SqlUtil; + +import java.util.List; +import java.util.Optional; + +/** + *

链式 {@link BaseMapper} 查询。 + * + *

要求实现类除了包含有 {@link BaseMapper} 接口的引用外,还必须具有 {@link QueryWrapper} + * 的查询条件构建功能。在使用时: + *

    + *
  • 通过 {@link #baseMapper()} 获取该实现类对应的 {@link BaseMapper} 引用。 + *
  • 通过 {@link #toQueryWrapper()} 将该实现类转换为 {@link QueryWrapper} 对象。 + *
+ * + * @param 实体类类型 + * @author 王帅 + * @since 2023-08-08 + */ +public interface MapperQueryChain extends ChainQuery { + + /** + * 该实现类对应的 {@link BaseMapper} 对象。 + * + * @return {@link BaseMapper} + */ + BaseMapper baseMapper(); + + /** + * 将该实现类转换为 {@link QueryWrapper} 对象。 + * + * @return {@link QueryWrapper} + */ + QueryWrapper toQueryWrapper(); + + /** + * 查询数据数量。 + * + * @return 数据数量 + */ + default long count() { + return baseMapper().selectCountByQuery(toQueryWrapper()); + } + + /** + * 判断数据是否存在。 + * + * @return {@code true} 数据存在,{@code false} 数据不存在 + */ + default boolean exists() { + return SqlUtil.toBool(count()); + } + + /** + * {@inheritDoc} + */ + default T one() { + return baseMapper().selectOneByQuery(toQueryWrapper()); + } + + /** + * {@inheritDoc} + */ + default R oneAs(Class asType) { + return baseMapper().selectOneByQueryAs(toQueryWrapper(), asType); + } + + /** + * 获取第一列,且第一条数据。 + * + * @return 第一列数据 + */ + default Object obj() { + return baseMapper().selectObjectByQuery(toQueryWrapper()); + } + + /** + * 获取第一列,且第一条数据并转换为指定类型,比如 {@code Long}, {@code String} 等。 + * + * @param asType 接收数据类型 + * @param 接收数据类型 + * @return 第一列数据 + */ + default R objAs(Class asType) { + return baseMapper().selectObjectByQueryAs(toQueryWrapper(), asType); + } + + /** + * 获取第一列,且第一条数据,并封装为 {@link Optional} 返回。 + * + * @return 第一列数据 + */ + default Optional objOpt() { + return Optional.ofNullable(obj()); + } + + /** + * 获取第一列,且第一条数据并转换为指定类型,比如 {@code Long}, {@code String} + * 等,封装为 {@link Optional} 返回。 + * + * @param asType 接收数据类型 + * @param 接收数据类型 + * @return 第一列数据 + */ + default Optional objAsOpt(Class asType) { + return Optional.ofNullable(objAs(asType)); + } + + /** + * 获取第一列的所有数据。 + * + * @return 第一列数据 + */ + default List objList() { + return baseMapper().selectObjectListByQuery(toQueryWrapper()); + } + + /** + * 获取第一列的所有数据,并转换为指定类型,比如 {@code Long}, {@code String} 等。 + * + * @param asType 接收数据类型 + * @param 接收数据类型 + * @return 第一列数据 + */ + default List objListAs(Class asType) { + return baseMapper().selectObjectListByQueryAs(toQueryWrapper(), asType); + } + + /** + * {@inheritDoc} + */ + default List list() { + return baseMapper().selectListByQuery(toQueryWrapper()); + } + + /** + * {@inheritDoc} + */ + default List listAs(Class asType) { + return baseMapper().selectListByQueryAs(toQueryWrapper(), asType); + } + + /** + * {@inheritDoc} + */ + default Page page(Page page) { + return baseMapper().paginate(page, toQueryWrapper()); + } + + /** + * {@inheritDoc} + */ + default Page pageAs(Page page, Class asType) { + return baseMapper().paginateAs(page, toQueryWrapper(), asType); + } + + /** + * 使用 {@code Fields Query} 的方式进行关联查询。 + * + * @return {@code Fields Query} 查询 + */ + default FieldsBuilder withFields() { + return new FieldsBuilder<>(this); + } + + /** + * 使用 {@code Relations Query} 的方式进行关联查询。 + * + * @return {@code Relations Query} 查询 + */ + default RelationsBuilder withRelations() { + return new RelationsBuilder<>(this); + } + +} From f5c04c4bf7c7d3c2d2df8b781e9739269f364bdd Mon Sep 17 00:00:00 2001 From: Suomm <1474983351@qq.com> Date: Tue, 8 Aug 2023 16:27:06 +0800 Subject: [PATCH 03/15] =?UTF-8?q?feat:=20=E6=8A=BD=E8=B1=A1=E5=85=B3?= =?UTF-8?q?=E8=81=94=E6=9F=A5=E8=AF=A2=E6=9E=84=E5=BB=BA=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/query/AbstractQueryBuilder.java | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 mybatis-flex-core/src/main/java/com/mybatisflex/core/query/AbstractQueryBuilder.java diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/query/AbstractQueryBuilder.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/query/AbstractQueryBuilder.java new file mode 100644 index 00000000..eacfc83a --- /dev/null +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/query/AbstractQueryBuilder.java @@ -0,0 +1,49 @@ +/* + * 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.query; + +import com.mybatisflex.core.BaseMapper; + +/** + * 抽象关联查询。 + * + * @author 王帅 + * @since 2023-08-08 + */ +public abstract class AbstractQueryBuilder implements ChainQuery { + + protected final MapperQueryChain delegate; + + protected AbstractQueryBuilder(MapperQueryChain delegate) { + this.delegate = delegate; + } + + /** + * @return BaseMapper + */ + protected BaseMapper baseMapper() { + return delegate.baseMapper(); + } + + /** + * @return QueryWrapper + */ + protected QueryWrapper queryWrapper() { + return delegate.toQueryWrapper(); + } + +} From f91baac5cae25ff3e474f61ddb5dd3ae2a90f649 Mon Sep 17 00:00:00 2001 From: Suomm <1474983351@qq.com> Date: Tue, 8 Aug 2023 16:27:55 +0800 Subject: [PATCH 04/15] =?UTF-8?q?feat:=20=E5=B1=9E=E6=80=A7=E6=9F=A5?= =?UTF-8?q?=E8=AF=A2=E6=9E=84=E5=BB=BA=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mybatisflex/core/query/FieldsBuilder.java | 141 ++++++++++++++++++ 1 file changed, 141 insertions(+) create mode 100644 mybatis-flex-core/src/main/java/com/mybatisflex/core/query/FieldsBuilder.java diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/query/FieldsBuilder.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/query/FieldsBuilder.java new file mode 100644 index 00000000..1eb980da --- /dev/null +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/query/FieldsBuilder.java @@ -0,0 +1,141 @@ +/* + * 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.query; + +import com.mybatisflex.core.field.FieldQuery; +import com.mybatisflex.core.field.FieldQueryManager; +import com.mybatisflex.core.field.QueryBuilder; +import com.mybatisflex.core.paginate.Page; +import com.mybatisflex.core.util.FieldWrapper; +import com.mybatisflex.core.util.LambdaGetter; +import com.mybatisflex.core.util.LambdaUtil; + +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 使用 {@code Fields Query} 的方式进行关联查询。 + * + * @author 王帅 + * @since 2023-08-08 + */ +public class FieldsBuilder extends AbstractQueryBuilder { + + protected final Map fieldQueryMap; + + public FieldsBuilder(MapperQueryChain delegate) { + super(delegate); + this.fieldQueryMap = new HashMap<>(); + } + + /** + * 设置属性对应的 {@code QueryWrapper} 查询。 + * + * @param field 属性 + * @param builder {@code QueryWrapper} 构建 + * @param 属性类型 + * @return 属性查询构建 + */ + public FieldsBuilder fieldMapping(LambdaGetter field, QueryBuilder builder) { + return fieldMapping(field, false, builder); + } + + /** + * 设置属性对应的 {@code QueryWrapper} 查询。 + * + * @param field 属性 + * @param prevent 阻止对嵌套类属性的查询 + * @param builder {@code QueryWrapper} 构建 + * @param 属性类型 + * @return 属性查询构建 + */ + public FieldsBuilder fieldMapping(LambdaGetter field, boolean prevent, QueryBuilder builder) { + String fieldName = LambdaUtil.getFieldName(field); + Class entityClass = LambdaUtil.getImplClass(field); + FieldQuery fieldQuery = new FieldQuery(); + fieldQuery.setPrevent(prevent); + fieldQuery.setFieldName(fieldName); + fieldQuery.setQueryBuilder(builder); + fieldQuery.setEntityClass(entityClass); + fieldQuery.setFieldWrapper(FieldWrapper.of(entityClass, fieldName)); + this.fieldQueryMap.put(entityClass.getName() + '#' + fieldName, fieldQuery); + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public T one() { + List entities = Collections.singletonList(baseMapper().selectOneByQuery(queryWrapper())); + FieldQueryManager.queryFields(baseMapper(), entities, fieldQueryMap); + return entities.get(0); + } + + /** + * {@inheritDoc} + */ + @Override + public R oneAs(Class asType) { + List entities = Collections.singletonList(baseMapper().selectOneByQueryAs(queryWrapper(), asType)); + FieldQueryManager.queryFields(baseMapper(), entities, fieldQueryMap); + return entities.get(0); + } + + /** + * {@inheritDoc} + */ + @Override + public List list() { + List entities = baseMapper().selectListByQuery(queryWrapper()); + FieldQueryManager.queryFields(baseMapper(), entities, fieldQueryMap); + return entities; + } + + /** + * {@inheritDoc} + */ + @Override + public List listAs(Class asType) { + List entities = baseMapper().selectListByQueryAs(queryWrapper(), asType); + FieldQueryManager.queryFields(baseMapper(), entities, fieldQueryMap); + return entities; + } + + /** + * {@inheritDoc} + */ + @Override + public Page page(Page page) { + baseMapper().paginate(page, queryWrapper()); + FieldQueryManager.queryFields(baseMapper(), page.getRecords(), fieldQueryMap); + return page; + } + + /** + * {@inheritDoc} + */ + @Override + public Page pageAs(Page page, Class asType) { + baseMapper().paginateAs(page, queryWrapper(), asType); + FieldQueryManager.queryFields(baseMapper(), page.getRecords(), fieldQueryMap); + return page; + } + +} From b6f3553c3faf79667c658247d61425c3f6fdc026 Mon Sep 17 00:00:00 2001 From: Suomm <1474983351@qq.com> Date: Tue, 8 Aug 2023 16:28:06 +0800 Subject: [PATCH 05/15] =?UTF-8?q?feat:=20Relation=20=E6=B3=A8=E8=A7=A3?= =?UTF-8?q?=E6=9F=A5=E8=AF=A2=E6=9E=84=E5=BB=BA=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/query/RelationsBuilder.java | 118 ++++++++++++++++++ 1 file changed, 118 insertions(+) create mode 100644 mybatis-flex-core/src/main/java/com/mybatisflex/core/query/RelationsBuilder.java diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/query/RelationsBuilder.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/query/RelationsBuilder.java new file mode 100644 index 00000000..50b00275 --- /dev/null +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/query/RelationsBuilder.java @@ -0,0 +1,118 @@ +/* + * 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.query; + +import com.mybatisflex.core.paginate.Page; +import com.mybatisflex.core.relation.RelationManager; + +import java.util.List; + +/** + * 使用 {@code Relations Query} 的方式进行关联查询。 + * + * @author 王帅 + * @since 2023-08-08 + */ +public class RelationsBuilder extends AbstractQueryBuilder { + + public RelationsBuilder(MapperQueryChain delegate) { + super(delegate); + } + + /** + * 忽略查询部分 {@code Relations} 注解标记的属性。 + * + * @param fields 属性 + * @return {@code Relations} 查询构建 + */ + public RelationsBuilder ignoreRelations(String... fields) { + RelationManager.addIgnoreRelations(fields); + return this; + } + + /** + * 设置父子关系查询中,默认的递归查询深度。 + * + * @param maxDepth 查询深度 + * @return {@code Relations} 查询构建 + */ + public RelationsBuilder maxDepth(int maxDepth) { + RelationManager.setMaxDepth(maxDepth); + return this; + } + + /** + * 添加额外的 {@code Relations} 查询条件。 + * + * @param key 键 + * @param value 值 + * @return {@code Relations} 查询构建 + */ + public RelationsBuilder extraConditionParam(String key, Object value) { + RelationManager.addExtraConditionParam(key, value); + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public T one() { + return baseMapper().selectOneWithRelationsByQuery(queryWrapper()); + } + + /** + * {@inheritDoc} + */ + @Override + public R oneAs(Class asType) { + return baseMapper().selectOneWithRelationsByQueryAs(queryWrapper(), asType); + } + + /** + * {@inheritDoc} + */ + @Override + public List list() { + return baseMapper().selectListWithRelationsByQuery(queryWrapper()); + } + + /** + * {@inheritDoc} + */ + @Override + public List listAs(Class asType) { + return baseMapper().selectListWithRelationsByQueryAs(queryWrapper(), asType); + } + + /** + * {@inheritDoc} + */ + @Override + public Page page(Page page) { + return baseMapper().paginateWithRelations(page, queryWrapper()); + } + + /** + * {@inheritDoc} + */ + @Override + public Page pageAs(Page page, Class asType) { + return baseMapper().paginateWithRelationsAs(page, queryWrapper(), asType); + } + +} From d7131f48e7f78c1e24c7cbc934e28d1cb49a37af Mon Sep 17 00:00:00 2001 From: Suomm <1474983351@qq.com> Date: Tue, 8 Aug 2023 16:28:42 +0800 Subject: [PATCH 06/15] =?UTF-8?q?refactor:=20=E9=87=8D=E6=9E=84=20Relation?= =?UTF-8?q?=20=E6=B3=A8=E8=A7=A3=E6=9F=A5=E8=AF=A2=E6=9E=84=E5=BB=BA?= =?UTF-8?q?=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../activerecord/query/RelationsQuery.java | 116 +++++------------- 1 file changed, 32 insertions(+), 84 deletions(-) diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/activerecord/query/RelationsQuery.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/activerecord/query/RelationsQuery.java index fe11e913..86254ef6 100644 --- a/mybatis-flex-core/src/main/java/com/mybatisflex/core/activerecord/query/RelationsQuery.java +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/activerecord/query/RelationsQuery.java @@ -17,10 +17,7 @@ package com.mybatisflex.core.activerecord.query; import com.mybatisflex.core.activerecord.Model; -import com.mybatisflex.core.paginate.Page; -import com.mybatisflex.core.relation.RelationManager; - -import java.util.List; +import com.mybatisflex.core.query.RelationsBuilder; /** * 使用 {@code Relations Query} 的方式进行关联查询。 @@ -28,102 +25,53 @@ import java.util.List; * @author 王帅 * @since 2023-07-30 */ -public class RelationsQuery> extends AbstractQuery { +public class RelationsQuery> extends RelationsBuilder { public RelationsQuery(Model model) { super(model); } - /** - * 忽略查询部分 {@code Relations} 注解标记的属性。 - * - * @param fields 属性 - * @return {@code Relations} 查询构建 - */ + @Override public RelationsQuery ignoreRelations(String... fields) { - RelationManager.addIgnoreRelations(fields); - return this; - } - - /** - * 设置父子关系查询中,默认的递归查询深度。 - * - * @param maxDepth 查询深度 - * @return {@code Relations} 查询构建 - */ - public RelationsQuery maxDepth(int maxDepth) { - RelationManager.setMaxDepth(maxDepth); - return this; - } - - /** - * 添加额外的 {@code Relations} 查询条件。 - * - * @param key 键 - * @param value 值 - * @return {@code Relations} 查询构建 - */ - public RelationsQuery extraConditionParam(String key, Object value) { - RelationManager.addExtraConditionParam(key, value); + super.ignoreRelations(fields); return this; } @Override + public RelationsQuery maxDepth(int maxDepth) { + super.maxDepth(maxDepth); + return this; + } + + @Override + public RelationsQuery extraConditionParam(String key, Object value) { + super.extraConditionParam(key, value); + return this; + } + + protected Object[] pkValues() { + // 懒加载,实际用到的时候才会生成 主键值 + return ((Model) delegate).pkValues(); + } + + /** + * 根据主键查询一条数据。 + * + * @return 一条数据 + */ public T oneById() { return baseMapper().selectOneWithRelationsById(pkValues()); } - @Override + /** + * 根据主键查询一条数据,返回的数据为 asType 类型。 + * + * @param asType 接收数据类型 + * @param 接收数据类型 + * @return 一条数据 + */ public R oneByIdAs(Class asType) { return baseMapper().selectOneWithRelationsByIdAs(pkValues(), asType); } - /** - * {@inheritDoc} - */ - @Override - public T one() { - return baseMapper().selectOneWithRelationsByQuery(queryWrapper()); - } - - /** - * {@inheritDoc} - */ - @Override - public R oneAs(Class asType) { - return baseMapper().selectOneWithRelationsByQueryAs(queryWrapper(), asType); - } - - /** - * {@inheritDoc} - */ - @Override - public List list() { - return baseMapper().selectListWithRelationsByQuery(queryWrapper()); - } - - /** - * {@inheritDoc} - */ - @Override - public List listAs(Class asType) { - return baseMapper().selectListWithRelationsByQueryAs(queryWrapper(), asType); - } - - /** - * {@inheritDoc} - */ - @Override - public Page page(Page page) { - return baseMapper().paginateWithRelations(page, queryWrapper()); - } - - /** - * {@inheritDoc} - */ - @Override - public Page pageAs(Page page, Class asType) { - return baseMapper().paginateWithRelationsAs(page, queryWrapper(), asType); - } - } From d22d9498bfe8b2101c8d90a07631f8f08d1a03d4 Mon Sep 17 00:00:00 2001 From: Suomm <1474983351@qq.com> Date: Tue, 8 Aug 2023 16:28:56 +0800 Subject: [PATCH 07/15] =?UTF-8?q?refactor:=20=E9=87=8D=E6=9E=84=E5=B1=9E?= =?UTF-8?q?=E6=80=A7=E6=9F=A5=E8=AF=A2=E6=9E=84=E5=BB=BA=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/activerecord/query/FieldsQuery.java | 129 ++++-------------- 1 file changed, 24 insertions(+), 105 deletions(-) diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/activerecord/query/FieldsQuery.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/activerecord/query/FieldsQuery.java index 0958d3af..3bc69815 100644 --- a/mybatis-flex-core/src/main/java/com/mybatisflex/core/activerecord/query/FieldsQuery.java +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/activerecord/query/FieldsQuery.java @@ -17,19 +17,14 @@ package com.mybatisflex.core.activerecord.query; import com.mybatisflex.core.activerecord.Model; -import com.mybatisflex.core.field.FieldQuery; import com.mybatisflex.core.field.FieldQueryManager; import com.mybatisflex.core.field.QueryBuilder; import com.mybatisflex.core.mybatis.MappedStatementTypes; -import com.mybatisflex.core.paginate.Page; -import com.mybatisflex.core.util.FieldWrapper; +import com.mybatisflex.core.query.FieldsBuilder; import com.mybatisflex.core.util.LambdaGetter; -import com.mybatisflex.core.util.LambdaUtil; import java.util.Collections; -import java.util.HashMap; import java.util.List; -import java.util.Map; /** * 使用 {@code Fields Query} 的方式进行关联查询。 @@ -37,53 +32,34 @@ import java.util.Map; * @author 王帅 * @since 2023-07-30 */ -public class FieldsQuery> extends AbstractQuery { - - private final Map fieldQueryMap; +public class FieldsQuery> extends FieldsBuilder { public FieldsQuery(Model model) { super(model); - this.fieldQueryMap = new HashMap<>(); } - /** - * 设置属性对应的 {@code QueryWrapper} 查询。 - * - * @param field 属性 - * @param builder {@code QueryWrapper} 构建 - * @param 属性类型 - * @return 属性查询构建 - */ + @Override public FieldsQuery fieldMapping(LambdaGetter field, QueryBuilder builder) { - return fieldMapping(field, false, builder); - } - - /** - * 设置属性对应的 {@code QueryWrapper} 查询。 - * - * @param field 属性 - * @param prevent 阻止对嵌套类属性的查询 - * @param builder {@code QueryWrapper} 构建 - * @param 属性类型 - * @return 属性查询构建 - */ - public FieldsQuery fieldMapping(LambdaGetter field, boolean prevent, QueryBuilder builder) { - String fieldName = LambdaUtil.getFieldName(field); - Class entityClass = LambdaUtil.getImplClass(field); - FieldQuery fieldQuery = new FieldQuery(); - fieldQuery.setPrevent(prevent); - fieldQuery.setFieldName(fieldName); - fieldQuery.setQueryBuilder(builder); - fieldQuery.setEntityClass(entityClass); - fieldQuery.setFieldWrapper(FieldWrapper.of(entityClass, fieldName)); - this.fieldQueryMap.put(entityClass.getName() + '#' + fieldName, fieldQuery); + super.fieldMapping(field, builder); return this; } - /** - * {@inheritDoc} - */ @Override + public FieldsBuilder fieldMapping(LambdaGetter field, boolean prevent, QueryBuilder builder) { + super.fieldMapping(field, prevent, builder); + return this; + } + + protected Object[] pkValues() { + // 懒加载,实际用到的时候才会生成 主键值 + return ((Model) delegate).pkValues(); + } + + /** + * 根据主键查询一条数据。 + * + * @return 一条数据 + */ public T oneById() { List entities = Collections.singletonList(baseMapper().selectOneById(pkValues())); FieldQueryManager.queryFields(baseMapper(), entities, fieldQueryMap); @@ -91,9 +67,12 @@ public class FieldsQuery> extends AbstractQuery { } /** - * {@inheritDoc} + * 根据主键查询一条数据,返回的数据为 asType 类型。 + * + * @param asType 接收数据类型 + * @param 接收数据类型 + * @return 一条数据 */ - @Override @SuppressWarnings("unchecked") public R oneByIdAs(Class asType) { try { @@ -106,64 +85,4 @@ public class FieldsQuery> extends AbstractQuery { } } - /** - * {@inheritDoc} - */ - @Override - public T one() { - List entities = Collections.singletonList(baseMapper().selectOneByQuery(queryWrapper())); - FieldQueryManager.queryFields(baseMapper(), entities, fieldQueryMap); - return entities.get(0); - } - - /** - * {@inheritDoc} - */ - @Override - public R oneAs(Class asType) { - List entities = Collections.singletonList(baseMapper().selectOneByQueryAs(queryWrapper(), asType)); - FieldQueryManager.queryFields(baseMapper(), entities, fieldQueryMap); - return entities.get(0); - } - - /** - * {@inheritDoc} - */ - @Override - public List list() { - List entities = baseMapper().selectListByQuery(queryWrapper()); - FieldQueryManager.queryFields(baseMapper(), entities, fieldQueryMap); - return entities; - } - - /** - * {@inheritDoc} - */ - @Override - public List listAs(Class asType) { - List entities = baseMapper().selectListByQueryAs(queryWrapper(), asType); - FieldQueryManager.queryFields(baseMapper(), entities, fieldQueryMap); - return entities; - } - - /** - * {@inheritDoc} - */ - @Override - public Page page(Page page) { - baseMapper().paginate(page, queryWrapper()); - FieldQueryManager.queryFields(baseMapper(), page.getRecords(), fieldQueryMap); - return page; - } - - /** - * {@inheritDoc} - */ - @Override - public Page pageAs(Page page, Class asType) { - baseMapper().paginateAs(page, queryWrapper(), asType); - FieldQueryManager.queryFields(baseMapper(), page.getRecords(), fieldQueryMap); - return page; - } - } From fc00f8e120945bdf6b55a07f3992a0a8726891f5 Mon Sep 17 00:00:00 2001 From: Suomm <1474983351@qq.com> Date: Tue, 8 Aug 2023 16:29:27 +0800 Subject: [PATCH 08/15] =?UTF-8?q?remove:=20=E5=88=A0=E9=99=A4=E5=BA=9F?= =?UTF-8?q?=E5=BC=83=E7=9A=84=E7=B1=BB=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../activerecord/query/AbstractQuery.java | 160 ------------------ 1 file changed, 160 deletions(-) delete mode 100644 mybatis-flex-core/src/main/java/com/mybatisflex/core/activerecord/query/AbstractQuery.java diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/activerecord/query/AbstractQuery.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/activerecord/query/AbstractQuery.java deleted file mode 100644 index 3610dc87..00000000 --- a/mybatis-flex-core/src/main/java/com/mybatisflex/core/activerecord/query/AbstractQuery.java +++ /dev/null @@ -1,160 +0,0 @@ -/* - * 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.BaseMapper; -import com.mybatisflex.core.activerecord.Model; -import com.mybatisflex.core.paginate.Page; -import com.mybatisflex.core.query.QueryWrapper; - -import java.util.List; -import java.util.Optional; - -/** - * 抽象关联查询。 - * - * @author 王帅 - * @since 2023-07-30 - */ -public abstract class AbstractQuery> { - - protected final Model model; - - protected AbstractQuery(Model model) { - this.model = model; - } - - /** - * @return 主键 - */ - protected Object[] pkValues() { - return model.pkValues(); - } - - /** - * @return BaseMapper - */ - protected BaseMapper baseMapper() { - return model.baseMapper(); - } - - /** - * @return QueryWrapper - */ - protected QueryWrapper queryWrapper() { - return model.queryWrapper(); - } - - /** - * 根据实体类主键获取一条数据。 - * - * @return 数据 - */ - public abstract T oneById(); - - /** - * 根据实体类主键获取一条数据,并封装为 {@link Optional} 返回。 - * - * @return 数据 - */ - public Optional oneByIdOpt() { - return Optional.ofNullable(oneById()); - } - - /** - * 根据实体类主键获取一条数据。 - * - * @return 数据 - */ - public abstract R oneByIdAs(Class asType); - - /** - * 根据实体类主键获取一条数据,并封装为 {@link Optional} 返回。 - * - * @return 数据 - */ - public Optional oneByIdAsOpt(Class asType) { - return Optional.ofNullable(oneByIdAs(asType)); - } - - /** - * 根据实体类构建的条件获取一条数据。 - * - * @return 数据 - */ - public abstract T one(); - - /** - * 根据实体类构建的条件获取一条数据,返回的数据为 asType 类型。 - * - * @param asType 接收数据类型 - * @return 数据 - */ - public abstract R oneAs(Class asType); - - /** - * 根据实体类构建的条件获取一条数据,并封装为 {@link Optional} 返回。 - * - * @return 数据 - */ - public Optional oneOpt() { - return Optional.ofNullable(one()); - } - - /** - * 根据实体类构建的条件获取一条数据,返回的数据为 asType 类型,并封装为 {@link Optional} 返回。 - * - * @param asType 接收数据类型 - * @return 数据 - */ - public Optional oneOptAs(Class asType) { - return Optional.ofNullable(oneAs(asType)); - } - - /** - * 根据实体类构建的条件获取多条数据。 - * - * @return 数据列表 - */ - public abstract List list(); - - /** - * 根据实体类构建的条件获取多条数据,返回的数据为 asType 类型。 - * - * @param asType 接收数据类型 - * @return 数据列表 - */ - public abstract List listAs(Class asType); - - /** - * 根据实体类构建的条件获取分页数据。 - * - * @param page 分页对象 - * @return 分页数据 - */ - public abstract Page page(Page page); - - /** - * 根据实体类构建的条件获取分页数据,返回的数据为 asType 类型。 - * - * @param page 分页对象 - * @param asType 接收数据类型 - * @return 分页数据 - */ - public abstract Page pageAs(Page page, Class asType); - -} From 6efad5d3cde24af346ae9a5a06ca19530c63901a Mon Sep 17 00:00:00 2001 From: Suomm <1474983351@qq.com> Date: Tue, 8 Aug 2023 16:29:47 +0800 Subject: [PATCH 09/15] =?UTF-8?q?style:=20=E6=A0=87=E8=AE=B0=E5=BA=9F?= =?UTF-8?q?=E5=BC=83=E6=96=B9=E6=B3=95=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mybatisflex/core/query/QueryChain.java | 104 +++++++----------- 1 file changed, 41 insertions(+), 63 deletions(-) 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 ded14920..5b14a0ee 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 @@ -20,18 +20,17 @@ import com.mybatisflex.core.BaseMapper; import com.mybatisflex.core.paginate.Page; import com.mybatisflex.core.table.TableInfo; import com.mybatisflex.core.table.TableInfoFactory; -import com.mybatisflex.core.util.SqlUtil; import java.util.List; import java.util.Optional; /** - * {@link QueryWrapper}链式调用。 + * {@link QueryWrapper} 链式调用。 * * @author 王帅 * @since 2023-07-22 */ -public class QueryChain extends QueryWrapperAdapter> { +public class QueryChain extends QueryWrapperAdapter> implements MapperQueryChain { private final BaseMapper baseMapper; @@ -43,98 +42,76 @@ public class QueryChain extends QueryWrapperAdapter> { return new QueryChain<>(baseMapper); } - public long count() { - return baseMapper.selectCountByQuery(this); + @Override + public BaseMapper baseMapper() { + return baseMapper; } - public boolean exists() { - return SqlUtil.toBool(count()); - } - - public T one() { - return baseMapper.selectOneByQuery(this); - } - - public R oneAs(Class asType) { - return baseMapper.selectOneByQueryAs(this, asType); + @Override + public QueryWrapper toQueryWrapper() { + return this; } + /** + * @deprecated 该方法将在 1.6.0 版本移除 + */ + @Deprecated public T oneWithRelations() { return baseMapper.selectOneWithRelationsByQuery(this); } + /** + * @deprecated 该方法将在 1.6.0 版本移除 + */ + @Deprecated public R oneWithRelationsAs(Class asType) { return baseMapper.selectOneWithRelationsByQueryAs(this, asType); } - public Optional oneOpt() { - return Optional.ofNullable(baseMapper.selectOneByQuery(this)); - } - - public Optional oneAsOpt(Class asType) { - return Optional.ofNullable(baseMapper.selectOneByQueryAs(this, asType)); - } - + /** + * @deprecated 该方法将在 1.6.0 版本移除 + */ + @Deprecated public Optional oneWithRelationsOpt() { return Optional.ofNullable(baseMapper.selectOneWithRelationsByQuery(this)); } + /** + * @deprecated 该方法将在 1.6.0 版本移除 + */ + @Deprecated public Optional oneWithRelationsAsOpt(Class asType) { return Optional.ofNullable(baseMapper.selectOneWithRelationsByQueryAs(this, asType)); } - public Object obj() { - return baseMapper.selectObjectByQuery(this); - } - - public R objAs(Class asType) { - return baseMapper.selectObjectByQueryAs(this, asType); - } - - public Optional objOpt() { - return Optional.ofNullable(baseMapper.selectObjectByQuery(this)); - } - - public Optional objAsOpt(Class asType) { - return Optional.ofNullable(baseMapper.selectObjectByQueryAs(this, asType)); - } - - public List objList() { - return baseMapper.selectObjectListByQuery(this); - } - - public List objListAs(Class asType) { - return baseMapper.selectObjectListByQueryAs(this, asType); - } - - public List list() { - return baseMapper.selectListByQuery(this); - } - + /** + * @deprecated 该方法将在 1.6.0 版本移除 + */ + @Deprecated public List listWithRelations() { return baseMapper.selectListWithRelationsByQuery(this); } - public List listAs(Class asType) { - return baseMapper.selectListByQueryAs(this, asType); - } - + /** + * @deprecated 该方法将在 1.6.0 版本移除 + */ + @Deprecated public List listWithRelationsAs(Class asType) { return baseMapper.selectListWithRelationsByQueryAs(this, asType); } - public Page page(Page page) { - return baseMapper.paginate(page, this); - } - + /** + * @deprecated 该方法将在 1.6.0 版本移除 + */ + @Deprecated public Page pageWithRelations(Page page) { return baseMapper.paginateWithRelations(page, this); } - public Page pageAs(Page page, Class asType) { - return baseMapper.paginateAs(page, this, asType); - } - + /** + * @deprecated 该方法将在 1.6.0 版本移除 + */ + @Deprecated public Page pageWithRelationsAs(Page page, Class asType) { return baseMapper.paginateWithRelationsAs(page, this, asType); } @@ -145,4 +122,5 @@ public class QueryChain extends QueryWrapperAdapter> { CPI.setFromIfNecessary(this, tableInfo.getSchema(), tableInfo.getTableName()); return super.toSQL(); } + } From 011e23f944c8332c762b595186bfe45826419014 Mon Sep 17 00:00:00 2001 From: Suomm <1474983351@qq.com> Date: Tue, 8 Aug 2023 16:30:07 +0800 Subject: [PATCH 10/15] =?UTF-8?q?refactor:=20=E4=BB=A3=E7=A0=81=E5=A4=8D?= =?UTF-8?q?=E7=94=A8=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mybatisflex/core/activerecord/Model.java | 177 ++---------------- 1 file changed, 12 insertions(+), 165 deletions(-) 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 dc58aa56..d6d2bd11 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 @@ -16,15 +16,15 @@ package com.mybatisflex.core.activerecord; +import com.mybatisflex.core.BaseMapper; import com.mybatisflex.core.activerecord.query.FieldsQuery; import com.mybatisflex.core.activerecord.query.QueryModel; import com.mybatisflex.core.activerecord.query.RelationsQuery; -import com.mybatisflex.core.paginate.Page; +import com.mybatisflex.core.query.MapperQueryChain; +import com.mybatisflex.core.query.QueryWrapper; import com.mybatisflex.core.util.SqlUtil; import java.io.Serializable; -import java.util.List; -import java.util.Optional; /** * Active Record 模型。 @@ -36,7 +36,7 @@ import java.util.Optional; @SuppressWarnings({"unused", "unchecked"}) public abstract class Model> extends QueryModel - implements MapperModel, Serializable { + implements MapperModel, MapperQueryChain, Serializable { /** * 根据实体类构建的条件删除数据。 @@ -66,175 +66,22 @@ public abstract class Model> return SqlUtil.toBool(baseMapper().updateByQuery((T) this, ignoreNulls, queryWrapper())); } - /** - * 根据实体类构建的条件查询数据数量。 - * - * @return 数据数量 - */ - public long count() { - return baseMapper().selectCountByQuery(queryWrapper()); + @Override + public BaseMapper baseMapper() { + return MapperModel.super.baseMapper(); } - /** - * 根据实体类构建的条件判断数据是否存在。 - * - * @return {@code true} 数据存在,{@code false} 数据不存在 - */ - public boolean exists() { - return SqlUtil.toBool(count()); + @Override + public QueryWrapper toQueryWrapper() { + return queryWrapper(); } - /** - * 根据实体类构建的条件获取一条数据。 - * - * @return 数据 - */ - public T one() { - return baseMapper().selectOneByQuery(queryWrapper()); - } - - /** - * 根据实体类构建的条件获取一条数据,返回的数据为 asType 类型。 - * - * @param asType 接收数据类型 - * @return 数据 - */ - public R oneAs(Class asType) { - return baseMapper().selectOneByQueryAs(queryWrapper(), asType); - } - - - /** - * 根据实体类构建的条件获取一条数据,并封装为 {@link Optional} 返回。 - * - * @return 数据 - */ - public Optional oneOpt() { - return Optional.ofNullable(one()); - } - - /** - * 根据实体类构建的条件获取一条数据,返回的数据为 asType 类型,并封装为 {@link Optional} 返回。 - * - * @param asType 接收数据类型 - * @return 数据 - */ - public Optional oneAsOpt(Class asType) { - return Optional.ofNullable(oneAs(asType)); - } - - /** - * 根据实体类构建的条件获取第一列,且第一条数据。 - * - * @return 第一列数据 - */ - public Object obj() { - return baseMapper().selectObjectByQuery(queryWrapper()); - } - - /** - * 根据实体类构建的条件获取第一列,且第一条数据并转换为指定类型,比如 {@code Long}, {@code String} 等。 - * - * @param asType 接收数据类型 - * @return 第一列数据 - */ - public R objAs(Class asType) { - return baseMapper().selectObjectByQueryAs(queryWrapper(), asType); - } - - /** - * 根据实体类构建的条件获取第一列,且第一条数据,并封装为 {@link Optional} 返回。 - * - * @return 第一列数据 - */ - public Optional objOpt() { - return Optional.ofNullable(obj()); - } - - /** - * 根据实体类构建的条件获取第一列,且第一条数据并转换为指定类型,比如 {@code Long}, {@code String} - * 等,封装为 {@link Optional} 返回。 - * - * @param asType 接收数据类型 - * @return 第一列数据 - */ - public Optional objAsOpt(Class asType) { - return Optional.ofNullable(objAs(asType)); - } - - /** - * 根据实体类构建的条件获取第一列的所有数据。 - * - * @return 第一列数据 - */ - public List objList() { - return baseMapper().selectObjectListByQuery(queryWrapper()); - } - - /** - * 根据实体类构建的条件获取第一列的所有数据,并转换为指定类型,比如 {@code Long}, {@code String} 等。 - * - * @param asType 接收数据类型 - * @return 第一列数据 - */ - public List objListAs(Class asType) { - return baseMapper().selectObjectListByQueryAs(queryWrapper(), asType); - } - - /** - * 根据实体类构建的条件获取多条数据。 - * - * @return 数据列表 - */ - public List list() { - return baseMapper().selectListByQuery(queryWrapper()); - } - - /** - * 根据实体类构建的条件获取多条数据,返回的数据为 asType 类型。 - * - * @param asType 接收数据类型 - * @return 数据列表 - */ - public List listAs(Class asType) { - return baseMapper().selectListByQueryAs(queryWrapper(), asType); - } - - /** - * 根据实体类构建的条件获取分页数据。 - * - * @param page 分页对象 - * @return 分页数据 - */ - public Page page(Page page) { - return baseMapper().paginate(page, queryWrapper()); - } - - /** - * 根据实体类构建的条件获取分页数据,返回的数据为 asType 类型。 - * - * @param page 分页对象 - * @param asType 接收数据类型 - * @return 分页数据 - */ - public Page pageAs(Page page, Class asType) { - return baseMapper().paginateAs(page, queryWrapper(), asType); - } - - /** - * 使用 {@code Fields Query} 的方式进行关联查询。 - * - * @return {@code Fields Query} 查询 - */ + @Override public FieldsQuery withFields() { return new FieldsQuery<>(this); } - /** - * 使用 {@code Relations Query} 的方式进行关联查询。 - * - * @return {@code Relations Query} 查询 - */ + @Override public RelationsQuery withRelations() { return new RelationsQuery<>(this); } From 8b0d03807f93d490955fb023df265fb656fcc2bc Mon Sep 17 00:00:00 2001 From: Suomm <1474983351@qq.com> Date: Tue, 8 Aug 2023 16:47:13 +0800 Subject: [PATCH 11/15] =?UTF-8?q?test:=20=E6=B7=BB=E5=8A=A0=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 --- .../src/main/resources/application.yml | 36 ++++---- .../test/mapper/QueryChainTest.java | 85 +++++++++++++++++++ 2 files changed, 103 insertions(+), 18 deletions(-) create mode 100644 mybatis-flex-test/mybatis-flex-spring-boot-test/src/test/java/com/mybatisflex/test/mapper/QueryChainTest.java diff --git a/mybatis-flex-test/mybatis-flex-spring-boot-test/src/main/resources/application.yml b/mybatis-flex-test/mybatis-flex-spring-boot-test/src/main/resources/application.yml index 4dca4a42..51c5d0e4 100644 --- a/mybatis-flex-test/mybatis-flex-spring-boot-test/src/main/resources/application.yml +++ b/mybatis-flex-test/mybatis-flex-spring-boot-test/src/main/resources/application.yml @@ -3,20 +3,20 @@ spring: # h2: # console: # enabled: true -# datasource: -## driver-class-name: com.mysql.cj.jdbc.Driver -# url: jdbc:mysql://localhost:3306/flex_test -# username: root -# password: 131496 + datasource: +# driver-class-name: com.mysql.cj.jdbc.Driver + url: jdbc:mysql://localhost:3306/flex_test + username: root + password: 12345678 # driver-class-name: # datasource: # driver-class-name: org.h2.Driver # username: root # password: test - sql: - init: - schema-locations: classpath:schema.sql - data-locations: classpath:data.sql +# sql: +# init: +# schema-locations: classpath:schema.sql +# data-locations: classpath:data.sql mybatis-flex: admin-config: enable: true @@ -37,12 +37,12 @@ mybatis-flex: # username: root # password: 12345678 #mybatis-flex: - datasource: - ds3333: - url: jdbc:mysql://127.0.0.1:3306/flex_test - username: root - password: 131496 - ds2: - url: jdbc:mysql://127.0.0.1:3306/flex_test1 - username: root - password: 131496 +# datasource: +# ds3333: +# url: jdbc:mysql://127.0.0.1:3306/flex_test +# username: root +# password: 131496 +# ds2: +# url: jdbc:mysql://127.0.0.1:3306/flex_test1 +# username: root +# password: 131496 diff --git a/mybatis-flex-test/mybatis-flex-spring-boot-test/src/test/java/com/mybatisflex/test/mapper/QueryChainTest.java b/mybatis-flex-test/mybatis-flex-spring-boot-test/src/test/java/com/mybatisflex/test/mapper/QueryChainTest.java new file mode 100644 index 00000000..1fcf639c --- /dev/null +++ b/mybatis-flex-test/mybatis-flex-spring-boot-test/src/test/java/com/mybatisflex/test/mapper/QueryChainTest.java @@ -0,0 +1,85 @@ +/* + * 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.test.mapper; + +import com.mybatisflex.core.field.QueryBuilder; +import com.mybatisflex.core.query.QueryChain; +import com.mybatisflex.core.query.QueryWrapper; +import com.mybatisflex.test.model.User; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; + +import static com.mybatisflex.test.model.table.RoleTableDef.ROLE; +import static com.mybatisflex.test.model.table.UserRoleTableDef.USER_ROLE; +import static com.mybatisflex.test.model.table.UserTableDef.USER; + +/** + * @author 王帅 + * @since 2023-08-08 + */ +@SpringBootTest +class QueryChainTest { + + @Autowired + UserMapper userMapper; + + @Test + void testFields() { + QueryBuilder builder = user -> + QueryWrapper.create() + .select() + .from(ROLE) + .where(ROLE.ROLE_ID.in( + QueryWrapper.create() + .select(USER_ROLE.ROLE_ID) + .from(USER_ROLE) + .where(USER_ROLE.USER_ID.eq(user.getUserId())) + )); + + User user1 = QueryChain.of(userMapper) + .where(USER.USER_ID.eq(1)) + .withFields() + .fieldMapping(User::getRoleList, builder) + .one(); + + User user2 = User.create() + .where(USER.USER_ID.eq(1)) + .withFields() + .fieldMapping(User::getRoleList, builder) + .one(); + + Assertions.assertEquals(user1.toString(), user2.toString()); + } + + @Test + void testRelations() { + User user1 = QueryChain.of(userMapper) + .where(USER.USER_ID.eq(2)) + .withRelations() + .one(); + + User user2 = User.create() + .where(USER.USER_ID.eq(2)) + .withRelations() + .one(); + + Assertions.assertEquals(user1.toString(), user2.toString()); + } + +} From 27432736d5f9dbc2fa7b8f3dc68fc7f33b6e2518 Mon Sep 17 00:00:00 2001 From: Suomm <1474983351@qq.com> Date: Tue, 8 Aug 2023 16:58:31 +0800 Subject: [PATCH 12/15] =?UTF-8?q?feat:=20Relation=20=E6=9E=84=E5=BB=BA?= =?UTF-8?q?=E5=BF=BD=E7=95=A5=E5=AD=97=E6=AE=B5=E6=94=AF=E6=8C=81=20Lambda?= =?UTF-8?q?=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 --- .../core/activerecord/query/RelationsQuery.java | 7 +++++++ .../com/mybatisflex/core/query/RelationsBuilder.java | 12 ++++++++++++ 2 files changed, 19 insertions(+) diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/activerecord/query/RelationsQuery.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/activerecord/query/RelationsQuery.java index 86254ef6..4f7a4b25 100644 --- a/mybatis-flex-core/src/main/java/com/mybatisflex/core/activerecord/query/RelationsQuery.java +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/activerecord/query/RelationsQuery.java @@ -18,6 +18,7 @@ package com.mybatisflex.core.activerecord.query; import com.mybatisflex.core.activerecord.Model; import com.mybatisflex.core.query.RelationsBuilder; +import com.mybatisflex.core.util.LambdaGetter; /** * 使用 {@code Relations Query} 的方式进行关联查询。 @@ -37,6 +38,12 @@ public class RelationsQuery> extends RelationsBuilder { return this; } + @Override + public RelationsQuery ignoreRelations(LambdaGetter... fields) { + super.ignoreRelations(fields); + return this; + } + @Override public RelationsQuery maxDepth(int maxDepth) { super.maxDepth(maxDepth); diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/query/RelationsBuilder.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/query/RelationsBuilder.java index 50b00275..d159501e 100644 --- a/mybatis-flex-core/src/main/java/com/mybatisflex/core/query/RelationsBuilder.java +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/query/RelationsBuilder.java @@ -18,6 +18,7 @@ package com.mybatisflex.core.query; import com.mybatisflex.core.paginate.Page; import com.mybatisflex.core.relation.RelationManager; +import com.mybatisflex.core.util.LambdaGetter; import java.util.List; @@ -44,6 +45,17 @@ public class RelationsBuilder extends AbstractQueryBuilder { return this; } + /** + * 忽略查询部分 {@code Relations} 注解标记的属性。 + * + * @param fields 属性 + * @return {@code Relations} 查询构建 + */ + public RelationsBuilder ignoreRelations(LambdaGetter... fields) { + RelationManager.addIgnoreRelations(fields); + return this; + } + /** * 设置父子关系查询中,默认的递归查询深度。 * From ca0df9881e65390abc278fe1bd437e781d27ed91 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, 8 Aug 2023 17:15:57 +0800 Subject: [PATCH 13/15] doc: update docs --- docs/zh/awesome-things.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/zh/awesome-things.md b/docs/zh/awesome-things.md index 19340be9..d6812ffe 100644 --- a/docs/zh/awesome-things.md +++ b/docs/zh/awesome-things.md @@ -84,6 +84,9 @@ - [MyBatis-Flex 视频教程 - 30 数据脱敏的简单使用](https://www.bilibili.com/video/BV1gz4y1s7Wg) - [MyBatis-Flex 视频教程 - 31 枚举属性的使用](https://www.bilibili.com/video/BV1mm4y1W7SD) - [MyBatis-Flex 视频教程 - 32 关联查询(Join Query)](https://www.bilibili.com/video/BV1B8411d7iC) +- [MyBatis-Flex 视频教程 - 33 关联查询(Field Query)](https://www.bilibili.com/video/BV17k4y1g7vt) +- [MyBatis-Flex 视频教程 - 34 关联查询(Relation Query)](https://www.bilibili.com/video/BV1bj411r7A4) +- [MyBatis-Flex 视频教程 - 35 关联查询对比](https://www.bilibili.com/video/BV1oF411f7dr) From 9354f200c6c3922331a7fd223ca843bddd4dfcdd 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, 8 Aug 2023 18:37:52 +0800 Subject: [PATCH 14/15] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E4=BD=BF?= =?UTF-8?q?=E7=94=A8=E5=A4=9A=E6=95=B0=E6=8D=AE=E6=BA=90=20+=20seata=20?= =?UTF-8?q?=E5=88=86=E5=B8=83=E5=BC=8F=E4=BA=8B=E5=8A=A1=E6=97=B6=EF=BC=8C?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E6=BA=90=E8=A7=A3=E5=AF=86=E9=94=99=E8=AF=AF?= =?UTF-8?q?=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/datasource/DataSourceManager.java | 3 +++ .../core/datasource/FlexDataSource.java | 17 +++++++++++++++-- .../boot/MultiDataSourceAutoConfiguration.java | 14 +++++++++----- 3 files changed, 27 insertions(+), 7 deletions(-) diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/datasource/DataSourceManager.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/datasource/DataSourceManager.java index 1e3e9c47..eb3ee12a 100644 --- a/mybatis-flex-core/src/main/java/com/mybatisflex/core/datasource/DataSourceManager.java +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/datasource/DataSourceManager.java @@ -21,6 +21,9 @@ import org.apache.ibatis.logging.LogFactory; import javax.sql.DataSource; import java.lang.reflect.Method; +/** + * @author michael + */ public class DataSourceManager { private static DataSourceDecipher decipher; diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/datasource/FlexDataSource.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/datasource/FlexDataSource.java index 8dd60a95..2886d8cd 100644 --- a/mybatis-flex-core/src/main/java/com/mybatisflex/core/datasource/FlexDataSource.java +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/datasource/FlexDataSource.java @@ -49,8 +49,13 @@ public class FlexDataSource extends AbstractDataSource { private final DataSource defaultDataSource; public FlexDataSource(String dataSourceKey, DataSource dataSource) { + this(dataSourceKey, dataSource, true); + } - DataSourceManager.decryptDataSource(dataSource); + public FlexDataSource(String dataSourceKey, DataSource dataSource, boolean needDecryptDataSource) { + if (needDecryptDataSource) { + DataSourceManager.decryptDataSource(dataSource); + } this.defaultDataSourceKey = dataSourceKey; this.defaultDataSource = dataSource; @@ -61,11 +66,19 @@ public class FlexDataSource extends AbstractDataSource { } public void addDataSource(String dataSourceKey, DataSource dataSource) { - DataSourceManager.decryptDataSource(dataSource); + addDataSource(dataSourceKey, dataSource, true); + } + + + public void addDataSource(String dataSourceKey, DataSource dataSource, boolean needDecryptDataSource) { + if (needDecryptDataSource) { + DataSourceManager.decryptDataSource(dataSource); + } dataSourceMap.put(dataSourceKey, dataSource); dbTypeHashMap.put(dataSourceKey, DbTypeUtil.getDbType(dataSource)); } + public void removeDatasource(String dataSourceKey) { dataSourceMap.remove(dataSourceKey); dbTypeHashMap.remove(dataSourceKey); diff --git a/mybatis-flex-spring-boot-starter/src/main/java/com/mybatisflex/spring/boot/MultiDataSourceAutoConfiguration.java b/mybatis-flex-spring-boot-starter/src/main/java/com/mybatisflex/spring/boot/MultiDataSourceAutoConfiguration.java index ffdddc98..f8b155ea 100644 --- a/mybatis-flex-spring-boot-starter/src/main/java/com/mybatisflex/spring/boot/MultiDataSourceAutoConfiguration.java +++ b/mybatis-flex-spring-boot-starter/src/main/java/com/mybatisflex/spring/boot/MultiDataSourceAutoConfiguration.java @@ -81,18 +81,22 @@ public class MultiDataSourceAutoConfiguration { DataSourceManager.setDecipher(dataSourceDecipher); for (Map.Entry> entry : dataSourceProperties.entrySet()) { + DataSource dataSource = new DataSourceBuilder(entry.getValue()).build(); - if (seataConfig !=null &&seataConfig.isEnable()){ - if (seataConfig.getSeataMode() ==SeataMode.XA){ + DataSourceManager.decryptDataSource(dataSource); + + if (seataConfig != null && seataConfig.isEnable()) { + if (seataConfig.getSeataMode() == SeataMode.XA) { dataSource = new DataSourceProxyXA(dataSource); - }else { + } else { dataSource = new DataSourceProxy(dataSource); } } + if (flexDataSource == null) { - flexDataSource = new FlexDataSource(entry.getKey(), dataSource); + flexDataSource = new FlexDataSource(entry.getKey(), dataSource, false); } else { - flexDataSource.addDataSource(entry.getKey(), dataSource); + flexDataSource.addDataSource(entry.getKey(), dataSource, false); } } } From 11f0b6dd68689b057a21a9a14edfa510113fa670 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, 8 Aug 2023 19:28:24 +0800 Subject: [PATCH 15/15] doc: update seata docs --- docs/zh/core/tx.md | 134 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 109 insertions(+), 25 deletions(-) diff --git a/docs/zh/core/tx.md b/docs/zh/core/tx.md index c41f77ba..084370e0 100644 --- a/docs/zh/core/tx.md +++ b/docs/zh/core/tx.md @@ -87,14 +87,12 @@ MyBatis-Flex 已支持 Spring 框架的 `@Transactional`,在使用 SpringBoot > 注意:若项目未使用 SpringBoot,只用到了 Spring,需要参考 MyBatis-Flex 的 [FlexTransactionAutoConfiguration](https://gitee.com/mybatis-flex/mybatis-flex/blob/main/mybatis-flex-spring-boot-starter/src/main/java/com/mybatisflex/spring/boot/FlexTransactionAutoConfiguration.java) > 进行事务配置,才能正常使用 `@Transactional` 注解。 -## 特征 +## 多数据源注意事项 -- 1、支持嵌套事务 -- 2、支持多数据源 +注意:在多数据源的情况下,所有数据源的数据库请求(Connection)会执行相同的 `commit` 或者 `rollback`,MyBatis-Flex 只保证了程序端的原子操作, +但并不能保证多个数据源之间的原子操作。例如: -> 注意:在多数据源的情况下,所有数据源的数据库请求(Connection)会执行相同的 commit 或者 rollback,但并非原子操作。例如: - -```java +```java 1,6,13,19 @Transactional public void doSomething(){ @@ -117,7 +115,7 @@ public void doSomething(){ } ``` -在以上的例子中,两次 `Db.update(...)` 虽然是两个不同的数据源,但它们都在同一个事务 `@Transactional` 里,因此,当抛出异常的时候, +在以上的例子中,执行了两次 `Db.updateBySql(...)`,它们是两个不同的数据源,但它们都在同一个事务 `@Transactional` 里,因此,当抛出异常的时候, 它们都会进行回滚(rollback)。 以上提到的 `并非原子操作`,指的是: @@ -127,26 +125,112 @@ public void doSomething(){ ## Seata 分布式事务 -Seata 是一款开源的分布式事务解决方案,致力于在微服务架构下提供高性能和简单易用的分布式事务服务。 +Seata 是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务。 +Seata 将为用户提供了 AT、TCC、SAGA 和 XA 事务模式,为用户打造一站式的分布式解决方案。 官方网站:https://seata.io/zh-cn/index.html -1. 首先,先了解事务的基础(自行百度), -2. 在了解seata事务的项目 官网地址:https://seata.io/zh-cn/docs -3. 然后根据官方的[快速开始](https://seata.io/zh-cn/docs/user/quickstart.html)在下载最新版的seata-server并在本地跑起一个 -4. seata-server服务 -5. 然后使用[mybatis-flex-test](https://gitee.com/mybatis-flex/mybatis-flex/tree/main/mybatis-flex-test)模块 下面的mybatis-flex-spring-boot-seata进行测试 ->此demo只是一个纯演示的demo,模仿的是[官方事例](https://github.com/seata/seata-samples/tree/master/springboot-mybatis) -进行整合,微服务合并成一个多数据源进行测试,当然,这种方法是不提倡的,seata事务并且本地多数据源的方式可能本身就存在设计思路问题,可能存在过度设计,此demo只是作为一个演示。 + +### 开始使用 + +**第 1 步:在 `application.yml` 配置开启 Seata 分布式事务功能:** + +```yaml +mybatis-flex: + seata-config: + enable: true + seata-mode: XA # 支持 xa 或者 ta +``` +- XA:指的是: 分布式事务协议(X/Open Distributed Transaction Processing),它是一种由 X/Open 组织制定的分布式事务标准, +XA 使用两阶段提交(2PC,Two-Phase Commit)来保证所有资源同时提交或回滚任何特定的事务。 +目前,几乎所有主流的数据库都对 XA 规范 提供了支持,是 Seata 默认使用的模式。 + +- AT: 是一种无侵入的分布式事务解决方案。在 AT 模式下,用户只需关注自己的 “`业务SQL`”, +用户的 “`业务SQL`” 作为一阶段,Seata 会根据 SQL 内容,自动生成事务的二阶段提交和回滚操作。 + +**第 2 步:在 `application.yml` 添加 Seata 的相关配置:** + +```yaml +seata: + enabled: true + application-id: business-service + tx-service-group: my_test_tx_group + enable-auto-data-source-proxy: false #必须 +# use-jdk-proxy: false + client: + rm: + async-commit-buffer-limit: 1000 + report-retry-count: 5 + table-meta-check-enable: false + report-success-enable: false + lock: + retry-interval: 10 + retry-times: 30 + retry-policy-branch-rollback-on-conflict: true + tm: + commit-retry-count: 5 + rollback-retry-count: 5 + undo: + data-validation: true + log-serialization: jackson + log-table: undo_log + log: + exceptionRate: 100 + service: + vgroup-mapping: + my_test_tx_group: default + grouplist: + default: 127.0.0.1:8091 + #enable-degrade: false + #disable-global-transaction: false + transport: + shutdown: + wait: 3 + thread-factory: + boss-thread-prefix: NettyBoss + worker-thread-prefix: NettyServerNIOWorker + server-executor-thread-prefix: NettyServerBizHandler + share-boss-worker: false + client-selector-thread-prefix: NettyClientSelector + client-selector-thread-size: 1 + client-worker-thread-prefix: NettyClientWorkerThread + worker-thread-size: default + boss-thread-size: 1 + type: TCP + server: NIO + heartbeat: true + serialization: seata + compressor: none + enable-client-batch-send-request: true + config: + type: file + registry: + type: file +``` + +> 以上配置的含义,请参考 Seata 官方网站:https://seata.io/zh-cn/docs/user/configurations.html + +**3、通过使用 `@GloabalTransactional` 开始 Seata 分布式事务。** + +```java 1 +@GlobalTransactional +public void purchase(String userId, String commodityCode, int orderCount) { + LOGGER.info("purchase begin ... xid: " + RootContext.getXID()); + stockClient.deduct(commodityCode, orderCount); + orderClient.create(userId, commodityCode, orderCount); +} +``` + +> 更多关于 Seata 的知识,请异步 Seata 官方网站了解:https://seata.io/zh-cn/docs ,也可以参考 Seata +> 的官方示例快速开始:https://seata.io/zh-cn/docs/user/quickstart.html + ### 注意事项 ->使用seata的时候必须数据源代理 -`seata.enable-auto-data-source-proxy: false` -`pom`自行引入[seata-spring-boot-starter](https://mvnrepository.com/artifact/io.seata/seata-spring-boot-starter)依赖, +在使用 Seata 分布式事务时,请注意添加 Seata 的相关 Maven 依赖,例如: -application.yml需要配置如下参数 -1. `mybatis-flex.seata-config.enable` - - 配置含义:seata事务是否开启,true开启,默认false关闭 -2. `mybatis-flex.seata-config.seata-mode` - - 默认启动的事务类型,目前只支持XA或者AT,默认AT +```xml + + io.seata + seata-spring-boot-starter + 1.7.0 + +```