diff --git a/docs/zh/base/querywrapper.md b/docs/zh/base/querywrapper.md index 92584add..53127c85 100644 --- a/docs/zh/base/querywrapper.md +++ b/docs/zh/base/querywrapper.md @@ -1004,6 +1004,7 @@ SELECT * FROM WHERE `id` >= 100 AND `user_name` LIKE '%michael%' QueryWrapper query = QueryWrapper.create() .from(Article.class) .leftJoin(Account.class).as("a").on( + //无其他特殊条件可简化成:.on(Account::getId, Article::getAccountId) wrapper -> wrapper.where(Account::getId).eq(Article::getAccountId) ) .where(Account::getId).ge(100, If::notEmpty) @@ -1012,7 +1013,7 @@ QueryWrapper query = QueryWrapper.create() .or(Account::getAge).gt(200) .and(Article::getAccountId).eq(200) .or(wrapper1 -> { - wrapper1.where(Account::getId).like("a", If::notEmpty); + wrapper1.where(Account::getId).like("a"); }) ; }); diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/mybatis/SqlArgsParameterHandler.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/mybatis/SqlArgsParameterHandler.java index 6e2ac8f5..b25dc797 100644 --- a/mybatis-flex-core/src/main/java/com/mybatisflex/core/mybatis/SqlArgsParameterHandler.java +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/mybatis/SqlArgsParameterHandler.java @@ -17,6 +17,7 @@ package com.mybatisflex.core.mybatis; import com.mybatisflex.core.FlexConsts; import com.mybatisflex.core.exception.FlexExceptions; +import com.mybatisflex.core.util.EnumWrapper; import org.apache.ibatis.mapping.BoundSql; import org.apache.ibatis.mapping.MappedStatement; import org.apache.ibatis.scripting.defaults.DefaultParameterHandler; diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/mybatis/TypeHandlerObject.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/mybatis/TypeHandlerObject.java index 40a0c782..88f6f801 100644 --- a/mybatis-flex-core/src/main/java/com/mybatisflex/core/mybatis/TypeHandlerObject.java +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/mybatis/TypeHandlerObject.java @@ -42,4 +42,12 @@ public class TypeHandlerObject implements Serializable { return value; } + @Override + public String toString() { + return "TypeHandlerObject{" + + "value=" + value + + ", typeHandler=" + typeHandler.getClass().getSimpleName() + + '}'; + } + } diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/query/Joiner.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/query/Joiner.java index 96c45b55..e6ebb5b7 100644 --- a/mybatis-flex-core/src/main/java/com/mybatisflex/core/query/Joiner.java +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/query/Joiner.java @@ -15,6 +15,9 @@ */ package com.mybatisflex.core.query; +import com.mybatisflex.core.util.LambdaGetter; +import com.mybatisflex.core.util.LambdaUtil; + import java.util.ListIterator; import java.util.function.Consumer; @@ -73,5 +76,12 @@ public class Joiner { return queryWrapper; } + public M on(LambdaGetter column1, LambdaGetter column2) { + QueryCondition queryCondition = LambdaUtil.getQueryColumn(column1).eq(LambdaUtil.getQueryColumn(column2)); + join.on(queryCondition); + return queryWrapper; + } + + } diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/query/QueryCondition.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/query/QueryCondition.java index adbb994f..0562e930 100644 --- a/mybatis-flex-core/src/main/java/com/mybatisflex/core/query/QueryCondition.java +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/query/QueryCondition.java @@ -66,17 +66,17 @@ public class QueryCondition implements CloneSupport { public static QueryCondition create(String schema, String table, String column, String logic, Object value) { - QueryCondition condition = new QueryCondition(); - condition.setColumn(new QueryColumn(schema, table, column)); - condition.setLogic(logic); - condition.setValue(value); - return condition; + return create(new QueryColumn(schema, table, column), logic, value); } public static QueryCondition create(QueryColumn queryColumn, Object value) { return create(queryColumn, SqlConsts.EQUALS, value); } + public static QueryCondition create(QueryColumn queryColumn, SqlOperator logic, Object value) { + return create(queryColumn, logic.getValue(), value); + } + public static QueryCondition create(QueryColumn queryColumn, String logic, Object value) { QueryCondition condition = new QueryCondition(); condition.setColumn(queryColumn); @@ -85,14 +85,6 @@ public class QueryCondition implements CloneSupport { return condition; } - public static QueryCondition create(QueryColumn queryColumn, SqlOperator logic, Object value) { - QueryCondition condition = new QueryCondition(); - condition.setColumn(queryColumn); - condition.setLogic(logic.getValue()); - condition.setValue(value); - return condition; - } - public QueryColumn getColumn() { return column; } diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/query/WrapperUtil.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/query/WrapperUtil.java index 941f72c3..18cf039e 100644 --- a/mybatis-flex-core/src/main/java/com/mybatisflex/core/query/WrapperUtil.java +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/query/WrapperUtil.java @@ -109,7 +109,7 @@ class WrapperUtil { addParam(params, value); getValues(condition.next, params); } - + @SuppressWarnings("all") private static void addParam(List paras, Object value) { if (value == null) { paras.add(null); @@ -120,13 +120,12 @@ class WrapperUtil { } else if (value instanceof QueryWrapper) { Object[] valueArray = ((QueryWrapper) value).getAllValueArray(); paras.addAll(Arrays.asList(valueArray)); - } else if (value.getClass().isEnum()) { + } else if (value instanceof Enum) { + // 枚举类型,处理枚举实际值 EnumWrapper enumWrapper = EnumWrapper.of(value.getClass()); - if (enumWrapper.hasEnumValueAnnotation()) { - paras.add(enumWrapper.getEnumValue((Enum) value)); - } else { - paras.add(((Enum) value).name()); - } + // 如果是使用注解标识枚举实际值,则直接获取实际值,但如果是依靠全局枚举TypeHandler处理,则此处只能先存入枚举实例,在SQL执行时才能处理实际值 + value = enumWrapper.hasEnumValueAnnotation() ? enumWrapper.getEnumValue((Enum) value) : value; + paras.add(value); } else { paras.add(value); } diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/table/TableInfo.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/table/TableInfo.java index a9e421d3..b47d57aa 100644 --- a/mybatis-flex-core/src/main/java/com/mybatisflex/core/table/TableInfo.java +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/table/TableInfo.java @@ -700,11 +700,7 @@ public class TableInfo { // fixed: https://gitee.com/mybatis-flex/mybatis-flex/issues/I7TFBK if (value.getClass().isEnum()) { EnumWrapper enumWrapper = EnumWrapper.of(value.getClass()); - if (enumWrapper.hasEnumValueAnnotation()) { - value = enumWrapper.getEnumValue((Enum) value); - } else { - value = ((Enum) value).name(); - } + value = enumWrapper.getEnumValue((Enum) value); } } diff --git a/mybatis-flex-core/src/main/java/com/mybatisflex/core/util/EnumWrapper.java b/mybatis-flex-core/src/main/java/com/mybatisflex/core/util/EnumWrapper.java index 77effa1a..98d29daf 100644 --- a/mybatis-flex-core/src/main/java/com/mybatisflex/core/util/EnumWrapper.java +++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/util/EnumWrapper.java @@ -88,10 +88,25 @@ public class EnumWrapper> { } } - + /** + * 获取枚举值 + * 顺序: + * 1、@EnumValue标识的get方法 + * 2、@EnumValue标识的属性 + * 3、没有使用@EnumValue,取枚举name + * + * @param object + * @return + */ public Object getEnumValue(E object) { try { - return getterMethod != null ? getterMethod.invoke(object) : property.get(object); + if (getterMethod != null) { + return getterMethod.invoke(object); + } else if(property != null){ + return property.get(object); + } else { + return object.name(); + } } catch (Exception e) { throw FlexExceptions.wrap(e); } diff --git a/mybatis-flex-core/src/test/java/com/mybatisflex/coretest/LambdaSqlTest.java b/mybatis-flex-core/src/test/java/com/mybatisflex/coretest/LambdaSqlTest.java index c05afe87..682d534e 100644 --- a/mybatis-flex-core/src/test/java/com/mybatisflex/coretest/LambdaSqlTest.java +++ b/mybatis-flex-core/src/test/java/com/mybatisflex/coretest/LambdaSqlTest.java @@ -145,5 +145,20 @@ public class LambdaSqlTest { "WHERE\n" + " ` ac `.` age ` >= 18", SqlFormatter.format(queryWrapper.toSQL())); } + @Test + public void test06() { + QueryWrapper queryWrapper = QueryWrapper.create() + .select() + .from(Account.class).join(Article.class).on(Article::getAccountId, Account::getId) + .where(Account::getAge).ge(18); + printSQL(queryWrapper); + assertEquals("SELECT\n" + + " *\n" + + "FROM\n" + + " ` tb_account `\n" + + " JOIN ` tb_article ` ON ` tb_article `.` account_id ` = ` tb_account `.` id `\n" + + "WHERE\n" + + " ` tb_account `.` age ` >= 18", SqlFormatter.format(queryWrapper.toSQL())); + } } diff --git a/mybatis-flex-test/mybatis-flex-spring-test/src/main/java/com/mybatisflex/test/AppConfig.java b/mybatis-flex-test/mybatis-flex-spring-test/src/main/java/com/mybatisflex/test/AppConfig.java index 50243867..5259b9e9 100644 --- a/mybatis-flex-test/mybatis-flex-spring-test/src/main/java/com/mybatisflex/test/AppConfig.java +++ b/mybatis-flex-test/mybatis-flex-spring-test/src/main/java/com/mybatisflex/test/AppConfig.java @@ -17,6 +17,7 @@ package com.mybatisflex.test; import com.mybatisflex.core.mybatis.FlexConfiguration; import com.mybatisflex.spring.FlexSqlSessionFactoryBean; +import com.mybatisflex.test.model.EnumTypeHandler; import org.apache.ibatis.logging.stdout.StdOutImpl; import org.apache.ibatis.session.SqlSessionFactory; import org.mybatis.spring.SqlSessionFactoryBean; @@ -52,6 +53,7 @@ public class AppConfig implements ApplicationListener { factoryBean.setDataSource(dataSource); FlexConfiguration configuration = new FlexConfiguration(); configuration.setLogImpl(StdOutImpl.class); + configuration.setDefaultEnumTypeHandler(EnumTypeHandler.class); factoryBean.setConfiguration(configuration); return factoryBean.getObject(); } diff --git a/mybatis-flex-test/mybatis-flex-spring-test/src/main/java/com/mybatisflex/test/model/Account.java b/mybatis-flex-test/mybatis-flex-spring-test/src/main/java/com/mybatisflex/test/model/Account.java index 8370fd04..05d4e063 100644 --- a/mybatis-flex-test/mybatis-flex-spring-test/src/main/java/com/mybatisflex/test/model/Account.java +++ b/mybatis-flex-test/mybatis-flex-spring-test/src/main/java/com/mybatisflex/test/model/Account.java @@ -15,6 +15,7 @@ */ package com.mybatisflex.test.model; +import com.mybatisflex.annotation.Column; import com.mybatisflex.annotation.Id; import com.mybatisflex.annotation.Table; @@ -28,6 +29,7 @@ public class Account { private String userName; private Integer age; private Date birthday; + private Sex sex; public Long getId() { return id; @@ -61,6 +63,13 @@ public class Account { this.birthday = birthday; } + public Sex getSex() { + return sex; + } + + public void setSex(Sex sex) { + this.sex = sex; + } @Override public String toString() { return "Account{" + @@ -68,6 +77,7 @@ public class Account { ", userName='" + userName + '\'' + ", age=" + age + ", birthday=" + birthday + + ", sex=" + sex + '}'; } diff --git a/mybatis-flex-test/mybatis-flex-spring-test/src/main/java/com/mybatisflex/test/model/BaseEnum.java b/mybatis-flex-test/mybatis-flex-spring-test/src/main/java/com/mybatisflex/test/model/BaseEnum.java new file mode 100644 index 00000000..b8107cff --- /dev/null +++ b/mybatis-flex-test/mybatis-flex-spring-test/src/main/java/com/mybatisflex/test/model/BaseEnum.java @@ -0,0 +1,14 @@ +package com.mybatisflex.test.model; + +/** + * 基础枚举接口 + * @author luozhan + */ +public interface BaseEnum { + + /** + * 获取枚举值 + * @return 枚举值 + */ + int getValue(); +} diff --git a/mybatis-flex-test/mybatis-flex-spring-test/src/main/java/com/mybatisflex/test/model/EnumTypeHandler.java b/mybatis-flex-test/mybatis-flex-spring-test/src/main/java/com/mybatisflex/test/model/EnumTypeHandler.java new file mode 100644 index 00000000..c0a84be1 --- /dev/null +++ b/mybatis-flex-test/mybatis-flex-spring-test/src/main/java/com/mybatisflex/test/model/EnumTypeHandler.java @@ -0,0 +1,57 @@ +package com.mybatisflex.test.model; + +import org.apache.ibatis.type.BaseTypeHandler; +import org.apache.ibatis.type.JdbcType; + +import java.sql.CallableStatement; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.stream.Stream; + +/** + * 枚举类型处理器 + * + * @author luozhan + */ +public class EnumTypeHandler & BaseEnum> extends BaseTypeHandler { + private final Class enumClass; + + public EnumTypeHandler(Class enumClass) { + this.enumClass = enumClass; + } + + @Override + public void setNonNullParameter(PreparedStatement ps, int i, E parameter, JdbcType jdbcType) throws SQLException { + Integer value = parameter.getValue(); + ps.setObject(i, value); + } + + @Override + public E getNullableResult(ResultSet rs, String columnName) throws SQLException { + int value = rs.getInt(columnName); + return getEnumByValue(value); + } + + + @Override + public E getNullableResult(ResultSet rs, int columnIndex) throws SQLException { + int value = rs.getInt(columnIndex); + return getEnumByValue(value); + } + + @Override + public E getNullableResult(CallableStatement cs, int columnIndex) throws SQLException { + int value = cs.getInt(columnIndex); + return getEnumByValue(value); + } + + /** + * 根据枚举值获取枚举对象 + * @param value 枚举值 + * @return 枚举对象 + */ + private E getEnumByValue(int value) { + return Stream.of(enumClass.getEnumConstants()).filter(e -> e.getValue() == value).findAny().orElse(null); + } +} diff --git a/mybatis-flex-test/mybatis-flex-spring-test/src/main/java/com/mybatisflex/test/model/Sex.java b/mybatis-flex-test/mybatis-flex-spring-test/src/main/java/com/mybatisflex/test/model/Sex.java new file mode 100644 index 00000000..b6db0ff2 --- /dev/null +++ b/mybatis-flex-test/mybatis-flex-spring-test/src/main/java/com/mybatisflex/test/model/Sex.java @@ -0,0 +1,25 @@ +package com.mybatisflex.test.model; + + +/** + * 性别枚举 + * @author luozhan + */ + +public enum Sex implements BaseEnum { + // + MALE(1), + FEMALE(2), + UNKNOWN(0); + + private final int value; + + Sex(Integer value) { + this.value = value; + } + + @Override + public int getValue() { + return value; + } +} diff --git a/mybatis-flex-test/mybatis-flex-spring-test/src/main/resources/data.sql b/mybatis-flex-test/mybatis-flex-spring-test/src/main/resources/data.sql index fb75a0ae..923dce23 100644 --- a/mybatis-flex-test/mybatis-flex-spring-test/src/main/resources/data.sql +++ b/mybatis-flex-test/mybatis-flex-spring-test/src/main/resources/data.sql @@ -1,5 +1,5 @@ INSERT INTO tb_account -VALUES (1, 'Michael Yang', 18, '2020-01-11'); +VALUES (1, 'Michael Yang', 18, '2020-01-11', 1); INSERT INTO tb_class VALUES (1, 1, 'class111'); diff --git a/mybatis-flex-test/mybatis-flex-spring-test/src/main/resources/schema.sql b/mybatis-flex-test/mybatis-flex-spring-test/src/main/resources/schema.sql index a77acf68..4fe6b3f5 100644 --- a/mybatis-flex-test/mybatis-flex-spring-test/src/main/resources/schema.sql +++ b/mybatis-flex-test/mybatis-flex-spring-test/src/main/resources/schema.sql @@ -3,7 +3,8 @@ CREATE TABLE IF NOT EXISTS `tb_account` `id` INTEGER PRIMARY KEY, `user_name` VARCHAR(100) NOT NULL, `age` Integer, - `birthday` DATETIME + `birthday` DATETIME, + `sex` tinyint ); CREATE TABLE IF NOT EXISTS `tb_class` diff --git a/mybatis-flex-test/mybatis-flex-spring-test/src/test/java/com/mybatisflex/test/EnumTest.java b/mybatis-flex-test/mybatis-flex-spring-test/src/test/java/com/mybatisflex/test/EnumTest.java new file mode 100644 index 00000000..39638a96 --- /dev/null +++ b/mybatis-flex-test/mybatis-flex-spring-test/src/test/java/com/mybatisflex/test/EnumTest.java @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2022-2023, Mybatis-Flex (fuhai999@gmail.com). + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.mybatisflex.test; + +import com.mybatisflex.core.query.QueryWrapper; +import com.mybatisflex.core.row.Db; +import com.mybatisflex.core.row.Row; +import com.mybatisflex.test.mapper.AccountMapper; +import com.mybatisflex.test.model.Account; +import com.mybatisflex.test.model.Sex; +import com.mybatisflex.test.model.TbClass; +import org.assertj.core.api.WithAssertions; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import java.util.List; + +import static com.mybatisflex.test.tabledef.Tables.ACCOUNT; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(classes = AppConfig.class) +public class EnumTest implements WithAssertions { + + @Autowired + AccountMapper accountMapper; + + @Test + public void test_global_enum_type_handler() { + QueryWrapper query = new QueryWrapper() + .select() + .from(ACCOUNT).where(ACCOUNT.SEX.in(Sex.MALE, Sex.FEMALE)); + // 注意,此处虽然显示是MALE、FEMALE,但是如果使用了枚举的typeHandler,实际sql执行时会使用typeHandler进行处理 + assertThat(query.toSQL()).isEqualTo("SELECT * FROM `tb_account` WHERE `sex` IN ('MALE', 'FEMALE')"); + List list = accountMapper.selectListByQuery(query); + assertThat(list).isNotNull(); + for (Account account : list) { + assertThat(account.getSex()).isIn(Sex.MALE, Sex.FEMALE); + } + } + @Test + public void test_create_entity_with_enum_type() { + Account account = new Account(); + account.setSex(Sex.MALE); + QueryWrapper queryWrapper = QueryWrapper.create(account); + String sql = queryWrapper.toSQL(); + System.out.println(sql); + // 注意,此处虽然显示是MALE,但是如果使用了枚举的typeHandler,实际sql执行时会使用typeHandler进行处理 + assertThat(sql).isEqualTo("SELECT `id`, `user_name`, `age`, `birthday`, `sex` FROM `tb_account` WHERE `sex` = 'MALE'"); + List list = accountMapper.selectListByQuery(queryWrapper); + assertThat(list).isNotNull(); + for (Account item : list) { + assertThat(item.getSex()).isEqualTo(Sex.MALE); + } + } + +} diff --git a/mybatis-flex-test/mybatis-flex-spring-test/src/test/java/com/mybatisflex/test/issue113/def/TClassTableDef.java b/mybatis-flex-test/mybatis-flex-spring-test/src/test/java/com/mybatisflex/test/issue113/def/TClassTableDef.java index e234f606..579179ee 100644 --- a/mybatis-flex-test/mybatis-flex-spring-test/src/test/java/com/mybatisflex/test/issue113/def/TClassTableDef.java +++ b/mybatis-flex-test/mybatis-flex-spring-test/src/test/java/com/mybatisflex/test/issue113/def/TClassTableDef.java @@ -28,6 +28,8 @@ public class TClassTableDef extends QueryTable { public final QueryColumn CLASS_NAME = new QueryColumn(this, "class_name"); + public final QueryColumn SEX = new QueryColumn(this, "sex"); + public TClassTableDef() { super("", "tb_class"); }