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