在 Spring Boot、Hibernate 中使用 @Query 注解以 JSON 格式(键值对)查询结果

Posted

技术标签:

【中文标题】在 Spring Boot、Hibernate 中使用 @Query 注解以 JSON 格式(键值对)查询结果【英文标题】:Query result in JSON format (key value pair) on using @Query annotation in Spring Boot, Hibernate 【发布时间】:2019-04-13 19:53:45 【问题描述】:

我的控制器

@GetMapping(value="/getAllDetails")
public List<PriceListEntity> getAllDetails() 
    return MyRepository.getAllDetails();

我的仓库

@Repository
public interface MyRepository extends CrudRepository<TestNativeQ, String> 
    @Query( value="SELECT qplt.name price_list_name,  qplab.status_code, qplab.start_date, (SELECT charge_definition_code FROM oalfsaas_repl.QP_CHARGE_DEFINITIONS_B WHERE charge_definition_id=qplab.charge_definition_id  ) chargedefinitioncode "
            + "FROM  PriceListEntity qplab, PriceListLineEntity qplt "
            + " WHERE qplab.price_list_id  =qplt.price_list_id ", nativeQuery = false)
    public List<PriceListEntity> getAllDetails();

实际结果:

["ABC", "DEF", "15/05/2018", "XXZ"]

预期结果

[name: "ABC", statuscode: "DEF", startDate: "15/05/2018", chargedefintioncode: "XXZ"]

查询与多个表连接,并且在列级别也有子查询。

【问题讨论】:

你是如何得到这个输出的?使用系统输出? 不,这是在调用此路径“/getAllDetails”。 我想您正在使用杰克逊进行 json 操作。那里不可能有任何问题。尝试在api中返回之前打印数据,看看它是否真的像你在这里发布的那样。 【参考方案1】:

您实际上是在使用您的 select 进行投影,它不会返回任何特定对象,而是 一个元组,它是您在查询中选择的对象数组。无论以何种方式生成 JSON,都没有名称,只有值。

您需要创建一个 DTO 来保存您希望在 JSON 中通过名称传递的值。

一个最小的例子,有一个简单的实体,如:

@Entity
@Getter
@RequiredArgsConstructor
public class TestClass 
    @Id
    @GeneratedValue
    private Long id;

    @NonNull
    private String a,b,c;

并且愿意通过 - 例如 - 只有 ab 可能会有类似的 DTO:

@RequiredArgsConstructor
public class TupleDto 
    @NonNull
    private String a,b;

在你的情况下是某种PriceListDetailsDto

存储库可能被声明为:

public interface TestClassRepository extends CrudRepository<TestClass, Long> 

    @Query(value="SELECT new org.example.TupleDto(tc.a, tc.b) FROM TestClass tc")
    List<TupleDto> fetchAB();


注意:上面使用了运算符new 和实体构造函数的完整路径。

这样,Spring 存储库知道如何分配选定的字段,并且在从此 DTO 生成 JSON 时,将导致字段具有名称(DTO 中的名称)。

JPQL 中的 new 运算符只是在 java 中调用 new - 因此任何行数据 a,b,c 都可用于构造 Java 对象,该对象的类构造函数接受相同的参数数量和类型(并且以相同的顺序) ) 所以,new MyEntityObject(a,b,c).

还要注意:在这种简单的情况下,如果修改原始实体以允许 c 中的空值并添加相应的构造函数,则原始实体可以用作 DTO。在您的元组由许多表构成的情况下,您需要创建一个 DTO 来保存这些值。

【讨论】:

感谢回答,在列级别有子查询的情况下可以使用这种方式吗?另外这里的 BaseEntity 是什么? @ManojKumar 我不确定您所说的列级别是什么意思。但稍后会添加一个小更新来回答。基础实体只有 @Id 第四列是子查询 @ManojKumar 我明白了。只需添加子查询返回给您的 DTO 及其构造函数的列。在结果集中,它仍然是一列或多列。因此,如果子查询类似于 select charge_definition_code,请将 charge_definition_code 添加到您的 DTO 及其构造函数中。

以上是关于在 Spring Boot、Hibernate 中使用 @Query 注解以 JSON 格式(键值对)查询结果的主要内容,如果未能解决你的问题,请参考以下文章

在 Spring Boot 中配置 Hibernate 以忽略通过依赖项导入的标有 Entity 的某些类

spring boot中使用hibernate拦截器的问题

在 Spring Boot 中使用 Hibernate 为 DAO 层配置单元测试

JPA/Hibernate 在 Spring Boot 应用程序中插入不存在的表

Hibernate 和 CRUDRepository Spring Boot

如何在 Spring Boot 中自动装配 Hibernate SessionFactory