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.InsertListener;
019import com.mybatisflex.annotation.KeyType;
020import com.mybatisflex.annotation.SetListener;
021import com.mybatisflex.annotation.UpdateListener;
022import com.mybatisflex.core.FlexConsts;
023import com.mybatisflex.core.FlexGlobalConfig;
024import com.mybatisflex.core.exception.FlexExceptions;
025import com.mybatisflex.core.javassist.ModifyAttrsRecord;
026import com.mybatisflex.core.mybatis.TypeHandlerObject;
027import com.mybatisflex.core.query.*;
028import com.mybatisflex.core.row.Row;
029import com.mybatisflex.core.tenant.TenantManager;
030import com.mybatisflex.core.util.*;
031import org.apache.ibatis.mapping.ResultFlag;
032import org.apache.ibatis.mapping.ResultMap;
033import org.apache.ibatis.mapping.ResultMapping;
034import org.apache.ibatis.reflection.MetaObject;
035import org.apache.ibatis.reflection.Reflector;
036import org.apache.ibatis.reflection.ReflectorFactory;
037import org.apache.ibatis.session.Configuration;
038import org.apache.ibatis.type.TypeHandler;
039import org.apache.ibatis.util.MapUtil;
040
041import java.lang.reflect.Proxy;
042import java.sql.ResultSet;
043import java.sql.SQLException;
044import java.util.*;
045import java.util.concurrent.ConcurrentHashMap;
046import java.util.stream.Collectors;
047
048public class TableInfo {
049
050    private String schema; //schema
051    private String tableName; //表名
052    private Class<?> entityClass; //实体类
053    private boolean camelToUnderline = true;
054    private String dataSource;
055
056    //逻辑删除数据库列名
057    private String logicDeleteColumn;
058
059    //乐观锁字段
060    private String versionColumn;
061
062    //租户ID 字段
063    private String tenantIdColumn;
064
065    //数据插入时,默认插入数据字段
066    private Map<String, String> onInsertColumns;
067
068    //数据更新时,默认更新内容的字段
069    private Map<String, String> onUpdateColumns;
070
071    //大字段列
072    private String[] largeColumns = new String[0];
073
074    // 所有的字段,但除了主键的列
075    private String[] columns = new String[0];
076
077    //主键字段
078    private String[] primaryKeys = new String[0];
079
080    // 默认查询列
081    private String[] defaultColumns = new String[0];
082
083    //在插入数据的时候,支持主动插入的主键字段
084    //通过自定义生成器生成 或者 Sequence 在 before 生成的时候,是需要主动插入数据的
085    private String[] insertPrimaryKeys;
086
087    private List<ColumnInfo> columnInfoList;
088    private List<IdInfo> primaryKeyList;
089
090    //column 和 java 属性的称的关系映射
091    private Map<String, ColumnInfo> columnInfoMapping = new HashMap<>();
092    private Map<String, String> propertyColumnMapping = new HashMap<>();
093
094    private List<InsertListener> onInsertListeners;
095    private List<UpdateListener> onUpdateListeners;
096    private List<SetListener> onSetListeners;
097
098
099    private final ReflectorFactory reflectorFactory = new BaseReflectorFactory() {
100        @Override
101        public Reflector findForClass(Class<?> type) {
102            return getReflector();
103        }
104    };
105    private Reflector reflector; //反射工具
106
107    public String getSchema() {
108        return schema;
109    }
110
111    public void setSchema(String schema) {
112        this.schema = schema;
113    }
114
115    public String getTableName() {
116        return tableName;
117    }
118
119    public void setTableName(String tableName) {
120        this.tableName = tableName;
121    }
122
123    public Class<?> getEntityClass() {
124        return entityClass;
125    }
126
127    public void setEntityClass(Class<?> entityClass) {
128        this.entityClass = entityClass;
129    }
130
131    public boolean isCamelToUnderline() {
132        return camelToUnderline;
133    }
134
135    public void setCamelToUnderline(boolean camelToUnderline) {
136        this.camelToUnderline = camelToUnderline;
137    }
138
139    public String getDataSource() {
140        return dataSource;
141    }
142
143    public void setDataSource(String dataSource) {
144        this.dataSource = dataSource;
145    }
146
147    public String getLogicDeleteColumn() {
148        return logicDeleteColumn;
149    }
150
151    public void setLogicDeleteColumn(String logicDeleteColumn) {
152        this.logicDeleteColumn = logicDeleteColumn;
153    }
154
155    public String getVersionColumn() {
156        return versionColumn;
157    }
158
159    public void setVersionColumn(String versionColumn) {
160        this.versionColumn = versionColumn;
161    }
162
163    public String getTenantIdColumn() {
164        return tenantIdColumn;
165    }
166
167    public void setTenantIdColumn(String tenantIdColumn) {
168        this.tenantIdColumn = tenantIdColumn;
169    }
170
171    public Map<String, String> getOnInsertColumns() {
172        return onInsertColumns;
173    }
174
175    public void setOnInsertColumns(Map<String, String> onInsertColumns) {
176        this.onInsertColumns = onInsertColumns;
177    }
178
179    public Map<String, String> getOnUpdateColumns() {
180        return onUpdateColumns;
181    }
182
183    public void setOnUpdateColumns(Map<String, String> onUpdateColumns) {
184        this.onUpdateColumns = onUpdateColumns;
185    }
186
187    public String[] getLargeColumns() {
188        return largeColumns;
189    }
190
191    public void setLargeColumns(String[] largeColumns) {
192        this.largeColumns = largeColumns;
193    }
194
195    public String[] getDefaultColumns() {
196        return defaultColumns;
197    }
198
199    public void setDefaultColumns(String[] defaultColumns) {
200        this.defaultColumns = defaultColumns;
201    }
202
203    public String[] getInsertPrimaryKeys() {
204        return insertPrimaryKeys;
205    }
206
207    public void setInsertPrimaryKeys(String[] insertPrimaryKeys) {
208        this.insertPrimaryKeys = insertPrimaryKeys;
209    }
210
211    public Reflector getReflector() {
212        return reflector;
213    }
214
215    public ReflectorFactory getReflectorFactory() {
216        return reflectorFactory;
217    }
218
219    public void setReflector(Reflector reflector) {
220        this.reflector = reflector;
221    }
222
223    public String[] getColumns() {
224        return columns;
225    }
226
227
228    public void setColumns(String[] columns) {
229        this.columns = columns;
230    }
231
232    public String[] getPrimaryKeys() {
233        return primaryKeys;
234    }
235
236    public void setPrimaryKeys(String[] primaryKeys) {
237        this.primaryKeys = primaryKeys;
238    }
239
240
241    public List<InsertListener> getOnInsertListeners() {
242        return onInsertListeners;
243    }
244
245    public void setOnInsertListeners(List<InsertListener> onInsertListeners) {
246        this.onInsertListeners = onInsertListeners;
247    }
248
249    public List<UpdateListener> getOnUpdateListeners() {
250        return onUpdateListeners;
251    }
252
253    public void setOnUpdateListeners(List<UpdateListener> onUpdateListeners) {
254        this.onUpdateListeners = onUpdateListeners;
255    }
256
257    public List<SetListener> getOnSetListeners() {
258        return onSetListeners;
259    }
260
261    public void setOnSetListeners(List<SetListener> onSetListeners) {
262        this.onSetListeners = onSetListeners;
263    }
264
265    public List<ColumnInfo> getColumnInfoList() {
266        return columnInfoList;
267    }
268
269
270    void setColumnInfoList(List<ColumnInfo> columnInfoList) {
271        this.columnInfoList = columnInfoList;
272        this.columns = new String[columnInfoList.size()];
273        for (int i = 0; i < columnInfoList.size(); i++) {
274            ColumnInfo columnInfo = columnInfoList.get(i);
275            columns[i] = columnInfo.getColumn();
276            columnInfoMapping.put(columnInfo.column, columnInfo);
277            propertyColumnMapping.put(columnInfo.property, columnInfo.column);
278        }
279    }
280
281
282    public List<IdInfo> getPrimaryKeyList() {
283        return primaryKeyList;
284    }
285
286    void setPrimaryKeyList(List<IdInfo> primaryKeyList) {
287        this.primaryKeyList = primaryKeyList;
288        this.primaryKeys = new String[primaryKeyList.size()];
289
290        List<String> insertIdFields = new ArrayList<>();
291        for (int i = 0; i < primaryKeyList.size(); i++) {
292            IdInfo idInfo = primaryKeyList.get(i);
293            primaryKeys[i] = idInfo.getColumn();
294
295            if (idInfo.getKeyType() != KeyType.Auto && (idInfo.getBefore() != null && idInfo.getBefore())) {
296                insertIdFields.add(idInfo.getColumn());
297            }
298
299            columnInfoMapping.put(idInfo.column, idInfo);
300            propertyColumnMapping.put(idInfo.property, idInfo.column);
301        }
302        this.insertPrimaryKeys = insertIdFields.toArray(new String[0]);
303    }
304
305
306    /**
307     * 插入(新增)数据时,获取所有要插入的字段
308     *
309     * @param entity
310     * @param ignoreNulls
311     * @return 字段列表
312     */
313    public String[] obtainInsertColumns(Object entity, boolean ignoreNulls) {
314        if (!ignoreNulls) {
315            return ArrayUtil.concat(insertPrimaryKeys, columns);
316        } else {
317            MetaObject metaObject = EntityMetaObject.forObject(entity, reflectorFactory);
318            List<String> retColumns = new ArrayList<>();
319            for (String insertColumn : columns) {
320                if (onInsertColumns != null && onInsertColumns.containsKey(insertColumn)) {
321                    retColumns.add(insertColumn);
322                } else {
323                    Object value = buildColumnSqlArg(metaObject, insertColumn);
324                    if (value == null) {
325                        continue;
326                    }
327                    retColumns.add(insertColumn);
328                }
329            }
330            return ArrayUtil.concat(insertPrimaryKeys, retColumns.toArray(new String[0]));
331        }
332    }
333
334
335    /**
336     * 构建 insert 的 Sql 参数
337     *
338     * @param entity      从 entity 中获取
339     * @param ignoreNulls 是否忽略 null 值
340     * @return 数组
341     */
342    public Object[] buildInsertSqlArgs(Object entity, boolean ignoreNulls) {
343        MetaObject metaObject = EntityMetaObject.forObject(entity, reflectorFactory);
344        String[] insertColumns = obtainInsertColumns(entity, ignoreNulls);
345
346        List<Object> values = new ArrayList<>(insertColumns.length);
347        for (String insertColumn : insertColumns) {
348            if (onInsertColumns == null || !onInsertColumns.containsKey(insertColumn)) {
349                Object value = buildColumnSqlArg(metaObject, insertColumn);
350                if (ignoreNulls && value == null) {
351                    continue;
352                }
353                values.add(value);
354            }
355        }
356        return values.toArray();
357    }
358
359
360    /**
361     * 获取要修改的值
362     *
363     * @param entity
364     * @param ignoreNulls
365     */
366    public Set<String> obtainUpdateColumns(Object entity, boolean ignoreNulls, boolean includePrimary) {
367        MetaObject metaObject = EntityMetaObject.forObject(entity, reflectorFactory);
368        Set<String> columns = new LinkedHashSet<>(); //需使用 LinkedHashSet 保证 columns 的顺序
369        if (entity instanceof ModifyAttrsRecord) {
370            Set<String> properties = ((ModifyAttrsRecord) entity).obtainModifyAttrs();
371            if (properties.isEmpty()) {
372                return Collections.emptySet();
373            }
374            for (String property : properties) {
375                String column = propertyColumnMapping.get(property);
376                if (onUpdateColumns != null && onUpdateColumns.containsKey(column)) {
377                    continue;
378                }
379
380                //过滤乐观锁字段 和 租户字段
381                if (ObjectUtil.equalsAny(column, versionColumn, tenantIdColumn)) {
382                    continue;
383                }
384
385                if (!includePrimary && ArrayUtil.contains(primaryKeys, column)) {
386                    continue;
387                }
388
389                // ModifyAttrsRecord 忽略 ignoreNulls 的设置
390                // Object value = getPropertyValue(metaObject, property);
391                // if (ignoreNulls && value == null) {
392                //     continue;
393                // }
394                columns.add(column);
395            }
396        }
397        //not ModifyAttrsRecord
398        else {
399            for (String column : this.columns) {
400                if (onUpdateColumns != null && onUpdateColumns.containsKey(column)) {
401                    continue;
402                }
403
404                //过滤乐观锁字段 和 租户字段
405                if (ObjectUtil.equalsAny(column, versionColumn, tenantIdColumn)) {
406                    continue;
407                }
408
409                Object value = buildColumnSqlArg(metaObject, column);
410                if (ignoreNulls && value == null) {
411                    continue;
412                }
413
414                columns.add(column);
415            }
416
417            // 普通 entity(非 ModifyAttrsRecord) 忽略 includePrimary 的设置
418//            if (includePrimary) {
419//                for (String column : this.primaryKeys) {
420//                    Object value = getColumnValue(metaObject, column);
421//                    if (ignoreNulls && value == null) {
422//                        continue;
423//                    }
424//                    columns.add(column);
425//                }
426//            }
427        }
428        return columns;
429    }
430
431    /**
432     * 获取所有要修改的值,默认为全部除了主键以外的字段
433     *
434     * @param entity 实体对象
435     * @return 数组
436     */
437    public Object[] buildUpdateSqlArgs(Object entity, boolean ignoreNulls, boolean includePrimary) {
438        MetaObject metaObject = EntityMetaObject.forObject(entity, reflectorFactory);
439        List<Object> values = new ArrayList<>();
440        if (entity instanceof ModifyAttrsRecord) {
441            Set<String> properties = ((ModifyAttrsRecord) entity).obtainModifyAttrs();
442            if (properties.isEmpty()) {
443                return values.toArray();
444            }
445            for (String property : properties) {
446                String column = propertyColumnMapping.get(property);
447                if (onUpdateColumns != null && onUpdateColumns.containsKey(column)) {
448                    continue;
449                }
450                //过滤乐观锁字段 和 租户字段
451                if (ObjectUtil.equalsAny(column, versionColumn, tenantIdColumn)) {
452                    continue;
453                }
454
455                if (!includePrimary && ArrayUtil.contains(primaryKeys, column)) {
456                    continue;
457                }
458
459                Object value = getPropertyValue(metaObject, property);
460
461                // ModifyAttrsRecord 忽略 ignoreNulls 的设置,
462                // 当使用 ModifyAttrsRecord 时,可以理解为要对字段进行 null 值进行更新,否则没必要使用 ModifyAttrsRecord
463                // if (ignoreNulls && value == null) {
464                //    continue;
465                // }
466                values.add(value);
467            }
468        }
469        // normal entity. not ModifyAttrsRecord
470        else {
471            for (String column : this.columns) {
472                if (onUpdateColumns != null && onUpdateColumns.containsKey(column)) {
473                    continue;
474                }
475
476                //过滤乐观锁字段 和 租户字段
477                if (ObjectUtil.equalsAny(column, versionColumn, tenantIdColumn)) {
478                    continue;
479                }
480
481                // 普通 entity 忽略 includePrimary 的设置,
482                // 因为 for 循环中的 this.columns 本身就不包含有主键
483                // if (includePrimary) {
484                // }
485
486                Object value = buildColumnSqlArg(metaObject, column);
487                if (ignoreNulls && value == null) {
488                    continue;
489                }
490
491                values.add(value);
492            }
493        }
494
495        return values.toArray();
496    }
497
498
499    /**
500     * 构建主键的 sql 参数数据
501     *
502     * @param entity
503     */
504    public Object[] buildPkSqlArgs(Object entity) {
505        MetaObject metaObject = EntityMetaObject.forObject(entity, reflectorFactory);
506        Object[] values = new Object[primaryKeys.length];
507        for (int i = 0; i < primaryKeys.length; i++) {
508            values[i] = buildColumnSqlArg(metaObject, primaryKeys[i]);
509        }
510        return values;
511    }
512
513
514    public Object[] buildTenantIdArgs() {
515        if (StringUtil.isBlank(tenantIdColumn)) {
516            return null;
517        }
518
519        return TenantManager.getTenantIds();
520    }
521
522    private static final String APPEND_CONDITIONS_FLAG = "appendConditions";
523
524    public void appendConditions(Object entity, QueryWrapper queryWrapper) {
525
526        Object appendConditions = CPI.getContext(queryWrapper, APPEND_CONDITIONS_FLAG);
527        if (Boolean.TRUE.equals(appendConditions)) {
528            return;
529        } else {
530            CPI.putContext(queryWrapper, APPEND_CONDITIONS_FLAG, Boolean.TRUE);
531        }
532
533        //select * from (select ... from ) 中的子查询处理
534        List<QueryTable> queryTables = CPI.getQueryTables(queryWrapper);
535        if (queryTables != null && !queryTables.isEmpty()) {
536            for (QueryTable queryTable : queryTables) {
537                if (queryTable instanceof SelectQueryTable) {
538                    QueryWrapper selectQueryWrapper = ((SelectQueryTable) queryTable).getQueryWrapper();
539                    List<QueryTable> selectQueryTables = CPI.getQueryTables(selectQueryWrapper);
540                    if (selectQueryTables != null && !selectQueryTables.isEmpty()) {
541                        for (QueryTable selectQueryTable : selectQueryTables) {
542                            TableInfo tableInfo = TableInfoFactory.ofTableName(selectQueryTable.getName());
543                            if (tableInfo != null) {
544                                tableInfo.appendConditions(entity, selectQueryWrapper);
545                            }
546                        }
547                    }
548                }
549            }
550        }
551
552        //添加乐观锁条件,只有在 update 的时候进行处理
553        if (StringUtil.isNotBlank(versionColumn) && entity != null) {
554            Object versionValue = buildColumnSqlArg(entity, versionColumn);
555            if (versionValue == null) {
556                throw FlexExceptions.wrap("The version value of entity[%s] must not be null.", entity);
557            }
558            queryWrapper.and(QueryCondition.create(tableName, versionColumn, QueryCondition.LOGIC_EQUALS, versionValue));
559        }
560
561        //逻辑删除
562        if (StringUtil.isNotBlank(logicDeleteColumn)) {
563            queryWrapper.and(QueryCondition.create(tableName, logicDeleteColumn, QueryCondition.LOGIC_EQUALS
564                    , FlexGlobalConfig.getDefaultConfig().getNormalValueOfLogicDelete()));
565        }
566
567        //多租户
568        Object[] tenantIdArgs = buildTenantIdArgs();
569        if (ArrayUtil.isNotEmpty(tenantIdArgs)) {
570            if (tenantIdArgs.length == 1) {
571                queryWrapper.and(QueryCondition.create(tableName, tenantIdColumn, QueryCondition.LOGIC_EQUALS, tenantIdArgs[0]));
572            } else {
573                queryWrapper.and(QueryCondition.create(tableName, tenantIdColumn, QueryCondition.LOGIC_IN, tenantIdArgs));
574            }
575        }
576
577        //子查询
578        List<QueryWrapper> childSelects = CPI.getChildSelect(queryWrapper);
579        if (CollectionUtil.isNotEmpty(childSelects)) {
580            for (QueryWrapper childQueryWrapper : childSelects) {
581                List<QueryTable> childQueryTables = CPI.getQueryTables(childQueryWrapper);
582                for (QueryTable queryTable : childQueryTables) {
583                    TableInfo tableInfo = TableInfoFactory.ofTableName(queryTable.getName());
584                    if (tableInfo != null) {
585                        tableInfo.appendConditions(entity, childQueryWrapper);
586                    }
587                }
588            }
589        }
590
591        //union
592        List<UnionWrapper> unions = CPI.getUnions(queryWrapper);
593        if (CollectionUtil.isNotEmpty(unions)) {
594            for (UnionWrapper union : unions) {
595                QueryWrapper unionQueryWrapper = union.getQueryWrapper();
596                List<QueryTable> unionQueryTables = CPI.getQueryTables(unionQueryWrapper);
597                for (QueryTable queryTable : unionQueryTables) {
598                    TableInfo tableInfo = TableInfoFactory.ofTableName(queryTable.getName());
599                    if (tableInfo != null) {
600                        tableInfo.appendConditions(entity, unionQueryWrapper);
601                    }
602                }
603            }
604        }
605
606    }
607
608
609    public String getKeyProperties() {
610        StringJoiner joiner = new StringJoiner(",");
611        for (IdInfo value : primaryKeyList) {
612            joiner.add(FlexConsts.ENTITY + "." + value.getProperty());
613        }
614        return joiner.toString();
615    }
616
617
618    public String getKeyColumns() {
619        StringJoiner joiner = new StringJoiner(",");
620        for (IdInfo value : primaryKeyList) {
621            joiner.add(value.getColumn());
622        }
623        return joiner.toString();
624    }
625
626    public List<QueryColumn> getDefaultQueryColumn() {
627        return Arrays.stream(defaultColumns)
628                .map(name -> new QueryColumn(getTableName(), name))
629                .collect(Collectors.toList());
630    }
631
632    public ResultMap buildResultMap(Configuration configuration) {
633        String resultMapId = entityClass.getName();
634        List<ResultMapping> resultMappings = new ArrayList<>();
635
636        for (ColumnInfo columnInfo : columnInfoList) {
637            ResultMapping mapping = new ResultMapping.Builder(configuration, columnInfo.getProperty(),
638                    columnInfo.getColumn(), columnInfo.getPropertyType())
639                    .jdbcType(columnInfo.getJdbcType())
640                    .typeHandler(columnInfo.buildTypeHandler())
641                    .build();
642            resultMappings.add(mapping);
643        }
644
645        for (IdInfo idInfo : primaryKeyList) {
646            ResultMapping mapping = new ResultMapping.Builder(configuration, idInfo.getProperty(),
647                    idInfo.getColumn(), idInfo.getPropertyType())
648                    .flags(CollectionUtil.newArrayList(ResultFlag.ID))
649                    .jdbcType(idInfo.getJdbcType())
650                    .typeHandler(idInfo.buildTypeHandler())
651                    .build();
652            resultMappings.add(mapping);
653        }
654
655        return new ResultMap.Builder(configuration, resultMapId, entityClass, resultMappings).build();
656    }
657
658
659    private Object buildColumnSqlArg(MetaObject metaObject, String column) {
660        ColumnInfo columnInfo = columnInfoMapping.get(column);
661        Object value = getPropertyValue(metaObject, columnInfo.property);
662
663        TypeHandler typeHandler = columnInfo.buildTypeHandler();
664        if (value != null && typeHandler != null) {
665            return new TypeHandlerObject(typeHandler, value, columnInfo.getJdbcType());
666        }
667
668        return value;
669    }
670
671
672    public Object buildColumnSqlArg(Object entityObject, String column) {
673        MetaObject metaObject = EntityMetaObject.forObject(entityObject, reflectorFactory);
674        return buildColumnSqlArg(metaObject, column);
675    }
676
677
678    private Object getPropertyValue(MetaObject metaObject, String property) {
679        if (property != null && metaObject.hasGetter(property)) {
680            return metaObject.getValue(property);
681        }
682        return null;
683    }
684
685
686    /**
687     * 通过 row 实例类转换为一个 entity
688     *
689     * @return entity
690     */
691    public <T> T newInstanceByRow(Row row, int index) {
692        Object instance = ClassUtil.newInstance(entityClass);
693        MetaObject metaObject = EntityMetaObject.forObject(instance, reflectorFactory);
694        Set<String> rowKeys = row.keySet();
695        columnInfoMapping.forEach((column, columnInfo) -> {
696            if (index <= 0) {
697                for (String rowKey : rowKeys) {
698                    if (column.equalsIgnoreCase(rowKey)) {
699                        setInstancePropertyValue(row, instance, metaObject, columnInfo, rowKey);
700                    }
701                }
702            } else {
703                for (int i = index; i >= 0; i--) {
704                    String newColumn = i <= 0 ? column : column + "$" + i;
705                    boolean fillValue = false;
706                    for (String rowKey : rowKeys) {
707                        if (newColumn.equalsIgnoreCase(rowKey)) {
708                            setInstancePropertyValue(row, instance, metaObject, columnInfo, rowKey);
709                            fillValue = true;
710                            break;
711                        }
712                    }
713                    if (fillValue) {
714                        break;
715                    }
716                }
717            }
718        });
719        return (T) instance;
720    }
721
722
723    private void setInstancePropertyValue(Row row, Object instance, MetaObject metaObject, ColumnInfo columnInfo, String rowKey) {
724        Object rowValue = row.get(rowKey);
725        TypeHandler<?> typeHandler = columnInfo.buildTypeHandler();
726        if (typeHandler != null) {
727            try {
728                //通过 typeHandler 转换数据
729                rowValue = typeHandler.getResult(getResultSet(rowValue), 0);
730            } catch (SQLException e) {
731                //ignore
732            }
733        }
734        if (rowValue != null && !metaObject.getSetterType(columnInfo.property).isAssignableFrom(rowValue.getClass())) {
735            rowValue = ConvertUtil.convert(rowValue, metaObject.getSetterType(columnInfo.property), true);
736        }
737        rowValue = invokeOnSetListener(instance, columnInfo.getProperty(), rowValue);
738        metaObject.setValue(columnInfo.property, rowValue);
739    }
740
741
742    private ResultSet getResultSet(Object value) {
743        return (ResultSet) Proxy.newProxyInstance(TableInfo.class.getClassLoader(),
744                new Class[]{ResultSet.class}, (proxy, method, args) -> value);
745    }
746
747
748    /**
749     * 初始化乐观锁版本号
750     *
751     * @param entityObject
752     */
753    public void initVersionValueIfNecessary(Object entityObject) {
754        if (StringUtil.isBlank(versionColumn)) {
755            return;
756        }
757
758        MetaObject metaObject = EntityMetaObject.forObject(entityObject, reflectorFactory);
759        Object columnValue = getPropertyValue(metaObject, columnInfoMapping.get(versionColumn).property);
760        if (columnValue == null) {
761            String name = columnInfoMapping.get(versionColumn).property;
762            Class<?> clazz = metaObject.getSetterType(name);
763            metaObject.setValue(name, ConvertUtil.convert(0L, clazz));
764        }
765    }
766
767    /**
768     * 设置租户id
769     *
770     * @param entityObject
771     */
772    public void initTenantIdIfNecessary(Object entityObject) {
773        if (StringUtil.isBlank(tenantIdColumn)) {
774            return;
775        }
776
777        MetaObject metaObject = EntityMetaObject.forObject(entityObject, reflectorFactory);
778        Object[] tenantIds = TenantManager.getTenantIds();
779        if (tenantIds == null || tenantIds.length == 0) {
780            return;
781        }
782
783        //默认使用第一个作为插入的租户ID
784        Object tenantId = tenantIds[0];
785        if (tenantId != null) {
786            metaObject.setValue(columnInfoMapping.get(tenantIdColumn).property, tenantId);
787        }
788    }
789
790    /**
791     * 初始化逻辑删除的默认值
792     *
793     * @param entityObject
794     */
795    public void initLogicDeleteValueIfNecessary(Object entityObject) {
796        if (StringUtil.isBlank(logicDeleteColumn)) {
797            return;
798        }
799
800        MetaObject metaObject = EntityMetaObject.forObject(entityObject, reflectorFactory);
801        Object columnValue = getPropertyValue(metaObject, columnInfoMapping.get(logicDeleteColumn).property);
802        if (columnValue == null) {
803            String property = columnInfoMapping.get(logicDeleteColumn).property;
804            Class<?> setterType = metaObject.getSetterType(property);
805
806            Object normalValueOfLogicDelete = FlexGlobalConfig.getDefaultConfig().getNormalValueOfLogicDelete();
807            metaObject.setValue(property, ConvertUtil.convert(normalValueOfLogicDelete, setterType));
808        }
809    }
810
811
812    private static Map<Class<?>, List<InsertListener>> insertListenerCache = new ConcurrentHashMap<>();
813
814    public void invokeOnInsertListener(Object entity) {
815        List<InsertListener> listeners = MapUtil.computeIfAbsent(insertListenerCache, entityClass, aClass -> {
816            List<InsertListener> globalListeners = FlexGlobalConfig.getDefaultConfig()
817                    .getSupportedInsertListener(entityClass, CollectionUtil.isNotEmpty(onInsertListeners));
818            List<InsertListener> allListeners = CollectionUtil.merge(onInsertListeners, globalListeners);
819            Collections.sort(allListeners);
820            return allListeners;
821        });
822        listeners.forEach(insertListener -> insertListener.onInsert(entity));
823    }
824
825
826    private static Map<Class<?>, List<UpdateListener>> updateListenerCache = new ConcurrentHashMap<>();
827
828    public void invokeOnUpdateListener(Object entity) {
829        List<UpdateListener> listeners = MapUtil.computeIfAbsent(updateListenerCache, entityClass, aClass -> {
830            List<UpdateListener> globalListeners = FlexGlobalConfig.getDefaultConfig()
831                    .getSupportedUpdateListener(entityClass, CollectionUtil.isNotEmpty(onUpdateListeners));
832            List<UpdateListener> allListeners = CollectionUtil.merge(onUpdateListeners, globalListeners);
833            Collections.sort(allListeners);
834            return allListeners;
835        });
836        listeners.forEach(insertListener -> insertListener.onUpdate(entity));
837    }
838
839
840    private static Map<Class<?>, List<SetListener>> setListenerCache = new ConcurrentHashMap<>();
841
842    public Object invokeOnSetListener(Object entity, String property, Object value) {
843        List<SetListener> listeners = MapUtil.computeIfAbsent(setListenerCache, entityClass, aClass -> {
844            List<SetListener> globalListeners = FlexGlobalConfig.getDefaultConfig()
845                    .getSupportedSetListener(entityClass, CollectionUtil.isNotEmpty(onSetListeners));
846            List<SetListener> allListeners = CollectionUtil.merge(onSetListeners, globalListeners);
847            Collections.sort(allListeners);
848            return allListeners;
849        });
850        for (SetListener setListener : listeners) {
851            value = setListener.onSet(entity, property, value);
852        }
853        return value;
854    }
855}