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

Hibernate 6.x如何注册返回表的PostgreSQL函数用于JPQL?

在Hibernate 6.x中使用PostgreSQL返回表的自定义函数并映射到DTO

一、核心问题解答

可以在Hibernate 6.x中注册返回表的PostgreSQL自定义函数,并将其结果自动映射到JPQL中的DTO,但需要完成方言注册和DTO映射的正确配置。

二、具体实现步骤

1. 自定义PostgreSQL方言注册表值函数

继承官方PostgreSQLDialect,在构造方法中注册你的自定义函数,明确其返回类型关联目标DTO:

public class CustomPostgreSQLDialect extends PostgreSQLDialect {
    public CustomPostgreSQLDialect() {
        super();
        // 注册表值函数,指定返回类型为目标DTO
        addFunction(
            "get_ordine_dettagli",
            new StandardSQLFunction(
                "get_ordine_dettagli",
                new EntityType(OrdineDettagli.class, null)
            )
        );
    }
}

在配置文件中指定使用该方言:

spring.jpa.properties.hibernate.dialect=com.yourpackage.CustomPostgreSQLDialect

2. 定义可映射的DTO

确保DTO满足Hibernate的映射要求,推荐两种方式:

  • Java 16+记录类(自动生成构造函数与字段访问逻辑):
public record OrdineDettagli(Long id, String prodotto, Integer quantita, BigDecimal totale) {}
  • 普通不可变类(添加@Immutable注解并提供匹配列的构造函数):
@Immutable
public class OrdineDettagli {
    private Long id;
    private String prodotto;
    private Integer quantita;
    private BigDecimal totale;

    // 构造函数参数需与函数返回列的顺序/名称完全匹配
    public OrdineDettagli(Long id, String prodotto, Integer quantita, BigDecimal totale) {
        this.id = id;
        this.prodotto = prodotto;
        this.quantita = quantita;
        this.totale = totale;
    }

    // 提供getter方法
    public Long getId() { return id; }
    public String getProdotto() { return prodotto; }
    public Integer getQuantita() { return quantita; }
    public BigDecimal getTotale() { return totale; }
}

3. 编写JPQL查询

你原有的写法可直接使用,确保函数名与注册名称一致:

@Repository
public interface OrdineRepository extends JpaRepository<Ordine, Long> {
    @Query("SELECT o FROM get_ordine_dettagli(:id, :data) o")
    List<OrdineDettagli> getDettagliOrdine(@Param("id") Long id, @Param("data") LocalDate data);
}

三、替代方案(若注册函数遇阻)

如果表值函数的JPQL注册出现兼容性问题,以下两种方案更可靠:

方案1:原生查询+@SqlResultSetMapping

通过结果集映射明确列与DTO的对应关系:

@SqlResultSetMapping(
    name = "OrdineDettagliMapping",
    classes = @ConstructorResult(
        targetClass = OrdineDettagli.class,
        columns = {
            @ColumnResult(name = "id", type = Long.class),
            @ColumnResult(name = "prodotto", type = String.class),
            @ColumnResult(name = "quantita", type = Integer.class),
            @ColumnResult(name = "totale", type = BigDecimal.class)
        }
    )
)
@NamedNativeQuery(
    name = "Ordine.getDettagliOrdine",
    query = "SELECT * FROM get_ordine_dettagli(:id, :data)",
    resultSetMapping = "OrdineDettagliMapping"
)
public class Ordine {
    // 实体原有代码
}

在Repository中直接调用命名查询:

@Repository
public interface OrdineRepository extends JpaRepository<Ordine, Long> {
    List<OrdineDettagli> getDettagliOrdine(@Param("id") Long id, @Param("data") LocalDate data);
}

方案2:Spring Data Projection

用接口形式定义DTO,通过原生查询自动映射:

public interface OrdineDettagliProjection {
    Long getId();
    String getProdotto();
    Integer getQuantita();
    BigDecimal getTotale();
}

Repository中编写原生查询:

@Repository
public interface OrdineRepository extends JpaRepository<Ordine, Long> {
    @Query(value = "SELECT * FROM get_ordine_dettagli(:id, :data)", nativeQuery = true)
    List<OrdineDettagliProjection> getDettagliOrdine(@Param("id") Long id, @Param("data") LocalDate data);
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 23:28:11