com.baomidou.mybatisplus.extension.conditions.query.LambdaJoinQueryWrapper Maven / Gradle / Ivy
/*
* Copyright (c) 2011-2022, baomidou ([email protected]).
*
* 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.baomidou.mybatisplus.extension.conditions.query;
import static com.baomidou.mybatisplus.core.enums.SqlKeyword.AND;
import static com.baomidou.mybatisplus.core.enums.SqlKeyword.BETWEEN;
import static com.baomidou.mybatisplus.core.enums.SqlKeyword.NOT_BETWEEN;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.ibatis.reflection.property.PropertyNamer;
import com.baomidou.mybatisplus.core.conditions.AbstractJoinWrapper;
import com.baomidou.mybatisplus.core.conditions.SharedString;
import com.baomidou.mybatisplus.core.conditions.query.Query;
import com.baomidou.mybatisplus.core.conditions.segments.MergeSegments;
import com.baomidou.mybatisplus.core.enums.BaseFuncEnum;
import com.baomidou.mybatisplus.core.enums.SqlKeyword;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Constants;
import com.baomidou.mybatisplus.core.toolkit.ExceptionUtils;
import com.baomidou.mybatisplus.core.toolkit.LambdaUtils;
import com.baomidou.mybatisplus.core.toolkit.support.LambdaMeta;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.baomidou.mybatisplus.extension.conditions.query.interfaces.JoinCompareFun;
import com.baomidou.mybatisplus.extension.conditions.query.interfaces.LambdaJoinFunc;
/**
* 本类使用SFunction来构造多表查询条件
* demo:--需要注意的是 如果要添加其他表的过滤条件或者排序字段,请在调用了join方法后直接调用类似下面这种写法,否则编译不通过
* LambdaJoinQueryWrapper wrapper = new LambdaJoinQueryWrapper<>(User.class);
* wrapper.eq(User::getSchoolId,1);
* wrapper.innerJoin(School.class).like(School::getSchoolName,"一");
* mapper.selectJoinList(wrapper);
*
* @author wanglei
* @since 2022-03-17
*/
public class LambdaJoinQueryWrapper extends AbstractJoinWrapper,
LambdaJoinQueryWrapper> implements LambdaJoinFunc, Query, T, SFunction>, JoinCompareFun, T> {
/**
* 主表model的class
*/
private Class> mainClass;
public LambdaJoinQueryWrapper(Class> mainClass) {
super(mainClass);
this.mainClass = mainClass;
super.initNeed();
}
/**
* 非对外公开的构造方法,只用于生产嵌套 sql
*
* @param entityClass 本不应该需要的
*/
private LambdaJoinQueryWrapper(Class> mainClass, T entity, Class entityClass, AtomicInteger paramNameSeq,
Map paramNameValuePairs, MergeSegments mergeSegments, SharedString paramAlias,
SharedString lastSql, SharedString sqlComment, SharedString sqlFirst, StringBuilder joinFroms,Map, String> aliasMap) {
super(mainClass);
super.setEntity(entity);
super.setEntityClass(entityClass);
this.mainClass = mainClass;
this.paramNameSeq = paramNameSeq;
this.paramNameValuePairs = paramNameValuePairs;
this.expression = mergeSegments;
this.paramAlias = paramAlias;
this.lastSql = lastSql;
this.sqlComment = sqlComment;
this.sqlFirst = sqlFirst;
this.joinFroms = joinFroms;
this.aliasMap = aliasMap;
}
@Override
protected LambdaJoinQueryWrapper instance() {
return new LambdaJoinQueryWrapper<>(mainClass, getEntity(), getEntityClass(), paramNameSeq, paramNameValuePairs, new MergeSegments(),
paramAlias, SharedString.emptyString(), SharedString.emptyString(), SharedString.emptyString(), this.joinFroms,this.aliasMap);
}
@Override
public LambdaJoinQueryWrapper join(Class joinClass, SFunction leftField, SFunction rightField, String joinType) {
pubJoin(joinClass, leftField, rightField, joinType);
return (LambdaJoinQueryWrapper) this;
}
public LambdaJoinQueryWrapper end(Class clz) {
return (LambdaJoinQueryWrapper) this;
}
@Override
protected String customBuildJoin(LEFT leftProperty, RIGHT rightProperty) {
LambdaMeta leftMeta = LambdaUtils.extract((SFunction, ?>) leftProperty);
LambdaMeta rightMeta = LambdaUtils.extract((SFunction, ?>) rightProperty);
// 关联表别名
String leftAlias = aliasMap.get(leftMeta.getInstantiatedClass());
// 关联表别名
String rightAlias = aliasMap.get(rightMeta.getInstantiatedClass());
getCache(leftMeta.getInstantiatedClass(), PropertyNamer.methodToProperty(leftMeta.getImplMethodName()));
return Constants.SPACE + leftAlias + Constants.DOT + getCache(leftMeta.getInstantiatedClass(), PropertyNamer.methodToProperty(leftMeta.getImplMethodName())).getColumn()
+ Constants.EQUALS + rightAlias + Constants.DOT + getCache(rightMeta.getInstantiatedClass(), PropertyNamer.methodToProperty(rightMeta.getImplMethodName())).getColumn();
}
/**
* 软删除字段处理
*
* @param joinClass
*/
@Override
protected void initLogicDelete(Class> joinClass, String joinType) {
TableInfo tableInfo = TableInfoHelper.getTableInfo(joinClass);
// 不是left join的时候
if (tableInfo.getLogicDeleteFieldInfo() != null) {
this.joinFroms.append(Constants.SPACE + Constants.AND + Constants.SPACE + aliasMap.get(joinClass) + Constants.DOT
+ tableInfo.getLogicDeleteFieldInfo().getColumn() + Constants.SPACE + Constants.EQUALS + Constants.SPACE +
parseLogicNotDeleteValue(tableInfo.getLogicDeleteFieldInfo()));
}
//如果没有join其他的表,需要把主表的软删除字段放到on上
if (this.aliasMap.size() == 2) {
tableInfo = TableInfoHelper.getTableInfo(this.mainClass);
if (tableInfo.getLogicDeleteFieldInfo() != null) {
this.joinFroms.append(Constants.SPACE + Constants.AND + Constants.SPACE + aliasMap.get(this.mainClass) + Constants.DOT
+ tableInfo.getLogicDeleteFieldInfo().getColumn() + Constants.SPACE + Constants.EQUALS + Constants.SPACE +
parseLogicNotDeleteValue(tableInfo.getLogicDeleteFieldInfo()));
}
}
}
@Override
public MergeSegments getExpression() {
//如果没有join其他的表,需要把主表的软删除字段放到where上
if (this.aliasMap.size() == 1 && !isAppendMainLogicDelete) {
isAppendMainLogicDelete = true;
TableInfo tableInfo = TableInfoHelper.getTableInfo(this.mainClass);
if (tableInfo.getLogicDeleteFieldInfo() != null) {
eq(LambdaUtils.getSFunction(this.mainClass, tableInfo.getLogicDeleteFieldInfo().getPropertyType()
, tableInfo.getLogicDeleteFieldInfo().getProperty())
, parseLogicNotDeleteValue(tableInfo.getLogicDeleteFieldInfo()));
}
}
return expression;
}
@Override
protected String columnToString(SFunction column) {
return extractColumn(column);
}
protected String extractColumn(SFunction, ?> column) {
LambdaMeta lambdaMeta = LambdaUtils.extract(column);
if (!super.aliasMap.containsKey(lambdaMeta.getInstantiatedClass())) {
throw ExceptionUtils.mpe("not join class: \"%s\".", lambdaMeta.getInstantiatedClass().getName());
}
return super.aliasMap.get(lambdaMeta.getInstantiatedClass()) + "." + getCache(lambdaMeta.getInstantiatedClass(),
PropertyNamer.methodToProperty(lambdaMeta.getImplMethodName())).getColumn();
}
@Override
@SafeVarargs
public final LambdaJoinQueryWrapper select(SFunction... columns) {
return select(Arrays.asList(columns));
}
public LambdaJoinQueryWrapper select(List> columns) {
if (CollectionUtils.isNotEmpty(columns)) {
for (SFunction, ?> column : columns) {
LambdaMeta lambdaMeta = LambdaUtils.extract(column);
selectColumns.add(SelectColumn.of(lambdaMeta.getInstantiatedClass(), getCache(lambdaMeta.getInstantiatedClass(),
PropertyNamer.methodToProperty(lambdaMeta.getImplMethodName())).getColumn()));
}
}
return typedThis;
}
/**
* 查询函数列,如果column不指定,则查询 *
* select xx(column) as alias
*/
@Override
public final LambdaJoinQueryWrapper selectFun(BaseFuncEnum fun, SFunction alias, SFunction column) {
LambdaMeta aliasLambdaMeta = LambdaUtils.extract(alias);
LambdaMeta columnLambdaMeta = column == null ? null : LambdaUtils.extract(column);
String columnStr = column == null ? "*" : aliasMap.get(columnLambdaMeta.getInstantiatedClass()) + Constants.DOT
+ getCache(columnLambdaMeta.getInstantiatedClass(), PropertyNamer.methodToProperty(columnLambdaMeta.getImplMethodName())).getColumn();
String funStr = String.format(fun.getSql(), columnStr);
this.funSqlSelect.add(new SharedString(funStr + Constants.AS + PropertyNamer.methodToProperty(aliasLambdaMeta.getImplMethodName())));
return typedThis;
}
@Override
public LambdaJoinQueryWrapper eq(boolean condition, SFunction column, SFunction val) {
return addCondition(condition, column, SqlKeyword.EQ, val);
}
@Override
public LambdaJoinQueryWrapper ne(boolean condition, SFunction column, SFunction val) {
return addCondition(condition, column, SqlKeyword.NE, val);
}
@Override
public LambdaJoinQueryWrapper gt(boolean condition, SFunction column, SFunction val) {
return addCondition(condition, column, SqlKeyword.GT, val);
}
@Override
public LambdaJoinQueryWrapper ge(boolean condition, SFunction column, SFunction val) {
return addCondition(condition, column, SqlKeyword.GE, val);
}
@Override
public LambdaJoinQueryWrapper lt(boolean condition, SFunction column, SFunction val) {
return addCondition(condition, column, SqlKeyword.LT, val);
}
@Override
public LambdaJoinQueryWrapper le(boolean condition, SFunction column, SFunction val) {
return addCondition(condition, column, SqlKeyword.LE, val);
}
@Override
public LambdaJoinQueryWrapper between(boolean condition, SFunction column, SFunction val1, SFunction val2) {
return maybeDo(condition, () -> appendSqlSegments(columnToSqlSegment(column), BETWEEN,
() -> extractColumn(val1), AND, () -> extractColumn(val2)));
}
@Override
public LambdaJoinQueryWrapper notBetween(boolean condition, SFunction column, SFunction val1, SFunction val2) {
return maybeDo(condition, () -> appendSqlSegments(columnToSqlSegment(column), NOT_BETWEEN,
() -> extractColumn(val1), AND, () -> extractColumn(val2)));
}
/**
* 普通查询条件
*
* @param condition 是否执行
* @param column 属性
* @param sqlKeyword SQL 关键词
* @param val 条件值
*/
protected LambdaJoinQueryWrapper addCondition(boolean condition, SFunction column, SqlKeyword sqlKeyword, SFunction val) {
return maybeDo(condition, () -> appendSqlSegments(columnToSqlSegment(column), sqlKeyword,
() -> extractColumn(val)));
}
}