001/*
002 *  Copyright (c) 2022-2023, Mybatis-Flex (fuhai999@gmail.com).
003 *  <p>
004 *  Licensed under the Apache License, Version 2.0 (the "License");
005 *  you may not use this file except in compliance with the License.
006 *  You may obtain a copy of the License at
007 *  <p>
008 *  http://www.apache.org/licenses/LICENSE-2.0
009 *  <p>
010 *  Unless required by applicable law or agreed to in writing, software
011 *  distributed under the License is distributed on an "AS IS" BASIS,
012 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 *  See the License for the specific language governing permissions and
014 *  limitations under the License.
015 */
016package com.mybatisflex.core.table;
017
018import com.mybatisflex.annotation.Column;
019import com.mybatisflex.annotation.InsertListener;
020import com.mybatisflex.annotation.KeyType;
021import com.mybatisflex.annotation.SetListener;
022import com.mybatisflex.annotation.UpdateListener;
023import com.mybatisflex.core.FlexConsts;
024import com.mybatisflex.core.FlexGlobalConfig;
025import com.mybatisflex.core.constant.SqlConsts;
026import com.mybatisflex.core.constant.SqlOperator;
027import com.mybatisflex.core.dialect.IDialect;
028import com.mybatisflex.core.exception.FlexExceptions;
029import com.mybatisflex.core.exception.locale.LocalizedFormats;
030import com.mybatisflex.core.logicdelete.LogicDeleteManager;
031import com.mybatisflex.core.mybatis.TypeHandlerObject;
032import com.mybatisflex.core.query.CPI;
033import com.mybatisflex.core.query.Join;
034import com.mybatisflex.core.query.QueryColumn;
035import com.mybatisflex.core.query.QueryCondition;
036import com.mybatisflex.core.query.QueryMethods;
037import com.mybatisflex.core.query.QueryTable;
038import com.mybatisflex.core.query.QueryWrapper;
039import com.mybatisflex.core.query.SelectQueryColumn;
040import com.mybatisflex.core.query.SelectQueryTable;
041import com.mybatisflex.core.query.SqlOperators;
042import com.mybatisflex.core.query.UnionWrapper;
043import com.mybatisflex.core.row.Row;
044import com.mybatisflex.core.tenant.TenantManager;
045import com.mybatisflex.core.update.RawValue;
046import com.mybatisflex.core.update.UpdateWrapper;
047import com.mybatisflex.core.util.ArrayUtil;
048import com.mybatisflex.core.util.ClassUtil;
049import com.mybatisflex.core.util.CollectionUtil;
050import com.mybatisflex.core.util.ConvertUtil;
051import com.mybatisflex.core.util.EnumWrapper;
052import com.mybatisflex.core.util.FieldWrapper;
053import com.mybatisflex.core.util.ObjectUtil;
054import com.mybatisflex.core.util.SqlUtil;
055import com.mybatisflex.core.util.StringUtil;
056import org.apache.ibatis.mapping.ResultFlag;
057import org.apache.ibatis.mapping.ResultMap;
058import org.apache.ibatis.mapping.ResultMapping;
059import org.apache.ibatis.reflection.MetaObject;
060import org.apache.ibatis.reflection.Reflector;
061import org.apache.ibatis.reflection.ReflectorFactory;
062import org.apache.ibatis.session.Configuration;
063import org.apache.ibatis.type.TypeHandler;
064import org.apache.ibatis.util.MapUtil;
065
066import java.lang.reflect.Field;
067import java.lang.reflect.Proxy;
068import java.sql.ResultSet;
069import java.sql.SQLException;
070import java.util.ArrayList;
071import java.util.Arrays;
072import java.util.Collections;
073import java.util.HashMap;
074import java.util.HashSet;
075import java.util.LinkedHashMap;
076import java.util.LinkedHashSet;
077import java.util.List;
078import java.util.Map;
079import java.util.Objects;
080import java.util.Set;
081import java.util.StringJoiner;
082import java.util.concurrent.ConcurrentHashMap;
083import java.util.function.Function;
084import java.util.stream.Collectors;
085import java.util.stream.Stream;
086
087import static com.mybatisflex.core.constant.SqlConsts.AND;
088import static com.mybatisflex.core.constant.SqlConsts.EQUALS_PLACEHOLDER;
089import static com.mybatisflex.core.constant.SqlConsts.IN;
090
091public class TableInfo {
092
093    private String schema; //schema
094    private String tableName; //表名
095    private Class<?> entityClass; //实体类
096    private boolean camelToUnderline = true;
097    private String dataSource;
098
099    //逻辑删除数据库列名
100    private String logicDeleteColumn;
101
102    //乐观锁字段
103    private String versionColumn;
104
105    //租户ID 字段
106    private String tenantIdColumn;
107
108    //数据插入时,默认插入数据字段
109    private Map<String, String> onInsertColumns;
110
111    //数据更新时,默认更新内容的字段
112    private Map<String, String> onUpdateColumns;
113
114    //大字段列
115    private String[] largeColumns = new String[0];
116
117    private String[] allColumns = new String[0];
118
119    //所有的字段,但除了主键的列
120    private String[] columns = new String[0];
121
122    //主键字段
123    private String[] primaryColumns = new String[0];
124
125    // 默认查询列,排除 large 等字段
126    private String[] defaultQueryColumns = new String[0];
127
128    //在插入数据的时候,支持主动插入的主键字段,自增字段不需要主动插入
129    //但通过自定义生成器生成 或者 Sequence 在 before 生成的时候,是需要主动插入数据的
130    private String[] insertPrimaryKeys;
131
132    private List<ColumnInfo> columnInfoList;
133    private List<IdInfo> primaryKeyList;
134
135    //column 和 java 属性的称的关系映射
136    private final Map<String, ColumnInfo> columnInfoMapping = new HashMap<>();
137    private final Map<String, QueryColumn> columnQueryMapping = new HashMap<>();
138
139    //property:column
140    private final Map<String, String> propertyColumnMapping = new LinkedHashMap<>();
141
142    private List<InsertListener> onInsertListeners;
143    private List<UpdateListener> onUpdateListeners;
144    private List<SetListener> onSetListeners;
145
146    /**
147     * 对应 MapperXML 配置文件中 {@code <resultMap>} 标签下的 {@code <association>} 标签。
148     */
149    private Map<String, Class<?>> associationType;
150
151    /**
152     * 对应 MapperXML 配置文件中 {@code <resultMap>} 标签下的 {@code <collection>} 标签。
153     */
154    private Map<Field, Class<?>> collectionType;
155
156
157    private final ReflectorFactory reflectorFactory = new BaseReflectorFactory() {
158        @Override
159        public Reflector findForClass(Class<?> type) {
160            return getReflector();
161        }
162    };
163    private Reflector reflector; //反射工具
164
165    public String getSchema() {
166        return schema;
167    }
168
169    public void setSchema(String schema) {
170        this.schema = schema;
171    }
172
173    public String getTableName() {
174        return tableName;
175    }
176
177    public String getTableNameWithSchema() {
178        return StringUtil.buildSchemaWithTable(schema, tableName);
179    }
180
181    public String getWrapSchemaAndTableName(IDialect dialect) {
182        if (StringUtil.isNotBlank(schema)) {
183            String table = dialect.getRealTable(tableName);
184            return dialect.wrap(dialect.getRealSchema(schema, table)) + "." + dialect.wrap(table);
185        } else {
186            return dialect.wrap(dialect.getRealTable(tableName));
187        }
188    }
189
190    public void setTableName(String tableName) {
191        int indexOf = tableName.indexOf(".");
192        if (indexOf > 0) {
193            if (StringUtil.isBlank(schema)) {
194                this.schema = tableName.substring(0, indexOf);
195                this.tableName = tableName.substring(indexOf + 1);
196            } else {
197                this.tableName = tableName;
198            }
199        } else {
200            this.tableName = tableName;
201        }
202    }
203
204    public Class<?> getEntityClass() {
205        return entityClass;
206    }
207
208    public void setEntityClass(Class<?> entityClass) {
209        this.entityClass = entityClass;
210    }
211
212    public boolean isCamelToUnderline() {
213        return camelToUnderline;
214    }
215
216    public void setCamelToUnderline(boolean camelToUnderline) {
217        this.camelToUnderline = camelToUnderline;
218    }
219
220    public String getDataSource() {
221        return dataSource;
222    }
223
224    public void setDataSource(String dataSource) {
225        this.dataSource = dataSource;
226    }
227
228    public String getLogicDeleteColumnOrSkip() {
229        return LogicDeleteManager.getLogicDeleteColumn(logicDeleteColumn);
230    }
231
232    public String getLogicDeleteColumn() {
233        return logicDeleteColumn;
234    }
235
236    public void setLogicDeleteColumn(String logicDeleteColumn) {
237        this.logicDeleteColumn = logicDeleteColumn;
238    }
239
240    public String getVersionColumn() {
241        return versionColumn;
242    }
243
244    public void setVersionColumn(String versionColumn) {
245        this.versionColumn = versionColumn;
246    }
247
248    public String getTenantIdColumn() {
249        return tenantIdColumn;
250    }
251
252    public void setTenantIdColumn(String tenantIdColumn) {
253        this.tenantIdColumn = tenantIdColumn;
254    }
255
256    public Map<String, String> getOnInsertColumns() {
257        return onInsertColumns;
258    }
259
260    public void setOnInsertColumns(Map<String, String> onInsertColumns) {
261        this.onInsertColumns = onInsertColumns;
262    }
263
264    public Map<String, String> getOnUpdateColumns() {
265        return onUpdateColumns;
266    }
267
268    public void setOnUpdateColumns(Map<String, String> onUpdateColumns) {
269        this.onUpdateColumns = onUpdateColumns;
270    }
271
272    public String[] getLargeColumns() {
273        return largeColumns;
274    }
275
276    public void setLargeColumns(String[] largeColumns) {
277        this.largeColumns = largeColumns;
278    }
279
280    public String[] getDefaultQueryColumns() {
281        return defaultQueryColumns;
282    }
283
284    public void setDefaultQueryColumns(String[] defaultQueryColumns) {
285        this.defaultQueryColumns = defaultQueryColumns;
286    }
287
288    public String[] getInsertPrimaryKeys() {
289        return insertPrimaryKeys;
290    }
291
292    public void setInsertPrimaryKeys(String[] insertPrimaryKeys) {
293        this.insertPrimaryKeys = insertPrimaryKeys;
294    }
295
296    public Reflector getReflector() {
297        return reflector;
298    }
299
300    public ReflectorFactory getReflectorFactory() {
301        return reflectorFactory;
302    }
303
304    public void setReflector(Reflector reflector) {
305        this.reflector = reflector;
306    }
307
308    public String[] getAllColumns() {
309        return allColumns;
310    }
311
312    public void setAllColumns(String[] allColumns) {
313        this.allColumns = allColumns;
314    }
315
316    public String[] getColumns() {
317        return columns;
318    }
319
320
321    public void setColumns(String[] columns) {
322        this.columns = columns;
323    }
324
325    public String[] getPrimaryColumns() {
326        return primaryColumns;
327    }
328
329    public void setPrimaryColumns(String[] primaryColumns) {
330        this.primaryColumns = primaryColumns;
331    }
332
333
334    public List<InsertListener> getOnInsertListeners() {
335        return onInsertListeners;
336    }
337
338    public void setOnInsertListeners(List<InsertListener> onInsertListeners) {
339        this.onInsertListeners = onInsertListeners;
340    }
341
342    public List<UpdateListener> getOnUpdateListeners() {
343        return onUpdateListeners;
344    }
345
346    public void setOnUpdateListeners(List<UpdateListener> onUpdateListeners) {
347        this.onUpdateListeners = onUpdateListeners;
348    }
349
350    public List<SetListener> getOnSetListeners() {
351        return onSetListeners;
352    }
353
354    public void setOnSetListeners(List<SetListener> onSetListeners) {
355        this.onSetListeners = onSetListeners;
356    }
357
358    public List<ColumnInfo> getColumnInfoList() {
359        return columnInfoList;
360    }
361
362    public String getColumnByProperty(String property) {
363        String column = propertyColumnMapping.get(property);
364        return StringUtil.isNotBlank(column) ? column : property;
365    }
366
367    public Map<String, Class<?>> getAssociationType() {
368        return associationType;
369    }
370
371    public void setAssociationType(Map<String, Class<?>> associationType) {
372        this.associationType = associationType;
373    }
374
375    public void addAssociationType(String fieldName, Class<?> clazz) {
376        if (associationType == null) {
377            associationType = new HashMap<>();
378        }
379        associationType.put(fieldName, clazz);
380    }
381
382    public Map<Field, Class<?>> getCollectionType() {
383        return collectionType;
384    }
385
386    public void setCollectionType(Map<Field, Class<?>> collectionType) {
387        this.collectionType = collectionType;
388    }
389
390    public void addCollectionType(Field field, Class<?> genericClass) {
391        if (collectionType == null) {
392            collectionType = new HashMap<>();
393        }
394        collectionType.put(field, genericClass);
395    }
396
397    void setColumnInfoList(List<ColumnInfo> columnInfoList) {
398        this.columnInfoList = columnInfoList;
399        List<String> columnNames = new ArrayList<>();
400        for (int i = 0; i < columnInfoList.size(); i++) {
401            ColumnInfo columnInfo = columnInfoList.get(i);
402            //真正的字段(没有做忽略标识)
403            if (!columnInfo.isIgnore()) {
404                columnNames.add(columnInfo.column);
405
406                columnInfoMapping.put(columnInfo.column, columnInfo);
407                propertyColumnMapping.put(columnInfo.property, columnInfo.column);
408
409                String[] alias = columnInfo.getAlias();
410                columnQueryMapping.put(columnInfo.column, new QueryColumn(schema, tableName, columnInfo.column, alias != null && alias.length > 0 ? alias[0] : null));
411            }
412        }
413
414        this.columns = columnNames.toArray(new String[]{});
415        this.allColumns = ArrayUtil.concat(allColumns, columns);
416    }
417
418
419    public List<IdInfo> getPrimaryKeyList() {
420        return primaryKeyList;
421    }
422
423    void setPrimaryKeyList(List<IdInfo> primaryKeyList) {
424        this.primaryKeyList = primaryKeyList;
425        this.primaryColumns = new String[primaryKeyList.size()];
426
427        List<String> insertIdFields = new ArrayList<>();
428
429        for (int i = 0; i < primaryKeyList.size(); i++) {
430            IdInfo idInfo = primaryKeyList.get(i);
431            primaryColumns[i] = idInfo.getColumn();
432
433            if (idInfo.getKeyType() != KeyType.Auto
434                && (idInfo.getBefore() != null && idInfo.getBefore())
435            ) {
436                insertIdFields.add(idInfo.getColumn());
437            }
438
439            columnInfoMapping.put(idInfo.column, idInfo);
440            propertyColumnMapping.put(idInfo.property, idInfo.column);
441
442            String[] alias = idInfo.getAlias();
443            columnQueryMapping.put(idInfo.column, new QueryColumn(schema, tableName, idInfo.column, alias != null && alias.length > 0 ? alias[0] : null));
444        }
445        this.allColumns = ArrayUtil.concat(allColumns, primaryColumns);
446        this.insertPrimaryKeys = insertIdFields.toArray(new String[0]);
447    }
448
449
450    /**
451     * 构建 insert 的 Sql 参数
452     *
453     * @param entity      从 entity 中获取
454     * @param ignoreNulls 是否忽略 null 值
455     * @return 数组
456     */
457    public Object[] buildInsertSqlArgs(Object entity, boolean ignoreNulls) {
458        MetaObject metaObject = EntityMetaObject.forObject(entity, reflectorFactory);
459        String[] insertColumns = obtainInsertColumns(entity, ignoreNulls);
460
461        Map<String, RawValue> rawValueMap = obtainUpdateRawValueMap(entity);
462
463        List<Object> values = new ArrayList<>(insertColumns.length);
464        for (String insertColumn : insertColumns) {
465            if (onInsertColumns == null || !onInsertColumns.containsKey(insertColumn)) {
466                if (rawValueMap.containsKey(insertColumn)) {
467                    continue;
468                }
469                Object value = buildColumnSqlArg(metaObject, insertColumn);
470                if (ignoreNulls && value == null) {
471                    continue;
472                }
473                values.add(value);
474            }
475        }
476        return values.toArray();
477    }
478
479    /**
480     * 插入(新增)数据时,获取所有要插入的字段
481     *
482     * @param entity
483     * @param ignoreNulls
484     * @return 字段列表
485     */
486    public String[] obtainInsertColumns(Object entity, boolean ignoreNulls) {
487        if (!ignoreNulls) {
488            return ArrayUtil.concat(insertPrimaryKeys, columns);
489        }
490        // 忽略 null 字段,
491        else {
492            MetaObject metaObject = EntityMetaObject.forObject(entity, reflectorFactory);
493            List<String> retColumns = new ArrayList<>();
494            for (String insertColumn : allColumns) {
495                if (onInsertColumns != null && onInsertColumns.containsKey(insertColumn)) {
496                    retColumns.add(insertColumn);
497                } else {
498                    Object value = buildColumnSqlArg(metaObject, insertColumn);
499                    if (value == null) {
500                        continue;
501                    }
502                    retColumns.add(insertColumn);
503                }
504            }
505            return retColumns.toArray(new String[0]);
506        }
507    }
508
509
510    public Object[] buildInsertSqlArgsWithPk(Object entity, boolean ignoreNulls) {
511        MetaObject metaObject = EntityMetaObject.forObject(entity, reflectorFactory);
512        String[] insertColumns = obtainInsertColumnsWithPk(entity, ignoreNulls);
513
514        List<Object> values = new ArrayList<>(insertColumns.length);
515        for (String insertColumn : insertColumns) {
516            if (onInsertColumns == null || !onInsertColumns.containsKey(insertColumn)) {
517                Object value = buildColumnSqlArg(metaObject, insertColumn);
518                if (ignoreNulls && value == null) {
519                    continue;
520                }
521                values.add(value);
522            }
523        }
524        return values.toArray();
525    }
526
527
528    /**
529     * 插入(新增)数据时,获取所有要插入的字段
530     *
531     * @param entity
532     * @param ignoreNulls
533     * @return 字段列表
534     */
535    public String[] obtainInsertColumnsWithPk(Object entity, boolean ignoreNulls) {
536        if (!ignoreNulls) {
537            return allColumns;
538        } else {
539            MetaObject metaObject = EntityMetaObject.forObject(entity, reflectorFactory);
540            List<String> retColumns = new ArrayList<>();
541            for (String primaryKey : primaryColumns) {
542                Object value = buildColumnSqlArg(metaObject, primaryKey);
543                if (value == null) {
544                    throw new IllegalArgumentException("Entity Primary Key value must not be null.");
545                }
546                retColumns.add(primaryKey);
547            }
548            for (String insertColumn : columns) {
549                if (onInsertColumns != null && onInsertColumns.containsKey(insertColumn)) {
550                    retColumns.add(insertColumn);
551                } else {
552                    Object value = buildColumnSqlArg(metaObject, insertColumn);
553                    if (value == null) {
554                        continue;
555                    }
556                    retColumns.add(insertColumn);
557                }
558            }
559            return retColumns.toArray(new String[0]);
560        }
561    }
562
563
564    @SuppressWarnings({"unchecked", "rawtypes"})
565    public Map<String, RawValue> obtainUpdateRawValueMap(Object entity) {
566        if (!(entity instanceof UpdateWrapper)) {
567            return Collections.emptyMap();
568        }
569
570        Map<String, Object> updates = ((UpdateWrapper) entity).getUpdates();
571        if (updates.isEmpty()) {
572            return Collections.emptyMap();
573        }
574
575        Map<String, RawValue> map = new HashMap<>();
576        updates.forEach((key, value) -> {
577            if (value instanceof RawValue) {
578                String column = getColumnByProperty(key);
579                map.put(column, (RawValue) value);
580            }
581        });
582
583        return map;
584    }
585
586    /**
587     * 获取要修改的值
588     *
589     * @param entity
590     * @param ignoreNulls
591     */
592    public Set<String> obtainUpdateColumns(Object entity, boolean ignoreNulls, boolean includePrimary) {
593        MetaObject metaObject = EntityMetaObject.forObject(entity, reflectorFactory);
594        Set<String> columns = new LinkedHashSet<>(); //需使用 LinkedHashSet 保证 columns 的顺序
595        if (entity instanceof UpdateWrapper) {
596            Map<String, Object> updates = ((UpdateWrapper) entity).getUpdates();
597            if (updates.isEmpty()) {
598                return Collections.emptySet();
599            }
600            for (String property : updates.keySet()) {
601
602                String column = getColumnByProperty(property);
603
604                if (onUpdateColumns != null && onUpdateColumns.containsKey(column)) {
605                    continue;
606                }
607
608                //过滤乐观锁字段 和 租户字段
609                if (ObjectUtil.equalsAny(column, versionColumn, tenantIdColumn)) {
610                    continue;
611                }
612
613                if (!includePrimary && ArrayUtil.contains(primaryColumns, column)) {
614                    continue;
615                }
616
617//                Object value = updates.get(property);
618                // ModifyAttrsRecord 忽略 ignoreNulls 的设置
619                // Object value = getPropertyValue(metaObject, property);
620                // if (ignoreNulls && value == null) {
621                //     continue;
622                // }
623                columns.add(column);
624            }
625        }
626        //not ModifyAttrsRecord
627        else {
628            for (String column : this.columns) {
629                if (onUpdateColumns != null && onUpdateColumns.containsKey(column)) {
630                    continue;
631                }
632
633                //过滤乐观锁字段 和 租户字段
634                if (ObjectUtil.equalsAny(column, versionColumn, tenantIdColumn)) {
635                    continue;
636                }
637
638                Object value = buildColumnSqlArg(metaObject, column);
639                if (ignoreNulls && value == null) {
640                    continue;
641                }
642
643                columns.add(column);
644            }
645        }
646        return columns;
647    }
648
649    /**
650     * 获取所有要修改的值,默认为全部除了主键以外的字段
651     *
652     * @param entity 实体对象
653     * @return 数组
654     */
655    public Object[] buildUpdateSqlArgs(Object entity, boolean ignoreNulls, boolean includePrimary) {
656
657        List<Object> values = new ArrayList<>();
658        if (entity instanceof UpdateWrapper) {
659            Map<String, Object> updates = ((UpdateWrapper) entity).getUpdates();
660            if (updates.isEmpty()) {
661                return FlexConsts.EMPTY_ARRAY;
662            }
663            for (String property : updates.keySet()) {
664
665                String column = getColumnByProperty(property);
666
667                if (onUpdateColumns != null && onUpdateColumns.containsKey(column)) {
668                    continue;
669                }
670                //过滤乐观锁字段 和 租户字段
671                if (ObjectUtil.equalsAny(column, versionColumn, tenantIdColumn)) {
672                    continue;
673                }
674
675                if (!includePrimary && ArrayUtil.contains(primaryColumns, column)) {
676                    continue;
677                }
678
679                Object value = updates.get(property);
680                if (value instanceof RawValue) {
681                    continue;
682                }
683
684                if (value != null) {
685                    ColumnInfo columnInfo = columnInfoMapping.get(column);
686                    if (columnInfo != null) {
687                        TypeHandler typeHandler = columnInfo.buildTypeHandler(null);
688                        if (typeHandler != null) {
689                            value = new TypeHandlerObject(typeHandler, value, columnInfo.getJdbcType());
690                        }
691                    }
692
693                    // fixed: https://gitee.com/mybatis-flex/mybatis-flex/issues/I7TFBK
694                    if (value.getClass().isEnum()) {
695                        EnumWrapper enumWrapper = EnumWrapper.of(value.getClass());
696                        if (enumWrapper.hasEnumValueAnnotation()) {
697                            value = enumWrapper.getEnumValue((Enum) value);
698                        } else {
699                            value = ((Enum<?>) value).name();
700                        }
701                    }
702                }
703
704                // ModifyAttrsRecord 忽略 ignoreNulls 的设置,
705                // 当使用 ModifyAttrsRecord 时,可以理解为要对字段进行 null 值进行更新,否则没必要使用 ModifyAttrsRecord
706                // if (ignoreNulls && value == null) {
707                //    continue;
708                // }
709                values.add(value);
710            }
711        }
712        // normal entity. not ModifyAttrsRecord
713        else {
714            MetaObject metaObject = EntityMetaObject.forObject(entity, reflectorFactory);
715
716            for (String column : this.columns) {
717                if (onUpdateColumns != null && onUpdateColumns.containsKey(column)) {
718                    continue;
719                }
720
721                //过滤乐观锁字段 和 租户字段
722                if (ObjectUtil.equalsAny(column, versionColumn, tenantIdColumn)) {
723                    continue;
724                }
725
726                // 普通 entity 忽略 includePrimary 的设置,
727                // 因为 for 循环中的 this.columns 本身就不包含有主键
728                // if (includePrimary) {
729                // }
730
731                Object value = buildColumnSqlArg(metaObject, column);
732                if (ignoreNulls && value == null) {
733                    continue;
734                }
735
736                values.add(value);
737            }
738        }
739
740        return values.toArray();
741    }
742
743
744    /**
745     * 构建主键的 sql 参数数据
746     *
747     * @param entity
748     */
749    public Object[] buildPkSqlArgs(Object entity) {
750        MetaObject metaObject = EntityMetaObject.forObject(entity, reflectorFactory);
751        Object[] values = new Object[primaryColumns.length];
752        for (int i = 0; i < primaryColumns.length; i++) {
753            values[i] = buildColumnSqlArg(metaObject, primaryColumns[i]);
754        }
755        return values;
756    }
757
758    public Object getValue(Object entity, String property) {
759        FieldWrapper fieldWrapper = FieldWrapper.of(entityClass, property);
760        return fieldWrapper.get(entity);
761    }
762
763    /**
764     * 获取主键值
765     *
766     * @param entity
767     * @return 主键值,有多个主键时返回数组
768     */
769    public Object getPkValue(Object entity) {
770        //绝大多数情况为 1 个主键
771        if (primaryColumns.length == 1) {
772            MetaObject metaObject = EntityMetaObject.forObject(entity, reflectorFactory);
773            ColumnInfo columnInfo = columnInfoMapping.get(primaryColumns[0]);
774            return getPropertyValue(metaObject, columnInfo.property);
775        }
776        //多个主键
777        else if (primaryColumns.length > 1) {
778            MetaObject metaObject = EntityMetaObject.forObject(entity, reflectorFactory);
779            Object[] values = new Object[primaryColumns.length];
780            for (int i = 0; i < primaryColumns.length; i++) {
781                ColumnInfo columnInfo = columnInfoMapping.get(primaryColumns[i]);
782                values[i] = getPropertyValue(metaObject, columnInfo.property);
783            }
784            return values;
785        }
786        //无主键
787        else {
788            return null;
789        }
790    }
791
792
793    public Object[] buildTenantIdArgs() {
794        if (StringUtil.isBlank(tenantIdColumn)) {
795            return null;
796        }
797
798        return TenantManager.getTenantIds();
799    }
800
801
802    public String buildTenantCondition(String sql, Object[] tenantIdArgs, IDialect dialect) {
803        if (ArrayUtil.isNotEmpty(tenantIdArgs)) {
804            if (tenantIdArgs.length == 1) {
805                return sql + AND + dialect.wrap(tenantIdColumn) + EQUALS_PLACEHOLDER;
806            } else {
807                return sql + AND + dialect.wrap(tenantIdColumn) + IN + SqlUtil.buildSqlParamPlaceholder(tenantIdArgs.length);
808            }
809        } else {
810            return sql;
811        }
812    }
813
814    public void buildTenantCondition(StringBuilder sql, Object[] tenantIdArgs, IDialect dialect) {
815        if (ArrayUtil.isNotEmpty(tenantIdArgs)) {
816            if (tenantIdArgs.length == 1) {
817                sql.append(AND).append(dialect.wrap(tenantIdColumn)).append(EQUALS_PLACEHOLDER);
818            } else {
819                sql.append(AND).append(dialect.wrap(tenantIdColumn)).append(IN).append(SqlUtil.buildSqlParamPlaceholder(tenantIdArgs.length));
820            }
821        }
822    }
823
824
825    public void buildTenantCondition(QueryWrapper queryWrapper) {
826        Object[] tenantIdArgs = buildTenantIdArgs();
827        if (ArrayUtil.isNotEmpty(tenantIdArgs)) {
828            if (tenantIdArgs.length == 1) {
829                queryWrapper.where(QueryCondition.create(schema, tableName, tenantIdColumn, SqlConsts.EQUALS, tenantIdArgs[0]));
830            } else {
831                queryWrapper.where(QueryCondition.create(schema, tableName, tenantIdColumn, SqlConsts.IN, tenantIdArgs));
832            }
833        }
834    }
835
836
837    private static final String APPEND_CONDITIONS_FLAG = "appendConditions";
838
839    public void appendConditions(Object entity, QueryWrapper queryWrapper) {
840
841        Object appendConditions = CPI.getContext(queryWrapper, APPEND_CONDITIONS_FLAG);
842        if (Boolean.TRUE.equals(appendConditions)) {
843            return;
844        } else {
845            CPI.putContext(queryWrapper, APPEND_CONDITIONS_FLAG, Boolean.TRUE);
846        }
847
848        //select xxx.id,(select..) from xxx
849        List<QueryColumn> selectColumns = CPI.getSelectColumns(queryWrapper);
850        if (selectColumns != null && !selectColumns.isEmpty()) {
851            for (QueryColumn queryColumn : selectColumns) {
852                if (queryColumn instanceof SelectQueryColumn) {
853                    QueryWrapper selectColumnQueryWrapper = CPI.getQueryWrapper((SelectQueryColumn) queryColumn);
854                    doAppendConditions(entity, selectColumnQueryWrapper);
855                }
856            }
857        }
858
859        //select * from (select ... from ) 中的子查询处理
860        List<QueryTable> queryTables = CPI.getQueryTables(queryWrapper);
861        if (queryTables != null && !queryTables.isEmpty()) {
862            for (QueryTable queryTable : queryTables) {
863                if (queryTable instanceof SelectQueryTable) {
864                    QueryWrapper selectQueryWrapper = ((SelectQueryTable) queryTable).getQueryWrapper();
865                    doAppendConditions(entity, selectQueryWrapper);
866                }
867            }
868        }
869
870        //添加乐观锁条件,只有在 update 的时候进行处理
871        if (StringUtil.isNotBlank(versionColumn) && entity != null) {
872            Object versionValue = buildColumnSqlArg(entity, versionColumn);
873            if (versionValue == null) {
874                throw FlexExceptions.wrap(LocalizedFormats.ENTITY_VERSION_NULL, entity);
875            }
876            queryWrapper.and(QueryCondition.create(schema, tableName, versionColumn, SqlConsts.EQUALS, versionValue));
877        }
878
879        //逻辑删除
880        if (StringUtil.isNotBlank(getLogicDeleteColumnOrSkip())) {
881            String joinTableAlias = CPI.getContext(queryWrapper, "joinTableAlias");
882            LogicDeleteManager.getProcessor().buildQueryCondition(queryWrapper, this, joinTableAlias);
883        }
884
885        //多租户
886        buildTenantCondition(queryWrapper);
887
888
889        //子查询
890        List<QueryWrapper> childSelects = CPI.getChildSelect(queryWrapper);
891        if (CollectionUtil.isNotEmpty(childSelects)) {
892            for (QueryWrapper childQueryWrapper : childSelects) {
893                doAppendConditions(entity, childQueryWrapper);
894            }
895        }
896
897
898        //join
899        List<Join> joins = CPI.getJoins(queryWrapper);
900        if (CollectionUtil.isNotEmpty(joins)) {
901            for (Join join : joins) {
902                QueryTable joinQueryTable = CPI.getJoinQueryTable(join);
903
904                //join select
905                if (joinQueryTable instanceof SelectQueryTable) {
906                    QueryWrapper childQuery = ((SelectQueryTable) joinQueryTable).getQueryWrapper();
907                    doAppendConditions(entity, childQuery);
908                }
909                //join table
910                else {
911                    String nameWithSchema = joinQueryTable.getNameWithSchema();
912                    if (StringUtil.isNotBlank(nameWithSchema)) {
913                        TableInfo tableInfo = TableInfoFactory.ofTableName(nameWithSchema);
914                        if (tableInfo != null) {
915                            QueryCondition joinQueryCondition = CPI.getJoinQueryCondition(join);
916                            QueryWrapper newWrapper = QueryWrapper.create()
917                                .where(joinQueryCondition);
918                            CPI.putContext(newWrapper, "joinTableAlias", joinQueryTable.getAlias());
919                            tableInfo.appendConditions(entity, newWrapper);
920                            QueryCondition whereQueryCondition = CPI.getWhereQueryCondition(newWrapper);
921                            CPI.setJoinQueryCondition(join, whereQueryCondition);
922                        }
923                    }
924                }
925            }
926        }
927
928        //union
929        List<UnionWrapper> unions = CPI.getUnions(queryWrapper);
930        if (CollectionUtil.isNotEmpty(unions)) {
931            for (UnionWrapper union : unions) {
932                QueryWrapper unionQueryWrapper = union.getQueryWrapper();
933                doAppendConditions(entity, unionQueryWrapper);
934            }
935        }
936    }
937
938
939    private void doAppendConditions(Object entity, QueryWrapper queryWrapper) {
940        List<QueryTable> queryTables = CPI.getQueryTables(queryWrapper);
941        if (queryTables != null && !queryTables.isEmpty()) {
942            for (QueryTable queryTable : queryTables) {
943                if (queryTable instanceof SelectQueryTable) {
944                    QueryWrapper childQuery = ((SelectQueryTable) queryTable).getQueryWrapper();
945                    doAppendConditions(entity, childQuery);
946                } else {
947                    String nameWithSchema = queryTable.getNameWithSchema();
948                    if (StringUtil.isNotBlank(nameWithSchema)) {
949                        TableInfo tableInfo = TableInfoFactory.ofTableName(nameWithSchema);
950                        if (tableInfo != null) {
951                            tableInfo.appendConditions(entity, queryWrapper);
952                        }
953                    }
954                }
955            }
956        }
957    }
958
959
960    public QueryWrapper buildQueryWrapper(Object entity, SqlOperators operators) {
961        QueryColumn[] queryColumns = new QueryColumn[defaultQueryColumns.length];
962        for (int i = 0; i < defaultQueryColumns.length; i++) {
963            queryColumns[i] = columnQueryMapping.get(defaultQueryColumns[i]);
964        }
965
966        QueryWrapper queryWrapper = QueryWrapper.create();
967
968        String tableNameWithSchema = getTableNameWithSchema();
969        queryWrapper.select(queryColumns).from(tableNameWithSchema);
970
971        MetaObject metaObject = EntityMetaObject.forObject(entity, reflectorFactory);
972        propertyColumnMapping.forEach((property, column) -> {
973            if (column.equals(logicDeleteColumn)) {
974                return;
975            }
976            Object value = metaObject.getValue(property);
977            if (value != null && !"".equals(value)) {
978                QueryColumn queryColumn = buildQueryColumn(column);
979                if (operators != null && operators.containsKey(property)) {
980                    SqlOperator operator = operators.get(property);
981                    if (operator == SqlOperator.LIKE || operator == SqlOperator.NOT_LIKE) {
982                        value = "%" + value + "%";
983                    }
984                    queryWrapper.and(QueryCondition.create(queryColumn, operator, value));
985                } else {
986                    queryWrapper.and(queryColumn.eq(value));
987                }
988            }
989        });
990        return queryWrapper;
991    }
992
993
994    public QueryColumn buildQueryColumn(String column) {
995        String tableNameWithSchema = getTableNameWithSchema();
996        QueryColumn queryColumn = TableDefs.getQueryColumn(entityClass, tableNameWithSchema, column);
997        if (queryColumn == null) {
998            queryColumn = QueryMethods.column(tableNameWithSchema, column);
999        }
1000        return queryColumn;
1001    }
1002
1003
1004    public String getKeyProperties() {
1005        StringJoiner joiner = new StringJoiner(",");
1006        for (IdInfo value : primaryKeyList) {
1007            joiner.add(FlexConsts.ENTITY + "." + value.getProperty());
1008        }
1009        return joiner.toString();
1010    }
1011
1012
1013    public String getKeyColumns() {
1014        StringJoiner joiner = new StringJoiner(",");
1015        for (IdInfo value : primaryKeyList) {
1016            joiner.add(value.getColumn());
1017        }
1018        return joiner.toString();
1019    }
1020
1021    public List<QueryColumn> getDefaultQueryColumn() {
1022        return Arrays.stream(defaultQueryColumns)
1023            .map(columnQueryMapping::get)
1024            .collect(Collectors.toList());
1025    }
1026
1027
1028    public ResultMap buildResultMap(Configuration configuration) {
1029        // 所有的嵌套类对象引用
1030        Stream<Class<?>> ct = collectionType == null ? Stream.empty() : collectionType.values().stream();
1031        Stream<Class<?>> at = associationType == null ? Stream.empty() : associationType.values().stream();
1032
1033        Stream<String> nestedColumns = Stream.concat(at, ct)
1034            .map(TableInfoFactory::ofEntityClass)
1035            .flatMap(e -> Arrays.stream(e.allColumns));
1036
1037        // 预加载所有重复列,用于判断重名属性
1038        List<String> existedColumns = Stream.concat(Arrays.stream(allColumns), nestedColumns)
1039            .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()))
1040            .entrySet()
1041            .stream()
1042            .filter(e -> e.getValue().intValue() > 1)
1043            .map(Map.Entry::getKey)
1044            .collect(Collectors.toList());
1045
1046        return doBuildResultMap(configuration, new HashSet<>(), existedColumns, false, getTableNameWithSchema());
1047    }
1048
1049    private ResultMap doBuildResultMap(Configuration configuration, Set<String> resultMapIds, List<String> existedColumns, boolean isNested, String nestedPrefix) {
1050
1051        String resultMapId = isNested ? "nested-" + nestedPrefix + ":" + entityClass.getName() : entityClass.getName();
1052
1053        // 是否有循环引用
1054        boolean withCircularReference = resultMapIds.contains(resultMapId) || resultMapIds.contains(entityClass.getName());
1055        if (withCircularReference) {
1056            return null;
1057        }
1058
1059        resultMapIds.add(resultMapId);
1060
1061        if (configuration.hasResultMap(resultMapId)) {
1062            return configuration.getResultMap(resultMapId);
1063        }
1064
1065        List<ResultMapping> resultMappings = new ArrayList<>();
1066
1067        // <resultMap> 标签下的 <id> 标签映射
1068        for (IdInfo idInfo : primaryKeyList) {
1069            doBuildColumnResultMapping(configuration, resultMappings, existedColumns, idInfo, CollectionUtil.newArrayList(ResultFlag.ID), isNested);
1070        }
1071
1072        // <resultMap> 标签下的 <result> 标签映射
1073        for (ColumnInfo columnInfo : columnInfoList) {
1074            doBuildColumnResultMapping(configuration, resultMappings, existedColumns, columnInfo, Collections.emptyList(), isNested);
1075        }
1076
1077        // <resultMap> 标签下的 <association> 标签映射
1078        if (associationType != null) {
1079            associationType.forEach((fieldName, fieldType) -> {
1080                // 获取嵌套类型的信息,也就是 javaType 属性
1081                TableInfo tableInfo = TableInfoFactory.ofEntityClass(fieldType);
1082                // 构建嵌套类型的 ResultMap 对象,也就是 <association> 标签下的内容
1083                ResultMap nestedResultMap = tableInfo.doBuildResultMap(configuration, resultMapIds, existedColumns, true, nestedPrefix);
1084                if (nestedResultMap != null) {
1085                    resultMappings.add(new ResultMapping.Builder(configuration, fieldName)
1086                        .javaType(fieldType)
1087                        .nestedResultMapId(nestedResultMap.getId())
1088                        .build());
1089                }
1090            });
1091        }
1092
1093        // <resultMap> 标签下的 <collection> 标签映射
1094        if (collectionType != null) {
1095            collectionType.forEach((field, genericClass) -> {
1096                if (TableInfoFactory.defaultSupportColumnTypes.contains(genericClass)) {
1097                    // List<String> List<Integer> 等
1098                    String columnName = TableInfoFactory.getColumnName(camelToUnderline, field, field.getAnnotation(Column.class));
1099                    // 映射 <result column="..."/>
1100                    ResultMapping resultMapping = new ResultMapping.Builder(configuration, null)
1101                        .column(columnName)
1102                        .typeHandler(configuration.getTypeHandlerRegistry().getTypeHandler(genericClass))
1103                        .build();
1104                    String nestedResultMapId = entityClass.getName() + "." + field.getName();
1105                    ResultMap nestedResultMap;
1106                    if (configuration.hasResultMap(nestedResultMapId)) {
1107                        nestedResultMap = configuration.getResultMap(nestedResultMapId);
1108                    } else {
1109                        nestedResultMap = new ResultMap.Builder(configuration, nestedResultMapId, genericClass, Collections.singletonList(resultMapping)).build();
1110                        configuration.addResultMap(nestedResultMap);
1111                    }
1112                    // 映射 <collection property="..." ofType="genericClass">
1113                    resultMappings.add(new ResultMapping.Builder(configuration, field.getName())
1114                        .javaType(field.getType())
1115                        .nestedResultMapId(nestedResultMap.getId())
1116                        .build());
1117                } else {
1118                    // 获取集合泛型类型的信息,也就是 ofType 属性
1119                    TableInfo tableInfo = TableInfoFactory.ofEntityClass(genericClass);
1120                    // 构建嵌套类型的 ResultMap 对象,也就是 <collection> 标签下的内容
1121                    ResultMap nestedResultMap = tableInfo.doBuildResultMap(configuration, resultMapIds, existedColumns, true, nestedPrefix);
1122                    if (nestedResultMap != null) {
1123                        resultMappings.add(new ResultMapping.Builder(configuration, field.getName())
1124                            .javaType(field.getType())
1125                            .nestedResultMapId(nestedResultMap.getId())
1126                            .build());
1127                    }
1128                }
1129            });
1130        }
1131
1132        ResultMap resultMap = new ResultMap.Builder(configuration, resultMapId, entityClass, resultMappings).build();
1133        configuration.addResultMap(resultMap);
1134        resultMapIds.add(resultMapId);
1135        return resultMap;
1136    }
1137
1138    private void doBuildColumnResultMapping(Configuration configuration, List<ResultMapping> resultMappings
1139        , List<String> existedColumns, ColumnInfo columnInfo, List<ResultFlag> flags, boolean isNested) {
1140
1141        if (!isNested) {
1142            if (existedColumns.contains(columnInfo.column)) {
1143                // userName -> tb_user$user_name
1144                resultMappings.add(new ResultMapping.Builder(configuration
1145                    , columnInfo.property
1146                    , tableName + "$" + columnInfo.column
1147                    , columnInfo.propertyType)
1148                    .jdbcType(columnInfo.getJdbcType())
1149                    .flags(flags)
1150                    .typeHandler(columnInfo.buildTypeHandler(configuration))
1151                    .build());
1152            }
1153            buildDefaultResultMapping(configuration, resultMappings, columnInfo, flags);
1154        } else {
1155            if (existedColumns.contains(columnInfo.column)) {
1156                // userName -> tb_user$user_name
1157                resultMappings.add(new ResultMapping.Builder(configuration
1158                    , columnInfo.property
1159                    , tableName + "$" + columnInfo.column
1160                    , columnInfo.propertyType)
1161                    .jdbcType(columnInfo.getJdbcType())
1162                    .flags(flags)
1163                    .typeHandler(columnInfo.buildTypeHandler(configuration))
1164                    .build());
1165            } else {
1166                buildDefaultResultMapping(configuration, resultMappings, columnInfo, flags);
1167            }
1168        }
1169
1170        if (ArrayUtil.isNotEmpty(columnInfo.alias)) {
1171            for (String alias : columnInfo.alias) {
1172                // userName -> alias
1173                resultMappings.add(new ResultMapping.Builder(configuration
1174                    , columnInfo.property
1175                    , alias
1176                    , columnInfo.propertyType)
1177                    .jdbcType(columnInfo.getJdbcType())
1178                    .flags(flags)
1179                    .typeHandler(columnInfo.buildTypeHandler(configuration))
1180                    .build());
1181            }
1182        }
1183
1184    }
1185
1186    private void buildDefaultResultMapping(Configuration configuration, List<ResultMapping> resultMappings, ColumnInfo columnInfo, List<ResultFlag> flags) {
1187        // userName -> user_name
1188        resultMappings.add(new ResultMapping.Builder(configuration
1189            , columnInfo.property
1190            , columnInfo.column
1191            , columnInfo.propertyType)
1192            .jdbcType(columnInfo.getJdbcType())
1193            .flags(flags)
1194            .typeHandler(columnInfo.buildTypeHandler(configuration))
1195            .build());
1196
1197        if (!Objects.equals(columnInfo.column, columnInfo.property)) {
1198            // userName -> userName
1199            resultMappings.add(new ResultMapping.Builder(configuration
1200                , columnInfo.property
1201                , columnInfo.property
1202                , columnInfo.propertyType)
1203                .jdbcType(columnInfo.getJdbcType())
1204                .flags(flags)
1205                .typeHandler(columnInfo.buildTypeHandler(configuration))
1206                .build());
1207        }
1208    }
1209
1210
1211    private Object buildColumnSqlArg(MetaObject metaObject, String column) {
1212        ColumnInfo columnInfo = columnInfoMapping.get(column);
1213        Object value = getPropertyValue(metaObject, columnInfo.property);
1214        if (value != null) {
1215            TypeHandler<?> typeHandler = columnInfo.buildTypeHandler(null);
1216            if (typeHandler != null) {
1217                return new TypeHandlerObject(typeHandler, value, columnInfo.getJdbcType());
1218            }
1219        }
1220        return value;
1221    }
1222
1223
1224    public Object buildColumnSqlArg(Object entityObject, String column) {
1225        MetaObject metaObject = EntityMetaObject.forObject(entityObject, reflectorFactory);
1226        return buildColumnSqlArg(metaObject, column);
1227    }
1228
1229
1230    public Object getPropertyValue(MetaObject metaObject, String property) {
1231        if (property != null && metaObject.hasGetter(property)) {
1232            return metaObject.getValue(property);
1233        }
1234        return null;
1235    }
1236
1237
1238    /**
1239     * 通过 row 实例类转换为一个 entity
1240     *
1241     * @return entity
1242     */
1243    public <T> T newInstanceByRow(Row row, int index) {
1244        Object instance = ClassUtil.newInstance(entityClass);
1245        MetaObject metaObject = EntityMetaObject.forObject(instance, reflectorFactory);
1246        Set<String> rowKeys = row.keySet();
1247        columnInfoMapping.forEach((column, columnInfo) -> {
1248            if (index <= 0) {
1249                String replace = column.replace("_", "");
1250                for (String rowKey : rowKeys) {
1251                    // 修复: 开启 mapUnderscoreToCamelCase = true 时, row 无法转换 entity 的问题
1252                    if (rowKey.equalsIgnoreCase(column) || rowKey.equalsIgnoreCase(replace)) {
1253                        setInstancePropertyValue(row, instance, metaObject, columnInfo, rowKey);
1254                    }
1255                }
1256            } else {
1257                for (int i = index; i >= 0; i--) {
1258                    String newColumn = i <= 0 ? column : column + "$" + i;
1259                    boolean fillValue = false;
1260                    String replace = column.replace("_", "");
1261                    for (String rowKey : rowKeys) {
1262                        // 修复: 开启 mapUnderscoreToCamelCase = true 时, row 无法转换 entity 的问题
1263                        if (rowKey.equalsIgnoreCase(newColumn) || rowKey.equalsIgnoreCase(replace)) {
1264                            setInstancePropertyValue(row, instance, metaObject, columnInfo, rowKey);
1265                            fillValue = true;
1266                            break;
1267                        }
1268                    }
1269                    if (fillValue) {
1270                        break;
1271                    }
1272                }
1273            }
1274        });
1275        //noinspection unchecked
1276        return (T) instance;
1277    }
1278
1279
1280    private void setInstancePropertyValue(Row row, Object instance, MetaObject metaObject, ColumnInfo columnInfo, String rowKey) {
1281        Object rowValue = row.get(rowKey);
1282        TypeHandler<?> typeHandler = columnInfo.buildTypeHandler(null);
1283        if (typeHandler != null) {
1284            try {
1285                //通过 typeHandler 转换数据
1286                rowValue = typeHandler.getResult(getResultSet(rowValue), 0);
1287            } catch (SQLException e) {
1288                //ignore
1289            }
1290        }
1291        if (rowValue != null && !metaObject.getSetterType(columnInfo.property).isAssignableFrom(rowValue.getClass())) {
1292            rowValue = ConvertUtil.convert(rowValue, metaObject.getSetterType(columnInfo.property), true);
1293        }
1294        rowValue = invokeOnSetListener(instance, columnInfo.property, rowValue);
1295        metaObject.setValue(columnInfo.property, rowValue);
1296    }
1297
1298
1299    private ResultSet getResultSet(Object value) {
1300        return (ResultSet) Proxy.newProxyInstance(TableInfo.class.getClassLoader(),
1301            new Class[]{ResultSet.class}, (proxy, method, args) -> value);
1302    }
1303
1304
1305    /**
1306     * 初始化乐观锁版本号
1307     *
1308     * @param entityObject
1309     */
1310    public void initVersionValueIfNecessary(Object entityObject) {
1311        if (StringUtil.isBlank(versionColumn)) {
1312            return;
1313        }
1314
1315        MetaObject metaObject = EntityMetaObject.forObject(entityObject, reflectorFactory);
1316        Object columnValue = getPropertyValue(metaObject, columnInfoMapping.get(versionColumn).property);
1317        if (columnValue == null) {
1318            String name = columnInfoMapping.get(versionColumn).property;
1319            Class<?> clazz = metaObject.getSetterType(name);
1320            metaObject.setValue(name, ConvertUtil.convert(0L, clazz));
1321        }
1322    }
1323
1324    /**
1325     * 设置租户id
1326     *
1327     * @param entityObject
1328     */
1329    public void initTenantIdIfNecessary(Object entityObject) {
1330        if (StringUtil.isBlank(tenantIdColumn)) {
1331            return;
1332        }
1333
1334        MetaObject metaObject = EntityMetaObject.forObject(entityObject, reflectorFactory);
1335        Object[] tenantIds = TenantManager.getTenantIds();
1336        if (tenantIds == null || tenantIds.length == 0) {
1337            return;
1338        }
1339
1340        //默认使用第一个作为插入的租户ID
1341        Object tenantId = tenantIds[0];
1342        if (tenantId != null) {
1343            String property = columnInfoMapping.get(tenantIdColumn).property;
1344            Class<?> setterType = metaObject.getSetterType(property);
1345            metaObject.setValue(property, ConvertUtil.convert(tenantId, setterType));
1346        }
1347    }
1348
1349    /**
1350     * 初始化逻辑删除的默认值
1351     *
1352     * @param entityObject
1353     */
1354    public void initLogicDeleteValueIfNecessary(Object entityObject) {
1355        if (StringUtil.isBlank(getLogicDeleteColumnOrSkip())) {
1356            return;
1357        }
1358
1359        MetaObject metaObject = EntityMetaObject.forObject(entityObject, reflectorFactory);
1360        ColumnInfo logicDeleteColumn = columnInfoMapping.get(this.logicDeleteColumn);
1361        Object columnValue = getPropertyValue(metaObject, logicDeleteColumn.property);
1362        if (columnValue == null) {
1363            Object normalValueOfLogicDelete = LogicDeleteManager.getProcessor().getLogicNormalValue();
1364            if (normalValueOfLogicDelete != null) {
1365                String property = logicDeleteColumn.property;
1366                Class<?> setterType = metaObject.getSetterType(property);
1367                metaObject.setValue(property, ConvertUtil.convert(normalValueOfLogicDelete, setterType));
1368            }
1369        }
1370    }
1371
1372
1373    private static final Map<Class<?>, List<InsertListener>> insertListenerCache = new ConcurrentHashMap<>();
1374
1375    public void invokeOnInsertListener(Object entity) {
1376        List<InsertListener> listeners = MapUtil.computeIfAbsent(insertListenerCache, entityClass, aClass -> {
1377            List<InsertListener> globalListeners = FlexGlobalConfig.getDefaultConfig()
1378                .getSupportedInsertListener(entityClass);
1379            List<InsertListener> allListeners = CollectionUtil.merge(onInsertListeners, globalListeners);
1380            Collections.sort(allListeners);
1381            return allListeners;
1382        });
1383        listeners.forEach(insertListener -> insertListener.onInsert(entity));
1384    }
1385
1386
1387    private static final Map<Class<?>, List<UpdateListener>> updateListenerCache = new ConcurrentHashMap<>();
1388
1389    public void invokeOnUpdateListener(Object entity) {
1390        List<UpdateListener> listeners = MapUtil.computeIfAbsent(updateListenerCache, entityClass, aClass -> {
1391            List<UpdateListener> globalListeners = FlexGlobalConfig.getDefaultConfig()
1392                .getSupportedUpdateListener(entityClass);
1393            List<UpdateListener> allListeners = CollectionUtil.merge(onUpdateListeners, globalListeners);
1394            Collections.sort(allListeners);
1395            return allListeners;
1396        });
1397        listeners.forEach(insertListener -> insertListener.onUpdate(entity));
1398    }
1399
1400
1401    private static final Map<Class<?>, List<SetListener>> setListenerCache = new ConcurrentHashMap<>();
1402
1403    public Object invokeOnSetListener(Object entity, String property, Object value) {
1404        List<SetListener> listeners = MapUtil.computeIfAbsent(setListenerCache, entityClass, aClass -> {
1405            List<SetListener> globalListeners = FlexGlobalConfig.getDefaultConfig()
1406                .getSupportedSetListener(entityClass);
1407            List<SetListener> allListeners = CollectionUtil.merge(onSetListeners, globalListeners);
1408            Collections.sort(allListeners);
1409            return allListeners;
1410        });
1411        for (SetListener setListener : listeners) {
1412            value = setListener.onSet(entity, property, value);
1413        }
1414        return value;
1415    }
1416
1417    public QueryColumn getQueryColumnByProperty(String property) {
1418        String column = getColumnByProperty(property);
1419        return columnQueryMapping.get(column);
1420    }
1421
1422}