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

如何在原生查询中通过Projection获取JSON类型列?

如何通过Projection获取JSON列(解决Hibernate方言映射错误)

当使用原生查询关联其他表并通过接口Projection查询特定列时,Hibernate无法正确映射JSONB列,报错没有JDBC类型1111的方言映射。全实体查询时正常,无JSON列场景下Projection也能正常工作。

你的实体类和Projection定义如下:

实体类

@Entity
public class EntityWithJsonColumn
// ... 其他字段
@Type(type = "jsonb")
@Column(columnDefinition = "jsonb")
private Map<String,Object> additionalInfo;
// ...

Projection接口

public interface DataProjection {
// ... 其他方法
@Value("#{target.id}")
Long getID();

@Value("#{target.additionalInfo}")
Map<String,Object> getAdditionalInfo();
// ...
}

解决方案

方法1:SQL转换+Projection默认方法处理

在原生SQL中将JSON列转换为字符串,再在Projection中通过默认方法将字符串反序列化为Map:

  1. 修改原生查询,将JSON列转为文本:
SELECT e.id, e.additional_info::text AS additionalInfo 
FROM entity_with_json_column e 
JOIN other_table ot ON ... -- 你的关联条件
  1. 更新Projection接口,新增字符串接收方法和默认转换方法:
public interface DataProjection {
    Long getID();
    // 先接收转换后的字符串
    String getAdditionalInfo();

    // 默认方法将字符串转为Map
    default Map<String, Object> parseAdditionalInfo() {
        ObjectMapper mapper = new ObjectMapper();
        try {
            return mapper.readValue(getAdditionalInfo(), new TypeReference<Map<String, Object>>() {});
        } catch (JsonProcessingException e) {
            throw new RuntimeException("解析JSON列失败", e);
        }
    }
}

方法2:使用@SqlResultSetMapping指定类型映射

通过定义结果集映射,显式告诉Hibernate如何处理JSON列:

  1. 创建DTO类作为投影目标(替代接口Projection):
public class DataDto {
    private Long id;
    private Map<String, Object> additionalInfo;

    public DataDto(Long id, Map<String, Object> additionalInfo) {
        this.id = id;
        this.additionalInfo = additionalInfo;
    }

    // getter方法
    public Long getId() { return id; }
    public Map<String, Object> getAdditionalInfo() { return additionalInfo; }
}
  1. 在实体类上添加结果集映射:
@Entity
@SqlResultSetMapping(
    name = "DataDtoMapping",
    classes = @ConstructorResult(
        targetClass = DataDto.class,
        columns = {
            @ColumnResult(name = "id", type = Long.class),
            @ColumnResult(name = "additionalInfo", type = JsonBinaryType.class)
        }
    )
)
public class EntityWithJsonColumn {
    // ... 现有字段和注解
}
  1. 在Repository中使用该映射执行原生查询:
@Repository
public interface EntityWithJsonColumnRepository extends JpaRepository<EntityWithJsonColumn, Long> {
    @Query(
        value = "SELECT e.id, e.additional_info AS additionalInfo FROM entity_with_json_column e JOIN other_table ot ON ...",
        nativeQuery = true
    )
    @SqlResultSetMapping(name = "DataDtoMapping")
    List<DataDto> findProjectedData();
}

方法3:扩展Hibernate方言全局映射

通过自定义方言,让Hibernate自动识别JDBC类型1111(对应JSON)并映射为JSON类型:

  1. 创建自定义PostgreSQL方言(如果用其他数据库,替换对应方言类):
public class CustomPostgresDialect extends PostgreSQL10Dialect {
    public CustomPostgresDialect() {
        super();
        // 将JDBC类型1111映射为Hibernate的JsonBinaryType
        registerHibernateType(Types.OTHER, JsonBinaryType.class.getName());
    }
}
  1. 在配置文件中指定自定义方言:
# application.properties
spring.jpa.properties.hibernate.dialect=com.yourpackage.CustomPostgresDialect

配置完成后,原有的接口Projection无需修改,原生查询即可正确映射JSON列到Map。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 09:03:07