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