mirror of
https://gitee.com/mybatis-flex/mybatis-flex.git
synced 2025-12-07 00:58:24 +08:00
commit
8616d8a72d
@ -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();
|
||||
```
|
||||
|
||||
@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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() {
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user