CASE WHEN 在 querydsl 中从列表生成
CASE WHEN in querydsl generate from list
我想为 QueryDsl 中的 SELECT
子句创建一个 NumberExpression
,使用 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);
问题在于 CASE 语句由三部分组成:
- 初始案例 (
CaseBuilder
)
- 中间部分(
CaseBuilder.Cases
)
- 最后一部分 (
CaseBuilder.Cases#otherwise(...)
)
不幸的是,这些构建器类型没有提供通用接口,这基本上使您可以从 window 中选择流畅的 reducer。最初的情况总是需要单独处理:
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
构建器,因此此操作不可并行化。有关 foldLeft
与 reduce
的更详细答案,请参阅 。
旁注:
你这不是在重新发明轮子吗?从 QPaymentOrderEntity
的属性来看,PaymentMode
和 SettlementSystem
似乎是托管类型。仅加入 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
集成)。
我想为 QueryDsl 中的 SELECT
子句创建一个 NumberExpression
,使用 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);
问题在于 CASE 语句由三部分组成:
- 初始案例 (
CaseBuilder
) - 中间部分(
CaseBuilder.Cases
) - 最后一部分 (
CaseBuilder.Cases#otherwise(...)
)
不幸的是,这些构建器类型没有提供通用接口,这基本上使您可以从 window 中选择流畅的 reducer。最初的情况总是需要单独处理:
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
构建器,因此此操作不可并行化。有关 foldLeft
与 reduce
的更详细答案,请参阅 。
旁注:
你这不是在重新发明轮子吗?从 QPaymentOrderEntity
的属性来看,PaymentMode
和 SettlementSystem
似乎是托管类型。仅加入 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
集成)。