MultiSqlBuilder
实现了多表查询的功能,MultiSqlBuilderTest
是相关的测试用例,看这些测试代码,就明白怎么用了。
设计约定:考虑到执行效率与便于维护性
Sql
语句形式多表查询如果是Sql
语句固定的,那就好办,直接写一条Sql
语句到程序中就可以了,然后把结果转成前端AntDesgin
所需的格式。但是:
where
条件,最多的场景是追加过滤条件。通俗将是追加and
条件。order
内容,可以是追加的(优先级比较高),也可以是将原先以有的替换掉。AntDesgin
前端比较喜欢的形式传递。Sql
注入。首先写一个基础的 Sql 语句
/*** 查询成绩表* @param params ant格式的查询条件* @return AbstractListResponse*/public AbstractListResponse<Map<String,Object>> selectByAntSearchByPageBySql(AntSearchListParams params){String sql="select A.*,B.course_name,C.student_name,C.student_age,C.student_sex " +"from wk_student_scores A " +" ,wk_course B " +" ,wk_student C " +"where A.student_id=C.student_id " +" and A.course_id=B.course_id " +" ORDER BY A.gmt_create desc";return multiSqlBuilder.selectByAntSearchByPage(sql,params);}
其次通过传递参数,来改变 Sql 语句
{"select": "","wheres": {"studentName_like": "tom","gmtModified_greater": "2001-05-05 10:15:25","studentId_between": "1,300"},"current": 1,"pageSize": 20,"order": "studentName,studentSex desc"}
参数说明:
- 使用驼峰形式表示字段,这与前端的 js 规范是一致的。
- where 条件后的下划线比是操作符,详细可以参考这里。
- 这里没有指定表明,默认是 Sql 语句中的 From 的第一个表,没有这个字段,采取查询另外一张表。有一个默认的顺序。当然也可以指定表,看下章节内容。
返回AntDesgin
表格可以接受的格式,AbstractListResponse
如果不指定表名,会按照from wk_student_scores A ,wk_course B ,wk_student C
顺序来匹配字段。
{"select": "","wheres": {"studentName_like": "tom","c.gmtModified_greater": "2001-05-05 10:15:25","a.studentId_between": "1,300"},"current": 1,"pageSize": 20,"order": "studentName,studentSex desc"}
参数还是一样,就是传递进去的分页参数无效。
public List<Map<String, Object>> selectByAntSearchAllBySql(AntSearchListParams params){String sql="select A.*,B.course_name,C.student_name,C.student_age,C.student_sex " +"from wk_student_scores A " +" ,wk_course B " +" ,wk_student C " +"where A.student_id=C.student_id " +" and A.course_id=B.course_id " +" ORDER BY A.gmt_create desc";return multiSqlBuilder.selectByAntSearchByAll(sql,params,false);}
这里面有几个撰写 Sql
语句的约束:
Select
要查询的字段,尽量不要重复,这点需要手工处理。order by
有一个默认的查询,新添加排序,可以选择排在默认排序前面,也可以替换原有的排序。后续可能要完善的
ec_
表可能会变化,应该做成动态的,为了代码的可读性,就没有做替换,今后可以做替换。Mybatis
功能。Sql
语句拼接。MybatisDynamic
形式这里只说明MybatisDynamic
中 80%的场景用到的地方,关于特殊用法,看其他细节。
有一些前提条件:
MybatisDynamic
写法举例MybatisDynamic
写的代码,如果习惯了也很好,感觉不错。主要的好处如下:
SelectStatementProvider selectStatement = select(studentScores.allColumns(),course.courseName,student.studentName,student.studentAge,student.studentSex).from(studentScores).join(course).on(studentScores.courseId,equalTo(course.courseId)).join(student).on(student.studentId,equalTo(studentScores.studentId)).orderBy(studentScores.gmtModified.descending()).build().render(RenderingStrategies.MYBATIS3);
输出的Sql
语句如下:
select wk_student_scores.*, wk_course.course_name, wk_student.student_name, wk_student.student_age, wk_student.student_sexfrom wk_student_scoresjoin wk_course on wk_student_scores.course_id = wk_course.course_idjoin wk_student on wk_student.student_id = wk_student_scores.student_idorder by gmt_modified DESC
也可以手工根据条件撰写 where 语句,如果变化情况那么复杂的话
.where(student.studentId,isGreaterThan(studentId_).filter(Objects::nonNull))
,如果传入的参数为空,就不添加这个 where 条件。
SelectStatementProvider selectStatement = select(studentScores.allColumns(),course.courseName,student.studentName,student.studentAge,student.studentSex).from(studentScores).join(course).on(studentScores.courseId,equalTo(course.courseId)).join(student).on(student.studentId,equalTo(studentScores.studentId)).where(student.studentId,isGreaterThan(studentId_).filter(Objects::nonNull)).orderBy(studentScores.gmtModified.descending()).build().render(RenderingStrategies.MYBATIS3);return selectStatement.getSelectStatement();
通过前端传递过来的参数,虽然有局限性,但是满足了 80%的场景。
具体步骤如下
QueryExpressionDSL<SelectModel>.JoinSpecificationFinisher selectDSL
,基本的 Sql 查询条件。WhereDSL.StandaloneWhereFinisher defaultWhereDSL
,可以为空。Collection<SortSpecification> defaultOrderByColumns
。multiMybatisBuilder
的函数selectByAntSearchByAll
或者selectByAntSearchByPage
,一个是分页,一个是不分页。public List<Map<String, Object>> selectByAntSearchAllByMybatis(AntSearchListParams params) {//撰写selectDSLQueryExpressionDSL<SelectModel>.JoinSpecificationFinisher selectDSL = select(studentScores.allColumns(), course.courseName, student.studentName, student.studentAge, student.studentSex).from(studentScores, "a").join(course, "b").on(studentScores.courseId, equalTo(course.courseId)).join(student, "c").on(student.studentId, equalTo(studentScores.studentId));//撰写初始的where条件Long studentId_ = 1L;WhereDSL.StandaloneWhereFinisher defaultWhereDSL= SqlBuilder.where().and(studentScores.studentId, isGreaterThan(studentId_));//撰写初始的排序条件,这里注意别出现错误,要排序的内容,一定要在select中Collection<SortSpecification> defaultOrderByColumns = new ArrayList<>();defaultOrderByColumns.add(studentScores.gmtModified.descending());return multiMybatisBuilder.selectByAntSearchByAll(selectDSL,defaultWhereDSL,defaultOrderByColumns,params);}
如何接受参数,分两种。在多表可能大部分都是 postJson 格式。
例如:where_studentId=123&where_studentName_like=%tom%&orderBy=studentName,studentSex desc
调用 RequestAnalysis,自动解析出 request 中的查询条件
@RequestMapping("/hello")public List<StudentInfo> hello() {HttpServletRequest request= RequestContextHolderUtil.getRequest();SqlMaps sqlMaps= RequestAnalysis.analysis(request);WhereObject sqlObject=whereBuilder.build("wk_student_info",sqlMaps);List<StudentInfo> list =dynamicSqlService.selectByWhere(sqlObject.getWhereDSL(),sqlObject.getOrder());return list;}
直接在前端就把检索条件拼接好了,后台就不用转换了
@PostMapping("/selectListForAdmin")@AntdResultpublic AbstractListResponse selectListForAdmin(@RequestBody AntSearchListParams params) {return goodsCommonService.selectListForAdmin(params);}