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

如何用JPA将数据填充到非实体类列表?含单州查询升级需求

环境信息

  • java 8
  • spring Boot 2.2.11.RELEASE
  • spring 5.2.10.RELEASE
  • hibernate 5.4.22.FINAL
  • mysql-connector-java 8.0.22

详情

实体类

@Entity
@Table( name="phone_number")
public class PhoneNumber implements java.io.Serializable {

    private static final long serialVersionUID = -2620178064909933422L;

    @Id
    @Column( name="full_number", nullable=false, length=10)
    private String phoneNumber;    
    
    @Column( name="area_code", nullable=false, length=3)
    private String areaCode;
    
    @Column( name="exchange", nullable=false, length=3)
    private String exchange;
    
    @Column( name="postfix", nullable=false, length=4)
    private String postfix;
    
    @Column( name="state_name", nullable=false)
    private String state;
}

非持久化POJO

public class PhoneNumberByState {
    
    private String state;
    private String areaCode;
    private BigInteger total;
   
}

ServiceImpl方法问题

现有方法执行报错:

public List<PhoneNumberByState> groupPhoneNumbersByStateAndAreaCode() {
    String query = "SELECT state, areaCode, COUNT(*) AS 'total' FROM PhoneNumber GROUP BY state, areaCode ORDER BY state, areaCode";

    // 需要JPA实现逻辑
    List<PhoneNumberByState> lisst = (List<PhoneNumberByState>) em.createQuery( query, PhoneNumber.class);
    // 抛出错误:Cannot create TypedQuery for query with more than one return using requested result type
    
    return lisst;
}

错误原因:查询返回state、areaCode、count(*)三个字段的组合,而非完整PhoneNumber实体,无法用PhoneNumber.class作为结果类型,也不能直接强转为PhoneNumberByState列表。

整体目标:将查询结果列表用于填充jsp页面。

附加需求:支持按州/省名称查询

现有代码无法编译,需完善JPA实现逻辑:

public List<PhoneNumberByState> groupPhoneNumbersByStateAndAreaCodeForOneState( String nameOfState) {
    String query = "SELECT state, areaCode, COUNT(*) AS 'total' FROM PhoneNumber WHERE state = ?1 GROUP BY state, areaCode ORDER BY state, areaCode";

    // 需要JPA实现逻辑
    List<PhoneNumberByState> tq = ????
    tq.setParameter( 1,  nameOfState);
    // 无法编译
    
    return tq.getResultList();
}

解决方案

方法一:构造函数表达式映射(推荐)

先给PhoneNumberByState添加匹配查询结果的构造函数:

public class PhoneNumberByState {
    
    private String state;
    private String areaCode;
    private BigInteger total;
   
    // 新增构造函数
    public PhoneNumberByState(String state, String areaCode, BigInteger total) {
        this.state = state;
        this.areaCode = areaCode;
        this.total = total;
    }

    // 可选:添加无参构造
    public PhoneNumberByState() {}

    // 补充getter/setter方法
    public String getState() { return state; }
    public void setState(String state) { this.state = state; }
    public String getAreaCode() { return areaCode; }
    public void setAreaCode(String areaCode) { this.areaCode = areaCode; }
    public BigInteger getTotal() { return total; }
    public void setTotal(BigInteger total) { this.total = total; }
}

1. 全局分组查询方法

public List<PhoneNumberByState> groupPhoneNumbersByStateAndAreaCode() {
    // 注意替换为PhoneNumberByState实际包路径
    String query = "SELECT NEW com.yourpackage.PhoneNumberByState(p.state, p.areaCode, COUNT(*)) " +
                   "FROM PhoneNumber p GROUP BY p.state, p.areaCode ORDER BY p.state, p.areaCode";

    TypedQuery<PhoneNumberByState> typedQuery = em.createQuery(query, PhoneNumberByState.class);
    return typedQuery.getResultList();
}

2. 按州/省名称查询方法

public List<PhoneNumberByState> groupPhoneNumbersByStateAndAreaCodeForOneState(String nameOfState) {
    String query = "SELECT NEW com.yourpackage.PhoneNumberByState(p.state, p.areaCode, COUNT(*)) " +
                   "FROM PhoneNumber p WHERE p.state = :stateName " +
                   "GROUP BY p.state, p.areaCode ORDER BY p.state, p.areaCode";

    TypedQuery<PhoneNumberByState> typedQuery = em.createQuery(query, PhoneNumberByState.class);
    typedQuery.setParameter("stateName", nameOfState);
    return typedQuery.getResultList();
}

方法二:Tuple接收后手动映射

若不想修改POJO构造函数,可通过Tuple接收结果再手动转换:

全局分组查询方法

public List<PhoneNumberByState> groupPhoneNumbersByStateAndAreaCode() {
    String query = "SELECT p.state, p.areaCode, COUNT(*) AS total FROM PhoneNumber p GROUP BY p.state, p.areaCode ORDER BY p.state, p.areaCode";

    List<Tuple> resultTuples = em.createQuery(query, Tuple.class).getResultList();
    List<PhoneNumberByState> resultList = new ArrayList<>();

    for (Tuple tuple : resultTuples) {
        PhoneNumberByState dto = new PhoneNumberByState();
        dto.setState(tuple.get("state", String.class));
        dto.setAreaCode(tuple.get("areaCode", String.class));
        dto.setTotal((BigInteger) tuple.get("total"));
        resultList.add(dto);
    }

    return resultList;
}

按州/省名称查询方法

public List<PhoneNumberByState> groupPhoneNumbersByStateAndAreaCodeForOneState(String nameOfState) {
    String query = "SELECT p.state, p.areaCode, COUNT(*) AS total FROM PhoneNumber p WHERE p.state = :stateName GROUP BY p.state, p.areaCode ORDER BY p.state, p.areaCode";

    TypedQuery<Tuple> typedQuery = em.createQuery(query, Tuple.class);
    typedQuery.setParameter("stateName", nameOfState);
    List<Tuple> resultTuples = typedQuery.getResultList();

    List<PhoneNumberByState> resultList = new ArrayList<>();
    for (Tuple tuple : resultTuples) {
        PhoneNumberByState dto = new PhoneNumberByState();
        dto.setState(tuple.get("state", String.class));
        dto.setAreaCode(tuple.get("areaCode", String.class));
        dto.setTotal((BigInteger) tuple.get("total"));
        resultList.add(dto);
    }

    return resultList;
}

方法三:SqlResultSetMapping映射(复杂场景适用)

在PhoneNumber实体上添加映射配置:

@Entity
@Table(name="phone_number")
@SqlResultSetMapping(
    name = "PhoneNumberByStateMapping",
    classes = @ConstructorResult(
        targetClass = PhoneNumberByState.class,
        columns = {
            @ColumnResult(name = "state", type = String.class),
            @ColumnResult(name = "areaCode", type = String.class),
            @ColumnResult(name = "total", type = BigInteger.class)
        }
    )
)
public class PhoneNumber implements java.io.Serializable {
    // 原有代码不变
}

修改查询方法:

public List<PhoneNumberByState> groupPhoneNumbersByStateAndAreaCode() {
    String query = "SELECT state, areaCode, COUNT(*) AS total FROM PhoneNumber GROUP BY state, areaCode ORDER BY state, areaCode";

    Query nativeQuery = em.createNativeQuery(query, "PhoneNumberByStateMapping");
    return nativeQuery.getResultList();
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 04:52:14