-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
feat:新增根据实体中的属性进行查询指定属性 #793
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
貌似没有处理逻辑删除 |
|
升级jdk8时合并。 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR adds an “additional select” mapper/provider to query entities by non-null fields in a record parameter while allowing callers to specify which columns/properties to return.
Changes:
- Introduces
SelectSpecifyColumnsMapperwith methods to select by explicit column names or by entity properties (Fn). - Adds
SelectSpecifyColumnsProviderto generate dynamic SELECT SQL with a<foreach>column list andrecord-based WHERE conditions.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 8 comments.
| File | Description |
|---|---|
| extra/src/main/java/tk/mybatis/mapper/additional/select/SelectSpecifyColumnsProvider.java | Builds dynamic SELECT SQL for “specified columns/properties” queries and constructs a record-based WHERE clause. |
| extra/src/main/java/tk/mybatis/mapper/additional/select/SelectSpecifyColumnsMapper.java | Exposes new mapper methods to query with specified return columns/properties. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| sql.append("SELECT "); | ||
| sql.append("<foreach collection=\"columns\" item=\"item\" open=\"\" separator=\",\" close=\"\">"); | ||
| sql.append("${item}"); | ||
| sql.append("</foreach>"); |
Copilot
AI
Feb 11, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
selectByColumns directly interpolates user-provided columns via ${item}. This is raw string substitution and allows SQL injection (e.g., id, (select ...)), and also bypasses any column-name quoting rules. Consider mapping requested names to an allow-list derived from EntityHelper.getColumns(entityClass) (or only accepting Fn<T, ?> like selectByPropertys) and fail fast when an unknown column is requested.
| public static String whereAllIfColumns(Class<?> entityClass, boolean empty, boolean useVersion) { | ||
| StringBuilder sql = new StringBuilder(); | ||
| sql.append("<where>"); | ||
| Set<EntityColumn> columnSet = EntityHelper.getColumns(entityClass); | ||
| Iterator var5 = columnSet.iterator(); | ||
|
|
||
| while (true) { | ||
| EntityColumn column; | ||
| do { | ||
| if (!var5.hasNext()) { | ||
| if (useVersion) { | ||
| sql.append(SqlHelper.whereVersion(entityClass)); | ||
| } | ||
|
|
||
| sql.append("</where>"); | ||
| return sql.toString(); | ||
| } | ||
|
|
||
| column = (EntityColumn) var5.next(); | ||
| } while (useVersion && column.getEntityField().isAnnotationPresent(Version.class)); | ||
|
|
||
| sql.append(getIfNotNull(column, " AND " + getColumnEqualsHolder(column), empty)); | ||
| } |
Copilot
AI
Feb 11, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This provider reimplements SqlHelper.whereAllIfColumns but omits the logic-delete predicate that the core helper adds. For entities with a logic-delete column, this will return logically deleted rows. Align with core behavior by detecting the logic-delete column and appending SqlHelper.whereLogicDelete(entityClass, false) inside the <where> block (similar to core/.../SqlHelper.whereAllIfColumns).
| StringBuilder sql = new StringBuilder(); | ||
| sql.append("<if test=\""); | ||
|
|
||
| sql.append("record.").append(column.getProperty()).append(" != null"); | ||
| if (empty && column.getJavaType().equals(String.class)) { | ||
| sql.append(" and ").append(column.getProperty()).append(" != '' "); | ||
| } | ||
|
|
||
| sql.append("\">"); | ||
| sql.append(contents); | ||
| sql.append("</if>"); | ||
| return sql.toString(); | ||
| } | ||
|
|
||
| public static String getColumnEqualsHolder(EntityColumn column) { | ||
|
|
||
| return column.getColumn() + " = " + getColumnHolder(column); | ||
| } | ||
|
|
||
| public static String getColumnHolder(EntityColumn column) { | ||
|
|
||
| StringBuffer sb = new StringBuffer("#{"); | ||
|
|
||
| sb.append("record.").append(column.getProperty()); | ||
|
|
||
| if (column.getJdbcType() != null) { | ||
| sb.append(", jdbcType="); | ||
| sb.append(column.getJdbcType().toString()); | ||
| } | ||
|
|
||
| if (column.getTypeHandler() != null) { | ||
| sb.append(", typeHandler="); | ||
| sb.append(column.getTypeHandler().getCanonicalName()); | ||
| } | ||
|
|
||
| if (column.isUseJavaType() && !column.getJavaType().isArray()) { | ||
| sb.append(", javaType="); | ||
| sb.append(column.getJavaType().getCanonicalName()); | ||
| } | ||
|
|
||
| sb.append("}"); | ||
|
|
||
| return sb.toString(); |
Copilot
AI
Feb 11, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
whereAllIfColumns, getColumnEqualsHolder, and getColumnHolder duplicate existing core helpers (SqlHelper.getIfNotNull(entityName, ...) and EntityColumn.getColumnEqualsHolder(entityName)). Reusing the shared helpers will reduce maintenance risk and keep behavior consistent (e.g., version + logic-delete handling, JDBC/typeHandler formatting).
| StringBuilder sql = new StringBuilder(); | |
| sql.append("<if test=\""); | |
| sql.append("record.").append(column.getProperty()).append(" != null"); | |
| if (empty && column.getJavaType().equals(String.class)) { | |
| sql.append(" and ").append(column.getProperty()).append(" != '' "); | |
| } | |
| sql.append("\">"); | |
| sql.append(contents); | |
| sql.append("</if>"); | |
| return sql.toString(); | |
| } | |
| public static String getColumnEqualsHolder(EntityColumn column) { | |
| return column.getColumn() + " = " + getColumnHolder(column); | |
| } | |
| public static String getColumnHolder(EntityColumn column) { | |
| StringBuffer sb = new StringBuffer("#{"); | |
| sb.append("record.").append(column.getProperty()); | |
| if (column.getJdbcType() != null) { | |
| sb.append(", jdbcType="); | |
| sb.append(column.getJdbcType().toString()); | |
| } | |
| if (column.getTypeHandler() != null) { | |
| sb.append(", typeHandler="); | |
| sb.append(column.getTypeHandler().getCanonicalName()); | |
| } | |
| if (column.isUseJavaType() && !column.getJavaType().isArray()) { | |
| sb.append(", javaType="); | |
| sb.append(column.getJavaType().getCanonicalName()); | |
| } | |
| sb.append("}"); | |
| return sb.toString(); | |
| // Delegate to core helper to keep behavior (e.g., version and logic-delete handling) consistent | |
| return SqlHelper.getIfNotNull("record", column, contents, empty); | |
| } | |
| public static String getColumnEqualsHolder(EntityColumn column) { | |
| // Delegate to EntityColumn helper, using "record" as the entity alias | |
| return column.getColumnEqualsHolder("record"); | |
| } | |
| public static String getColumnHolder(EntityColumn column) { | |
| // Delegate to EntityColumn helper, using "record" as the entity alias | |
| return column.getColumnHolder("record"); |
| type = SelectSpecifyColumnsProvider.class, | ||
| method = "dynamicSQL" | ||
| ) | ||
| List<T> selectByPropertys(@Param("record") T record, @Param("fns") List<Fn<T, ?>> fns); |
Copilot
AI
Feb 11, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Public API method name selectByPropertys has a spelling error (“Propertys”). Since this is a new mapper method, consider renaming to selectByProperties (and the provider method accordingly) to avoid locking in a misspelled API.
| List<T> selectByPropertys(@Param("record") T record, @Param("fns") List<Fn<T, ?>> fns); | |
| List<T> selectByProperties(@Param("record") T record, @Param("fns") List<Fn<T, ?>> fns); |
| @SelectProvider( | ||
| type = SelectSpecifyColumnsProvider.class, | ||
| method = "dynamicSQL" | ||
| ) | ||
| List<T> selectByColumns(@Param("record") T record, @Param("columns") List<String> columns); | ||
|
|
||
| /** | ||
| * 根据条件查询实体, 并指定属性 | ||
| * | ||
| * @param record 查询实体条件 | ||
| * @param fns 指定的返回实体属性 | ||
| * @return | ||
| */ | ||
| @SelectProvider( | ||
| type = SelectSpecifyColumnsProvider.class, | ||
| method = "dynamicSQL" | ||
| ) | ||
| List<T> selectByPropertys(@Param("record") T record, @Param("fns") List<Fn<T, ?>> fns); |
Copilot
AI
Feb 11, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
New mapper methods (selectByColumns / selectByPropertys) introduce new SQL-generation paths, but there are no corresponding tests under extra/src/test/java/tk/mybatis/mapper/additional/select (unlike SelectByPropertyMapperTest). Adding coverage that verifies selected columns, WHERE binding via record, and logic-delete behavior would help prevent regressions.
| StringBuilder sql = new StringBuilder(); | ||
| sql.append("SELECT "); | ||
| sql.append("<foreach collection=\"columns\" item=\"item\" open=\"\" separator=\",\" close=\"\">"); | ||
| sql.append("${item}"); | ||
| sql.append("</foreach>"); | ||
| sql.append(SqlHelper.fromTable(entityClass, this.tableName(entityClass))); |
Copilot
AI
Feb 11, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If columns is null or empty, the <foreach> renders nothing and produces invalid SQL (SELECT FROM ...). Add a guard (e.g., <choose>/<if>) to default to SqlHelper.selectAllColumns(entityClass) or throw a clear error when no columns are specified.
| sql.append("SELECT "); | ||
| String entityClassName = entityClass.getName(); | ||
| sql.append("<foreach collection=\"fns\" item=\"item\" open=\"\" separator=\",\" close=\"\">"); | ||
| String ognl = new StringBuilder("${@") | ||
| .append(propertyHelper) | ||
| .append("@getColumnByProperty(@java.lang.Class@forName(\"") | ||
| .append(entityClassName) | ||
| .append("\"), @tk.mybatis.mapper.weekend.reflection.Reflections@fnToFieldName(item))}").toString(); | ||
| sql.append(ognl); | ||
| sql.append("</foreach>"); |
Copilot
AI
Feb 11, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If fns is null or empty, the <foreach> renders nothing and produces invalid SQL (SELECT FROM ...). Add a guard to default to all columns or fail fast with a helpful error when no properties are specified.
|
|
||
| sql.append("record.").append(column.getProperty()).append(" != null"); | ||
| if (empty && column.getJavaType().equals(String.class)) { | ||
| sql.append(" and ").append(column.getProperty()).append(" != '' "); |
Copilot
AI
Feb 11, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
getIfNotNull builds the empty-string check as and <property> != '' but the preceding null-check uses record.<property>. This will cause OGNL evaluation errors (property not found) and the condition won’t work as intended. Prefix the empty-string check with record. as well (or delegate to SqlHelper.getIfNotNull("record", ...) to avoid drift).
| sql.append(" and ").append(column.getProperty()).append(" != '' "); | |
| sql.append(" and record.").append(column.getProperty()).append(" != '' "); |

No description provided.