!198 feat:Active Record 功能支持联表查询

Merge pull request !198 from 王帅/main
This commit is contained in:
Michael Yang 2023-07-28 04:28:45 +00:00 committed by Gitee
commit 8616d8a72d
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
9 changed files with 392 additions and 6 deletions

View File

@ -136,3 +136,26 @@ Account.create()
.where(Account::getAge).ge(18)
.page(Page.of(1,10));
```
## 多表关联
`Model` 提供了 `joins``@Relation` 两种方式实现多表关联查询,例如:用户与角色的关系:
- 通过 [joins](./relations-query.md#方案-3join-query) 联表方式查询数据:
```java
User.create()
.select(USER.ALL_COLUMNS,ROLE.ALL_COLUMNS)
.leftJoin(USER_ROLE).as("ur").on(USER_ROLE.USER_ID.eq(USER.USER_ID))
.leftJoin(ROLE).as("r").on(USER_ROLE.ROLE_ID.eq(ROLE.ROLE_ID))
.where(USER.USER_ID.eq(2))
.one();
```
- 通过 [@Relation](./relations-query.md#方案-1relations-注解) 相关注解查询数据:
```java
User.create()
.where(USER.USER_ID.eq(2))
.oneWithRelations();
```

View File

@ -56,7 +56,7 @@ public interface MapperModel<T> {
*
* @return 主键数据数组
*/
default Object[] getPkValues() {
default Object[] pkValues() {
TableInfo tableInfo = TableInfoFactory.ofEntityClass(getClass());
return tableInfo.buildPkSqlArgs(this);
}
@ -107,7 +107,7 @@ public interface MapperModel<T> {
* @return {@code true} 删除成功{@code false} 删除失败
*/
default boolean removeById() {
return SqlUtil.toBool(baseMapper().deleteById(getPkValues()));
return SqlUtil.toBool(baseMapper().deleteById(pkValues()));
}
/**
@ -135,7 +135,7 @@ public interface MapperModel<T> {
* @return 数据
*/
default T oneById() {
return baseMapper().selectOneById(getPkValues());
return baseMapper().selectOneById(pkValues());
}
/**
@ -147,4 +147,22 @@ public interface MapperModel<T> {
return Optional.ofNullable(oneById());
}
/**
* 根据实体类主键获取一条数据并查询 {@code @Relation} 注解关联的内容
*
* @return 数据
*/
default T oneWithRelationsById() {
return baseMapper().selectOneWithRelationsById(pkValues());
}
/**
* 根据实体类主键获取一条数据并查询 {@code @Relation} 注解关联的内容封装为 {@link Optional} 返回
*
* @return 数据
*/
default Optional<T> oneWithRelationsByIdOpt() {
return Optional.ofNullable(oneWithRelationsById());
}
}

View File

@ -87,7 +87,16 @@ public abstract class Model<T extends Model<T>>
* @return 数据
*/
public T one() {
return baseMapper().selectOneByQuery(getQueryWrapper().limit(1));
return baseMapper().selectOneByQuery(getQueryWrapper());
}
/**
* 根据实体类构建的条件获取一条数据并查询 {@code @Relation} 注解关联的内容
*
* @return 数据
*/
public T oneWithRelations() {
return baseMapper().selectOneWithRelationsByQuery(getQueryWrapper().limit(1));
}
/**
@ -99,6 +108,15 @@ public abstract class Model<T extends Model<T>>
return Optional.ofNullable(one());
}
/**
* 根据实体类构建的条件获取一条数据并查询 {@code @Relation} 注解关联的内容封装为 {@link Optional} 返回
*
* @return 数据
*/
public Optional<T> oneWithRelationsOpt() {
return Optional.ofNullable(oneWithRelations());
}
/**
* 根据实体类构建的条件获取多条数据
*
@ -108,6 +126,15 @@ public abstract class Model<T extends Model<T>>
return baseMapper().selectListByQuery(getQueryWrapper());
}
/**
* 根据实体类构建的条件获取多条数据并查询 {@code @Relation} 注解关联的内容
*
* @return 数据列表
*/
public List<T> listWithRelations() {
return baseMapper().selectListWithRelationsByQuery(getQueryWrapper());
}
/**
* 根据实体类构建的条件获取分页数据
*
@ -118,4 +145,14 @@ public abstract class Model<T extends Model<T>>
return baseMapper().paginate(page, getQueryWrapper());
}
/**
* 根据实体类构建的条件获取分页数据并查询 {@code @Relation} 注解关联的内容
*
* @param page 分页对象
* @return 分页数据
*/
public Page<T> pageWithRelations(Page<T> page) {
return baseMapper().paginateWithRelations(page, getQueryWrapper());
}
}

View File

@ -0,0 +1,55 @@
/*
* Copyright (c) 2022-2023, Mybatis-Flex (fuhai999@gmail.com).
* <p>
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.Join;
import com.mybatisflex.core.query.QueryCondition;
import com.mybatisflex.core.query.RawFragment;
/**
* Lambda joins 构建器
*
* @author 王帅
* @since 2023-07-28
*/
public class JoinBuilder<R extends QueryModel<R>> {
private final R queryModel;
private final Join join;
public JoinBuilder(R queryModel, Join join) {
this.queryModel = queryModel;
this.join = join;
}
public JoinBuilder<R> as(String alias) {
CPI.getJoinQueryTable(join).as(alias);
return this;
}
public R on(String on) {
join.on(new RawFragment(on));
return queryModel;
}
public R on(QueryCondition on) {
join.on(on);
return queryModel;
}
}

View File

@ -17,7 +17,11 @@
package com.mybatisflex.core.activerecord.query;
import com.mybatisflex.annotation.Column;
import com.mybatisflex.core.constant.SqlConsts;
import com.mybatisflex.core.query.*;
import com.mybatisflex.core.table.TableDef;
import com.mybatisflex.core.table.TableInfo;
import com.mybatisflex.core.table.TableInfoFactory;
import com.mybatisflex.core.util.LambdaGetter;
import com.mybatisflex.core.util.LambdaUtil;
@ -126,6 +130,198 @@ public abstract class QueryModel<T extends QueryModel<T>> {
return new WhereBuilder<>((T) this, LambdaUtil.getQueryColumn(column), SqlConnector.OR);
}
public JoinBuilder<T> leftJoin(String table) {
return joins(SqlConsts.LEFT_JOIN, new QueryTable(table), true);
}
public JoinBuilder<T> leftJoin(String table, boolean when) {
return joins(SqlConsts.LEFT_JOIN, new QueryTable(table), when);
}
public JoinBuilder<T> leftJoin(Class<?> entityClass) {
return joins(SqlConsts.LEFT_JOIN, entityClass, true);
}
public JoinBuilder<T> leftJoin(Class<?> entityClass, boolean when) {
return joins(SqlConsts.LEFT_JOIN, entityClass, when);
}
public JoinBuilder<T> leftJoin(TableDef table) {
return joins(SqlConsts.LEFT_JOIN, new QueryTable(table), true);
}
public JoinBuilder<T> leftJoin(TableDef table, boolean when) {
return joins(SqlConsts.LEFT_JOIN, new QueryTable(table), when);
}
public JoinBuilder<T> leftJoin(QueryWrapper table) {
return joins(SqlConsts.LEFT_JOIN, table, true);
}
public JoinBuilder<T> leftJoin(QueryWrapper table, boolean when) {
return joins(SqlConsts.LEFT_JOIN, table, when);
}
public JoinBuilder<T> rightJoin(String table) {
return joins(SqlConsts.RIGHT_JOIN, new QueryTable(table), true);
}
public JoinBuilder<T> rightJoin(String table, boolean when) {
return joins(SqlConsts.RIGHT_JOIN, new QueryTable(table), when);
}
public JoinBuilder<T> rightJoin(Class<?> entityClass) {
return joins(SqlConsts.RIGHT_JOIN, entityClass, true);
}
public JoinBuilder<T> rightJoin(Class<?> entityClass, boolean when) {
return joins(SqlConsts.RIGHT_JOIN, entityClass, when);
}
public JoinBuilder<T> rightJoin(TableDef table) {
return joins(SqlConsts.RIGHT_JOIN, new QueryTable(table), true);
}
public JoinBuilder<T> rightJoin(TableDef table, boolean when) {
return joins(SqlConsts.RIGHT_JOIN, new QueryTable(table), when);
}
public JoinBuilder<T> rightJoin(QueryWrapper table) {
return joins(SqlConsts.RIGHT_JOIN, table, true);
}
public JoinBuilder<T> rightJoin(QueryWrapper table, boolean when) {
return joins(SqlConsts.RIGHT_JOIN, table, when);
}
public JoinBuilder<T> innerJoin(String table) {
return joins(SqlConsts.INNER_JOIN, new QueryTable(table), true);
}
public JoinBuilder<T> innerJoin(String table, boolean when) {
return joins(SqlConsts.INNER_JOIN, new QueryTable(table), when);
}
public JoinBuilder<T> innerJoin(Class<?> entityClass) {
return joins(SqlConsts.INNER_JOIN, entityClass, true);
}
public JoinBuilder<T> innerJoin(Class<?> entityClass, boolean when) {
return joins(SqlConsts.INNER_JOIN, entityClass, when);
}
public JoinBuilder<T> innerJoin(TableDef table) {
return innerJoin(table, true);
}
public JoinBuilder<T> innerJoin(TableDef table, boolean when) {
return joins(SqlConsts.INNER_JOIN, new QueryTable(table), when);
}
public JoinBuilder<T> innerJoin(QueryWrapper table) {
return joins(SqlConsts.INNER_JOIN, table, true);
}
public JoinBuilder<T> innerJoin(QueryWrapper table, boolean when) {
return joins(SqlConsts.INNER_JOIN, table, when);
}
public JoinBuilder<T> fullJoin(String table) {
return joins(SqlConsts.FULL_JOIN, new QueryTable(table), true);
}
public JoinBuilder<T> fullJoin(String table, boolean when) {
return joins(SqlConsts.FULL_JOIN, new QueryTable(table), when);
}
public JoinBuilder<T> fullJoin(Class<?> entityClass) {
return joins(SqlConsts.FULL_JOIN, entityClass, true);
}
public JoinBuilder<T> fullJoin(Class<?> entityClass, boolean when) {
return joins(SqlConsts.FULL_JOIN, entityClass, when);
}
public JoinBuilder<T> fullJoin(TableDef table) {
return joins(SqlConsts.FULL_JOIN, new QueryTable(table), true);
}
public JoinBuilder<T> fullJoin(TableDef table, boolean when) {
return joins(SqlConsts.FULL_JOIN, new QueryTable(table), when);
}
public JoinBuilder<T> fullJoin(QueryWrapper table) {
return joins(SqlConsts.FULL_JOIN, table, true);
}
public JoinBuilder<T> fullJoin(QueryWrapper table, boolean when) {
return joins(SqlConsts.FULL_JOIN, table, when);
}
public JoinBuilder<T> crossJoin(String table) {
return joins(SqlConsts.CROSS_JOIN, new QueryTable(table), true);
}
public JoinBuilder<T> crossJoin(String table, boolean when) {
return joins(SqlConsts.CROSS_JOIN, new QueryTable(table), when);
}
public JoinBuilder<T> crossJoin(Class<?> entityClass) {
return joins(SqlConsts.CROSS_JOIN, entityClass, true);
}
public JoinBuilder<T> crossJoin(Class<?> entityClass, boolean when) {
return joins(SqlConsts.CROSS_JOIN, entityClass, when);
}
public JoinBuilder<T> crossJoin(TableDef table) {
return joins(SqlConsts.CROSS_JOIN, new QueryTable(table), true);
}
public JoinBuilder<T> crossJoin(TableDef table, boolean when) {
return joins(SqlConsts.CROSS_JOIN, new QueryTable(table), when);
}
public JoinBuilder<T> crossJoin(QueryWrapper table) {
return joins(SqlConsts.CROSS_JOIN, table, true);
}
public JoinBuilder<T> crossJoin(QueryWrapper table, boolean when) {
return joins(SqlConsts.CROSS_JOIN, table, when);
}
public JoinBuilder<T> join(String table) {
return joins(SqlConsts.JOIN, new QueryTable(table), true);
}
public JoinBuilder<T> join(String table, boolean when) {
return joins(SqlConsts.JOIN, new QueryTable(table), when);
}
public JoinBuilder<T> join(Class<?> entityClass) {
return joins(SqlConsts.JOIN, entityClass, true);
}
public JoinBuilder<T> join(Class<?> entityClass, boolean when) {
return joins(SqlConsts.JOIN, entityClass, when);
}
public JoinBuilder<T> join(TableDef table) {
return joins(SqlConsts.JOIN, new QueryTable(table), true);
}
public JoinBuilder<T> join(TableDef table, boolean when) {
return joins(SqlConsts.JOIN, new QueryTable(table), when);
}
public JoinBuilder<T> join(QueryWrapper table) {
return joins(SqlConsts.JOIN, table, true);
}
public JoinBuilder<T> join(QueryWrapper table, boolean when) {
return joins(SqlConsts.JOIN, table, when);
}
public T groupBy(String... names) {
getQueryWrapper().groupBy(names);
return (T) this;
@ -175,4 +371,22 @@ public abstract class QueryModel<T extends QueryModel<T>> {
return (T) this;
}
protected JoinBuilder<T> joins(String type, QueryTable table, boolean when) {
Join join = new Join(type, table, when);
CPI.addJoin(getQueryWrapper(), join);
return new JoinBuilder<>((T) this, join);
}
protected JoinBuilder<T> joins(String type, Class<?> entityClass, boolean when) {
TableInfo tableInfo = TableInfoFactory.ofEntityClass(entityClass);
QueryTable queryTable = new QueryTable(tableInfo.getSchema(), tableInfo.getTableName());
return joins(type, queryTable, when);
}
protected JoinBuilder<T> joins(String type, QueryWrapper queryWrapper, boolean when) {
Join join = new Join(type, queryWrapper, when);
CPI.addJoin(getQueryWrapper(), join);
return new JoinBuilder<>((T) this, join);
}
}

View File

@ -120,6 +120,11 @@ public class CPI {
queryWrapper.setJoinTables(joinTables);
}
public static void addJoin(QueryWrapper queryWrapper, Join join) {
queryWrapper.addJoinTable(join.getQueryTable());
queryWrapper.addJoin(join);
}
public static QueryCondition getWhereQueryCondition(QueryWrapper queryWrapper) {
return queryWrapper.getWhereQueryCondition();

View File

@ -16,6 +16,7 @@
package com.mybatisflex.test.model;
import com.mybatisflex.annotation.Column;
import com.mybatisflex.annotation.Id;
import com.mybatisflex.annotation.Table;
@ -36,6 +37,7 @@ public class Role implements Comparable<Role> {
private String roleKey;
private String roleName;
@Column(ignore = true)
private List<UserVO> userVOS;
public Integer getRoleId() {

View File

@ -17,7 +17,9 @@
package com.mybatisflex.test.model;
import com.mybatisflex.annotation.Id;
import com.mybatisflex.annotation.RelationManyToMany;
import com.mybatisflex.annotation.Table;
import com.mybatisflex.core.activerecord.Model;
import java.util.List;
@ -29,15 +31,26 @@ import java.util.List;
*/
@Table("tb_user")
public class User {
public class User extends Model<User> {
@Id
private Integer userId;
private String userName;
private String password;
//@Column(ignore = true)
@RelationManyToMany(
selfField = "userId",
targetField = "roleId",
joinTable = "tb_user_role",
joinSelfColumn = "user_id",
joinTargetColumn = "role_id"
)
private List<Role> roleList;
public static User create() {
return new User();
}
public Integer getUserId() {
return userId;
}

View File

@ -19,11 +19,15 @@ package com.mybatisflex.test.mapper;
import com.mybatisflex.core.mybatis.Mappers;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.test.model.Good;
import com.mybatisflex.test.model.User;
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;
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 王帅
@ -105,4 +109,19 @@ class ActiveRecordTest {
.forEach(System.out::println);
}
@Test
void testRelation() {
User user1 = User.create().select(USER.ALL_COLUMNS, ROLE.ALL_COLUMNS)
.leftJoin(USER_ROLE).as("ur").on(USER_ROLE.USER_ID.eq(USER.USER_ID))
.leftJoin(ROLE).as("r").on(USER_ROLE.ROLE_ID.eq(ROLE.ROLE_ID))
.where(USER.USER_ID.eq(2))
.one();
User user2 = User.create()
.where(USER.USER_ID.eq(2))
.oneWithRelations();
Assertions.assertEquals(user1.toString(), user2.toString());
}
}