From fe5ebc7ed732c6f061dfb4ea0bb0a45411e69fae Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E7=8E=8B=E5=B8=85?= <1474983351@qq.com>
Date: Tue, 13 Jun 2023 07:37:12 +0000
Subject: [PATCH] =?UTF-8?q?Revert=20"=E5=88=A0=E9=99=A4=E6=96=87=E4=BB=B6?=
=?UTF-8?q?=20mybatis-flex-core/src/main/java/com/mybatisflex/core/table/T?=
=?UTF-8?q?ableInfo.java"?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
This reverts commit d496b18ab0fbcbd92cb5d1e942c19f6f85e14ce4.
---
.../com/mybatisflex/core/table/TableInfo.java | 986 ++++++++++++++++++
1 file changed, 986 insertions(+)
create mode 100644 mybatis-flex-core/src/main/java/com/mybatisflex/core/table/TableInfo.java
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
new file mode 100644
index 00000000..f2985fc4
--- /dev/null
+++ b/mybatis-flex-core/src/main/java/com/mybatisflex/core/table/TableInfo.java
@@ -0,0 +1,986 @@
+/*
+ * 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.core.table;
+
+import com.mybatisflex.annotation.InsertListener;
+import com.mybatisflex.annotation.KeyType;
+import com.mybatisflex.annotation.SetListener;
+import com.mybatisflex.annotation.UpdateListener;
+import com.mybatisflex.core.FlexConsts;
+import com.mybatisflex.core.FlexGlobalConfig;
+import com.mybatisflex.core.constant.SqlConsts;
+import com.mybatisflex.core.dialect.IDialect;
+import com.mybatisflex.core.exception.FlexExceptions;
+import com.mybatisflex.core.javassist.ModifyAttrsRecord;
+import com.mybatisflex.core.mybatis.TypeHandlerObject;
+import com.mybatisflex.core.query.*;
+import com.mybatisflex.core.row.Row;
+import com.mybatisflex.core.tenant.TenantManager;
+import com.mybatisflex.core.util.*;
+import org.apache.ibatis.mapping.ResultFlag;
+import org.apache.ibatis.mapping.ResultMap;
+import org.apache.ibatis.mapping.ResultMapping;
+import org.apache.ibatis.reflection.MetaObject;
+import org.apache.ibatis.reflection.Reflector;
+import org.apache.ibatis.reflection.ReflectorFactory;
+import org.apache.ibatis.session.Configuration;
+import org.apache.ibatis.type.TypeHandler;
+import org.apache.ibatis.util.MapUtil;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Proxy;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.stream.Collectors;
+
+public class TableInfo {
+
+ private String schema; //schema
+ private String tableName; //表名
+ private Class> entityClass; //实体类
+ private boolean camelToUnderline = true;
+ private String dataSource;
+
+ //逻辑删除数据库列名
+ private String logicDeleteColumn;
+
+ //乐观锁字段
+ private String versionColumn;
+
+ //租户ID 字段
+ private String tenantIdColumn;
+
+ //数据插入时,默认插入数据字段
+ private Map onInsertColumns;
+
+ //数据更新时,默认更新内容的字段
+ private Map onUpdateColumns;
+
+ //大字段列
+ private String[] largeColumns = new String[0];
+
+ // 所有的字段,但除了主键的列
+ private String[] columns = new String[0];
+
+ //主键字段
+ private String[] primaryKeys = new String[0];
+
+ // 默认查询列
+ private String[] defaultColumns = new String[0];
+
+ //在插入数据的时候,支持主动插入的主键字段
+ //通过自定义生成器生成 或者 Sequence 在 before 生成的时候,是需要主动插入数据的
+ private String[] insertPrimaryKeys;
+
+ private List columnInfoList;
+ private List primaryKeyList;
+
+ //column 和 java 属性的称的关系映射
+ private final Map columnInfoMapping = new HashMap<>();
+ private final Map propertyColumnMapping = new HashMap<>();
+
+ private List onInsertListeners;
+ private List onUpdateListeners;
+ private List onSetListeners;
+
+ /**
+ * @deprecated 该功能有更好的方式实现,此属性可能会被移除。
+ */
+ @Deprecated
+ private Map> joinTypes;
+
+
+ /**
+ * 对应 MapperXML 配置文件中 {@code } 标签下的 {@code } 标签。
+ */
+ private Map> associationType;
+
+ /**
+ * 对应 MapperXML 配置文件中 {@code } 标签下的 {@code } 标签。
+ */
+ private Map> collectionType;
+
+
+ private final ReflectorFactory reflectorFactory = new BaseReflectorFactory() {
+ @Override
+ public Reflector findForClass(Class> type) {
+ return getReflector();
+ }
+ };
+ private Reflector reflector; //反射工具
+
+ public String getSchema() {
+ return schema;
+ }
+
+ public void setSchema(String schema) {
+ this.schema = schema;
+ }
+
+ public String getTableName() {
+ return tableName;
+ }
+
+ public String getWrapSchemaAndTableName(IDialect dialect) {
+ if (StringUtil.isNotBlank(schema)) {
+ return dialect.wrap(dialect.getRealSchema(schema)) + "." + dialect.wrap(dialect.getRealTable(tableName));
+ } else {
+ return dialect.wrap(dialect.getRealTable(tableName));
+ }
+ }
+
+ public void setTableName(String tableName) {
+ this.tableName = tableName;
+ }
+
+ public Class> getEntityClass() {
+ return entityClass;
+ }
+
+ public void setEntityClass(Class> entityClass) {
+ this.entityClass = entityClass;
+ }
+
+ public boolean isCamelToUnderline() {
+ return camelToUnderline;
+ }
+
+ public void setCamelToUnderline(boolean camelToUnderline) {
+ this.camelToUnderline = camelToUnderline;
+ }
+
+ public String getDataSource() {
+ return dataSource;
+ }
+
+ public void setDataSource(String dataSource) {
+ this.dataSource = dataSource;
+ }
+
+ public String getLogicDeleteColumn() {
+ return logicDeleteColumn;
+ }
+
+ public void setLogicDeleteColumn(String logicDeleteColumn) {
+ this.logicDeleteColumn = logicDeleteColumn;
+ }
+
+ public String getVersionColumn() {
+ return versionColumn;
+ }
+
+ public void setVersionColumn(String versionColumn) {
+ this.versionColumn = versionColumn;
+ }
+
+ public String getTenantIdColumn() {
+ return tenantIdColumn;
+ }
+
+ public void setTenantIdColumn(String tenantIdColumn) {
+ this.tenantIdColumn = tenantIdColumn;
+ }
+
+ public Map getOnInsertColumns() {
+ return onInsertColumns;
+ }
+
+ public void setOnInsertColumns(Map onInsertColumns) {
+ this.onInsertColumns = onInsertColumns;
+ }
+
+ public Map getOnUpdateColumns() {
+ return onUpdateColumns;
+ }
+
+ public void setOnUpdateColumns(Map onUpdateColumns) {
+ this.onUpdateColumns = onUpdateColumns;
+ }
+
+ public String[] getLargeColumns() {
+ return largeColumns;
+ }
+
+ public void setLargeColumns(String[] largeColumns) {
+ this.largeColumns = largeColumns;
+ }
+
+ public String[] getDefaultColumns() {
+ return defaultColumns;
+ }
+
+ public void setDefaultColumns(String[] defaultColumns) {
+ this.defaultColumns = defaultColumns;
+ }
+
+ public String[] getInsertPrimaryKeys() {
+ return insertPrimaryKeys;
+ }
+
+ public void setInsertPrimaryKeys(String[] insertPrimaryKeys) {
+ this.insertPrimaryKeys = insertPrimaryKeys;
+ }
+
+ public Reflector getReflector() {
+ return reflector;
+ }
+
+ public ReflectorFactory getReflectorFactory() {
+ return reflectorFactory;
+ }
+
+ public void setReflector(Reflector reflector) {
+ this.reflector = reflector;
+ }
+
+ public String[] getColumns() {
+ return columns;
+ }
+
+
+ public void setColumns(String[] columns) {
+ this.columns = columns;
+ }
+
+ public String[] getPrimaryKeys() {
+ return primaryKeys;
+ }
+
+ public void setPrimaryKeys(String[] primaryKeys) {
+ this.primaryKeys = primaryKeys;
+ }
+
+
+ public List getOnInsertListeners() {
+ return onInsertListeners;
+ }
+
+ public void setOnInsertListeners(List onInsertListeners) {
+ this.onInsertListeners = onInsertListeners;
+ }
+
+ public List getOnUpdateListeners() {
+ return onUpdateListeners;
+ }
+
+ public void setOnUpdateListeners(List onUpdateListeners) {
+ this.onUpdateListeners = onUpdateListeners;
+ }
+
+ public List getOnSetListeners() {
+ return onSetListeners;
+ }
+
+ public void setOnSetListeners(List onSetListeners) {
+ this.onSetListeners = onSetListeners;
+ }
+
+ public List getColumnInfoList() {
+ return columnInfoList;
+ }
+
+ public String getColumnByProperty(String property) {
+ return propertyColumnMapping.get(property);
+ }
+
+ public Map> getJoinTypes() {
+ return joinTypes;
+ }
+
+ public void setJoinTypes(Map> joinTypes) {
+ this.joinTypes = joinTypes;
+ }
+
+ public void addJoinType(String fieldName, Class> clazz) {
+ if (joinTypes == null) {
+ joinTypes = new HashMap<>();
+ }
+ joinTypes.put(fieldName, clazz);
+ }
+
+ public Map> getAssociationType() {
+ return associationType;
+ }
+
+ public void setAssociationType(Map> associationType) {
+ this.associationType = associationType;
+ }
+
+ public void addAssociationType(String fieldName, Class> clazz) {
+ if (associationType == null) {
+ associationType = new HashMap<>();
+ }
+ associationType.put(fieldName, clazz);
+ }
+
+ public Map> getCollectionType() {
+ return collectionType;
+ }
+
+ public void setCollectionType(Map> collectionType) {
+ this.collectionType = collectionType;
+ }
+
+ public void addCollectionType(Field field, Class> genericClass) {
+ if (collectionType == null) {
+ collectionType = new HashMap<>();
+ }
+ collectionType.put(field, genericClass);
+ }
+
+ void setColumnInfoList(List columnInfoList) {
+ this.columnInfoList = columnInfoList;
+ this.columns = new String[columnInfoList.size()];
+ for (int i = 0; i < columnInfoList.size(); i++) {
+ ColumnInfo columnInfo = columnInfoList.get(i);
+ columns[i] = columnInfo.getColumn();
+ columnInfoMapping.put(columnInfo.column, columnInfo);
+ propertyColumnMapping.put(columnInfo.property, columnInfo.column);
+ }
+ }
+
+
+ public List getPrimaryKeyList() {
+ return primaryKeyList;
+ }
+
+ void setPrimaryKeyList(List primaryKeyList) {
+ this.primaryKeyList = primaryKeyList;
+ this.primaryKeys = new String[primaryKeyList.size()];
+
+ List insertIdFields = new ArrayList<>();
+ for (int i = 0; i < primaryKeyList.size(); i++) {
+ IdInfo idInfo = primaryKeyList.get(i);
+ primaryKeys[i] = idInfo.getColumn();
+
+ if (idInfo.getKeyType() != KeyType.Auto && (idInfo.getBefore() != null && idInfo.getBefore())) {
+ insertIdFields.add(idInfo.getColumn());
+ }
+
+ columnInfoMapping.put(idInfo.column, idInfo);
+ propertyColumnMapping.put(idInfo.property, idInfo.column);
+ }
+ this.insertPrimaryKeys = insertIdFields.toArray(new String[0]);
+ }
+
+
+ /**
+ * 插入(新增)数据时,获取所有要插入的字段
+ *
+ * @param entity
+ * @param ignoreNulls
+ * @return 字段列表
+ */
+ public String[] obtainInsertColumns(Object entity, boolean ignoreNulls) {
+ if (!ignoreNulls) {
+ return ArrayUtil.concat(insertPrimaryKeys, columns);
+ } else {
+ MetaObject metaObject = EntityMetaObject.forObject(entity, reflectorFactory);
+ List retColumns = new ArrayList<>();
+ for (String insertColumn : columns) {
+ if (onInsertColumns != null && onInsertColumns.containsKey(insertColumn)) {
+ retColumns.add(insertColumn);
+ } else {
+ Object value = buildColumnSqlArg(metaObject, insertColumn);
+ if (value == null) {
+ continue;
+ }
+ retColumns.add(insertColumn);
+ }
+ }
+ return ArrayUtil.concat(insertPrimaryKeys, retColumns.toArray(new String[0]));
+ }
+ }
+
+
+ /**
+ * 构建 insert 的 Sql 参数
+ *
+ * @param entity 从 entity 中获取
+ * @param ignoreNulls 是否忽略 null 值
+ * @return 数组
+ */
+ public Object[] buildInsertSqlArgs(Object entity, boolean ignoreNulls) {
+ MetaObject metaObject = EntityMetaObject.forObject(entity, reflectorFactory);
+ String[] insertColumns = obtainInsertColumns(entity, ignoreNulls);
+
+ List values = new ArrayList<>(insertColumns.length);
+ for (String insertColumn : insertColumns) {
+ if (onInsertColumns == null || !onInsertColumns.containsKey(insertColumn)) {
+ Object value = buildColumnSqlArg(metaObject, insertColumn);
+ if (ignoreNulls && value == null) {
+ continue;
+ }
+ values.add(value);
+ }
+ }
+ return values.toArray();
+ }
+
+
+ /**
+ * 获取要修改的值
+ *
+ * @param entity
+ * @param ignoreNulls
+ */
+ public Set obtainUpdateColumns(Object entity, boolean ignoreNulls, boolean includePrimary) {
+ MetaObject metaObject = EntityMetaObject.forObject(entity, reflectorFactory);
+ Set columns = new LinkedHashSet<>(); //需使用 LinkedHashSet 保证 columns 的顺序
+ if (entity instanceof ModifyAttrsRecord) {
+ Set properties = ((ModifyAttrsRecord) entity).obtainModifyAttrs();
+ if (properties.isEmpty()) {
+ return Collections.emptySet();
+ }
+ for (String property : properties) {
+ String column = propertyColumnMapping.get(property);
+ if (onUpdateColumns != null && onUpdateColumns.containsKey(column)) {
+ continue;
+ }
+
+ //过滤乐观锁字段 和 租户字段
+ if (ObjectUtil.equalsAny(column, versionColumn, tenantIdColumn)) {
+ continue;
+ }
+
+ if (!includePrimary && ArrayUtil.contains(primaryKeys, column)) {
+ continue;
+ }
+
+ // ModifyAttrsRecord 忽略 ignoreNulls 的设置
+ // Object value = getPropertyValue(metaObject, property);
+ // if (ignoreNulls && value == null) {
+ // continue;
+ // }
+ columns.add(column);
+ }
+ }
+ //not ModifyAttrsRecord
+ else {
+ for (String column : this.columns) {
+ if (onUpdateColumns != null && onUpdateColumns.containsKey(column)) {
+ continue;
+ }
+
+ //过滤乐观锁字段 和 租户字段
+ if (ObjectUtil.equalsAny(column, versionColumn, tenantIdColumn)) {
+ continue;
+ }
+
+ Object value = buildColumnSqlArg(metaObject, column);
+ if (ignoreNulls && value == null) {
+ continue;
+ }
+
+ columns.add(column);
+ }
+
+ // 普通 entity(非 ModifyAttrsRecord) 忽略 includePrimary 的设置
+// if (includePrimary) {
+// for (String column : this.primaryKeys) {
+// Object value = getColumnValue(metaObject, column);
+// if (ignoreNulls && value == null) {
+// continue;
+// }
+// columns.add(column);
+// }
+// }
+ }
+ return columns;
+ }
+
+ /**
+ * 获取所有要修改的值,默认为全部除了主键以外的字段
+ *
+ * @param entity 实体对象
+ * @return 数组
+ */
+ public Object[] buildUpdateSqlArgs(Object entity, boolean ignoreNulls, boolean includePrimary) {
+ MetaObject metaObject = EntityMetaObject.forObject(entity, reflectorFactory);
+ List values = new ArrayList<>();
+ if (entity instanceof ModifyAttrsRecord) {
+ Set properties = ((ModifyAttrsRecord) entity).obtainModifyAttrs();
+ if (properties.isEmpty()) {
+ return values.toArray();
+ }
+ for (String property : properties) {
+ String column = propertyColumnMapping.get(property);
+ if (onUpdateColumns != null && onUpdateColumns.containsKey(column)) {
+ continue;
+ }
+ //过滤乐观锁字段 和 租户字段
+ if (ObjectUtil.equalsAny(column, versionColumn, tenantIdColumn)) {
+ continue;
+ }
+
+ if (!includePrimary && ArrayUtil.contains(primaryKeys, column)) {
+ continue;
+ }
+
+ Object value = buildColumnSqlArg(metaObject, column);
+ // ModifyAttrsRecord 忽略 ignoreNulls 的设置,
+ // 当使用 ModifyAttrsRecord 时,可以理解为要对字段进行 null 值进行更新,否则没必要使用 ModifyAttrsRecord
+ // if (ignoreNulls && value == null) {
+ // continue;
+ // }
+ values.add(value);
+ }
+ }
+ // normal entity. not ModifyAttrsRecord
+ else {
+ for (String column : this.columns) {
+ if (onUpdateColumns != null && onUpdateColumns.containsKey(column)) {
+ continue;
+ }
+
+ //过滤乐观锁字段 和 租户字段
+ if (ObjectUtil.equalsAny(column, versionColumn, tenantIdColumn)) {
+ continue;
+ }
+
+ // 普通 entity 忽略 includePrimary 的设置,
+ // 因为 for 循环中的 this.columns 本身就不包含有主键
+ // if (includePrimary) {
+ // }
+
+ Object value = buildColumnSqlArg(metaObject, column);
+ if (ignoreNulls && value == null) {
+ continue;
+ }
+
+ values.add(value);
+ }
+ }
+
+ return values.toArray();
+ }
+
+
+ /**
+ * 构建主键的 sql 参数数据
+ *
+ * @param entity
+ */
+ public Object[] buildPkSqlArgs(Object entity) {
+ MetaObject metaObject = EntityMetaObject.forObject(entity, reflectorFactory);
+ Object[] values = new Object[primaryKeys.length];
+ for (int i = 0; i < primaryKeys.length; i++) {
+ values[i] = buildColumnSqlArg(metaObject, primaryKeys[i]);
+ }
+ return values;
+ }
+
+
+ public Object[] buildTenantIdArgs() {
+ if (StringUtil.isBlank(tenantIdColumn)) {
+ return null;
+ }
+
+ return TenantManager.getTenantIds();
+ }
+
+ private static final String APPEND_CONDITIONS_FLAG = "appendConditions";
+
+ public void appendConditions(Object entity, QueryWrapper queryWrapper) {
+
+ Object appendConditions = CPI.getContext(queryWrapper, APPEND_CONDITIONS_FLAG);
+ if (Boolean.TRUE.equals(appendConditions)) {
+ return;
+ } else {
+ CPI.putContext(queryWrapper, APPEND_CONDITIONS_FLAG, Boolean.TRUE);
+ }
+
+ //select xxx.id,(select..) from xxx
+ List selectColumns = CPI.getSelectColumns(queryWrapper);
+ if (selectColumns != null && !selectColumns.isEmpty()) {
+ for (QueryColumn queryColumn : selectColumns) {
+ if (queryColumn instanceof SelectQueryColumn) {
+ QueryWrapper selectColumnQueryWrapper = CPI.getQueryWrapper((SelectQueryColumn) queryColumn);
+ doAppendConditions(entity, selectColumnQueryWrapper);
+ }
+ }
+ }
+
+ //select * from (select ... from ) 中的子查询处理
+ List queryTables = CPI.getQueryTables(queryWrapper);
+ if (queryTables != null && !queryTables.isEmpty()) {
+ for (QueryTable queryTable : queryTables) {
+ if (queryTable instanceof SelectQueryTable) {
+ QueryWrapper selectQueryWrapper = ((SelectQueryTable) queryTable).getQueryWrapper();
+ doAppendConditions(entity, selectQueryWrapper);
+ }
+ }
+ }
+
+ //添加乐观锁条件,只有在 update 的时候进行处理
+ if (StringUtil.isNotBlank(versionColumn) && entity != null) {
+ Object versionValue = buildColumnSqlArg(entity, versionColumn);
+ if (versionValue == null) {
+ throw FlexExceptions.wrap("The version value of entity[%s] must not be null.", entity);
+ }
+ queryWrapper.and(QueryCondition.create(schema, tableName, versionColumn, SqlConsts.EQUALS, versionValue));
+ }
+
+ //逻辑删除
+ if (StringUtil.isNotBlank(logicDeleteColumn)) {
+ queryWrapper.and(QueryCondition.create(schema, tableName, logicDeleteColumn, SqlConsts.EQUALS
+ , FlexGlobalConfig.getDefaultConfig().getNormalValueOfLogicDelete()));
+ }
+
+ //多租户
+ Object[] tenantIdArgs = buildTenantIdArgs();
+ if (ArrayUtil.isNotEmpty(tenantIdArgs)) {
+ if (tenantIdArgs.length == 1) {
+ queryWrapper.and(QueryCondition.create(schema, tableName, tenantIdColumn, SqlConsts.EQUALS, tenantIdArgs[0]));
+ } else {
+ queryWrapper.and(QueryCondition.create(schema, tableName, tenantIdColumn, SqlConsts.IN, tenantIdArgs));
+ }
+ }
+
+ //子查询
+ List childSelects = CPI.getChildSelect(queryWrapper);
+ if (CollectionUtil.isNotEmpty(childSelects)) {
+ for (QueryWrapper childQueryWrapper : childSelects) {
+ doAppendConditions(entity, childQueryWrapper);
+ }
+ }
+
+ //union
+ List unions = CPI.getUnions(queryWrapper);
+ if (CollectionUtil.isNotEmpty(unions)) {
+ for (UnionWrapper union : unions) {
+ QueryWrapper unionQueryWrapper = union.getQueryWrapper();
+ doAppendConditions(entity, unionQueryWrapper);
+ }
+ }
+ }
+
+
+ private void doAppendConditions(Object entity, QueryWrapper queryWrapper) {
+ List queryTables = CPI.getQueryTables(queryWrapper);
+ if (queryTables != null && !queryTables.isEmpty()) {
+ for (QueryTable queryTable : queryTables) {
+ TableInfo tableInfo = TableInfoFactory.ofTableName(queryTable.getName());
+ if (tableInfo != null) {
+ tableInfo.appendConditions(entity, queryWrapper);
+ }
+ }
+ }
+ }
+
+
+ public String getKeyProperties() {
+ StringJoiner joiner = new StringJoiner(",");
+ for (IdInfo value : primaryKeyList) {
+ joiner.add(FlexConsts.ENTITY + "." + value.getProperty());
+ }
+ return joiner.toString();
+ }
+
+
+ public String getKeyColumns() {
+ StringJoiner joiner = new StringJoiner(",");
+ for (IdInfo value : primaryKeyList) {
+ joiner.add(value.getColumn());
+ }
+ return joiner.toString();
+ }
+
+ public List getDefaultQueryColumn() {
+ return Arrays.stream(defaultColumns)
+ .map(name -> new QueryColumn(schema, getTableName(), name))
+ .collect(Collectors.toList());
+ }
+
+
+ public ResultMap buildResultMap(Configuration configuration) {
+ String resultMapId = entityClass.getName();
+ if (configuration.hasResultMap(resultMapId)) {
+ return configuration.getResultMap(resultMapId);
+ }
+ List resultMappings = new ArrayList<>();
+
+ // 标签下的 标签映射
+ for (ColumnInfo columnInfo : columnInfoList) {
+ ResultMapping mapping = new ResultMapping.Builder(configuration, columnInfo.property,
+ columnInfo.column, columnInfo.propertyType)
+ .jdbcType(columnInfo.getJdbcType())
+ .typeHandler(columnInfo.buildTypeHandler())
+ .build();
+ resultMappings.add(mapping);
+
+ //add property mapper for sql: select xxx as property ...
+ if (!Objects.equals(columnInfo.getColumn(), columnInfo.getProperty())) {
+ ResultMapping propertyMapping = new ResultMapping.Builder(configuration, columnInfo.property,
+ columnInfo.property, columnInfo.propertyType)
+ .jdbcType(columnInfo.getJdbcType())
+ .typeHandler(columnInfo.buildTypeHandler())
+ .build();
+ resultMappings.add(propertyMapping);
+ }
+ }
+
+ // 标签下的 标签映射
+ for (IdInfo idInfo : primaryKeyList) {
+ ResultMapping mapping = new ResultMapping.Builder(configuration, idInfo.property,
+ idInfo.column, idInfo.propertyType)
+ .flags(CollectionUtil.newArrayList(ResultFlag.ID))
+ .jdbcType(idInfo.getJdbcType())
+ .typeHandler(idInfo.buildTypeHandler())
+ .build();
+ resultMappings.add(mapping);
+ }
+
+ // 标签下的 标签映射
+ if (associationType != null) {
+ associationType.forEach((fieldName, fieldType) -> {
+ // 获取嵌套类型的信息,也就是 javaType 属性
+ TableInfo tableInfo = TableInfoFactory.ofEntityClass(fieldType);
+ // 构建嵌套类型的 ResultMap 对象,也就是 标签下的内容
+ ResultMap nestedResultMap = tableInfo.buildResultMap(configuration);
+ resultMappings.add(new ResultMapping.Builder(configuration, fieldName)
+ .javaType(fieldType)
+ .nestedResultMapId(nestedResultMap.getId())
+ .build());
+ });
+ }
+
+ // 标签下的 标签映射
+ if (collectionType != null) {
+ collectionType.forEach((field, genericClass) -> {
+ // 获取集合泛型类型的信息,也就是 ofType 属性
+ TableInfo tableInfo = TableInfoFactory.ofEntityClass(genericClass);
+ // 构建嵌套类型的 ResultMap 对象,也就是 标签下的内容
+ ResultMap nestedResultMap = tableInfo.buildResultMap(configuration);
+ resultMappings.add(new ResultMapping.Builder(configuration, field.getName())
+ .javaType(field.getType())
+ .nestedResultMapId(nestedResultMap.getId())
+ .build());
+ });
+ }
+
+ ResultMap resultMap = new ResultMap.Builder(configuration, resultMapId, entityClass, resultMappings).build();
+ configuration.addResultMap(resultMap);
+ return resultMap;
+ }
+
+
+ private Object buildColumnSqlArg(MetaObject metaObject, String column) {
+ ColumnInfo columnInfo = columnInfoMapping.get(column);
+ Object value = getPropertyValue(metaObject, columnInfo.property);
+
+ if (value != null) {
+ TypeHandler typeHandler = columnInfo.buildTypeHandler();
+ if (typeHandler != null) {
+ return new TypeHandlerObject(typeHandler, value, columnInfo.getJdbcType());
+ }
+ }
+
+ return value;
+ }
+
+
+ public Object buildColumnSqlArg(Object entityObject, String column) {
+ MetaObject metaObject = EntityMetaObject.forObject(entityObject, reflectorFactory);
+ return buildColumnSqlArg(metaObject, column);
+ }
+
+
+ private Object getPropertyValue(MetaObject metaObject, String property) {
+ if (property != null && metaObject.hasGetter(property)) {
+ return metaObject.getValue(property);
+ }
+ return null;
+ }
+
+
+ /**
+ * 通过 row 实例类转换为一个 entity
+ *
+ * @return entity
+ */
+ public T newInstanceByRow(Row row, int index) {
+ Object instance = ClassUtil.newInstance(entityClass);
+ MetaObject metaObject = EntityMetaObject.forObject(instance, reflectorFactory);
+ Set rowKeys = row.keySet();
+ columnInfoMapping.forEach((column, columnInfo) -> {
+ if (index <= 0) {
+ for (String rowKey : rowKeys) {
+ if (column.equalsIgnoreCase(rowKey)) {
+ setInstancePropertyValue(row, instance, metaObject, columnInfo, rowKey);
+ }
+ }
+ } else {
+ for (int i = index; i >= 0; i--) {
+ String newColumn = i <= 0 ? column : column + "$" + i;
+ boolean fillValue = false;
+ for (String rowKey : rowKeys) {
+ if (newColumn.equalsIgnoreCase(rowKey)) {
+ setInstancePropertyValue(row, instance, metaObject, columnInfo, rowKey);
+ fillValue = true;
+ break;
+ }
+ }
+ if (fillValue) {
+ break;
+ }
+ }
+ }
+ });
+ return (T) instance;
+ }
+
+
+ private void setInstancePropertyValue(Row row, Object instance, MetaObject metaObject, ColumnInfo columnInfo, String rowKey) {
+ Object rowValue = row.get(rowKey);
+ TypeHandler> typeHandler = columnInfo.buildTypeHandler();
+ if (typeHandler != null) {
+ try {
+ //通过 typeHandler 转换数据
+ rowValue = typeHandler.getResult(getResultSet(rowValue), 0);
+ } catch (SQLException e) {
+ //ignore
+ }
+ }
+ if (rowValue != null && !metaObject.getSetterType(columnInfo.property).isAssignableFrom(rowValue.getClass())) {
+ rowValue = ConvertUtil.convert(rowValue, metaObject.getSetterType(columnInfo.property), true);
+ }
+ rowValue = invokeOnSetListener(instance, columnInfo.getProperty(), rowValue);
+ metaObject.setValue(columnInfo.property, rowValue);
+ }
+
+
+ private ResultSet getResultSet(Object value) {
+ return (ResultSet) Proxy.newProxyInstance(TableInfo.class.getClassLoader(),
+ new Class[]{ResultSet.class}, (proxy, method, args) -> value);
+ }
+
+
+ /**
+ * 初始化乐观锁版本号
+ *
+ * @param entityObject
+ */
+ public void initVersionValueIfNecessary(Object entityObject) {
+ if (StringUtil.isBlank(versionColumn)) {
+ return;
+ }
+
+ MetaObject metaObject = EntityMetaObject.forObject(entityObject, reflectorFactory);
+ Object columnValue = getPropertyValue(metaObject, columnInfoMapping.get(versionColumn).property);
+ if (columnValue == null) {
+ String name = columnInfoMapping.get(versionColumn).property;
+ Class> clazz = metaObject.getSetterType(name);
+ metaObject.setValue(name, ConvertUtil.convert(0L, clazz));
+ }
+ }
+
+ /**
+ * 设置租户id
+ *
+ * @param entityObject
+ */
+ public void initTenantIdIfNecessary(Object entityObject) {
+ if (StringUtil.isBlank(tenantIdColumn)) {
+ return;
+ }
+
+ MetaObject metaObject = EntityMetaObject.forObject(entityObject, reflectorFactory);
+ Object[] tenantIds = TenantManager.getTenantIds();
+ if (tenantIds == null || tenantIds.length == 0) {
+ return;
+ }
+
+ //默认使用第一个作为插入的租户ID
+ Object tenantId = tenantIds[0];
+ if (tenantId != null) {
+ String property = columnInfoMapping.get(tenantIdColumn).property;
+ Class> setterType = metaObject.getSetterType(property);
+ metaObject.setValue(property, ConvertUtil.convert(tenantId, setterType));
+ }
+ }
+
+ /**
+ * 初始化逻辑删除的默认值
+ *
+ * @param entityObject
+ */
+ public void initLogicDeleteValueIfNecessary(Object entityObject) {
+ if (StringUtil.isBlank(logicDeleteColumn)) {
+ return;
+ }
+
+ MetaObject metaObject = EntityMetaObject.forObject(entityObject, reflectorFactory);
+ Object columnValue = getPropertyValue(metaObject, columnInfoMapping.get(logicDeleteColumn).property);
+ if (columnValue == null) {
+ String property = columnInfoMapping.get(logicDeleteColumn).property;
+ Class> setterType = metaObject.getSetterType(property);
+ Object normalValueOfLogicDelete = FlexGlobalConfig.getDefaultConfig().getNormalValueOfLogicDelete();
+ metaObject.setValue(property, ConvertUtil.convert(normalValueOfLogicDelete, setterType));
+ }
+ }
+
+
+ private static final Map, List> insertListenerCache = new ConcurrentHashMap<>();
+
+ public void invokeOnInsertListener(Object entity) {
+ List listeners = MapUtil.computeIfAbsent(insertListenerCache, entityClass, aClass -> {
+ List globalListeners = FlexGlobalConfig.getDefaultConfig()
+ .getSupportedInsertListener(entityClass, CollectionUtil.isNotEmpty(onInsertListeners));
+ List allListeners = CollectionUtil.merge(onInsertListeners, globalListeners);
+ Collections.sort(allListeners);
+ return allListeners;
+ });
+ listeners.forEach(insertListener -> insertListener.onInsert(entity));
+ }
+
+
+ private static final Map, List> updateListenerCache = new ConcurrentHashMap<>();
+
+ public void invokeOnUpdateListener(Object entity) {
+ List listeners = MapUtil.computeIfAbsent(updateListenerCache, entityClass, aClass -> {
+ List globalListeners = FlexGlobalConfig.getDefaultConfig()
+ .getSupportedUpdateListener(entityClass, CollectionUtil.isNotEmpty(onUpdateListeners));
+ List allListeners = CollectionUtil.merge(onUpdateListeners, globalListeners);
+ Collections.sort(allListeners);
+ return allListeners;
+ });
+ listeners.forEach(insertListener -> insertListener.onUpdate(entity));
+ }
+
+
+ private static final Map, List> setListenerCache = new ConcurrentHashMap<>();
+
+ public Object invokeOnSetListener(Object entity, String property, Object value) {
+ List listeners = MapUtil.computeIfAbsent(setListenerCache, entityClass, aClass -> {
+ List globalListeners = FlexGlobalConfig.getDefaultConfig()
+ .getSupportedSetListener(entityClass, CollectionUtil.isNotEmpty(onSetListeners));
+ List allListeners = CollectionUtil.merge(onSetListeners, globalListeners);
+ Collections.sort(allListeners);
+ return allListeners;
+ });
+ for (SetListener setListener : listeners) {
+ value = setListener.onSet(entity, property, value);
+ }
+ return value;
+ }
+
+ public QueryColumn getQueryColumnByProperty(String property) {
+ return new QueryColumn(schema, tableName, propertyColumnMapping.get(property));
+ }
+}