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.dialect.IDialect; 025import com.mybatisflex.core.exception.FlexExceptions; 026import com.mybatisflex.core.javassist.ModifyAttrsRecord; 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.util.*; 032import org.apache.ibatis.mapping.ResultFlag; 033import org.apache.ibatis.mapping.ResultMap; 034import org.apache.ibatis.mapping.ResultMapping; 035import org.apache.ibatis.reflection.MetaObject; 036import org.apache.ibatis.reflection.Reflector; 037import org.apache.ibatis.reflection.ReflectorFactory; 038import org.apache.ibatis.session.Configuration; 039import org.apache.ibatis.type.TypeHandler; 040import org.apache.ibatis.util.MapUtil; 041 042import java.lang.reflect.Field; 043import java.lang.reflect.Proxy; 044import java.sql.ResultSet; 045import java.sql.SQLException; 046import java.util.*; 047import java.util.concurrent.ConcurrentHashMap; 048import java.util.stream.Collectors; 049 050public class TableInfo { 051 052 private String schema; //schema 053 private String tableName; //表名 054 private Class<?> entityClass; //实体类 055 private boolean camelToUnderline = true; 056 private String dataSource; 057 058 //逻辑删除数据库列名 059 private String logicDeleteColumn; 060 061 //乐观锁字段 062 private String versionColumn; 063 064 //租户ID 字段 065 private String tenantIdColumn; 066 067 //数据插入时,默认插入数据字段 068 private Map<String, String> onInsertColumns; 069 070 //数据更新时,默认更新内容的字段 071 private Map<String, String> onUpdateColumns; 072 073 //大字段列 074 private String[] largeColumns = new String[0]; 075 076 // 所有的字段,但除了主键的列 077 private String[] columns = new String[0]; 078 079 //主键字段 080 private String[] primaryKeys = new String[0]; 081 082 // 默认查询列 083 private String[] defaultColumns = new String[0]; 084 085 //在插入数据的时候,支持主动插入的主键字段 086 //通过自定义生成器生成 或者 Sequence 在 before 生成的时候,是需要主动插入数据的 087 private String[] insertPrimaryKeys; 088 089 private List<ColumnInfo> columnInfoList; 090 private List<IdInfo> primaryKeyList; 091 092 //column 和 java 属性的称的关系映射 093 private final Map<String, ColumnInfo> columnInfoMapping = new HashMap<>(); 094 private final Map<String, String> propertyColumnMapping = new HashMap<>(); 095 096 private List<InsertListener> onInsertListeners; 097 private List<UpdateListener> onUpdateListeners; 098 private List<SetListener> onSetListeners; 099 100 /** 101 * @deprecated 该功能有更好的方式实现,此属性可能会被移除。 102 */ 103 @Deprecated 104 private Map<String, Class<?>> joinTypes; 105 106 107 /** 108 * 对应 MapperXML 配置文件中 {@code <resultMap>} 标签下的 {@code <association>} 标签。 109 */ 110 private Map<String, Class<?>> associationType; 111 112 /** 113 * 对应 MapperXML 配置文件中 {@code <resultMap>} 标签下的 {@code <collection>} 标签。 114 */ 115 private Map<Field, Class<?>> collectionType; 116 117 118 private final ReflectorFactory reflectorFactory = new BaseReflectorFactory() { 119 @Override 120 public Reflector findForClass(Class<?> type) { 121 return getReflector(); 122 } 123 }; 124 private Reflector reflector; //反射工具 125 126 public String getSchema() { 127 return schema; 128 } 129 130 public void setSchema(String schema) { 131 this.schema = schema; 132 } 133 134 public String getTableName() { 135 return tableName; 136 } 137 138 public String getWrapSchemaAndTableName(IDialect dialect) { 139 if (StringUtil.isNotBlank(schema)) { 140 return dialect.wrap(dialect.getRealSchema(schema)) + "." + dialect.wrap(dialect.getRealTable(tableName)); 141 } else { 142 return dialect.wrap(dialect.getRealTable(tableName)); 143 } 144 } 145 146 public void setTableName(String tableName) { 147 this.tableName = tableName; 148 } 149 150 public Class<?> getEntityClass() { 151 return entityClass; 152 } 153 154 public void setEntityClass(Class<?> entityClass) { 155 this.entityClass = entityClass; 156 } 157 158 public boolean isCamelToUnderline() { 159 return camelToUnderline; 160 } 161 162 public void setCamelToUnderline(boolean camelToUnderline) { 163 this.camelToUnderline = camelToUnderline; 164 } 165 166 public String getDataSource() { 167 return dataSource; 168 } 169 170 public void setDataSource(String dataSource) { 171 this.dataSource = dataSource; 172 } 173 174 public String getLogicDeleteColumn() { 175 return logicDeleteColumn; 176 } 177 178 public void setLogicDeleteColumn(String logicDeleteColumn) { 179 this.logicDeleteColumn = logicDeleteColumn; 180 } 181 182 public String getVersionColumn() { 183 return versionColumn; 184 } 185 186 public void setVersionColumn(String versionColumn) { 187 this.versionColumn = versionColumn; 188 } 189 190 public String getTenantIdColumn() { 191 return tenantIdColumn; 192 } 193 194 public void setTenantIdColumn(String tenantIdColumn) { 195 this.tenantIdColumn = tenantIdColumn; 196 } 197 198 public Map<String, String> getOnInsertColumns() { 199 return onInsertColumns; 200 } 201 202 public void setOnInsertColumns(Map<String, String> onInsertColumns) { 203 this.onInsertColumns = onInsertColumns; 204 } 205 206 public Map<String, String> getOnUpdateColumns() { 207 return onUpdateColumns; 208 } 209 210 public void setOnUpdateColumns(Map<String, String> onUpdateColumns) { 211 this.onUpdateColumns = onUpdateColumns; 212 } 213 214 public String[] getLargeColumns() { 215 return largeColumns; 216 } 217 218 public void setLargeColumns(String[] largeColumns) { 219 this.largeColumns = largeColumns; 220 } 221 222 public String[] getDefaultColumns() { 223 return defaultColumns; 224 } 225 226 public void setDefaultColumns(String[] defaultColumns) { 227 this.defaultColumns = defaultColumns; 228 } 229 230 public String[] getInsertPrimaryKeys() { 231 return insertPrimaryKeys; 232 } 233 234 public void setInsertPrimaryKeys(String[] insertPrimaryKeys) { 235 this.insertPrimaryKeys = insertPrimaryKeys; 236 } 237 238 public Reflector getReflector() { 239 return reflector; 240 } 241 242 public ReflectorFactory getReflectorFactory() { 243 return reflectorFactory; 244 } 245 246 public void setReflector(Reflector reflector) { 247 this.reflector = reflector; 248 } 249 250 public String[] getColumns() { 251 return columns; 252 } 253 254 255 public void setColumns(String[] columns) { 256 this.columns = columns; 257 } 258 259 public String[] getPrimaryKeys() { 260 return primaryKeys; 261 } 262 263 public void setPrimaryKeys(String[] primaryKeys) { 264 this.primaryKeys = primaryKeys; 265 } 266 267 268 public List<InsertListener> getOnInsertListeners() { 269 return onInsertListeners; 270 } 271 272 public void setOnInsertListeners(List<InsertListener> onInsertListeners) { 273 this.onInsertListeners = onInsertListeners; 274 } 275 276 public List<UpdateListener> getOnUpdateListeners() { 277 return onUpdateListeners; 278 } 279 280 public void setOnUpdateListeners(List<UpdateListener> onUpdateListeners) { 281 this.onUpdateListeners = onUpdateListeners; 282 } 283 284 public List<SetListener> getOnSetListeners() { 285 return onSetListeners; 286 } 287 288 public void setOnSetListeners(List<SetListener> onSetListeners) { 289 this.onSetListeners = onSetListeners; 290 } 291 292 public List<ColumnInfo> getColumnInfoList() { 293 return columnInfoList; 294 } 295 296 public String getColumnByProperty(String property) { 297 return propertyColumnMapping.get(property); 298 } 299 300 public Map<String, Class<?>> getJoinTypes() { 301 return joinTypes; 302 } 303 304 public void setJoinTypes(Map<String, Class<?>> joinTypes) { 305 this.joinTypes = joinTypes; 306 } 307 308 public void addJoinType(String fieldName, Class<?> clazz) { 309 if (joinTypes == null) { 310 joinTypes = new HashMap<>(); 311 } 312 joinTypes.put(fieldName, clazz); 313 } 314 315 public Map<String, Class<?>> getAssociationType() { 316 return associationType; 317 } 318 319 public void setAssociationType(Map<String, Class<?>> associationType) { 320 this.associationType = associationType; 321 } 322 323 public void addAssociationType(String fieldName, Class<?> clazz) { 324 if (associationType == null) { 325 associationType = new HashMap<>(); 326 } 327 associationType.put(fieldName, clazz); 328 } 329 330 public Map<Field, Class<?>> getCollectionType() { 331 return collectionType; 332 } 333 334 public void setCollectionType(Map<Field, Class<?>> collectionType) { 335 this.collectionType = collectionType; 336 } 337 338 public void addCollectionType(Field field, Class<?> genericClass) { 339 if (collectionType == null) { 340 collectionType = new HashMap<>(); 341 } 342 collectionType.put(field, genericClass); 343 } 344 345 void setColumnInfoList(List<ColumnInfo> columnInfoList) { 346 this.columnInfoList = columnInfoList; 347 this.columns = new String[columnInfoList.size()]; 348 for (int i = 0; i < columnInfoList.size(); i++) { 349 ColumnInfo columnInfo = columnInfoList.get(i); 350 columns[i] = columnInfo.getColumn(); 351 columnInfoMapping.put(columnInfo.column, columnInfo); 352 propertyColumnMapping.put(columnInfo.property, columnInfo.column); 353 } 354 } 355 356 357 public List<IdInfo> getPrimaryKeyList() { 358 return primaryKeyList; 359 } 360 361 void setPrimaryKeyList(List<IdInfo> primaryKeyList) { 362 this.primaryKeyList = primaryKeyList; 363 this.primaryKeys = new String[primaryKeyList.size()]; 364 365 List<String> insertIdFields = new ArrayList<>(); 366 for (int i = 0; i < primaryKeyList.size(); i++) { 367 IdInfo idInfo = primaryKeyList.get(i); 368 primaryKeys[i] = idInfo.getColumn(); 369 370 if (idInfo.getKeyType() != KeyType.Auto && (idInfo.getBefore() != null && idInfo.getBefore())) { 371 insertIdFields.add(idInfo.getColumn()); 372 } 373 374 columnInfoMapping.put(idInfo.column, idInfo); 375 propertyColumnMapping.put(idInfo.property, idInfo.column); 376 } 377 this.insertPrimaryKeys = insertIdFields.toArray(new String[0]); 378 } 379 380 381 /** 382 * 插入(新增)数据时,获取所有要插入的字段 383 * 384 * @param entity 385 * @param ignoreNulls 386 * @return 字段列表 387 */ 388 public String[] obtainInsertColumns(Object entity, boolean ignoreNulls) { 389 if (!ignoreNulls) { 390 return ArrayUtil.concat(insertPrimaryKeys, columns); 391 } else { 392 MetaObject metaObject = EntityMetaObject.forObject(entity, reflectorFactory); 393 List<String> retColumns = new ArrayList<>(); 394 for (String insertColumn : columns) { 395 if (onInsertColumns != null && onInsertColumns.containsKey(insertColumn)) { 396 retColumns.add(insertColumn); 397 } else { 398 Object value = buildColumnSqlArg(metaObject, insertColumn); 399 if (value == null) { 400 continue; 401 } 402 retColumns.add(insertColumn); 403 } 404 } 405 return ArrayUtil.concat(insertPrimaryKeys, retColumns.toArray(new String[0])); 406 } 407 } 408 409 410 /** 411 * 构建 insert 的 Sql 参数 412 * 413 * @param entity 从 entity 中获取 414 * @param ignoreNulls 是否忽略 null 值 415 * @return 数组 416 */ 417 public Object[] buildInsertSqlArgs(Object entity, boolean ignoreNulls) { 418 MetaObject metaObject = EntityMetaObject.forObject(entity, reflectorFactory); 419 String[] insertColumns = obtainInsertColumns(entity, ignoreNulls); 420 421 List<Object> values = new ArrayList<>(insertColumns.length); 422 for (String insertColumn : insertColumns) { 423 if (onInsertColumns == null || !onInsertColumns.containsKey(insertColumn)) { 424 Object value = buildColumnSqlArg(metaObject, insertColumn); 425 if (ignoreNulls && value == null) { 426 continue; 427 } 428 values.add(value); 429 } 430 } 431 return values.toArray(); 432 } 433 434 435 /** 436 * 获取要修改的值 437 * 438 * @param entity 439 * @param ignoreNulls 440 */ 441 public Set<String> obtainUpdateColumns(Object entity, boolean ignoreNulls, boolean includePrimary) { 442 MetaObject metaObject = EntityMetaObject.forObject(entity, reflectorFactory); 443 Set<String> columns = new LinkedHashSet<>(); //需使用 LinkedHashSet 保证 columns 的顺序 444 if (entity instanceof ModifyAttrsRecord) { 445 Set<String> properties = ((ModifyAttrsRecord) entity).obtainModifyAttrs(); 446 if (properties.isEmpty()) { 447 return Collections.emptySet(); 448 } 449 for (String property : properties) { 450 String column = propertyColumnMapping.get(property); 451 if (onUpdateColumns != null && onUpdateColumns.containsKey(column)) { 452 continue; 453 } 454 455 //过滤乐观锁字段 和 租户字段 456 if (ObjectUtil.equalsAny(column, versionColumn, tenantIdColumn)) { 457 continue; 458 } 459 460 if (!includePrimary && ArrayUtil.contains(primaryKeys, column)) { 461 continue; 462 } 463 464 // ModifyAttrsRecord 忽略 ignoreNulls 的设置 465 // Object value = getPropertyValue(metaObject, property); 466 // if (ignoreNulls && value == null) { 467 // continue; 468 // } 469 columns.add(column); 470 } 471 } 472 //not ModifyAttrsRecord 473 else { 474 for (String column : this.columns) { 475 if (onUpdateColumns != null && onUpdateColumns.containsKey(column)) { 476 continue; 477 } 478 479 //过滤乐观锁字段 和 租户字段 480 if (ObjectUtil.equalsAny(column, versionColumn, tenantIdColumn)) { 481 continue; 482 } 483 484 Object value = buildColumnSqlArg(metaObject, column); 485 if (ignoreNulls && value == null) { 486 continue; 487 } 488 489 columns.add(column); 490 } 491 492 // 普通 entity(非 ModifyAttrsRecord) 忽略 includePrimary 的设置 493// if (includePrimary) { 494// for (String column : this.primaryKeys) { 495// Object value = getColumnValue(metaObject, column); 496// if (ignoreNulls && value == null) { 497// continue; 498// } 499// columns.add(column); 500// } 501// } 502 } 503 return columns; 504 } 505 506 /** 507 * 获取所有要修改的值,默认为全部除了主键以外的字段 508 * 509 * @param entity 实体对象 510 * @return 数组 511 */ 512 public Object[] buildUpdateSqlArgs(Object entity, boolean ignoreNulls, boolean includePrimary) { 513 MetaObject metaObject = EntityMetaObject.forObject(entity, reflectorFactory); 514 List<Object> values = new ArrayList<>(); 515 if (entity instanceof ModifyAttrsRecord) { 516 Set<String> properties = ((ModifyAttrsRecord) entity).obtainModifyAttrs(); 517 if (properties.isEmpty()) { 518 return values.toArray(); 519 } 520 for (String property : properties) { 521 String column = propertyColumnMapping.get(property); 522 if (onUpdateColumns != null && onUpdateColumns.containsKey(column)) { 523 continue; 524 } 525 //过滤乐观锁字段 和 租户字段 526 if (ObjectUtil.equalsAny(column, versionColumn, tenantIdColumn)) { 527 continue; 528 } 529 530 if (!includePrimary && ArrayUtil.contains(primaryKeys, column)) { 531 continue; 532 } 533 534 Object value = buildColumnSqlArg(metaObject, column); 535 // ModifyAttrsRecord 忽略 ignoreNulls 的设置, 536 // 当使用 ModifyAttrsRecord 时,可以理解为要对字段进行 null 值进行更新,否则没必要使用 ModifyAttrsRecord 537 // if (ignoreNulls && value == null) { 538 // continue; 539 // } 540 values.add(value); 541 } 542 } 543 // normal entity. not ModifyAttrsRecord 544 else { 545 for (String column : this.columns) { 546 if (onUpdateColumns != null && onUpdateColumns.containsKey(column)) { 547 continue; 548 } 549 550 //过滤乐观锁字段 和 租户字段 551 if (ObjectUtil.equalsAny(column, versionColumn, tenantIdColumn)) { 552 continue; 553 } 554 555 // 普通 entity 忽略 includePrimary 的设置, 556 // 因为 for 循环中的 this.columns 本身就不包含有主键 557 // if (includePrimary) { 558 // } 559 560 Object value = buildColumnSqlArg(metaObject, column); 561 if (ignoreNulls && value == null) { 562 continue; 563 } 564 565 values.add(value); 566 } 567 } 568 569 return values.toArray(); 570 } 571 572 573 /** 574 * 构建主键的 sql 参数数据 575 * 576 * @param entity 577 */ 578 public Object[] buildPkSqlArgs(Object entity) { 579 MetaObject metaObject = EntityMetaObject.forObject(entity, reflectorFactory); 580 Object[] values = new Object[primaryKeys.length]; 581 for (int i = 0; i < primaryKeys.length; i++) { 582 values[i] = buildColumnSqlArg(metaObject, primaryKeys[i]); 583 } 584 return values; 585 } 586 587 588 public Object[] buildTenantIdArgs() { 589 if (StringUtil.isBlank(tenantIdColumn)) { 590 return null; 591 } 592 593 return TenantManager.getTenantIds(); 594 } 595 596 private static final String APPEND_CONDITIONS_FLAG = "appendConditions"; 597 598 public void appendConditions(Object entity, QueryWrapper queryWrapper) { 599 600 Object appendConditions = CPI.getContext(queryWrapper, APPEND_CONDITIONS_FLAG); 601 if (Boolean.TRUE.equals(appendConditions)) { 602 return; 603 } else { 604 CPI.putContext(queryWrapper, APPEND_CONDITIONS_FLAG, Boolean.TRUE); 605 } 606 607 //select xxx.id,(select..) from xxx 608 List<QueryColumn> selectColumns = CPI.getSelectColumns(queryWrapper); 609 if (selectColumns != null && !selectColumns.isEmpty()) { 610 for (QueryColumn queryColumn : selectColumns) { 611 if (queryColumn instanceof SelectQueryColumn) { 612 QueryWrapper selectColumnQueryWrapper = CPI.getQueryWrapper((SelectQueryColumn) queryColumn); 613 doAppendConditions(entity, selectColumnQueryWrapper); 614 } 615 } 616 } 617 618 //select * from (select ... from ) 中的子查询处理 619 List<QueryTable> queryTables = CPI.getQueryTables(queryWrapper); 620 if (queryTables != null && !queryTables.isEmpty()) { 621 for (QueryTable queryTable : queryTables) { 622 if (queryTable instanceof SelectQueryTable) { 623 QueryWrapper selectQueryWrapper = ((SelectQueryTable) queryTable).getQueryWrapper(); 624 doAppendConditions(entity, selectQueryWrapper); 625 } 626 } 627 } 628 629 //添加乐观锁条件,只有在 update 的时候进行处理 630 if (StringUtil.isNotBlank(versionColumn) && entity != null) { 631 Object versionValue = buildColumnSqlArg(entity, versionColumn); 632 if (versionValue == null) { 633 throw FlexExceptions.wrap("The version value of entity[%s] must not be null.", entity); 634 } 635 queryWrapper.and(QueryCondition.create(schema, tableName, versionColumn, QueryCondition.LOGIC_EQUALS, versionValue)); 636 } 637 638 //逻辑删除 639 if (StringUtil.isNotBlank(logicDeleteColumn)) { 640 queryWrapper.and(QueryCondition.create(schema, tableName, logicDeleteColumn, QueryCondition.LOGIC_EQUALS 641 , FlexGlobalConfig.getDefaultConfig().getNormalValueOfLogicDelete())); 642 } 643 644 //多租户 645 Object[] tenantIdArgs = buildTenantIdArgs(); 646 if (ArrayUtil.isNotEmpty(tenantIdArgs)) { 647 if (tenantIdArgs.length == 1) { 648 queryWrapper.and(QueryCondition.create(schema, tableName, tenantIdColumn, QueryCondition.LOGIC_EQUALS, tenantIdArgs[0])); 649 } else { 650 queryWrapper.and(QueryCondition.create(schema, tableName, tenantIdColumn, QueryCondition.LOGIC_IN, tenantIdArgs)); 651 } 652 } 653 654 //子查询 655 List<QueryWrapper> childSelects = CPI.getChildSelect(queryWrapper); 656 if (CollectionUtil.isNotEmpty(childSelects)) { 657 for (QueryWrapper childQueryWrapper : childSelects) { 658 doAppendConditions(entity, childQueryWrapper); 659 } 660 } 661 662 //union 663 List<UnionWrapper> unions = CPI.getUnions(queryWrapper); 664 if (CollectionUtil.isNotEmpty(unions)) { 665 for (UnionWrapper union : unions) { 666 QueryWrapper unionQueryWrapper = union.getQueryWrapper(); 667 doAppendConditions(entity, unionQueryWrapper); 668 } 669 } 670 } 671 672 673 private void doAppendConditions(Object entity, QueryWrapper queryWrapper) { 674 List<QueryTable> queryTables = CPI.getQueryTables(queryWrapper); 675 if (queryTables != null && !queryTables.isEmpty()) { 676 for (QueryTable queryTable : queryTables) { 677 TableInfo tableInfo = TableInfoFactory.ofTableName(queryTable.getName()); 678 if (tableInfo != null) { 679 tableInfo.appendConditions(entity, queryWrapper); 680 } 681 } 682 } 683 } 684 685 686 public String getKeyProperties() { 687 StringJoiner joiner = new StringJoiner(","); 688 for (IdInfo value : primaryKeyList) { 689 joiner.add(FlexConsts.ENTITY + "." + value.getProperty()); 690 } 691 return joiner.toString(); 692 } 693 694 695 public String getKeyColumns() { 696 StringJoiner joiner = new StringJoiner(","); 697 for (IdInfo value : primaryKeyList) { 698 joiner.add(value.getColumn()); 699 } 700 return joiner.toString(); 701 } 702 703 public List<QueryColumn> getDefaultQueryColumn() { 704 return Arrays.stream(defaultColumns) 705 .map(name -> new QueryColumn(schema, getTableName(), name)) 706 .collect(Collectors.toList()); 707 } 708 709 /** 710 * @deprecated 该功能有更好的方式实现,此方法可能会被移除。 711 */ 712 @Deprecated 713 public ResultMap buildResultMap(Configuration configuration) { 714 String resultMapId = entityClass.getName(); 715 List<ResultMapping> resultMappings = new ArrayList<>(); 716 717 for (ColumnInfo columnInfo : columnInfoList) { 718 ResultMapping mapping = new ResultMapping.Builder(configuration, columnInfo.property, 719 columnInfo.column, columnInfo.propertyType) 720 .jdbcType(columnInfo.getJdbcType()) 721 .typeHandler(columnInfo.buildTypeHandler()) 722 .build(); 723 resultMappings.add(mapping); 724 725 //add property mapper for sql: select xxx as property ... 726 if (!Objects.equals(columnInfo.getColumn(), columnInfo.getProperty())) { 727 ResultMapping propertyMapping = new ResultMapping.Builder(configuration, columnInfo.property, 728 columnInfo.property, columnInfo.propertyType) 729 .jdbcType(columnInfo.getJdbcType()) 730 .typeHandler(columnInfo.buildTypeHandler()) 731 .build(); 732 resultMappings.add(propertyMapping); 733 } 734 } 735 736 for (IdInfo idInfo : primaryKeyList) { 737 ResultMapping mapping = new ResultMapping.Builder(configuration, idInfo.property, 738 idInfo.column, idInfo.propertyType) 739 .flags(CollectionUtil.newArrayList(ResultFlag.ID)) 740 .jdbcType(idInfo.getJdbcType()) 741 .typeHandler(idInfo.buildTypeHandler()) 742 .build(); 743 resultMappings.add(mapping); 744 } 745 746 if (joinTypes != null && !joinTypes.isEmpty()) { 747 joinTypes.forEach((fieldName, fieldType) -> { 748 749 TableInfo joinTableInfo = TableInfoFactory.ofEntityClass(fieldType); 750 List<ColumnInfo> joinTableInfoColumnInfoList = joinTableInfo.getColumnInfoList(); 751 752 for (ColumnInfo joinColumnInfo : joinTableInfoColumnInfoList) { 753 if (!existColumn(resultMappings, joinColumnInfo.column)) { 754 ResultMapping mapping = new ResultMapping.Builder(configuration, fieldName + "." + joinColumnInfo.property, 755 joinColumnInfo.column, joinColumnInfo.propertyType) 756 .jdbcType(joinColumnInfo.jdbcType) 757 .typeHandler(joinColumnInfo.buildTypeHandler()) 758 .build(); 759 resultMappings.add(mapping); 760 } 761 762 //add property mapper for sql: select xxx as property ... 763 if (!existColumn(resultMappings, joinColumnInfo.property)) { 764 if (!Objects.equals(joinColumnInfo.column, joinColumnInfo.property)) { 765 ResultMapping propertyMapping = new ResultMapping.Builder(configuration, fieldName + "." + joinColumnInfo.property, 766 joinColumnInfo.property, joinColumnInfo.propertyType) 767 .jdbcType(joinColumnInfo.jdbcType) 768 .typeHandler(joinColumnInfo.buildTypeHandler()) 769 .build(); 770 resultMappings.add(propertyMapping); 771 } 772 } 773 } 774 }); 775 } 776 777 return new ResultMap.Builder(configuration, resultMapId, entityClass, resultMappings).build(); 778 } 779 780 public List<ResultMap> buildResultMapList(Configuration configuration) { 781 String resultMapId = entityClass.getName(); 782 List<ResultMap> resultMaps = new ArrayList<>(); 783 List<ResultMapping> resultMappings = new ArrayList<>(); 784 785 // <resultMap> 标签下的 <result> 标签映射 786 for (ColumnInfo columnInfo : columnInfoList) { 787 ResultMapping mapping = new ResultMapping.Builder(configuration, columnInfo.property, 788 columnInfo.column, columnInfo.propertyType) 789 .jdbcType(columnInfo.getJdbcType()) 790 .typeHandler(columnInfo.buildTypeHandler()) 791 .build(); 792 resultMappings.add(mapping); 793 794 //add property mapper for sql: select xxx as property ... 795 if (!Objects.equals(columnInfo.getColumn(), columnInfo.getProperty())) { 796 ResultMapping propertyMapping = new ResultMapping.Builder(configuration, columnInfo.property, 797 columnInfo.property, columnInfo.propertyType) 798 .jdbcType(columnInfo.getJdbcType()) 799 .typeHandler(columnInfo.buildTypeHandler()) 800 .build(); 801 resultMappings.add(propertyMapping); 802 } 803 } 804 805 // <resultMap> 标签下的 <id> 标签映射 806 for (IdInfo idInfo : primaryKeyList) { 807 ResultMapping mapping = new ResultMapping.Builder(configuration, idInfo.property, 808 idInfo.column, idInfo.propertyType) 809 .flags(CollectionUtil.newArrayList(ResultFlag.ID)) 810 .jdbcType(idInfo.getJdbcType()) 811 .typeHandler(idInfo.buildTypeHandler()) 812 .build(); 813 resultMappings.add(mapping); 814 } 815 816 // <resultMap> 标签下的 <association> 标签映射 817 if (associationType != null) { 818 associationType.forEach((fieldName, fieldType) -> { 819 // 获取嵌套类型的信息,也就是 javaType 属性 820 TableInfo tableInfo = TableInfoFactory.ofEntityClass(fieldType); 821 // 构建嵌套类型的 ResultMap 对象,也就是 <association> 标签下的内容 822 // 这里是递归调用,直到嵌套类型里面没有其他嵌套类型或者集合类型为止 823 List<ResultMap> resultMapList = tableInfo.buildResultMapList(configuration); 824 // 寻找是否有嵌套 ResultMap 引用 825 Optional<ResultMap> nestedResultMap = resultMapList.stream() 826 .filter(e -> fieldType.getName().equals(e.getId())) 827 .findFirst(); 828 // 处理嵌套类型 ResultMapping 引用 829 nestedResultMap.ifPresent(resultMap -> resultMappings.add(new ResultMapping.Builder(configuration, fieldName) 830 .javaType(fieldType) 831 .nestedResultMapId(resultMap.getId()) 832 .build())); 833 // 全部添加到 ResultMap 集合当中 834 resultMaps.addAll(resultMapList); 835 }); 836 } 837 838 // <resultMap> 标签下的 <collection> 标签映射 839 if (collectionType != null) { 840 collectionType.forEach((field, genericClass) -> { 841 // 获取集合泛型类型的信息,也就是 ofType 属性 842 TableInfo tableInfo = TableInfoFactory.ofEntityClass(genericClass); 843 // 构建嵌套类型的 ResultMap 对象,也就是 <collection> 标签下的内容 844 // 这里是递归调用,直到集合类型里面没有其他嵌套类型或者集合类型为止 845 List<ResultMap> resultMapList = tableInfo.buildResultMapList(configuration); 846 // 寻找是否有嵌套 ResultMap 引用 847 Optional<ResultMap> nestedResultMap = resultMapList.stream() 848 .filter(e -> genericClass.getName().equals(e.getId())) 849 .findFirst(); 850 // 处理嵌套类型 ResultMapping 引用 851 nestedResultMap.ifPresent(resultMap -> resultMappings.add(new ResultMapping.Builder(configuration, field.getName()) 852 .javaType(field.getType()) 853 .nestedResultMapId(resultMap.getId()) 854 .build())); 855 // 全部添加到 ResultMap 集合当中 856 resultMaps.addAll(resultMapList); 857 }); 858 } 859 860 resultMaps.add(new ResultMap.Builder(configuration, resultMapId, entityClass, resultMappings).build()); 861 862 return resultMaps; 863 } 864 865 private static boolean existColumn(List<ResultMapping> resultMappings, String name) { 866 for (ResultMapping resultMapping : resultMappings) { 867 if (resultMapping.getColumn().equalsIgnoreCase(name)) { 868 return true; 869 } 870 } 871 return false; 872 } 873 874 875 private Object buildColumnSqlArg(MetaObject metaObject, String column) { 876 ColumnInfo columnInfo = columnInfoMapping.get(column); 877 Object value = getPropertyValue(metaObject, columnInfo.property); 878 879 if (value != null) { 880 TypeHandler typeHandler = columnInfo.buildTypeHandler(); 881 if (typeHandler != null) { 882 return new TypeHandlerObject(typeHandler, value, columnInfo.getJdbcType()); 883 } 884 } 885 886 return value; 887 } 888 889 890 public Object buildColumnSqlArg(Object entityObject, String column) { 891 MetaObject metaObject = EntityMetaObject.forObject(entityObject, reflectorFactory); 892 return buildColumnSqlArg(metaObject, column); 893 } 894 895 896 private Object getPropertyValue(MetaObject metaObject, String property) { 897 if (property != null && metaObject.hasGetter(property)) { 898 return metaObject.getValue(property); 899 } 900 return null; 901 } 902 903 904 /** 905 * 通过 row 实例类转换为一个 entity 906 * 907 * @return entity 908 */ 909 public <T> T newInstanceByRow(Row row, int index) { 910 Object instance = ClassUtil.newInstance(entityClass); 911 MetaObject metaObject = EntityMetaObject.forObject(instance, reflectorFactory); 912 Set<String> rowKeys = row.keySet(); 913 columnInfoMapping.forEach((column, columnInfo) -> { 914 if (index <= 0) { 915 for (String rowKey : rowKeys) { 916 if (column.equalsIgnoreCase(rowKey)) { 917 setInstancePropertyValue(row, instance, metaObject, columnInfo, rowKey); 918 } 919 } 920 } else { 921 for (int i = index; i >= 0; i--) { 922 String newColumn = i <= 0 ? column : column + "$" + i; 923 boolean fillValue = false; 924 for (String rowKey : rowKeys) { 925 if (newColumn.equalsIgnoreCase(rowKey)) { 926 setInstancePropertyValue(row, instance, metaObject, columnInfo, rowKey); 927 fillValue = true; 928 break; 929 } 930 } 931 if (fillValue) { 932 break; 933 } 934 } 935 } 936 }); 937 return (T) instance; 938 } 939 940 941 private void setInstancePropertyValue(Row row, Object instance, MetaObject metaObject, ColumnInfo columnInfo, String rowKey) { 942 Object rowValue = row.get(rowKey); 943 TypeHandler<?> typeHandler = columnInfo.buildTypeHandler(); 944 if (typeHandler != null) { 945 try { 946 //通过 typeHandler 转换数据 947 rowValue = typeHandler.getResult(getResultSet(rowValue), 0); 948 } catch (SQLException e) { 949 //ignore 950 } 951 } 952 if (rowValue != null && !metaObject.getSetterType(columnInfo.property).isAssignableFrom(rowValue.getClass())) { 953 rowValue = ConvertUtil.convert(rowValue, metaObject.getSetterType(columnInfo.property), true); 954 } 955 rowValue = invokeOnSetListener(instance, columnInfo.getProperty(), rowValue); 956 metaObject.setValue(columnInfo.property, rowValue); 957 } 958 959 960 private ResultSet getResultSet(Object value) { 961 return (ResultSet) Proxy.newProxyInstance(TableInfo.class.getClassLoader(), 962 new Class[]{ResultSet.class}, (proxy, method, args) -> value); 963 } 964 965 966 /** 967 * 初始化乐观锁版本号 968 * 969 * @param entityObject 970 */ 971 public void initVersionValueIfNecessary(Object entityObject) { 972 if (StringUtil.isBlank(versionColumn)) { 973 return; 974 } 975 976 MetaObject metaObject = EntityMetaObject.forObject(entityObject, reflectorFactory); 977 Object columnValue = getPropertyValue(metaObject, columnInfoMapping.get(versionColumn).property); 978 if (columnValue == null) { 979 String name = columnInfoMapping.get(versionColumn).property; 980 Class<?> clazz = metaObject.getSetterType(name); 981 metaObject.setValue(name, ConvertUtil.convert(0L, clazz)); 982 } 983 } 984 985 /** 986 * 设置租户id 987 * 988 * @param entityObject 989 */ 990 public void initTenantIdIfNecessary(Object entityObject) { 991 if (StringUtil.isBlank(tenantIdColumn)) { 992 return; 993 } 994 995 MetaObject metaObject = EntityMetaObject.forObject(entityObject, reflectorFactory); 996 Object[] tenantIds = TenantManager.getTenantIds(); 997 if (tenantIds == null || tenantIds.length == 0) { 998 return; 999 } 1000 1001 //默认使用第一个作为插入的租户ID 1002 Object tenantId = tenantIds[0]; 1003 if (tenantId != null) { 1004 String property = columnInfoMapping.get(tenantIdColumn).property; 1005 Class<?> setterType = metaObject.getSetterType(property); 1006 metaObject.setValue(property, ConvertUtil.convert(tenantId, setterType)); 1007 } 1008 } 1009 1010 /** 1011 * 初始化逻辑删除的默认值 1012 * 1013 * @param entityObject 1014 */ 1015 public void initLogicDeleteValueIfNecessary(Object entityObject) { 1016 if (StringUtil.isBlank(logicDeleteColumn)) { 1017 return; 1018 } 1019 1020 MetaObject metaObject = EntityMetaObject.forObject(entityObject, reflectorFactory); 1021 Object columnValue = getPropertyValue(metaObject, columnInfoMapping.get(logicDeleteColumn).property); 1022 if (columnValue == null) { 1023 String property = columnInfoMapping.get(logicDeleteColumn).property; 1024 Class<?> setterType = metaObject.getSetterType(property); 1025 Object normalValueOfLogicDelete = FlexGlobalConfig.getDefaultConfig().getNormalValueOfLogicDelete(); 1026 metaObject.setValue(property, ConvertUtil.convert(normalValueOfLogicDelete, setterType)); 1027 } 1028 } 1029 1030 1031 private static final Map<Class<?>, List<InsertListener>> insertListenerCache = new ConcurrentHashMap<>(); 1032 1033 public void invokeOnInsertListener(Object entity) { 1034 List<InsertListener> listeners = MapUtil.computeIfAbsent(insertListenerCache, entityClass, aClass -> { 1035 List<InsertListener> globalListeners = FlexGlobalConfig.getDefaultConfig() 1036 .getSupportedInsertListener(entityClass, CollectionUtil.isNotEmpty(onInsertListeners)); 1037 List<InsertListener> allListeners = CollectionUtil.merge(onInsertListeners, globalListeners); 1038 Collections.sort(allListeners); 1039 return allListeners; 1040 }); 1041 listeners.forEach(insertListener -> insertListener.onInsert(entity)); 1042 } 1043 1044 1045 private static final Map<Class<?>, List<UpdateListener>> updateListenerCache = new ConcurrentHashMap<>(); 1046 1047 public void invokeOnUpdateListener(Object entity) { 1048 List<UpdateListener> listeners = MapUtil.computeIfAbsent(updateListenerCache, entityClass, aClass -> { 1049 List<UpdateListener> globalListeners = FlexGlobalConfig.getDefaultConfig() 1050 .getSupportedUpdateListener(entityClass, CollectionUtil.isNotEmpty(onUpdateListeners)); 1051 List<UpdateListener> allListeners = CollectionUtil.merge(onUpdateListeners, globalListeners); 1052 Collections.sort(allListeners); 1053 return allListeners; 1054 }); 1055 listeners.forEach(insertListener -> insertListener.onUpdate(entity)); 1056 } 1057 1058 1059 private static final Map<Class<?>, List<SetListener>> setListenerCache = new ConcurrentHashMap<>(); 1060 1061 public Object invokeOnSetListener(Object entity, String property, Object value) { 1062 List<SetListener> listeners = MapUtil.computeIfAbsent(setListenerCache, entityClass, aClass -> { 1063 List<SetListener> globalListeners = FlexGlobalConfig.getDefaultConfig() 1064 .getSupportedSetListener(entityClass, CollectionUtil.isNotEmpty(onSetListeners)); 1065 List<SetListener> allListeners = CollectionUtil.merge(onSetListeners, globalListeners); 1066 Collections.sort(allListeners); 1067 return allListeners; 1068 }); 1069 for (SetListener setListener : listeners) { 1070 value = setListener.onSet(entity, property, value); 1071 } 1072 return value; 1073 } 1074 1075 public QueryColumn getQueryColumnByProperty(String property) { 1076 return new QueryColumn(schema, tableName, propertyColumnMapping.get(property)); 1077 } 1078}