From 138a805ae787199a1693bd9ef075343a3b517d6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=80=E6=BA=90=E6=B5=B7=E5=93=A5?= Date: Wed, 24 May 2023 13:25:56 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9E=20=E4=B8=80=E5=AF=B9?= =?UTF-8?q?=E5=A4=9A=E3=80=81=E5=A4=9A=E5=AF=B9=E4=B8=80=20=E6=9F=A5?= =?UTF-8?q?=E8=AF=A2=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/.vitepress/config.ts | 1 + docs/zh/base/field-query.md | 88 +++++++++++++++++++ .../mybatisflex/core/field/FieldQuery.java | 51 +++++++++++ .../core/field/FieldQueryBuilder.java | 54 ++++++++++++ .../mybatisflex/core/field/QueryBuilder.java | 22 +++++ 5 files changed, 216 insertions(+) create mode 100644 docs/zh/base/field-query.md create mode 100644 mybatis-flex-core/src/main/java/com/mybatisflex/core/field/FieldQuery.java create mode 100644 mybatis-flex-core/src/main/java/com/mybatisflex/core/field/FieldQueryBuilder.java create mode 100644 mybatis-flex-core/src/main/java/com/mybatisflex/core/field/QueryBuilder.java diff --git a/docs/.vitepress/config.ts b/docs/.vitepress/config.ts index 6ed879d4..9aa14409 100644 --- a/docs/.vitepress/config.ts +++ b/docs/.vitepress/config.ts @@ -61,6 +61,7 @@ export default defineConfig({ {text: '增、删、改', link: '/zh/base/add-delete-update'}, {text: '查询和分页', link: '/zh/base/query'}, {text: '批量操作', link: '/zh/base/batch'}, + {text: '一对多、多对一', link: '/zh/base/field-query'}, {text: 'QueryWrapper', link: '/zh/base/querywrapper'}, {text: 'Db + Row', link: '/zh/base/db-row'}, {text: 'IService', link: '/zh/base/service'}, diff --git a/docs/zh/base/field-query.md b/docs/zh/base/field-query.md new file mode 100644 index 00000000..828a9dba --- /dev/null +++ b/docs/zh/base/field-query.md @@ -0,0 +1,88 @@ +# 一对多、多对一 + +在很多场景下,我们可能会用到 `一对多`、`一对一`、`多对一`等场景的关联查询,MyBatis-Flex 内置了相关的方法,用于支持此类场景。 + +## 代码示例 + +以下是文章的示例,一篇文章可能归属于多个分类。 + +```java +public class Article { + private Long id; + private String title; + private String content; + + //文章的归属分类,可能是 1 个或者多个 + private List categories; + + //getter setter +} +``` + +查询代码如下: + +```java {10-13} +QueryWrapper queryWrapper = QueryWrapper.create() + .select().form(ARTICLE) + .where(ARTICLE.id.ge(100)); + +List
articles = mapper.selectListByQuery(queryWrapper, fieldQueryBuilder -> { + fieldQueryBuilder + .field(Article::getCategories) // 或者 .field("categories") + .type(Category.class) //非集合,可以不指定 type + .queryWrapper(article -> QueryWrapper.create() + .select().from(CATEGORY) + .where(CATEGORY.id.in( + select("category_id").from("article_category_mapping") + .where("article_id = ?", article.getId()) + ) + )); + }); +``` + +通过以上代码可以看出,`Article.categories` 字段的结果,来源于 `queryWrapper()` 方法构建的 `QueryWrapper`。 + +其原理是:MyBatis-Flex 的内部逻辑是先查询出 `Article` 的数据,然后再根据 `Article` 构建出新的 SQL,查询分类,并赋值给 `Article.categories`, +假设 `Article` 有 10 条数据,那么最终会进行 11 次数据库查询。 + +查询的 SQL 大概如下: + +```sql +select * from tb_article where id >= 100; + +-- 以上 SQL 得到结果后,再执行查询分类的 SQL,如下: +select * from tb_category where id in +(select category_id from article_category_mapping where article_id = 100); + +select * from tb_category where id in +(select category_id from article_category_mapping where article_id = 101); + +select * from tb_category where id in +(select category_id from article_category_mapping where article_id = 102); + +select * from tb_category where id in +(select category_id from article_category_mapping where article_id = 103); + +select * from tb_category where id in +(select category_id from article_category_mapping where article_id = 104); + +select * from tb_category where id in +(select category_id from article_category_mapping where article_id = 105); + +select * from tb_category where id in +(select category_id from article_category_mapping where article_id = 106); + +select * from tb_category where id in +(select category_id from article_category_mapping where article_id = 107); + +select * from tb_category where id in +(select category_id from article_category_mapping where article_id = 108); + +select * from tb_category where id in +(select category_id from article_category_mapping where article_id = 109); +``` + +## 其他场景 + +通过以上内容看出,`Article` 的任何属性,都是可以通过传入 `FieldQueryBuilder` 来构建 `QueryWrapper` 进行再次查询, +这些不仅仅只适用于 `一对多`、`一对一`、`多对一`等场景。任何 `Article` 对象里的属性,需要二次查询赋值的,都是可以通过这种方式进行。 \ No newline at end of file diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/field/FieldQuery.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/field/FieldQuery.java new file mode 100644 index 00000000..e0d662a6 --- /dev/null +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/field/FieldQuery.java @@ -0,0 +1,51 @@ +/** + * 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.field; + +import com.mybatisflex.core.query.QueryWrapper; + +import java.io.Serializable; + +public class FieldQuery implements Serializable { + + private String field; + private Class mappingType; + private QueryWrapper queryWrapper; + + public String getField() { + return field; + } + + public void setField(String field) { + this.field = field; + } + + public Class getMappingType() { + return mappingType; + } + + public void setMappingType(Class mappingType) { + this.mappingType = mappingType; + } + + public QueryWrapper getQueryWrapper() { + return queryWrapper; + } + + public void setQueryWrapper(QueryWrapper queryWrapper) { + this.queryWrapper = queryWrapper; + } +} diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/field/FieldQueryBuilder.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/field/FieldQueryBuilder.java new file mode 100644 index 00000000..47d74353 --- /dev/null +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/field/FieldQueryBuilder.java @@ -0,0 +1,54 @@ +/** + * 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.field; + +import com.mybatisflex.core.util.LambdaGetter; +import com.mybatisflex.core.util.LambdaUtil; + +import java.io.Serializable; + +public class FieldQueryBuilder implements Serializable { + + private T entity; + private FieldQuery fieldQuery = new FieldQuery(); + + public FieldQueryBuilder(T entity) { + this.entity = entity; + } + + public FieldQueryBuilder field(String field){ + fieldQuery.setField(field); + return this; + } + + public FieldQueryBuilder field(LambdaGetter fn){ + return field(LambdaUtil.getFieldName(fn)); + } + + public FieldQueryBuilder type(Class mappingType){ + fieldQuery.setMappingType(mappingType); + return this; + } + + public FieldQueryBuilder queryWrapper(QueryBuilder fun){ + fieldQuery.setQueryWrapper(fun.build(entity)); + return this; + } + + public FieldQuery build() { + return fieldQuery; + } +} diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/field/QueryBuilder.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/field/QueryBuilder.java new file mode 100644 index 00000000..ff41c86e --- /dev/null +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/field/QueryBuilder.java @@ -0,0 +1,22 @@ +/** + * 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.field; + +import com.mybatisflex.core.query.QueryWrapper; + +public interface QueryBuilder { + QueryWrapper build(T entity); +}