首先,我们要知道,其实LambdaQueryWrapper是无法使用sum聚合函数的,因为LambdaQueryWrapper的select()方法无法传入字符串,但你有张良计,我有过墙梯,我们其实可以迂回来做。
先使用QueryWrapper,拼接我们需要的select,然后再转成LambdaQueryWrapper,具体如下:
order对象:(简单写需要的东西)
@Data
@TableName("t_order")
public class OrderModel {
/**
* 商户号
*/
private String merNo;
/**
* 订单号
*/
private BigDecimal orderId;
/**
* 手续费
*/
private BigDecimal feeAmt;
/**
* 到账金额
*/
private BigDecimal arrivalAmt;
/**
* 交易时间
*/
private LocalDate tradeDate;
}
代码如下:
Page<OrderModel> page = orderService.page(new Page<>(1, 20), new QueryWrapper<OrderModel>()
.select(" SUM(fee_amt) AS fee_amt, SUM(arrival_amt) AS arrival_amt, mer_no ")
.lambda()
.between(StrUtil.isNotBlank(commandReq.getStartDate()) && StrUtil.isNotBlank(commandReq.getEndDate()),
OrderModel::getTradeDate,
StrUtil.isNotBlank(startDateStr) ? LocalDate.parse(startDateStr) : null,
StrUtil.isNotBlank(endDateStr) ? LocalDate.parse(cendDateStr) : null)
.groupBy(OrderModel::getMerNo));
分页查询,按照商户号进行分组,手续费和到账金额进行汇总,如果时间不为空,用between范围查询。
先用QueryWrapper处理掉聚合函数,然后再用.lambda()转成LambdaQueryWrapper,保证下面能用lambda写法。SUM(fee_amt)
直接丢在fee_amt
里,就不用去新加属性了,如果不想,可以再加个对象里补个汇总字段。
@TableField(exist = false)
private BigDecimal FeeTotalAmt;
进行扩展,如果我们想多查一个订单号orderNo,第一种写法可以这样写:
.select(" SUM(fee_amt) AS fee_amt, SUM(arrival_amt) AS arrival_amt, mer_no, order_no ")
.lambda()
但是这样写的坏处就是,不够优雅,而且如果在java里改了属性名,会导致查询出问题,这也是我们想用LambdaQueryWrapper的原因。
但如果按照下面这种写法,也存在问题:
.select(" SUM(fee_amt) AS fee_amt, SUM(arrival_amt) AS arrival_amt, mer_no ")
.lambda()
.select(OrderModel::getOrderNo)
这样写会导致我们在QueryWrapper写的select被LambdaQueryWrapper覆盖调。所以第二种做法行不通,但不想用第一种写法,想用lambda,那么就得解决第二种写法出现的问题。
通过查看LambdaQueryWrapper的select方法,发现它是使用SFunction接收参数,并把参数使用stream流转成字符串。
那么,具体思路就有了,我们把SFunction根据流的方式,转成字符串,代码如下:
/**
* 处理sql查询字段名
* @param columns
* @return
*/
private String getParamSql(SFunction<OrderModel, ?>... columns) {
return Arrays.stream(columns).map(c -> StrUtil.toUnderlineCase(LambdaUtils.getName(c))).collect(Collectors.joining(StringPool.COMMA, StringPool.SPACE, StringPool.SPACE));
}
通过Arrays.stream()为可变数组创建流,然后使用LambdaUtils.getName()方法获取属性名,再用StrUtil.toUnderlineCase()把属性名从,小驼峰转成下划线,最后用.collect(Collectors.joining())拼成字符串,用逗号分隔,前后加空格。
然后我们就可以通过这个方法使用lambda啦,因为入参是用可变数组,所以所以传入多个,这里只传入一个orderNo。
.select(" SUM(fee_amt) AS fee_amt, SUM(arrival_amt) AS arrival_amt, mer_no ", getParamSql(OrderModel::getOrderNo))
.lambda()
完整代码如下:
Page<OrderModel> page = orderService.page(new Page<>(1, 20), new QueryWrapper<OrderModel>()
.select(" SUM(fee_amt) AS fee_amt, SUM(arrival_amt) AS arrival_amt, mer_no ", getParamSql(OrderModel::getOrderNo))
.lambda()
.between(StrUtil.isNotBlank(commandReq.getStartDate()) && StrUtil.isNotBlank(commandReq.getEndDate()),
OrderModel::getTradeDate,
StrUtil.isNotBlank(startDateStr) ? LocalDate.parse(startDateStr) : null,
StrUtil.isNotBlank(endDateStr) ? LocalDate.parse(cendDateStr) : null)
.groupBy(OrderModel::getMerNo));
虽然看起来还是不够优雅,但是我觉得已经是最优的方案了,如果有更好的写法,可以在评论区留言。
写法绝对是本人自己思考后写出来的,因为在网上搜了一个多小时,也没看到什么更优雅的写法,如果本篇文章对你有帮助的话,就动动点击下方大拇指,给个免费的赞,不然我真的会谢。