在querydsl中从列表生成的情况

问题描述 投票:0回答:1

我想使用NumberExpression构造为QueryDsl中的SELECT子句创建CASE WHEN THEN,以获取会话号(业务数据)。当前,我正在使用这种方法在String中创建SQL,这有很多原因,这是很糟糕的。

    private static StringBuilder getSelectStatement(
        UUID jobInstanceUuid,
        LocalDateTime jobInstanceStartDateTime,
        List<CotCandidate> cotCandidates
    ) {
        StringBuilder selectStatement = new StringBuilder();
        selectStatement.append("SELECT ");
        selectStatement.append(getCaseOfSessionNumber(cotCandidates));
        // skipped other fields for clarity
        selectStatement.append(getFromStatement());
       // skipped where, having, groupBy statements for clarity
       selectStatement.append(" ");

        return selectStatement;
    }

    private static String getCaseOfSessionNumber(List<CotCandidate> cotCandidates) {
        StringBuilder caseSessionNumber = new StringBuilder();
        caseSessionNumber.append("CASE ");
        cotCandidates.forEach(cot -> {
            caseSessionNumber.append(" WHEN (P.SETTLEMENT_SYSTEM = ");
            caseSessionNumber.append(toSqlString(cot.getSettlementSystem()));
            caseSessionNumber.append(" AND P.PAYMENT_MODE = ");
            caseSessionNumber.append(toSqlString(cot.getPaymentMode()));
            caseSessionNumber.append(" ) THEN ");
            caseSessionNumber.append(cot.getSessionNumb());
            caseSessionNumber.append(" ");
        });
        caseSessionNumber.append("END");
        return caseSessionNumber.toString();
    }

并且使用querydsl我希望达到这样的水平:

    void getJobExecutionQuery(List<CotCandidate> cotCandidates) {
        QPaymentOrderEntity order = QPaymentOrderEntity.paymentOrderEntity;
        JPAQueryFactory queryFactory = new JPAQueryFactory(entityManager);
        List<Tuple> tuple = queryFactory
            .from(order)
            .select(
                getSessionNumb(cotCandidates, order),
            )
            .fetch();
    }

    // This doesn't work cause without otherwise() in the end it return Case.Builder.Cases
    private NumberExpression<Integer> getSessionNumb(List<CotCandidate> cotCandidates, QPaymentOrderEntity order) {
        return cotCandidates.stream()
            .map( cot ->
            Expressions.cases()
                    .when(order.settlementSystem.eq(cot.getSettlementSystem())
                        .and(order.paymentMode.eq(cot.getPaymentMode())))
                    .then(cot.getSessionNumb())
            ).collect(?);
    }

The problem is that I don't know how to build dynamicly case when then : 
To be like that: 

            NumberExpression<Integer> sessionNumber = new CaseBuilder()
            .when(
                order.settlementSystem.eq(cotCandidates.get(0).getSettlementSystem())
                .and(order.paymentMode.eq(cotCandidates.get(0).getPaymentMode())))
            .then(cotCandidates.get(0).getSessionNumb())
            .when(
                order.settlementSystem.eq(cotCandidates.get(n).getSettlementSystem())
                    .and(order.paymentMode.eq(cotCandidates.get(n).getPaymentMode())))
            .then(cotCandidates.get(n).getSessionNumb())
            .otherwise(-1);
querydsl
1个回答
1
投票

问题在于,CASE语句由三部分组成:

  1. 初始大小写(CaseBuilder
  2. 中间部分(CaseBuilder.Cases
  3. 最后部分(CaseBuilder.Cases#otherwise(...)

不幸的是,这些构建器类型没有提供通用的界面,基本上不会将流利的减速器的选项扔到窗外。最初的情况总是必须单独处理:

QPaymentOrderEntity order = QPaymentOrderEntity.paymentOrderEntity;
CaseBuilder caseBuilder = Expressions.cases();
CotCandidate candidate = candidates.get(0);
CaseBuilder.Cases<Integer, NumberExpression<Integer>> intermediateBuilder = caseBuilder.when(order.paymentMode.eq(candidate.getPaymentMode())
        .and(order.settlementSystem.eq(candidate.getSettlementSystem()))).then(candidate.getSessionNumb());

for (int i = 1; i < candidates.size(); i++) {
    candidate = candidates.get(i); 
    intermediateBuilder = intermediateBuilder.when(order.paymentMode.eq(candidate.getPaymentMode())).then(candidate.getSessionNumb());
}

NumberExpression<Integer> finalExpression = intermediateBuilder.otherwise(-1);

从技术上讲,该循环是foldLeft操作。不幸的是,这很难用Stream表示,因为Stream API仅提供可并行化的reduce操作。不能将两个不同的CaseWhen构建器组合在一起,因此该操作不可并行化。有关foldLeftreduce的更详细答案,请参见https://stackoverflow.com/a/24316429/2104280


附带说明:

您不是在这里重新发明轮子吗?从QPaymentOrderEntity的属性来看,PaymentModeSettlementSystem似乎是托管类型。仅加入CotCandidates并从那里获取sessionNumb的查询可能会容易得多;

query().from(order).innerJoin(QCotCandidate.cotCandidate)
   .on(QCotCandidate.cotCandidate.settlementSystem.eq(order.settlementSystem)
       .and(QCotCandidate.paymentMode.settlementSystem.eq(order.paymentMode))
   .select(order, QCotCandidate.cotCandidate.sessionNumb)

无论如何,它CotCandiate可能不是受管实体。在这种情况下,您需要一个VALUES子句,默认情况下不需要JPQL。 (您可能需要考虑使用blaze-persistence-querydsl集成)。

© www.soinside.com 2019 - 2024. All rights reserved.