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