diff --git a/MAPPING.md b/MAPPING.md index 718ded6..110500c 100644 --- a/MAPPING.md +++ b/MAPPING.md @@ -62,7 +62,6 @@ public class UserDO { ```java /** * 一对一,一对多关系映射查询 - * 映射只对以Deep结尾有效,比如 getByIdDeep listByIdsDeep 等 * 如果不需要关系映射就使用mybatis plus原生方法即可,比如 getById listByIds 等 * * 注意:关系映射不会去关联查询,而是执行多次单表查询(对结果汇总后使用in语句查询,再对结果进行匹配) @@ -80,14 +79,15 @@ class MappingTest { @Test void test2() { - List list = userMapper.selectListDeep(Wrappers.emptyWrapper()); + List list = userMapper.selectRelation(mapper -> mapper.selectList(Wrappers.emptyWrapper())); list.forEach(System.out::println); } @Test void test3() { - Page page = userMapper.selectPageDeep(new Page<>(2, 2), Wrappers.emptyWrapper()); - page.getRecords().forEach(System.out::println); + Page page = new Page<>(2, 2); + Page result = userMapper.selectRelation(mapper -> mapper.selectPage(page, Wrappers.emptyWrapper())); + result.getRecords().forEach(System.out::println); } /** diff --git a/mybatis-plus-join-core/src/main/java/com/github/yulichang/base/mapper/MPJJoinMapper.java b/mybatis-plus-join-core/src/main/java/com/github/yulichang/base/mapper/MPJJoinMapper.java index 42627d8..0a21c2c 100644 --- a/mybatis-plus-join-core/src/main/java/com/github/yulichang/base/mapper/MPJJoinMapper.java +++ b/mybatis-plus-join-core/src/main/java/com/github/yulichang/base/mapper/MPJJoinMapper.java @@ -2,9 +2,12 @@ package com.github.yulichang.base.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.core.toolkit.Assert; import com.baomidou.mybatisplus.core.toolkit.Constants; import com.github.yulichang.interfaces.MPJBaseJoin; import com.github.yulichang.toolkit.Constant; +import com.github.yulichang.wrapper.DeleteJoinWrapper; +import com.github.yulichang.wrapper.UpdateJoinWrapper; import org.apache.ibatis.annotations.Param; import java.util.List; @@ -16,6 +19,29 @@ import java.util.Map; */ public interface MPJJoinMapper extends BaseMapper { + /** + * 根据 Wrapper 条件,连表删除 + * + * @param wrapper joinWrapper + */ + int deleteJoin(@Param(Constants.WRAPPER) MPJBaseJoin wrapper); + + /** + * 根据 whereEntity 条件,更新记录 + * + * @param entity 实体对象 (set 条件值,可以为 null) + * @param wrapper 实体对象封装操作类(可以为 null,里面的 entity 用于生成 where 语句) + */ + int updateJoin(@Param(Constants.ENTITY) T entity, @Param(Constants.WRAPPER) MPJBaseJoin wrapper); + + /** + * 根据 whereEntity 条件,更新记录 (null字段也会更新 !!!) + * + * @param entity 实体对象 (set 条件值,可以为 null) + * @param wrapper 实体对象封装操作类(可以为 null,里面的 entity 用于生成 where 语句) + */ + int updateJoinAndNull(@Param(Constants.ENTITY) T entity, @Param(Constants.WRAPPER) MPJBaseJoin wrapper); + /** * 根据 Wrapper 条件,查询总记录数 * diff --git a/mybatis-plus-join-core/src/main/java/com/github/yulichang/injector/MPJSqlInjector.java b/mybatis-plus-join-core/src/main/java/com/github/yulichang/injector/MPJSqlInjector.java index 68cffeb..65a61e6 100644 --- a/mybatis-plus-join-core/src/main/java/com/github/yulichang/injector/MPJSqlInjector.java +++ b/mybatis-plus-join-core/src/main/java/com/github/yulichang/injector/MPJSqlInjector.java @@ -9,7 +9,9 @@ import com.baomidou.mybatisplus.core.injector.methods.*; import com.baomidou.mybatisplus.core.mapper.Mapper; import com.baomidou.mybatisplus.core.metadata.TableInfo; import com.baomidou.mybatisplus.core.toolkit.ArrayUtils; +import com.baomidou.mybatisplus.core.toolkit.Assert; import com.baomidou.mybatisplus.core.toolkit.ClassUtils; +import com.baomidou.mybatisplus.core.toolkit.ExceptionUtils; import com.github.yulichang.adapter.v3431.AbstractMethodV3431; import com.github.yulichang.mapper.MPJTableMapperHelper; import com.github.yulichang.method.*; @@ -59,10 +61,10 @@ public class MPJSqlInjector extends DefaultSqlInjector { * 升级到 mybatis plus 3.4.3.2 后对之前的版本兼容 */ @Deprecated - @SuppressWarnings("unused") + @SuppressWarnings({"unused", "DeprecatedIsStillUsed"}) public List getMethodList(Class mapperClass) { if (VersionUtils.compare(MybatisPlusVersion.getVersion(), "3.4.3.2") >= 0) { - logger.error(() -> "DefaultSqlInjector 的 getMethodList(Class mapperClass) 方法已在 3.4.3.2+ 改为" + + throw ExceptionUtils.mpe("DefaultSqlInjector 的 getMethodList(Class mapperClass) 方法已在 3.4.3.2+ 改为" + "getMethodList(Class mapperClass, TableInfo tableInfo)\n"); } if (Objects.nonNull(sqlInjector)) { @@ -119,6 +121,8 @@ public class MPJSqlInjector extends DefaultSqlInjector { List list = new ArrayList<>(); if (VersionUtils.compare(MybatisPlusVersion.getVersion(), "3.5.0") >= 0) { list.add(new DeleteJoin(SqlMethod.DELETE_JOIN.getMethod())); + list.add(new UpdateJoin(SqlMethod.UPDATE_JOIN.getMethod())); + list.add(new UpdateJoinAndNull(SqlMethod.UPDATE_JOIN_AND_NULL.getMethod())); list.add(new SelectJoinCount(SqlMethod.SELECT_JOIN_COUNT.getMethod())); list.add(new SelectJoinOne(SqlMethod.SELECT_JOIN_ONE.getMethod())); list.add(new SelectJoinList(SqlMethod.SELECT_JOIN_LIST.getMethod())); @@ -128,6 +132,8 @@ public class MPJSqlInjector extends DefaultSqlInjector { list.add(new SelectJoinMapsPage(SqlMethod.SELECT_JOIN_MAPS_PAGE.getMethod())); } else { list.add(new DeleteJoin()); + list.add(new UpdateJoin()); + list.add(new UpdateJoinAndNull()); list.add(new SelectJoinCount()); list.add(new SelectJoinOne()); list.add(new SelectJoinList()); diff --git a/mybatis-plus-join-core/src/main/java/com/github/yulichang/interfaces/MPJBaseJoin.java b/mybatis-plus-join-core/src/main/java/com/github/yulichang/interfaces/MPJBaseJoin.java index ca63c02..2fbf71e 100644 --- a/mybatis-plus-join-core/src/main/java/com/github/yulichang/interfaces/MPJBaseJoin.java +++ b/mybatis-plus-join-core/src/main/java/com/github/yulichang/interfaces/MPJBaseJoin.java @@ -1,8 +1,18 @@ package com.github.yulichang.interfaces; +import com.baomidou.mybatisplus.core.toolkit.StringPool; + /** * @author yulichang */ @SuppressWarnings("unused") public interface MPJBaseJoin { + + default String getDeleteSql() { + return StringPool.EMPTY; + } + + default String getDeleteLogicSql() { + return StringPool.EMPTY; + } } diff --git a/mybatis-plus-join-core/src/main/java/com/github/yulichang/method/DeleteJoin.java b/mybatis-plus-join-core/src/main/java/com/github/yulichang/method/DeleteJoin.java new file mode 100644 index 0000000..0548e55 --- /dev/null +++ b/mybatis-plus-join-core/src/main/java/com/github/yulichang/method/DeleteJoin.java @@ -0,0 +1,53 @@ +package com.github.yulichang.method; + +import com.baomidou.mybatisplus.core.metadata.TableInfo; +import com.baomidou.mybatisplus.core.toolkit.Constants; +import com.baomidou.mybatisplus.core.toolkit.sql.SqlScriptUtils; +import com.github.yulichang.adapter.AdapterHelper; +import org.apache.ibatis.mapping.MappedStatement; +import org.apache.ibatis.mapping.SqlSource; + +/** + * copy {@link com.baomidou.mybatisplus.core.injector.methods.Delete} + * + * @author yulichang + */ +public class DeleteJoin extends MPJAbstractMethod { + + @SuppressWarnings("deprecation") + public DeleteJoin() { + super(); + } + + @SuppressWarnings("unused") + public DeleteJoin(String name) { + super(name); + } + + @Override + @SuppressWarnings("DuplicatedCode") + public MappedStatement injectMappedStatement(Class mapperClass, Class modelClass, TableInfo tableInfo) { + SqlMethod sqlMethod = SqlMethod.LOGIC_DELETE_JOIN; + if (AdapterHelper.getTableInfoAdapter().mpjHasLogic(tableInfo)) { + String sql = String.format(sqlMethod.getSql(), sqlFirst(), mpjTableName(tableInfo), sqlAlias(), sqlFrom(), + mpjDeleteLogic(tableInfo), sqlWhereEntityWrapper(true, tableInfo), sqlComment()); + SqlSource sqlSource = languageDriver.createSqlSource(configuration, sql, modelClass); + return this.addUpdateMappedStatement(mapperClass, modelClass, sqlMethod.getMethod(), sqlSource); + } else { + sqlMethod = SqlMethod.DELETE_JOIN; + String sql = String.format(sqlMethod.getSql(), sqlFirst(), mpjDelete(), mpjTableName(tableInfo), + sqlAlias(), sqlFrom(), sqlWhereEntityWrapper(true, tableInfo), sqlComment()); + SqlSource sqlSource = languageDriver.createSqlSource(configuration, sql, modelClass); + return this.addDeleteMappedStatement(mapperClass, sqlMethod.getMethod(), sqlSource); + } + } + + private String mpjDelete() { + return SqlScriptUtils.convertChoose(String.format("%s == null or %s.deleteSql == ''", Constants.WRAPPER, Constants.WRAPPER), + "${ew.alias}", "${ew.deleteSql}"); + } + + private String mpjDeleteLogic(TableInfo tableInfo) { + return "SET ${ew.alias}." + tableInfo.getLogicDeleteSql(false, false) + " ${ew.deleteLogicSql}"; + } +} diff --git a/mybatis-plus-join-core/src/main/java/com/github/yulichang/method/MPJBaseMethod.java b/mybatis-plus-join-core/src/main/java/com/github/yulichang/method/MPJBaseMethod.java index 4268dd5..1b4eb67 100644 --- a/mybatis-plus-join-core/src/main/java/com/github/yulichang/method/MPJBaseMethod.java +++ b/mybatis-plus-join-core/src/main/java/com/github/yulichang/method/MPJBaseMethod.java @@ -9,6 +9,7 @@ import com.baomidou.mybatisplus.core.toolkit.Constants; import com.baomidou.mybatisplus.core.toolkit.StringPool; import com.baomidou.mybatisplus.core.toolkit.StringUtils; import com.baomidou.mybatisplus.core.toolkit.sql.SqlScriptUtils; +import com.github.yulichang.adapter.AdapterHelper; import com.github.yulichang.annotation.DynamicTableName; import com.github.yulichang.config.ConfigProperties; import com.github.yulichang.toolkit.VersionUtils; @@ -200,4 +201,84 @@ public interface MPJBaseMethod extends Constants { boolean en = tableName.equals(encode); return String.format("${ew.getTableName%s(\"%s\")}", en ? "" : "Enc", en ? tableName : encode); } + + default String mpjSqlSet(boolean logic, boolean ew, TableInfo table, boolean judgeAliasNull, String alias, String prefix) { + String sqlScript = mpjGetAllSqlSet(table, logic, prefix); + if (judgeAliasNull) { + sqlScript = SqlScriptUtils.convertIf(sqlScript, String.format("%s != null", alias), true); + } + if (ew) { + sqlScript += NEWLINE; + sqlScript += mpjConvertIfEwParam(U_WRAPPER_SQL_SET, false); + } + sqlScript = SqlScriptUtils.convertSet(sqlScript); + return sqlScript; + } + + default String mpjConvertIfEwParam(final String param, final boolean newLine) { + return StringPool.EMPTY; + } + + /** + * 获取所有的 sql set 片段 + * + * @param ignoreLogicDelFiled 是否过滤掉逻辑删除字段 + * @param prefix 前缀 + * @return sql 脚本片段 + */ + default String mpjGetAllSqlSet(TableInfo tableInfo, boolean ignoreLogicDelFiled, final String prefix) { + final String newPrefix = prefix == null ? EMPTY : prefix; + return tableInfo.getFieldList().stream() + .filter(i -> { + if (ignoreLogicDelFiled) { + return !(AdapterHelper.getTableInfoAdapter().mpjHasLogic(tableInfo) && i.isLogicDelete()); + } + return true; + }).map(i -> mpjGetSqlSet(i, newPrefix)).filter(Objects::nonNull).collect(joining(NEWLINE)); + } + + /** + * 获取 set sql 片段 + * + * @param prefix 前缀 + * @return sql 脚本片段 + */ + default String mpjGetSqlSet(TableFieldInfo tableFieldInfo, final String prefix) { + return mpjGetSqlSet(tableFieldInfo, false, prefix); + } + + /** + * 获取 set sql 片段 + * + * @param ignoreIf 忽略 IF 包裹 + * @param prefix 前缀 + * @return sql 脚本片段 + */ + default String mpjGetSqlSet(TableFieldInfo tableFieldInfo, final boolean ignoreIf, final String prefix) { + final String newPrefix = prefix == null ? EMPTY : prefix; + // 默认: column= + String sqlSet = "${ew.alias}." + tableFieldInfo.getColumn() + EQUALS; + if (StringUtils.isNotBlank(tableFieldInfo.getUpdate())) { + sqlSet += String.format(tableFieldInfo.getUpdate(), tableFieldInfo.getColumn()); + } else { + sqlSet += SqlScriptUtils.safeParam(newPrefix + tableFieldInfo.getEl()); + } + sqlSet += COMMA; + if (ignoreIf) { + return sqlSet; + } + if (tableFieldInfo.isWithUpdateFill()) { + // 不进行 if 包裹 + return sqlSet; + } + return mpjConvertIf(tableFieldInfo, sqlSet, mpjConvertIfProperty(newPrefix, tableFieldInfo.getProperty()), tableFieldInfo.getUpdateStrategy()); + } + + default String mpjConvertIfProperty(String prefix, String property) { + return StringUtils.isNotBlank(prefix) ? prefix.substring(0, prefix.length() - 1) + "['" + property + "']" : property; + } + + default String mpjConvertIf(TableFieldInfo tableFieldInfo, final String sqlScript, final String property, final FieldStrategy fieldStrategy) { + return StringPool.EMPTY; + } } diff --git a/mybatis-plus-join-core/src/main/java/com/github/yulichang/method/SqlMethod.java b/mybatis-plus-join-core/src/main/java/com/github/yulichang/method/SqlMethod.java index c78c688..26dc29b 100644 --- a/mybatis-plus-join-core/src/main/java/com/github/yulichang/method/SqlMethod.java +++ b/mybatis-plus-join-core/src/main/java/com/github/yulichang/method/SqlMethod.java @@ -32,8 +32,29 @@ public enum SqlMethod { ""), SELECT_JOIN_MAPS_PAGE("selectJoinMapsPage", "返回Map集合并分页", - ""); + ""), + /** + * 连表删除 + */ + DELETE_JOIN("deleteJoin", "连表删除", + ""), + + /** + * 连表逻辑删除 + */ + LOGIC_DELETE_JOIN("deleteJoin", "连表逻辑删除", ""), + + /** + * 连表更新 + */ + UPDATE_JOIN("updateJoin", "连表更新", ""), + + /** + * 连表逻辑更新 (会更新null字段) + */ + UPDATE_JOIN_AND_NULL("updateJoinAndNull", "连表更新", ""), + ; private final String method; private final String sql; diff --git a/mybatis-plus-join-core/src/main/java/com/github/yulichang/method/UpdateJoin.java b/mybatis-plus-join-core/src/main/java/com/github/yulichang/method/UpdateJoin.java new file mode 100644 index 0000000..021f2c2 --- /dev/null +++ b/mybatis-plus-join-core/src/main/java/com/github/yulichang/method/UpdateJoin.java @@ -0,0 +1,66 @@ +package com.github.yulichang.method; + +import com.baomidou.mybatisplus.annotation.FieldStrategy; +import com.baomidou.mybatisplus.core.metadata.TableFieldInfo; +import com.baomidou.mybatisplus.core.metadata.TableInfo; +import com.baomidou.mybatisplus.core.toolkit.sql.SqlScriptUtils; +import com.github.yulichang.adapter.AdapterHelper; +import org.apache.ibatis.mapping.MappedStatement; +import org.apache.ibatis.mapping.SqlSource; + +/** + * copy {@link com.baomidou.mybatisplus.core.injector.methods.Update} + * + * @author yulichang + */ +public class UpdateJoin extends MPJAbstractMethod { + + @SuppressWarnings("deprecation") + public UpdateJoin() { + super(); + } + + @SuppressWarnings("unused") + public UpdateJoin(String name) { + super(name); + } + + @Override + @SuppressWarnings("DuplicatedCode") + public MappedStatement injectMappedStatement(Class mapperClass, Class modelClass, TableInfo tableInfo) { + SqlMethod sqlMethod = SqlMethod.UPDATE_JOIN; + String sql = String.format(sqlMethod.getSql(), sqlFirst(), mpjTableName(tableInfo), sqlAlias(), sqlFrom(), + mpjSqlSet(true, true, tableInfo, true, ENTITY, ENTITY_DOT), sqlWhereEntityWrapper(true, tableInfo), sqlComment()); + SqlSource sqlSource = languageDriver.createSqlSource(configuration, sql, modelClass); + return this.addUpdateMappedStatement(mapperClass, modelClass, sqlMethod.getMethod(), sqlSource); + } + + + @Override + public String mpjConvertIfEwParam(String param, boolean newLine) { + return super.convertIfEwParam(param, newLine); + } + + /** + * 转换成 if 标签的脚本片段 + * + * @param sqlScript sql 脚本片段 + * @param property 字段名 + * @param fieldStrategy 验证策略 + * @return if 脚本片段 + */ + @Override + public String mpjConvertIf(TableFieldInfo tableFieldInfo, final String sqlScript, final String property, final FieldStrategy fieldStrategy) { + if (fieldStrategy == FieldStrategy.NEVER) { + return null; + } + if (AdapterHelper.getTableInfoAdapter().mpjIsPrimitive(tableFieldInfo) || fieldStrategy == FieldStrategy.IGNORED) { + return sqlScript; + } + if (fieldStrategy == FieldStrategy.NOT_EMPTY && tableFieldInfo.isCharSequence()) { + return SqlScriptUtils.convertIf(sqlScript, String.format("%s != null and %s != ''", property, property), + false); + } + return SqlScriptUtils.convertIf(sqlScript, String.format("%s != null", property), false); + } +} diff --git a/mybatis-plus-join-core/src/main/java/com/github/yulichang/method/UpdateJoinAndNull.java b/mybatis-plus-join-core/src/main/java/com/github/yulichang/method/UpdateJoinAndNull.java new file mode 100644 index 0000000..477f8af --- /dev/null +++ b/mybatis-plus-join-core/src/main/java/com/github/yulichang/method/UpdateJoinAndNull.java @@ -0,0 +1,56 @@ +package com.github.yulichang.method; + +import com.baomidou.mybatisplus.annotation.FieldStrategy; +import com.baomidou.mybatisplus.core.metadata.TableFieldInfo; +import com.baomidou.mybatisplus.core.metadata.TableInfo; +import org.apache.ibatis.mapping.MappedStatement; +import org.apache.ibatis.mapping.SqlSource; + +/** + * copy {@link com.baomidou.mybatisplus.core.injector.methods.Update} + * + * @author yulichang + */ +public class UpdateJoinAndNull extends MPJAbstractMethod { + + @SuppressWarnings("deprecation") + public UpdateJoinAndNull() { + super(); + } + + @SuppressWarnings("unused") + public UpdateJoinAndNull(String name) { + super(name); + } + + @Override + @SuppressWarnings("DuplicatedCode") + public MappedStatement injectMappedStatement(Class mapperClass, Class modelClass, TableInfo tableInfo) { + SqlMethod sqlMethod = SqlMethod.UPDATE_JOIN_AND_NULL; + String sql = String.format(sqlMethod.getSql(), sqlFirst(), mpjTableName(tableInfo), sqlAlias(), sqlFrom(), + mpjSqlSet(true, true, tableInfo, true, ENTITY, ENTITY_DOT), sqlWhereEntityWrapper(true, tableInfo), sqlComment()); + SqlSource sqlSource = languageDriver.createSqlSource(configuration, sql, modelClass); + return this.addUpdateMappedStatement(mapperClass, modelClass, sqlMethod.getMethod(), sqlSource); + } + + @Override + public String mpjConvertIfEwParam(String param, boolean newLine) { + return super.convertIfEwParam(param, newLine); + } + + /** + * 转换成 if 标签的脚本片段 + * + * @param sqlScript sql 脚本片段 + * @param property 字段名 + * @param fieldStrategy 验证策略 + * @return if 脚本片段 + */ + @Override + public String mpjConvertIf(TableFieldInfo tableFieldInfo, final String sqlScript, final String property, final FieldStrategy fieldStrategy) { + if (fieldStrategy == FieldStrategy.NEVER) { + return null; + } + return sqlScript; + } +} diff --git a/mybatis-plus-join-core/src/main/java/com/github/yulichang/toolkit/JoinWrappers.java b/mybatis-plus-join-core/src/main/java/com/github/yulichang/toolkit/JoinWrappers.java index 5e6600e..cd6c695 100644 --- a/mybatis-plus-join-core/src/main/java/com/github/yulichang/toolkit/JoinWrappers.java +++ b/mybatis-plus-join-core/src/main/java/com/github/yulichang/toolkit/JoinWrappers.java @@ -1,7 +1,9 @@ package com.github.yulichang.toolkit; import com.github.yulichang.query.MPJQueryWrapper; +import com.github.yulichang.wrapper.DeleteJoinWrapper; import com.github.yulichang.wrapper.MPJLambdaWrapper; +import com.github.yulichang.wrapper.UpdateJoinWrapper; /** * @author yulichang @@ -56,7 +58,7 @@ public class JoinWrappers { * JoinWrappers.lambda("t", User.class) */ public static MPJLambdaWrapper lambda(String alias, Class clazz) { - return new MPJLambdaWrapper(alias).setEntityClass(clazz); + return new MPJLambdaWrapper(clazz, alias); } /** @@ -70,6 +72,27 @@ public class JoinWrappers { * JoinWrappers.lambda("t", user) */ public static MPJLambdaWrapper lambda(String alias, T entity) { - return new MPJLambdaWrapper(alias).setEntity(entity); + return new MPJLambdaWrapper(entity, alias); + } + + /** + * JoinWrappers.delete(User.class) + */ + public static DeleteJoinWrapper delete(Class clazz) { + return new DeleteJoinWrapper<>(clazz); + } + + /** + * JoinWrappers.update(User.class) + */ + public static UpdateJoinWrapper update(Class clazz) { + return new UpdateJoinWrapper<>(clazz); + } + + /** + * JoinWrappers.update("t", User.class) + */ + public static UpdateJoinWrapper update(String alias, Class clazz) { + return new UpdateJoinWrapper<>(clazz, alias); } } diff --git a/mybatis-plus-join-core/src/main/java/com/github/yulichang/toolkit/LogicInfoUtils.java b/mybatis-plus-join-core/src/main/java/com/github/yulichang/toolkit/LogicInfoUtils.java index 0e2544a..ed2ff2e 100644 --- a/mybatis-plus-join-core/src/main/java/com/github/yulichang/toolkit/LogicInfoUtils.java +++ b/mybatis-plus-join-core/src/main/java/com/github/yulichang/toolkit/LogicInfoUtils.java @@ -22,13 +22,15 @@ public class LogicInfoUtils implements Constants { private static final Map, Map> LOGIC_CACHE_NO_AND = new ConcurrentHashMap<>(); + private static final Map, Map> LOGIC_CACHE_INVERT = new ConcurrentHashMap<>(); + public static String getLogicInfo(Integer tableIndex, Class clazz, boolean hasAlias, String alias) { Map absent = LOGIC_CACHE.get(clazz); if (absent == null) { absent = new ConcurrentHashMap<>(); LOGIC_CACHE.put(clazz, absent); } - return absent.computeIfAbsent(hasAlias ? alias : (alias + tableIndex), key -> getLogicStr(key, clazz, true)); + return absent.computeIfAbsent(hasAlias ? alias : (alias + tableIndex), key -> getLogicStr(key, clazz, true, false)); } public static String getLogicInfoNoAnd(Integer tableIndex, Class clazz, boolean hasAlias, String alias) { @@ -37,21 +39,31 @@ public class LogicInfoUtils implements Constants { absent = new ConcurrentHashMap<>(); LOGIC_CACHE_NO_AND.put(clazz, absent); } - return absent.computeIfAbsent(hasAlias ? alias : (alias + tableIndex), key -> getLogicStr(key, clazz, false)); + return absent.computeIfAbsent(hasAlias ? alias : (alias + tableIndex), key -> getLogicStr(key, clazz, false, false)); } - private static String getLogicStr(String prefix, Class clazz, boolean and) { + public static String getLogicInfoInvert(Integer tableIndex, Class clazz, boolean hasAlias, String alias) { + Map absent = LOGIC_CACHE_INVERT.get(clazz); + if (absent == null) { + absent = new ConcurrentHashMap<>(); + LOGIC_CACHE_INVERT.put(clazz, absent); + } + return absent.computeIfAbsent(hasAlias ? alias : (alias + tableIndex), key -> getLogicStr(key, clazz, false, true)); + } + private static String getLogicStr(String prefix, Class clazz, boolean and, boolean invert) { String logicStr; TableInfo tableInfo = TableHelper.get(clazz); Asserts.hasTable(tableInfo, clazz); TableFieldInfo logicField = ConfigProperties.tableInfoAdapter.mpjGetLogicField(tableInfo); if (ConfigProperties.tableInfoAdapter.mpjHasLogic(tableInfo) && Objects.nonNull(logicField)) { - final String value = logicField.getLogicNotDeleteValue(); - if (NULL.equalsIgnoreCase(value)) { - logicStr = (and ? " AND " : EMPTY) + prefix + DOT + logicField.getColumn() + " IS NULL"; + final String notDeleteValue = logicField.getLogicNotDeleteValue(); + final String deleteValue = logicField.getLogicDeleteValue(); + if (NULL.equalsIgnoreCase(notDeleteValue)) { + logicStr = (and ? " AND " : EMPTY) + prefix + DOT + logicField.getColumn() + (invert ? " IS NOT NULL" : " IS NULL"); } else { - logicStr = (and ? " AND " : EMPTY) + prefix + DOT + logicField.getColumn() + EQUALS + String.format(logicField.isCharSequence() ? "'%s'" : "%s", value); + logicStr = (and ? " AND " : EMPTY) + prefix + DOT + logicField.getColumn() + EQUALS + + String.format(logicField.isCharSequence() ? "'%s'" : "%s", invert ? deleteValue : notDeleteValue); } } else { logicStr = StringPool.EMPTY; diff --git a/mybatis-plus-join-core/src/main/java/com/github/yulichang/toolkit/TableList.java b/mybatis-plus-join-core/src/main/java/com/github/yulichang/toolkit/TableList.java index bd9e37f..4b0bea7 100644 --- a/mybatis-plus-join-core/src/main/java/com/github/yulichang/toolkit/TableList.java +++ b/mybatis-plus-join-core/src/main/java/com/github/yulichang/toolkit/TableList.java @@ -1,5 +1,6 @@ package com.github.yulichang.toolkit; +import com.baomidou.mybatisplus.core.toolkit.Assert; import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; import lombok.Data; @@ -155,11 +156,20 @@ public class TableList { } } + public String getPrefixByClassAssert(Class clazz) { + if (Objects.equals(clazz, rootClass)) { + return alias; + } + Node node = getByClassFirst(clazz); + Assert.notNull(node, "sql 中无法找到 <%s> 类对应的表", clazz.getSimpleName()); + return node.hasAlias ? node.getAlias() : (node.getAlias() + node.getIndex()); + } + private Node getByIndex(int index) { return all.stream().filter(i -> i.getIndex() == index).findFirst().orElse(null); } - private Node getByClassFirst(Class clazz) { + public Node getByClassFirst(Class clazz) { return all.stream().filter(i -> i.getClazz() == clazz).findFirst().orElse(null); } @@ -167,6 +177,17 @@ public class TableList { return all.stream().filter(i -> i.getClazz() == clazz).collect(Collectors.toList()); } + + public boolean contain(Class clazz) { + if (Objects.isNull(clazz)) { + return false; + } + if (rootClass != null && rootClass == clazz) { + return true; + } + return all.stream().anyMatch(i -> i.getClazz() == clazz); + } + public void clear() { this.all.clear(); this.child.clear(); diff --git a/mybatis-plus-join-core/src/main/java/com/github/yulichang/wrapper/DeleteJoinWrapper.java b/mybatis-plus-join-core/src/main/java/com/github/yulichang/wrapper/DeleteJoinWrapper.java new file mode 100644 index 0000000..f7b2c43 --- /dev/null +++ b/mybatis-plus-join-core/src/main/java/com/github/yulichang/wrapper/DeleteJoinWrapper.java @@ -0,0 +1,234 @@ +package com.github.yulichang.wrapper; + +import com.baomidou.mybatisplus.core.conditions.SharedString; +import com.baomidou.mybatisplus.core.conditions.segments.MergeSegments; +import com.baomidou.mybatisplus.core.metadata.TableInfo; +import com.baomidou.mybatisplus.core.toolkit.*; +import com.github.yulichang.adapter.AdapterHelper; +import com.github.yulichang.toolkit.Asserts; +import com.github.yulichang.toolkit.LogicInfoUtils; +import com.github.yulichang.toolkit.TableHelper; +import com.github.yulichang.toolkit.TableList; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Collectors; + +/** + * @author yulichang + * @since 1.4.5 + */ +public class DeleteJoinWrapper extends MPJAbstractLambdaWrapper> { + + /** + * 删除表 + */ + private final SharedString deleteSql = new SharedString(); + + /** + * 删除的表 + */ + private List> deleteTableList; + + /** + * 删除的表 + */ + private List deleteTableName; + + /** + * 是否删除主表以及所有副表 + */ + private boolean deleteAll = false; + + + private DeleteJoinWrapper() { + super(); + } + + /** + * 推荐使用此构造方法 + */ + public DeleteJoinWrapper(Class clazz) { + super(clazz); + } + + /** + * 构造方法 + * + * @param clazz 主表class类 + * @param alias 主表别名 + */ + public DeleteJoinWrapper(Class clazz, String alias) { + super(clazz, alias); + } + + /** + * 获取删除的表 + */ + @Override + @SuppressWarnings("UnusedReturnValue") + public String getDeleteSql() { + if (StringUtils.isNotBlank(this.deleteSql.getStringValue())) { + return this.deleteSql.getStringValue(); + } + String delete = null; + if (deleteAll) { + List tables = tableList.getAll().stream().map(i -> i.isHasAlias() ? i.getAlias() : + (i.getAlias() + i.getIndex())).collect(Collectors.toList()); + tables.add(0, this.alias); + delete = String.join(StringPool.COMMA, tables); + } else { + if (CollectionUtils.isNotEmpty(deleteTableList)) { + delete = deleteTableList.stream().map(c -> tableList.getPrefixByClassAssert(c)).collect(Collectors.joining(StringPool.COMMA)); + } + } + if (CollectionUtils.isNotEmpty(deleteTableName)) { + delete = delete + StringPool.COMMA + String.join(StringPool.COMMA, deleteTableName); + } + if (StringUtils.isBlank(delete)) { + delete = this.alias; + } + deleteSql.setStringValue(delete); + return delete; + } + + /** + * 获取删除的表 + */ + @Override + public String getDeleteLogicSql() { + if (StringUtils.isNotBlank(this.deleteSql.getStringValue())) { + return this.deleteSql.getStringValue(); + } + String delete = null; + if (deleteAll) { + delete = tableList.getAll().stream().map(i -> LogicInfoUtils.getLogicInfoInvert(i.getIndex(), i.getClazz(), + i.isHasAlias(), i.getAlias())).collect(Collectors.joining(StringPool.COMMA)); + } else { + if (CollectionUtils.isNotEmpty(deleteTableList)) { + delete = deleteTableList.stream().map(c -> tableList.getByClassFirst(c)).map(i -> + LogicInfoUtils.getLogicInfoInvert(i.getIndex(), i.getClazz(), i.isHasAlias(), i.getAlias())) + .collect(Collectors.joining(StringPool.COMMA)); + } + } + if (CollectionUtils.isNotEmpty(deleteTableName)) { + delete = delete + StringPool.COMMA + String.join(StringPool.COMMA, deleteTableName); + } + if (StringUtils.isNotBlank(delete)) { + delete = StringPool.COMMA + delete; + }else { + delete = StringPool.EMPTY; + } + deleteSql.setStringValue(delete); + return delete; + } + + /** + * 删除表 + */ + public DeleteJoinWrapper deleteAll() { + this.deleteAll = true; + return typedThis; + } + + /** + * 删除表 + */ + public DeleteJoinWrapper delete(String... tables) { + if (CollectionUtils.isEmpty(deleteTableName)) { + deleteTableName = new ArrayList<>(); + deleteTableName.addAll(Arrays.asList(tables)); + } + return typedThis; + } + + /** + * 删除表 + */ + public DeleteJoinWrapper delete(Class... deleteClass) { + Class entityClass = getEntityClass(); + Assert.notNull(entityClass, "缺少主表类型, 请使用 new MPJLambdaWrapper<>(主表.class) 或 JoinWrappers.lambda(主表.class) 构造方法"); + if (CollectionUtils.isEmpty(deleteTableList)) { + deleteTableList = new ArrayList<>(); + } + TableInfo tableInfo = TableHelper.get(entityClass); + Asserts.hasTable(tableInfo, entityClass); + //检查 + boolean mainLogic = AdapterHelper.getTableInfoAdapter().mpjHasLogic(tableInfo); + boolean check = Arrays.stream(deleteClass).allMatch(t -> { + TableInfo ti = TableHelper.get(t); + Asserts.hasTable(ti, t); + return mainLogic == AdapterHelper.getTableInfoAdapter().mpjHasLogic(ti); + }); + if (!check) { + List> list = Arrays.stream(deleteClass).collect(Collectors.toList()); + throw ExceptionUtils.mpe("连表删除只适用于全部表(主表和副表)都是物理删除或全部都是逻辑删除, " + + "不支持同时存在物理删除和逻辑删除 [物理删除->(%s)] [逻辑删除->(%s)]", + list.stream().filter(t -> !AdapterHelper.getTableInfoAdapter().mpjHasLogic(TableHelper.get(t))) + .map(Class::getSimpleName).collect(Collectors.joining(StringPool.COMMA)), + list.stream().filter(t -> AdapterHelper.getTableInfoAdapter().mpjHasLogic(TableHelper.get(t))) + .map(Class::getSimpleName).collect(Collectors.joining(StringPool.COMMA))); + } + deleteTableList.addAll(Arrays.asList(deleteClass)); + return typedThis; + } + + /** + * 用于生成嵌套 sql + *

故 sqlSelect 不向下传递

+ */ + @Override + protected DeleteJoinWrapper instance() { + return instance(index, null, null, null); + } + + @Override + protected DeleteJoinWrapper instanceEmpty() { + return new DeleteJoinWrapper<>(); + } + + @Override + protected DeleteJoinWrapper instance(Integer index, String keyWord, Class joinClass, String tableName) { + return new DeleteJoinWrapper<>(getEntity(), getEntityClass(), paramNameSeq, paramNameValuePairs, + new MergeSegments(), SharedString.emptyString(), SharedString.emptyString(), SharedString.emptyString(), + this.tableList, index, keyWord, joinClass, tableName); + } + + /** + * 不建议直接 new 该实例,使用 JoinWrappers.delete(User.class) + */ + public DeleteJoinWrapper(T entity, Class entityClass, AtomicInteger paramNameSeq, + Map paramNameValuePairs, MergeSegments mergeSegments, + SharedString lastSql, SharedString sqlComment, SharedString sqlFirst, + TableList tableList, Integer index, String keyWord, Class joinClass, String tableName) { + super.setEntity(entity); + super.setEntityClass(entityClass); + this.paramNameSeq = paramNameSeq; + this.paramNameValuePairs = paramNameValuePairs; + this.expression = mergeSegments; + this.lastSql = lastSql; + this.sqlComment = sqlComment; + this.sqlFirst = sqlFirst; + this.tableList = tableList; + this.index = index; + this.keyWord = keyWord; + this.joinClass = joinClass; + this.tableName = tableName; + } + + @Override + public void clear() { + super.clear(); + if (CollectionUtils.isNotEmpty(deleteTableList)) { + deleteTableList.clear(); + } + if (CollectionUtils.isNotEmpty(deleteTableName)) { + deleteTableName.clear(); + } + this.deleteSql.toNull(); + this.deleteAll = false; + } +} diff --git a/mybatis-plus-join-core/src/main/java/com/github/yulichang/wrapper/MPJAbstractLambdaWrapper.java b/mybatis-plus-join-core/src/main/java/com/github/yulichang/wrapper/MPJAbstractLambdaWrapper.java index 5bbc773..83338e6 100644 --- a/mybatis-plus-join-core/src/main/java/com/github/yulichang/wrapper/MPJAbstractLambdaWrapper.java +++ b/mybatis-plus-join-core/src/main/java/com/github/yulichang/wrapper/MPJAbstractLambdaWrapper.java @@ -10,11 +10,10 @@ import com.baomidou.mybatisplus.core.toolkit.StringUtils; import com.baomidou.mybatisplus.core.toolkit.support.SFunction; import com.github.yulichang.config.ConfigProperties; import com.github.yulichang.config.enums.LogicDelTypeEnum; -import com.github.yulichang.toolkit.LambdaUtils; -import com.github.yulichang.toolkit.TableHelper; -import com.github.yulichang.toolkit.TableList; +import com.github.yulichang.toolkit.*; import com.github.yulichang.toolkit.support.ColumnCache; import com.github.yulichang.wrapper.enums.PrefixEnum; +import com.github.yulichang.wrapper.interfaces.QueryJoin; import com.github.yulichang.wrapper.segments.SelectCache; import lombok.Getter; @@ -24,8 +23,11 @@ import java.util.Arrays; import java.util.HashMap; import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.BiConsumer; import java.util.function.Function; +import java.util.stream.Collectors; +import static com.baomidou.mybatisplus.core.enums.WrapperKeyword.APPLY; import static java.util.stream.Collectors.joining; /** @@ -35,7 +37,7 @@ import static java.util.stream.Collectors.joining; */ @SuppressWarnings({"DuplicatedCode", "unused"}) public abstract class MPJAbstractLambdaWrapper> - extends MPJAbstractWrapper { + extends MPJAbstractWrapper implements QueryJoin { /** * 主表别名 @@ -66,6 +68,97 @@ public abstract class MPJAbstractLambdaWrapper clazz) { + initNeed(); + setEntityClass(clazz); + tableList.setRootClass(clazz); + } + + /** + * 构造方法 + * + * @param entity 主表实体 + */ + public MPJAbstractLambdaWrapper(T entity) { + initNeed(); + setEntity(entity); + if (entity != null) { + tableList.setRootClass(entity.getClass()); + } + } + + /** + * 自定义主表别名 + */ + public MPJAbstractLambdaWrapper(String alias) { + this.alias = alias; + initNeed(); + tableList.setAlias(alias); + } + + /** + * 构造方法 + * + * @param clazz 主表class类 + * @param alias 主表别名 + */ + public MPJAbstractLambdaWrapper(Class clazz, String alias) { + this.alias = alias; + setEntityClass(clazz); + initNeed(); + tableList.setAlias(alias); + tableList.setRootClass(clazz); + } + + /** + * 构造方法 + * + * @param entity 主表实体类 + * @param alias 主表别名 + */ + public MPJAbstractLambdaWrapper(T entity, String alias) { + this.alias = alias; + setEntity(entity); + initNeed(); + tableList.setAlias(alias); + if (entity != null) { + tableList.setRootClass(entity.getClass()); + } + } + /** * 设置表别名 * 设置表别名注意sql注入问题 @@ -163,6 +256,165 @@ public abstract class MPJAbstractLambdaWrapper + * 副表逻辑删除默认在where语句中 + * 但有时候需要让它出现在on语句中, 这两种写法区别还是很大的 + * 所以可以关闭副表逻辑删除, 通过on语句多条件, 自己实现on语句的逻辑删除 + */ + public Children disableSubLogicDel() { + this.subLogicSql = false; + return typedThis; + } + + public Children enableSubLogicDel() { + this.subLogicSql = true; + return typedThis; + } + + /** + * 关闭主表逻辑删除 + */ + public Children disableLogicDel() { + this.logicSql = false; + return typedThis; + } + + public Children enableLogicDel() { + this.logicSql = true; + return typedThis; + } + + /** + * 副表部分逻辑删除支持 + */ + public String getSubLogicSql() { + if (subLogicSql && logicDelType == LogicDelTypeEnum.WHERE) { + if (tableList.getAll().isEmpty()) { + return StringPool.EMPTY; + } + return tableList.getAll().stream().map(t -> LogicInfoUtils.getLogicInfo(t.getIndex(), + t.getClazz(), t.isHasAlias(), t.getAlias())).collect(Collectors.joining(StringPool.SPACE)); + } + return StringPool.EMPTY; + } + + /** + * 主表部分逻辑删除支持 + */ + public boolean getLogicSql() { + return this.logicSql; + } + + /** + * 调整逻辑删除位置为ON语句 + */ + public Children logicDelToOn() { + this.logicDelType = LogicDelTypeEnum.ON; + return typedThis; + } + + /** + * 调整逻辑删除位置为WHERE语句 + */ + public Children logicDelToWhere() { + this.logicDelType = LogicDelTypeEnum.WHERE; + return typedThis; + } + + /** + * 获取连表部分语句 + */ + public String getFrom() { + if (StringUtils.isBlank(from.getStringValue())) { + StringBuilder value = new StringBuilder(); + for (Children wrapper : onWrappers) { + if (StringUtils.isBlank(wrapper.from.getStringValue())) { + if (wrapper.subLogicSql && this.logicDelType == LogicDelTypeEnum.ON) { + TableInfo tableInfo = TableHelper.get(wrapper.getJoinClass()); + if (ConfigProperties.tableInfoAdapter.mpjHasLogic(tableInfo)) { + wrapper.appendSqlSegments(APPLY, () -> LogicInfoUtils.getLogicInfoNoAnd( + wrapper.getIndex(), wrapper.getJoinClass(), wrapper.isHasAlias(), wrapper.getAlias() + )); + } + } + value.append(StringPool.SPACE) + .append(wrapper.getKeyWord()) + .append(StringPool.SPACE) + .append(wrapper.getTableName()) + .append(StringPool.SPACE) + .append(wrapper.hasAlias ? wrapper.alias : (wrapper.alias + wrapper.getIndex())) + .append(Constant.ON) + .append(wrapper.getExpression().getNormal().getSqlSegment()); + } else { + value.append(StringPool.SPACE) + .append(wrapper.getKeyWord()) + .append(StringPool.SPACE) + .append(wrapper.from.getStringValue()) + .append(StringPool.SPACE); + } + } + from.setStringValue(value.toString()); + } + return from.getStringValue(); + } + + public String getAlias() { + return alias; + } + + /** + * 内部调用, 不建议使用 + */ + @Override + public Children join(String keyWord, Class clazz, String tableAlias, BiConsumer, Children> consumer) { + Integer oldIndex = this.getIndex(); + int newIndex = tableIndex; + TableInfo info = TableHelper.get(clazz); + Asserts.hasTable(info, clazz); + Children instance = instance(newIndex, keyWord, clazz, info.getTableName()); + instance.isNo = true; + instance.isMain = false; + onWrappers.add(instance); + if (StringUtils.isBlank(tableAlias)) { + tableList.put(oldIndex, clazz, false, ConfigProperties.tableAlias, newIndex); + instance.alias = ConfigProperties.tableAlias; + instance.hasAlias = false; + } else { + tableList.put(oldIndex, clazz, true, tableAlias, newIndex); + instance.alias = tableAlias; + instance.hasAlias = true; + } + tableIndex++; + this.index = newIndex; + boolean isM = this.isMain; + this.isMain = false; + consumer.accept(instance, typedThis); + this.isMain = isM; + this.index = oldIndex; + return typedThis; + } + + + /** + * 自定义关键词连接 + * + * @param keyWord 连表关键词 + * @param condition 条件 + * @param joinSql sql + */ + @Override + public Children join(String keyWord, boolean condition, String joinSql) { + if (condition) { + Children wrapper = instanceEmpty(); + wrapper.from.setStringValue(joinSql); + wrapper.keyWord = keyWord; + onWrappers.add(wrapper); + } + return typedThis; + } + /** * 是否使用默认注解 {@link OrderBy} 排序 * @@ -191,4 +443,20 @@ public abstract class MPJAbstractLambdaWrapper> onWrappers = new ArrayList<>(); + protected final List onWrappers = new ArrayList<>(); /** - * ß * 数据库表映射实体类 */ private T entity; @@ -517,6 +516,10 @@ public abstract class MPJAbstractWrapper joinClass, String tableName); + /** * 格式化 sql *

@@ -604,6 +607,12 @@ public abstract class MPJAbstractWrapper columns.forEach(c -> appendSqlSegments(ORDER_BY, columnToSqlSegment(columnSqlInjectFilter(c)), isAsc ? ASC : DESC))); } - - } diff --git a/mybatis-plus-join-core/src/main/java/com/github/yulichang/wrapper/MPJLambdaWrapper.java b/mybatis-plus-join-core/src/main/java/com/github/yulichang/wrapper/MPJLambdaWrapper.java index 1f0cfdb..6b0a64a 100644 --- a/mybatis-plus-join-core/src/main/java/com/github/yulichang/wrapper/MPJLambdaWrapper.java +++ b/mybatis-plus-join-core/src/main/java/com/github/yulichang/wrapper/MPJLambdaWrapper.java @@ -14,7 +14,6 @@ import com.github.yulichang.toolkit.*; import com.github.yulichang.toolkit.support.ColumnCache; import com.github.yulichang.wrapper.interfaces.Chain; import com.github.yulichang.wrapper.interfaces.Query; -import com.github.yulichang.wrapper.interfaces.QueryJoin; import com.github.yulichang.wrapper.interfaces.QueryLabel; import com.github.yulichang.wrapper.resultmap.Label; import com.github.yulichang.wrapper.segments.Select; @@ -24,7 +23,6 @@ import lombok.Getter; import java.util.*; import java.util.concurrent.atomic.AtomicInteger; -import java.util.function.BiConsumer; import java.util.stream.Collectors; import static com.baomidou.mybatisplus.core.enums.WrapperKeyword.APPLY; @@ -37,12 +35,16 @@ import static com.baomidou.mybatisplus.core.enums.WrapperKeyword.APPLY; */ @SuppressWarnings({"unused"}) public class MPJLambdaWrapper extends MPJAbstractLambdaWrapper> implements - Query>, QueryJoin, T>, QueryLabel>, Chain { + Query>, QueryLabel>, Chain { /** - * 查询表 + * 查询字段 sql */ - private final SharedString from = new SharedString(); + private SharedString sqlSelect = new SharedString(); + /** + * 是否 select distinct + */ + private boolean selectDistinct = false; /** * 查询的字段 */ @@ -53,47 +55,20 @@ public class MPJLambdaWrapper extends MPJAbstractLambdaWrapper> resultMapMybatisLabel = new ArrayList<>(); - /** - * 是否有表别名 - */ - @Getter - private boolean hasAlias; - /** - * 查询字段 sql - */ - private SharedString sqlSelect = new SharedString(); - /** - * 是否 select distinct - */ - private boolean selectDistinct = false; - /** - * 连表关键字 on 条件 func 使用 - */ - @Getter - private String keyWord; - /** - * 副表逻辑删除开关 - */ - private boolean subLogicSql = ConfigProperties.subTableLogic; - /** - * 主表逻辑删除开关 - */ - private boolean logicSql = true; + /** * 推荐使用 带 class 的构造方法 */ public MPJLambdaWrapper() { - super.initNeed(); + super(); } /** * 推荐使用此构造方法 */ public MPJLambdaWrapper(Class clazz) { - super.initNeed(); - setEntityClass(clazz); - tableList.setRootClass(clazz); + super(clazz); } /** @@ -102,20 +77,14 @@ public class MPJLambdaWrapper extends MPJAbstractLambdaWrapper extends MPJAbstractLambdaWrapper clazz, String alias) { - this.alias = alias; - setEntityClass(clazz); - super.initNeed(); - tableList.setAlias(alias); - tableList.setRootClass(clazz); + super(clazz, alias); } /** @@ -139,18 +104,11 @@ public class MPJLambdaWrapper extends MPJAbstractLambdaWrapperlambdaQuery() + * 不建议直接 new 该实例,使用 JoinWrappers.lambda(UserDO.class) */ MPJLambdaWrapper(T entity, Class entityClass, SharedString sqlSelect, AtomicInteger paramNameSeq, Map paramNameValuePairs, MergeSegments mergeSegments, @@ -266,47 +224,6 @@ public class MPJLambdaWrapper extends MPJAbstractLambdaWrapper wrapper : onWrappers) { - if (StringUtils.isBlank(wrapper.from.getStringValue())) { - if (wrapper.subLogicSql && this.logicDelType == LogicDelTypeEnum.ON) { - TableInfo tableInfo = TableHelper.get(wrapper.getJoinClass()); - if (ConfigProperties.tableInfoAdapter.mpjHasLogic(tableInfo)) { - wrapper.appendSqlSegments(APPLY, () -> LogicInfoUtils.getLogicInfoNoAnd( - wrapper.getIndex(), wrapper.getJoinClass(), wrapper.isHasAlias(), wrapper.getAlias() - )); - } - } - value.append(StringPool.SPACE) - .append(wrapper.getKeyWord()) - .append(StringPool.SPACE) - .append(wrapper.getTableName()) - .append(StringPool.SPACE) - .append(wrapper.hasAlias ? wrapper.alias : (wrapper.alias + wrapper.getIndex())) - .append(Constant.ON) - .append(wrapper.getExpression().getNormal().getSqlSegment()); - } else { - value.append(StringPool.SPACE) - .append(wrapper.getKeyWord()) - .append(StringPool.SPACE) - .append(wrapper.from.getStringValue()) - .append(StringPool.SPACE); - } - } - from.setStringValue(value.toString()); - } - return from.getStringValue(); - } - - public String getAlias() { - return alias; - } - public boolean getSelectDistinct() { return selectDistinct; @@ -321,6 +238,12 @@ public class MPJLambdaWrapper extends MPJAbstractLambdaWrapper instanceEmpty() { + return new MPJLambdaWrapper<>(); + } + + @Override protected MPJLambdaWrapper instance(Integer index, String keyWord, Class joinClass, String tableName) { return new MPJLambdaWrapper<>(getEntity(), getEntityClass(), null, paramNameSeq, paramNameValuePairs, new MergeSegments(), SharedString.emptyString(), SharedString.emptyString(), SharedString.emptyString(), @@ -330,127 +253,9 @@ public class MPJLambdaWrapper extends MPJAbstractLambdaWrapper - * 副表逻辑删除默认在where语句中 - * 但有时候需要让它出现在on语句中, 这两种写法区别还是很大的 - * 所以可以关闭副表逻辑删除, 通过on语句多条件, 自己实现on语句的逻辑删除 - */ - public MPJLambdaWrapper disableSubLogicDel() { - this.subLogicSql = false; - return typedThis; - } - - public MPJLambdaWrapper enableSubLogicDel() { - this.subLogicSql = true; - return typedThis; - } - - /** - * 关闭主表逻辑删除 - */ - public MPJLambdaWrapper disableLogicDel() { - this.logicSql = false; - return typedThis; - } - - public MPJLambdaWrapper enableLogicDel() { - this.logicSql = true; - return typedThis; - } - - /** - * 副表部分逻辑删除支持 - */ - public String getSubLogicSql() { - if (subLogicSql && logicDelType == LogicDelTypeEnum.WHERE) { - if (tableList.getAll().isEmpty()) { - return StringPool.EMPTY; - } - return tableList.getAll().stream().map(t -> LogicInfoUtils.getLogicInfo(t.getIndex(), - t.getClazz(), t.isHasAlias(), t.getAlias())).collect(Collectors.joining(StringPool.SPACE)); - } - return StringPool.EMPTY; - } - - /** - * 主表部分逻辑删除支持 - */ - public boolean getLogicSql() { - return this.logicSql; - } - - /** - * 调整逻辑删除位置为ON语句 - */ - public MPJLambdaWrapper logicDelToOn() { - this.logicDelType = LogicDelTypeEnum.ON; - return typedThis; - } - - /** - * 调整逻辑删除位置为WHERE语句 - */ - public MPJLambdaWrapper logicDelToWhere() { - this.logicDelType = LogicDelTypeEnum.WHERE; - return typedThis; - } - - /** - * 内部调用, 不建议使用 - */ - @Override - public MPJLambdaWrapper join(String keyWord, Class clazz, String tableAlias, BiConsumer, MPJLambdaWrapper> consumer) { - Integer oldIndex = this.getIndex(); - int newIndex = tableIndex; - TableInfo info = TableHelper.get(clazz); - Asserts.hasTable(info, clazz); - MPJLambdaWrapper instance = instance(newIndex, keyWord, clazz, info.getTableName()); - instance.isNo = true; - instance.isMain = false; - onWrappers.add(instance); - if (StringUtils.isBlank(tableAlias)) { - tableList.put(oldIndex, clazz, false, ConfigProperties.tableAlias, newIndex); - instance.alias = ConfigProperties.tableAlias; - instance.hasAlias = false; - } else { - tableList.put(oldIndex, clazz, true, tableAlias, newIndex); - instance.alias = tableAlias; - instance.hasAlias = true; - } - tableIndex++; - this.index = newIndex; - boolean isM = this.isMain; - this.isMain = false; - consumer.accept(instance, typedThis); - this.isMain = isM; - this.index = oldIndex; - return typedThis; - } - - - /** - * 自定义关键词连接 - * - * @param keyWord 连表关键词 - * @param condition 条件 - * @param joinSql sql - */ - @Override - public MPJLambdaWrapper join(String keyWord, boolean condition, String joinSql) { - if (condition) { - MPJLambdaWrapper wrapper = new MPJLambdaWrapper<>(); - wrapper.from.setStringValue(joinSql); - wrapper.keyWord = keyWord; - onWrappers.add(wrapper); - } - return typedThis; + resultMapMybatisLabel.clear(); } } diff --git a/mybatis-plus-join-core/src/main/java/com/github/yulichang/wrapper/UpdateJoinWrapper.java b/mybatis-plus-join-core/src/main/java/com/github/yulichang/wrapper/UpdateJoinWrapper.java new file mode 100644 index 0000000..5ad6ce6 --- /dev/null +++ b/mybatis-plus-join-core/src/main/java/com/github/yulichang/wrapper/UpdateJoinWrapper.java @@ -0,0 +1,252 @@ +package com.github.yulichang.wrapper; + +import com.baomidou.mybatisplus.core.conditions.SharedString; +import com.baomidou.mybatisplus.core.conditions.segments.MergeSegments; +import com.baomidou.mybatisplus.core.metadata.TableFieldInfo; +import com.baomidou.mybatisplus.core.metadata.TableInfo; +import com.baomidou.mybatisplus.core.toolkit.*; +import com.baomidou.mybatisplus.core.toolkit.support.SFunction; +import com.github.yulichang.adapter.AdapterHelper; +import com.github.yulichang.toolkit.Asserts; +import com.github.yulichang.toolkit.LambdaUtils; +import com.github.yulichang.toolkit.TableHelper; +import com.github.yulichang.toolkit.TableList; +import com.github.yulichang.wrapper.interfaces.Update; +import lombok.AllArgsConstructor; +import lombok.Data; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Collectors; + +/** + * @author yulichang + * @since 1.4.5 + */ +@SuppressWarnings("unused") +public class UpdateJoinWrapper extends MPJAbstractLambdaWrapper> + implements Update> { + /** + * SQL 更新字段内容,例如:name='1', age=2 + */ + private final SharedString sqlSetStr = new SharedString(); + /** + * SQL 更新字段内容,例如:name='1', age=2 + */ + private List sqlSet; + /** + * SQL 更新字段内容,例如:name='1', age=2 + */ + private List updateSet; + /** + * SQL 更新实体(更新非空字段) + */ + private List updateEntity; + /** + * SQL 更新实体(空字段也会更新) + */ + private List updateEntityNull; + + private UpdateJoinWrapper() { + super(); + } + + /** + * 推荐使用此构造方法 + */ + public UpdateJoinWrapper(Class clazz) { + super(clazz); + } + + public UpdateJoinWrapper(T entity) { + super(entity); + } + + public UpdateJoinWrapper(Class clazz, String alias) { + super(clazz, alias); + } + + public UpdateJoinWrapper(T entity, String alias) { + super(entity, alias); + } + + /** + * 设置更新的实体set语句部分, 更新非空字段 + *

+ * 注意!!! + * 这里这是的实体类是set部分, 不作为条件, where条件是wrapper.setEntity() + */ + public UpdateJoinWrapper setUpdateEntity(Object... entity) { + if (Objects.isNull(updateEntity)) { + updateEntity = new ArrayList<>(); + } + for (Object obj : entity) { + Assert.notNull(obj, "更新实体不能为空"); + updateEntity.add(obj); + } + return typedThis; + } + + /** + * 设置更新的实体set语句部分, 更新非空字段 + *

+ * 注意!!! + * 这里这是的实体类是set部分, 不作为条件, where条件是wrapper.setEntity() + */ + public UpdateJoinWrapper setUpdateEntityAndNull(Object... entity) { + if (Objects.isNull(updateEntityNull)) { + updateEntityNull = new ArrayList<>(); + } + for (Object obj : entity) { + Assert.notNull(obj, "更新实体不能为空"); + updateEntityNull.add(obj); + } + return typedThis; + } + + @Override + public UpdateJoinWrapper set(boolean condition, SFunction column, Object val, String mapping) { + return maybeDo(condition, () -> { + if (Objects.isNull(updateSet)) { + updateSet = new ArrayList<>(); + } + updateSet.add(new UpdateSet(column, val, mapping)); + }); + } + + @Override + public UpdateJoinWrapper setSql(boolean condition, String sql) { + if (condition && StringUtils.isNotBlank(sql)) { + if (Objects.isNull(sqlSet)) { + sqlSet = new ArrayList<>(); + } + sqlSet.add(sql); + } + return typedThis; + } + + @Override + public String getSqlSet() { + if (StringUtils.isNotBlank(sqlSetStr.getStringValue())) { + return sqlSetStr.getStringValue(); + } + StringBuilder set = new StringBuilder(StringPool.EMPTY); + if (CollectionUtils.isNotEmpty(updateSet)) { + set = new StringBuilder(updateSet.stream().map(i -> tableList.getPrefixByClass(LambdaUtils.getEntityClass(i.getColumn())) + + Constants.DOT + getCache(i.getColumn()).getColumn() + Constants.EQUALS + formatParam(i.mapping, i.value)) + .collect(Collectors.joining(StringPool.COMMA)) + StringPool.COMMA); + } + if (CollectionUtils.isNotEmpty(sqlSet)) { + set.append(String.join(StringPool.COMMA, sqlSet)).append(StringPool.COMMA); + } + if (CollectionUtils.isNotEmpty(updateEntity)) { + getSqlByEntity(set, true, updateEntity); + } + if (CollectionUtils.isNotEmpty(updateEntityNull)) { + getSqlByEntity(set, false, updateEntityNull); + } + sqlSetStr.setStringValue(set.toString()); + return set.toString(); + } + + /** + * 用于生成嵌套 sql + *

故 sqlSelect 不向下传递

+ */ + @Override + protected UpdateJoinWrapper instance() { + return instance(index, null, null, null); + } + + @Override + protected UpdateJoinWrapper instanceEmpty() { + return new UpdateJoinWrapper<>(); + } + + @Override + protected UpdateJoinWrapper instance(Integer index, String keyWord, Class joinClass, String tableName) { + return new UpdateJoinWrapper<>(getEntity(), getEntityClass(), paramNameSeq, paramNameValuePairs, + new MergeSegments(), SharedString.emptyString(), SharedString.emptyString(), SharedString.emptyString(), + this.tableList, index, keyWord, joinClass, tableName); + } + + /** + * 不建议直接 new 该实例,使用 JoinWrappers.update(User.class) + */ + public UpdateJoinWrapper(T entity, Class entityClass, AtomicInteger paramNameSeq, + Map paramNameValuePairs, MergeSegments mergeSegments, + SharedString lastSql, SharedString sqlComment, SharedString sqlFirst, + TableList tableList, Integer index, String keyWord, Class joinClass, String tableName) { + super.setEntity(entity); + super.setEntityClass(entityClass); + this.paramNameSeq = paramNameSeq; + this.paramNameValuePairs = paramNameValuePairs; + this.expression = mergeSegments; + this.lastSql = lastSql; + this.sqlComment = sqlComment; + this.sqlFirst = sqlFirst; + this.tableList = tableList; + this.index = index; + this.keyWord = keyWord; + this.joinClass = joinClass; + this.tableName = tableName; + } + + private void getSqlByEntity(StringBuilder sb, boolean filterNull, List entityList) { + for (Object obj : entityList) { + Assert.isTrue(tableList.contain(obj.getClass()), "更新的实体不是主表或关联表 <%>", obj.getClass().getSimpleName()); + TableInfo tableInfo = TableHelper.get(obj.getClass()); + Asserts.hasTable(tableInfo, obj.getClass()); + for (TableFieldInfo fieldInfo : tableInfo.getFieldList()) { + if (AdapterHelper.getTableInfoAdapter().mpjHasLogic(tableInfo) && fieldInfo.isLogicDelete()) { + continue; + } + Object val; + try { + val = fieldInfo.getField().get(obj); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + if (filterNull && Objects.isNull(val)) { + continue; + } + sb.append(tableList.getPrefixByClass(obj.getClass())).append(Constants.DOT) + .append(fieldInfo.getColumn()).append(Constants.EQUALS).append(formatParam(null, val)) + .append(StringPool.COMMA); + } + } + } + + @Override + public void clear() { + super.clear(); + sqlSetStr.toNull(); + if (CollectionUtils.isNotEmpty(sqlSet)) { + sqlSet.clear(); + } + if (CollectionUtils.isNotEmpty(updateSet)) { + updateSet.clear(); + } + if (CollectionUtils.isNotEmpty(updateEntity)) { + updateEntity.clear(); + } + if (CollectionUtils.isNotEmpty(updateEntityNull)) { + updateEntityNull.clear(); + } + } + + + @Data + @AllArgsConstructor + public static class UpdateSet { + + private SFunction column; + + private Object value; + + private String mapping; + } +} diff --git a/mybatis-plus-join-core/src/main/java/com/github/yulichang/wrapper/interfaces/QueryJoin.java b/mybatis-plus-join-core/src/main/java/com/github/yulichang/wrapper/interfaces/QueryJoin.java index 8d09e45..f4abfac 100644 --- a/mybatis-plus-join-core/src/main/java/com/github/yulichang/wrapper/interfaces/QueryJoin.java +++ b/mybatis-plus-join-core/src/main/java/com/github/yulichang/wrapper/interfaces/QueryJoin.java @@ -5,7 +5,6 @@ import com.github.yulichang.interfaces.MPJBaseJoin; import com.github.yulichang.query.interfaces.StringJoin; import com.github.yulichang.toolkit.Constant; import com.github.yulichang.wrapper.MPJAbstractLambdaWrapper; -import com.github.yulichang.wrapper.MPJLambdaWrapper; import java.util.function.BiConsumer; @@ -45,7 +44,7 @@ public interface QueryJoin extends MPJBaseJoin, String * @param left 条件 * @param right 条件 */ - default Children leftJoin(Class clazz, SFunction left, SFunction right, WrapperFunction> ext) { + default Children leftJoin(Class clazz, SFunction left, SFunction right, WrapperFunction ext) { return join(Constant.LEFT_JOIN, clazz, left, right, ext); } @@ -57,7 +56,7 @@ public interface QueryJoin extends MPJBaseJoin, String * @param clazz 关联实体类 * @param consumer 条件 */ - default Children leftJoin(Class clazz, BiConsumer, MPJLambdaWrapper> consumer) { + default Children leftJoin(Class clazz, BiConsumer, Children> consumer) { return join(Constant.LEFT_JOIN, clazz, consumer); } @@ -91,7 +90,7 @@ public interface QueryJoin extends MPJBaseJoin, String * @param left 条件 * @param right 条件 */ - default Children leftJoin(Class clazz, String alias, SFunction left, SFunction right, WrapperFunction> ext) { + default Children leftJoin(Class clazz, String alias, SFunction left, SFunction right, WrapperFunction ext) { return join(Constant.LEFT_JOIN, clazz, alias, left, right, ext); } @@ -103,7 +102,7 @@ public interface QueryJoin extends MPJBaseJoin, String * @param clazz 关联实体类 * @param consumer 条件 */ - default Children leftJoin(Class clazz, String alias, BiConsumer, MPJLambdaWrapper> consumer) { + default Children leftJoin(Class clazz, String alias, BiConsumer, Children> consumer) { return join(Constant.LEFT_JOIN, clazz, alias, consumer); } @@ -124,14 +123,14 @@ public interface QueryJoin extends MPJBaseJoin, String /** * ignore 参考 left join */ - default Children rightJoin(Class clazz, SFunction left, SFunction right, WrapperFunction> ext) { + default Children rightJoin(Class clazz, SFunction left, SFunction right, WrapperFunction ext) { return join(Constant.RIGHT_JOIN, clazz, left, right, ext); } /** * ignore 参考 left join */ - default Children rightJoin(Class clazz, BiConsumer, MPJLambdaWrapper> consumer) { + default Children rightJoin(Class clazz, BiConsumer, Children> consumer) { return join(Constant.RIGHT_JOIN, clazz, consumer); } @@ -152,14 +151,14 @@ public interface QueryJoin extends MPJBaseJoin, String /** * ignore 参考 left join */ - default Children rightJoin(Class clazz, String alias, SFunction left, SFunction right, WrapperFunction> ext) { + default Children rightJoin(Class clazz, String alias, SFunction left, SFunction right, WrapperFunction ext) { return join(Constant.RIGHT_JOIN, clazz, alias, left, right, ext); } /** * ignore 参考 left join */ - default Children rightJoin(Class clazz, String alias, BiConsumer, MPJLambdaWrapper> consumer) { + default Children rightJoin(Class clazz, String alias, BiConsumer, Children> consumer) { return join(Constant.RIGHT_JOIN, clazz, alias, consumer); } @@ -181,14 +180,14 @@ public interface QueryJoin extends MPJBaseJoin, String /** * ignore 参考 left join */ - default Children innerJoin(Class clazz, SFunction left, SFunction right, WrapperFunction> ext) { + default Children innerJoin(Class clazz, SFunction left, SFunction right, WrapperFunction ext) { return join(Constant.INNER_JOIN, clazz, left, right, ext); } /** * ignore 参考 left join */ - default Children innerJoin(Class clazz, BiConsumer, MPJLambdaWrapper> consumer) { + default Children innerJoin(Class clazz, BiConsumer, Children> consumer) { return join(Constant.INNER_JOIN, clazz, consumer); } @@ -210,14 +209,14 @@ public interface QueryJoin extends MPJBaseJoin, String /** * ignore 参考 left join */ - default Children innerJoin(Class clazz, String alias, SFunction left, SFunction right, WrapperFunction> ext) { + default Children innerJoin(Class clazz, String alias, SFunction left, SFunction right, WrapperFunction ext) { return join(Constant.INNER_JOIN, clazz, alias, left, right, ext); } /** * ignore 参考 left join */ - default Children innerJoin(Class clazz, String alias, BiConsumer, MPJLambdaWrapper> consumer) { + default Children innerJoin(Class clazz, String alias, BiConsumer, Children> consumer) { return join(Constant.INNER_JOIN, clazz, alias, consumer); } @@ -238,14 +237,14 @@ public interface QueryJoin extends MPJBaseJoin, String /** * ignore 参考 left join */ - default Children fullJoin(Class clazz, SFunction left, SFunction right, WrapperFunction> ext) { + default Children fullJoin(Class clazz, SFunction left, SFunction right, WrapperFunction ext) { return join(Constant.FULL_JOIN, clazz, left, right, ext); } /** * ignore 参考 left join */ - default Children fullJoin(Class clazz, BiConsumer, MPJLambdaWrapper> consumer) { + default Children fullJoin(Class clazz, BiConsumer, Children> consumer) { return join(Constant.FULL_JOIN, clazz, consumer); } @@ -266,14 +265,14 @@ public interface QueryJoin extends MPJBaseJoin, String /** * ignore 参考 left join */ - default Children fullJoin(Class clazz, String alias, SFunction left, SFunction right, WrapperFunction> ext) { + default Children fullJoin(Class clazz, String alias, SFunction left, SFunction right, WrapperFunction ext) { return join(Constant.FULL_JOIN, clazz, alias, left, right, ext); } /** * ignore 参考 left join */ - default Children fullJoin(Class clazz, String alias, BiConsumer, MPJLambdaWrapper> consumer) { + default Children fullJoin(Class clazz, String alias, BiConsumer, Children> consumer) { return join(Constant.FULL_JOIN, clazz, alias, consumer); } @@ -311,7 +310,7 @@ public interface QueryJoin extends MPJBaseJoin, String * @param left 条件 * @param right 条件 */ - default Children join(String keyWord, Class clazz, SFunction left, SFunction right, WrapperFunction> ext) { + default Children join(String keyWord, Class clazz, SFunction left, SFunction right, WrapperFunction ext) { return join(keyWord, clazz, (on, e) -> { on.eq(left, right); ext.apply(e); @@ -352,7 +351,7 @@ public interface QueryJoin extends MPJBaseJoin, String * @param left 条件 * @param right 条件 */ - default Children join(String keyWord, Class clazz, String alias, SFunction left, SFunction right, WrapperFunction> ext) { + default Children join(String keyWord, Class clazz, String alias, SFunction left, SFunction right, WrapperFunction ext) { return join(keyWord, clazz, alias, (on, e) -> { on.eq(left, right); ext.apply(e); @@ -362,12 +361,12 @@ public interface QueryJoin extends MPJBaseJoin, String /** * 内部使用, 不建议直接调用 */ - default Children join(String keyWord, Class clazz, BiConsumer, MPJLambdaWrapper> consumer) { + default Children join(String keyWord, Class clazz, BiConsumer, Children> consumer) { return join(keyWord, clazz, null, consumer); } /** * 内部使用, 不建议直接调用 */ - Children join(String keyWord, Class clazz, String alias, BiConsumer, MPJLambdaWrapper> consumer); + Children join(String keyWord, Class clazz, String alias, BiConsumer, Children> consumer); } diff --git a/mybatis-plus-join-core/src/main/java/com/github/yulichang/wrapper/interfaces/Update.java b/mybatis-plus-join-core/src/main/java/com/github/yulichang/wrapper/interfaces/Update.java new file mode 100644 index 0000000..3130c26 --- /dev/null +++ b/mybatis-plus-join-core/src/main/java/com/github/yulichang/wrapper/interfaces/Update.java @@ -0,0 +1,72 @@ +package com.github.yulichang.wrapper.interfaces; + +import com.baomidou.mybatisplus.core.toolkit.support.SFunction; + +import java.io.Serializable; + +/** + * copy {@link com.baomidou.mybatisplus.core.conditions.update.Update} + * + * @author yulichang + * @since 1.4.5 + */ +@SuppressWarnings("unused") +public interface Update extends Serializable { + + /** + * ignore + */ + default Children set(SFunction column, Object val) { + return set(true, column, val); + } + + /** + * 设置 更新 SQL 的 SET 片段 + * + * @param condition 是否加入 set + * @param column 字段 + * @param val 值 + * @return children + */ + default Children set(boolean condition, SFunction column, Object val) { + return set(condition, column, val, null); + } + + /** + * ignore + */ + default Children set(SFunction column, Object val, String mapping) { + return set(true, column, val, mapping); + } + + /** + * 设置 更新 SQL 的 SET 片段 + * + * @param condition 是否加入 set + * @param column 字段 + * @param val 值 + * @param mapping 例: javaType=int,jdbcType=NUMERIC,typeHandler=xxx.xxx.MyTypeHandler + * @return children + */ + Children set(boolean condition, SFunction column, Object val, String mapping); + + /** + * ignore + */ + default Children setSql(String sql) { + return setSql(true, sql); + } + + /** + * 设置 更新 SQL 的 SET 片段 + * + * @param sql set sql + * @return children + */ + Children setSql(boolean condition, String sql); + + /** + * 获取 更新 SQL 的 SET 片段 + */ + String getSqlSet(); +} diff --git a/mybatis-plus-join-test/test-base/src/main/java/com/github/yulichang/test/config/MybatisPlusConfig.java b/mybatis-plus-join-test/test-base/src/main/java/com/github/yulichang/test/config/MybatisPlusConfig.java index 293292b..3335def 100644 --- a/mybatis-plus-join-test/test-base/src/main/java/com/github/yulichang/test/config/MybatisPlusConfig.java +++ b/mybatis-plus-join-test/test-base/src/main/java/com/github/yulichang/test/config/MybatisPlusConfig.java @@ -72,22 +72,6 @@ public class MybatisPlusConfig { }; } -// @Bean -// @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection") -// public SqlSessionFactory sqlSessionFactory(DataSource dataSource, -// MybatisPlusInterceptor interceptor) throws Exception { -// MybatisSqlSessionFactoryBean factory = new MybatisSqlSessionFactoryBean(); -// factory.setDataSource(dataSource); -// GlobalConfig.DbConfig config = new GlobalConfig.DbConfig(); -// config.setLogicDeleteField("del"); -// config.setLogicDeleteValue("true"); -// config.setLogicNotDeleteValue("false"); -// factory.setGlobalConfig(new GlobalConfig().setSqlInjector(new MPJSqlInjector()) -// .setDbConfig(config)); -// factory.setPlugins(interceptor); -// return factory.getObject(); -// } - /** * 校验sql */ diff --git a/mybatis-plus-join-test/test-join/src/main/java/com/github/yulichang/test/join/entity/AddressDO.java b/mybatis-plus-join-test/test-join/src/main/java/com/github/yulichang/test/join/entity/AddressDO.java index c152959..35bb725 100644 --- a/mybatis-plus-join-test/test-join/src/main/java/com/github/yulichang/test/join/entity/AddressDO.java +++ b/mybatis-plus-join-test/test-join/src/main/java/com/github/yulichang/test/join/entity/AddressDO.java @@ -1,14 +1,20 @@ package com.github.yulichang.test.join.entity; +import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableName; -import lombok.ToString; +import lombok.*; import lombok.experimental.Accessors; import java.io.Serializable; +@Data +@EqualsAndHashCode(callSuper = true) @ToString @Accessors(chain = true) @TableName("address") public class AddressDO extends AddressGeneric implements Serializable { + @TableField(exist = false) + private boolean aaa; + } diff --git a/mybatis-plus-join-test/test-join/src/main/java/com/github/yulichang/test/join/entity/AddressGeneric.java b/mybatis-plus-join-test/test-join/src/main/java/com/github/yulichang/test/join/entity/AddressGeneric.java index c0f403e..a0223b5 100644 --- a/mybatis-plus-join-test/test-join/src/main/java/com/github/yulichang/test/join/entity/AddressGeneric.java +++ b/mybatis-plus-join-test/test-join/src/main/java/com/github/yulichang/test/join/entity/AddressGeneric.java @@ -4,8 +4,10 @@ package com.github.yulichang.test.join.entity; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableLogic; import lombok.Data; +import lombok.experimental.Accessors; @Data +@Accessors(chain = true) public class AddressGeneric { @TableId diff --git a/mybatis-plus-join-test/test-join/src/main/java/com/github/yulichang/test/join/entity/OrderDO.java b/mybatis-plus-join-test/test-join/src/main/java/com/github/yulichang/test/join/entity/OrderDO.java new file mode 100644 index 0000000..541e584 --- /dev/null +++ b/mybatis-plus-join-test/test-join/src/main/java/com/github/yulichang/test/join/entity/OrderDO.java @@ -0,0 +1,30 @@ +package com.github.yulichang.test.join.entity; + +import com.baomidou.mybatisplus.annotation.OrderBy; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.ToString; +import lombok.experimental.Accessors; +import org.springframework.core.annotation.Order; + +import java.io.Serializable; + +@Data +@ToString +@Accessors(chain = true) +@TableName("order_t") +public class OrderDO implements Serializable { + + @TableId + private Integer id; + + private Integer userId; + + @OrderBy + private String name; + + @TableField(exist = false) + private String userName; +} diff --git a/mybatis-plus-join-test/test-join/src/main/java/com/github/yulichang/test/join/mapper/OrderMapper.java b/mybatis-plus-join-test/test-join/src/main/java/com/github/yulichang/test/join/mapper/OrderMapper.java new file mode 100644 index 0000000..53fd2e3 --- /dev/null +++ b/mybatis-plus-join-test/test-join/src/main/java/com/github/yulichang/test/join/mapper/OrderMapper.java @@ -0,0 +1,10 @@ +package com.github.yulichang.test.join.mapper; + +import com.github.yulichang.test.join.entity.OrderDO; +import com.github.yulichang.test.join.entity.UserDO; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface OrderMapper extends MyBaseMapper { + +} diff --git a/mybatis-plus-join-test/test-join/src/main/resources/db/data.sql b/mybatis-plus-join-test/test-join/src/main/resources/db/data.sql index 165e33c..55ec13a 100644 --- a/mybatis-plus-join-test/test-join/src/main/resources/db/data.sql +++ b/mybatis-plus-join-test/test-join/src/main/resources/db/data.sql @@ -88,4 +88,15 @@ INSERT INTO user_dto (id, user_id, create_by, update_by, del) VALUES (5,1, 2, 3, false), (6,1, 2, 3, false), (7,1, 2, 3, false), -(8,1, 2, 3, false); \ No newline at end of file +(8,1, 2, 3, false); + +DELETE FROM order_t; +INSERT INTO order_t (id, user_id, age, name) VALUES +(1, 1, 8, '1,8'), +(2, 2, 7, '2,7'), +(3, 3, 6, '3,6'), +(4, 4, 5, '4,5'), +(5, 5, 4, '5,4'), +(6, 6, 3, '6,3'), +(7, 7, 2, '7,2'), +(8, 8, 1, '8,1'); \ No newline at end of file diff --git a/mybatis-plus-join-test/test-join/src/main/resources/db/schema.sql b/mybatis-plus-join-test/test-join/src/main/resources/db/schema.sql index e5f2bf4..6bdc76e 100644 --- a/mybatis-plus-join-test/test-join/src/main/resources/db/schema.sql +++ b/mybatis-plus-join-test/test-join/src/main/resources/db/schema.sql @@ -56,3 +56,12 @@ create table user_dto update_by int not null, del bit null ); + +create table order_t +( + id int auto_increment + primary key, + user_id int not null, + age int not null, + name varchar(255) not null +); diff --git a/mybatis-plus-join-test/test-join/src/test/java/com/github/yulichang/test/join/LambdaWrapperTest.java b/mybatis-plus-join-test/test-join/src/test/java/com/github/yulichang/test/join/LambdaWrapperTest.java index 0febcd6..a7d8bda 100644 --- a/mybatis-plus-join-test/test-join/src/test/java/com/github/yulichang/test/join/LambdaWrapperTest.java +++ b/mybatis-plus-join-test/test-join/src/test/java/com/github/yulichang/test/join/LambdaWrapperTest.java @@ -6,17 +6,16 @@ import com.baomidou.mybatisplus.core.toolkit.StringUtils; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.github.yulichang.test.join.dto.AddressDTO; import com.github.yulichang.test.join.dto.UserDTO; -import com.github.yulichang.test.join.entity.AddressDO; -import com.github.yulichang.test.join.entity.AreaDO; -import com.github.yulichang.test.join.entity.UserDO; -import com.github.yulichang.test.join.entity.UserDto; +import com.github.yulichang.test.join.entity.*; import com.github.yulichang.test.join.mapper.AddressMapper; +import com.github.yulichang.test.join.mapper.OrderMapper; import com.github.yulichang.test.join.mapper.UserDTOMapper; import com.github.yulichang.test.join.mapper.UserMapper; import com.github.yulichang.test.util.ThreadLocalUtils; import com.github.yulichang.toolkit.JoinWrappers; -import com.github.yulichang.toolkit.MPJWrappers; +import com.github.yulichang.wrapper.DeleteJoinWrapper; import com.github.yulichang.wrapper.MPJLambdaWrapper; +import com.github.yulichang.wrapper.UpdateJoinWrapper; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; @@ -48,6 +47,9 @@ class LambdaWrapperTest { @Autowired private AddressMapper addressMapper; + @Autowired + private OrderMapper orderMapper; + @Test void testJoin() { @@ -853,7 +855,7 @@ class LambdaWrapperTest { "WHERE t.del = false\n" + " AND (t.id <= ?)\n" + "ORDER BY t.id DESC\n"); - MPJLambdaWrapper wrapper = MPJWrappers.lambdaJoin(UserDO.class) + MPJLambdaWrapper wrapper = JoinWrappers.lambda(UserDO.class) .logicDelToOn() .selectAll(UserDO.class) .selectCollection(AddressDO.class, UserDTO::getAddressList, addr -> addr @@ -875,8 +877,6 @@ class LambdaWrapperTest { MPJLambdaWrapper wrapper = JoinWrappers.lambda(UserDO.class) .logicDelToOn() .selectAll(UserDO.class) -// .selectCollection(AddressDO.class, UserDTO::getAddressList, addr -> addr -// .id(AddressDO::getId)) .selectCollection(UserDTO::getAddressList, addr -> addr .id(AddressDO::getId, AddressDTO::getId) .result(UserDO::getName, AddressDTO::getAddress) @@ -900,13 +900,114 @@ class LambdaWrapperTest { ThreadLocalUtils.set("SELECT t.id,t.user_id,t.area_id,t.tel,t.address,t.del FROM address t LEFT JOIN `user` t1 ON (t1.address_id = t.id) LEFT JOIN `user` t2 ON (t2.pid = t1.id) WHERE t.del=false AND t1.del=false AND t2.del=false"); MPJLambdaWrapper wrapper = JoinWrappers.lambda(AddressDO.class) .selectAll(AddressDO.class) -// .selectAssociation(AddressDO::getUsera, map -> map -// .all("t1", UserDO.class) -// .result("t2", UserDO::getName, UserDO::getPname)) .leftJoin(UserDO.class, UserDO::getAddressId, AddressDO::getId) .leftJoin(UserDO.class, UserDO::getPid, UserDO::getId); List addressDOS = wrapper.list(); - System.out.println(1); + } + + /** + * 同一个类字段比较 + */ + @Test + void joinOwn() { + ThreadLocalUtils.set("SELECT t.id,t.pid,t.`name`,t.`json`,t.sex,t.head_img,t.create_time,t.address_id,t.address_id2,t.del,t.create_by,t.update_by FROM `user` t LEFT JOIN address t1 ON (t1.user_id = t.id) WHERE t.del=false AND t1.del=false AND (t1.id = t1.id)"); + MPJLambdaWrapper wrapper = JoinWrappers.lambda(UserDO.class) + .selectAll(UserDO.class) + .leftJoin(AddressDO.class, AddressDO::getUserId, UserDO::getId) + .eq(AddressDO::getId, AddressDO::getId); + + List addressDOS = wrapper.list(); + } + + /** + * 同一个类字段比较 + */ + @Test + void joinOwn1() { + ThreadLocalUtils.set("SELECT t.id,t.pid,t.`name`,t.`json`,t.sex,t.head_img,t.create_time,t.address_id,t.address_id2,t.del,t.create_by,t.update_by FROM `user` t LEFT JOIN address aaa ON (aaa.user_id = t.id) WHERE t.del=false AND aaa.del=false AND (aaa.id = t.id AND aaa.id = aaa.id)"); + MPJLambdaWrapper wrapper = JoinWrappers.lambda(UserDO.class) + .selectAll(UserDO.class) + .leftJoin(AddressDO.class, "aaa", AddressDO::getUserId, UserDO::getId, ext -> ext + .eq(AddressDO::getId, AddressDO::getId)) + .eq(AddressDO::getId, AddressDO::getId); + List addressDOS = wrapper.list(); + } + + /** + * 同一个类字段比较 + */ + @Test + void joinOrder() { + ThreadLocalUtils.set("SELECT id,user_id,name FROM order_t t ORDER BY t.name DESC"); + MPJLambdaWrapper wrapper = JoinWrappers.lambda(OrderDO.class); + List list = wrapper.list(); + + ThreadLocalUtils.set("SELECT t.id,t.user_id,t.name,t1.`name` AS userName FROM order_t t LEFT JOIN `user` t1 ON (t1.id = t.user_id) WHERE t1.del=false ORDER BY t.name DESC"); + MPJLambdaWrapper w = JoinWrappers.lambda(OrderDO.class) + .selectAll(OrderDO.class) + .selectAs(UserDO::getName, OrderDO::getUserName) + .leftJoin(UserDO.class, UserDO::getId, OrderDO::getUserId); + System.out.println(wrapper.getFrom()); + List l = w.list(); + } + + /** + * 同一个类字段比较 + */ + @Test + void delete() { + //物理删除 + ThreadLocalUtils.set("DELETE t FROM order_t t LEFT JOIN user_dto t1 ON (t1.id = t.user_id) WHERE (t.id = ?)"); + DeleteJoinWrapper w = JoinWrappers.delete(OrderDO.class) + .leftJoin(UserDto.class, UserDto::getId, OrderDO::getUserId) + .eq(OrderDO::getId, 1); + try { + int i = orderMapper.deleteJoin(w); + } catch (BadSqlGrammarException ignored) { + //忽略异常 h2不支持连表删除 + } + //逻辑删除 + ThreadLocalUtils.set("UPDATE `user` t LEFT JOIN address t1 ON (t1.user_id = t.id) LEFT JOIN area t2 ON (t2.id = t1.area_id) SET t.del=true ,t1.del=true,t2.del=true WHERE t.del=false AND t1.del=false AND t2.del=false AND (t.id = ?)"); + DeleteJoinWrapper wrapper = JoinWrappers.delete(UserDO.class) + .deleteAll() + .leftJoin(AddressDO.class, AddressDO::getUserId, UserDO::getId) + .leftJoin(AreaDO.class, AreaDO::getId, AddressDO::getAreaId) + .eq(OrderDO::getId, 1); + try { + DeleteJoinWrapper wrapper1 = new DeleteJoinWrapper<>(UserDO.class); + int i = userMapper.deleteJoin(wrapper); + } catch (BadSqlGrammarException ignored) { + //忽略异常 h2不支持连表删除 + } + } + + @Test + void update() { + ThreadLocalUtils.set("UPDATE `user` t LEFT JOIN address t1 ON (t1.user_id = t.id) SET t.update_by=?, t.`name`=?,t1.address=?,t1.tel=?,t1.address=?,t.`name`=?,t.update_by=?,t1.user_id=?,t1.area_id=?,t1.tel=?,t1.address=? WHERE t.del=false AND t1.del=false AND (t.id = ?)"); + UpdateJoinWrapper update = JoinWrappers.update(UserDO.class) + .set(UserDO::getName, "aaaaaa") + .set(AddressDO::getAddress, "bbbbb") + .setUpdateEntity(new AddressDO().setAddress("sadf").setTel("qqqqqqqq"), + new UserDO().setName("nnnnnnnnnnnn").setUpdateBy(1)) + .setUpdateEntityAndNull(new AddressDO()) + .leftJoin(AddressDO.class, AddressDO::getUserId, UserDO::getId) + .eq(OrderDO::getId, 1); + try { + int i = userMapper.updateJoin(new UserDO().setUpdateBy(123123), update); + } catch (BadSqlGrammarException ignored) { + //忽略异常 h2不支持连表删除 + } + + + ThreadLocalUtils.set("UPDATE `user` t LEFT JOIN address t1 ON (t1.user_id = t.id) SET t.pid=?, t.`name`=?, t.`json`=?, t.sex=?, t.head_img=?, t.create_time=?, t.address_id=?, t.address_id2=?, t.create_by=?, t.update_by=? WHERE t.del=false AND t1.del=false AND (t.id = ?)"); + UpdateJoinWrapper up = JoinWrappers.update(UserDO.class) + .leftJoin(AddressDO.class, AddressDO::getUserId, UserDO::getId) + .eq(OrderDO::getId, 1); + try { + int i = userMapper.updateJoinAndNull(new UserDO(), up); + } catch (BadSqlGrammarException ignored) { + //忽略异常 h2不支持连表删除 + } } } diff --git a/mybatis-plus-join-test/test-springboot3-jdk17/src/test/java/com/yulichang/test/springboot3jdk17/LambdaWrapperTest.java b/mybatis-plus-join-test/test-springboot3-jdk17/src/test/java/com/yulichang/test/springboot3jdk17/LambdaWrapperTest.java index 12a06a1..97ea155 100644 --- a/mybatis-plus-join-test/test-springboot3-jdk17/src/test/java/com/yulichang/test/springboot3jdk17/LambdaWrapperTest.java +++ b/mybatis-plus-join-test/test-springboot3-jdk17/src/test/java/com/yulichang/test/springboot3jdk17/LambdaWrapperTest.java @@ -5,7 +5,7 @@ import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.toolkit.StringUtils; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.github.yulichang.test.util.ThreadLocalUtils; -import com.github.yulichang.toolkit.MPJWrappers; +import com.github.yulichang.toolkit.JoinWrappers; import com.github.yulichang.wrapper.MPJLambdaWrapper; import com.yulichang.test.springboot3jdk17.dto.AddressDTO; import com.yulichang.test.springboot3jdk17.dto.UserDTO; @@ -571,7 +571,7 @@ class LambdaWrapperTest { Page page = new Page<>(1, 10); page.setSearchCount(false); IPage iPage = userMapper.selectJoinPage(page, UserDTO.class, - MPJWrappers.lambdaJoin() + JoinWrappers.lambda(UserDO.class) .selectAll(UserDO.class) .select(AddressDO::getAddress) .select(AreaDO::getProvince) @@ -607,7 +607,7 @@ class LambdaWrapperTest { AND (t.id = ? AND (t.head_img = ? OR t1.user_id = ?) AND t.id = ?) LIMIT ?"""); IPage page = userMapper.selectJoinPage(new Page<>(1, 10), UserDTO.class, - MPJWrappers.lambdaJoin() + JoinWrappers.lambda(UserDO.class) .selectAll(UserDO.class) .select(AddressDO::getAddress) .leftJoin(AddressDO.class, on -> on @@ -626,7 +626,7 @@ class LambdaWrapperTest { */ @Test void test4() { - UserDTO one = userMapper.selectJoinOne(UserDTO.class, MPJWrappers.lambdaJoin() + UserDTO one = userMapper.selectJoinOne(UserDTO.class, JoinWrappers.lambda(UserDO.class) .selectSum(UserDO::getId) .selectMax(UserDO::getId, UserDTO::getHeadImg) .leftJoin(AddressDO.class, AddressDO::getUserId, UserDO::getId)); @@ -667,7 +667,7 @@ class LambdaWrapperTest { */ @Test void test7() { - List> list = userMapper.selectJoinMaps(MPJWrappers.lambdaJoin() + List> list = userMapper.selectJoinMaps(JoinWrappers.lambda(UserDO.class) .selectAll(UserDO.class) .select(AddressDO::getAddress) .leftJoin(AddressDO.class, AddressDO::getUserId, UserDO::getId));