在 Spring Boot、Hibernate 中使用 @Query 注解以 JSON 格式(键值对)查询结果
Query result in JSON format (key value pair) on using @Query annotation in Spring Boot, Hibernate
我的控制器
@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"}]
该查询与多个 table 以及列级别的子查询进行了连接。
你实际上是在用你的 select 做一个投影,它没有 return 任何特定的对象,而是 一个元组 ,它是你 select 在您的查询中。无论以何种方式制作 JSON,都没有名称,只有值。
您需要创建一个 DTO 来保存要在 JSON 中按名称传递的值。
一个最小的例子,有一个像这样的简单实体:
@Entity
@Getter
@RequiredArgsConstructor
public class TestClass {
@Id
@GeneratedValue
private Long id;
@NonNull
private String a,b,c;
}
并且愿意通过 - 例如 - 只有 a
& b
可能有像这样的 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 存储库知道如何分配 selected 字段,当从这个 DTO 生成 JSON 时,将导致具有名称的字段(DTO 中的名称)。
JPQL 中的 new
运算符只是在 java 中调用 new
- 所以任何行数据 a,b,c
都可以用于构造 Java 对象该对象的 class 构造函数接受相同的参数数量和类型(并且以相同的顺序),所以 liie new MyEntityObject(a,b,c)
.
另请注意:在这种简单的情况下,如果将原始实体修改为允许在 c 中使用空值并添加相应的构造函数,则可以将其用作 DTO。在您的元组由许多表构成的情况下,您需要创建一个 DTO 来保存这些值。
我的控制器
@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"}]
该查询与多个 table 以及列级别的子查询进行了连接。
你实际上是在用你的 select 做一个投影,它没有 return 任何特定的对象,而是 一个元组 ,它是你 select 在您的查询中。无论以何种方式制作 JSON,都没有名称,只有值。
您需要创建一个 DTO 来保存要在 JSON 中按名称传递的值。
一个最小的例子,有一个像这样的简单实体:
@Entity
@Getter
@RequiredArgsConstructor
public class TestClass {
@Id
@GeneratedValue
private Long id;
@NonNull
private String a,b,c;
}
并且愿意通过 - 例如 - 只有 a
& b
可能有像这样的 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 存储库知道如何分配 selected 字段,当从这个 DTO 生成 JSON 时,将导致具有名称的字段(DTO 中的名称)。
JPQL 中的 new
运算符只是在 java 中调用 new
- 所以任何行数据 a,b,c
都可以用于构造 Java 对象该对象的 class 构造函数接受相同的参数数量和类型(并且以相同的顺序),所以 liie new MyEntityObject(a,b,c)
.
另请注意:在这种简单的情况下,如果将原始实体修改为允许在 c 中使用空值并添加相应的构造函数,则可以将其用作 DTO。在您的元组由许多表构成的情况下,您需要创建一个 DTO 来保存这些值。