You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Blaze-Persistence含UNION的查询如何返回FilterResult对象列表?

问题:Blaze-Persistence UNION查询无法返回预期的FilterResult列表

我编写了一个包含WITH CTE和UNION的Blaze-Persistence查询,SQL执行结果正确,但调用getResultList()后返回的是ArrayList<Object[4]>,而非预期的ArrayList<FilterResult>。移除UNION及其对应的查询部分时,.selectNew(FilterResult.class)可以正确构造ArrayList<FilterResult>。

如何让包含UNION的完整查询也返回ArrayList<FilterResult>?


相关代码

查询方法代码

public List<FilterResult> getFilters(HourSearchDto hourSearchDto) {
  ...
  FinalSetOperationCriteriaBuilder<FilterResult> cb = cbf.create(entityManager, FilterResult.class)
    // Start with the WITH()
    .with(HourCTE.class, false)
      .from(Hour.class, "hour")
      .bind("id").select("id")
      .bind("employeeId").select("employee.id")
      .bind("taskId").select("task.id")
      .where("UPPER(hour.description)").like().expression("'" + hourSearchDto.getDescription().toUpperCase() + "%'").noEscape()
    .end()
    // First select, for reference Employee. Use the selectNew(FilterResult.class) to map the result to FilterResult.
    .selectNew(FilterResult.class)
      .with("employee.id", "id")
      .with("'EMPLOYEE'", "referenceName")
      .with("COUNT(hour.employeeId)", "count")
      .with("FORMAT('%1$s (%2$s)', employee.firstName, COUNT(hour.employeeId))", "displayValue")
    .end()
    .from(Employee.class, "employee")
    .leftJoinOn(HourCTE.class, "hour")
      .on("hour.employeeId").eqExpression("employee.id")
    .end()
    // UNION to add next select.
    .union()
    // Next select, for reference Task. Simple select as first select above maps the result to FilterResult already.
    .select("task.id", "id")
    .select("'TASK'", "referenceName")
    .select("COUNT(hour.taskId)", "count")
    .select("FORMAT('%1$s (%2$s)', task.name, COUNT(hour.taskId))", "displayValue")
    .from(Task.class, "task")
    .leftJoinOn(HourCTE.class, "hour")
      .on("hour.taskId").eqExpression("task.id")
    .end()
    .endSet()
    .orderByAsc("referenceName")
    .orderByAsc("displayValue");

    return cb.getQuery().getResultList();
}

FilterResult类

public class FilterResult {

    @Id
    Long id;

    String referenceName;

    Long count;

    String displayValue;

    public FilterResult() {
    }

    public FilterResult(Long id, String referenceName, Long count, String displayValue) {
        this.id = id;
        this.referenceName = referenceName;
        this.count = count;
        this.displayValue = displayValue;
    }

    // Getters
}

HourCTE类

@CTE
@Entity
public class HourCTE {

    @Id
    private Long id;

    private Long employeeId;

    private Long taskId;
}

解决方案

Blaze-Persistence的UNION操作要求所有分支查询都明确指定结果映射规则,仅在第一个分支使用selectNew不足以让整个UNION查询返回目标DTO。你需要在UNION的第二个分支同样调用selectNew(FilterResult.class)来统一结果映射逻辑。

修改后的UNION分支代码如下:

// UNION to add next select.
.union()
// Next select, for reference Task. 显式指定结果映射到FilterResult
.selectNew(FilterResult.class)
  .with("task.id", "id")
  .with("'TASK'", "referenceName")
  .with("COUNT(hour.taskId)", "count")
  .with("FORMAT('%1$s (%2$s)', task.name, COUNT(hour.taskId))", "displayValue")
.end()
.from(Task.class, "task")
.leftJoinOn(HourCTE.class, "hour")
  .on("hour.taskId").eqExpression("task.id")
.end()

原因说明

UNION是多个独立查询的结果合并,Blaze-Persistence需要每个分支都明确结果如何映射到目标类。如果某一分支未指定映射规则,框架会默认返回字段值组成的Object数组,导致整个查询结果类型不一致,最终返回ArrayList<Object[4]>。只有所有分支都使用相同的selectNew配置,才能确保最终返回的是ArrayList<FilterResult>。


内容的提问来源于stack exchange,提问作者MacNetron

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 13:50:26