Spring数据存储库按列分组,包含其他列的对象列表

Posted

技术标签:

【中文标题】Spring数据存储库按列分组,包含其他列的对象列表【英文标题】:Spring data repository group by column, list of object with other columns 【发布时间】:2021-02-27 20:21:18 【问题描述】:

如何让 Spring 存储库返回一个自定义 DTS,该 DTS 按表中的 businessValue1 列分组,并具有 DTO 对象列表和表中的其他列

我要从中返回 DTS 的表

id | businessValue1 | businessValue2 | businessValue3
1  | "x"            | "uigaiun"      | "guthgi"
2  | "x"            | "rktjuhngit"   | "ujgthniuertn"
3  | "x"            | "nguitren"     | "ikljugnbe"
4  | "y"            | "iughnuitn"    | "eiubgnuie"
5  | "q"            | "rtiluhn"      | "iljughbl"
6  | "q"            | "tkiruln"      | "jutgnhet"

表示表格的 Java Entity 类

@Data
@AllArgsConstructor
@Entity
public class SomeEntity 

  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  @NotNull
  private long id;
  
  @NotNull
  private String businessValue1;
  
  @NotNull
  private String businessValue2;
  
  @NotNull
  private String businessValue3;

目标类:

表中其他列的 DTO 表示

@Data
@AllArgsConstructor
public class SomeDTO 

  private String businessValue2;
  
  private String businessValue3;

businessValue1 列的分组依据的 DTS 表示,其他列作为 DTO 列表

@Data
@AllArgsConstructor
public class SomeDTS 

  private String businessValue1;
  
  private List<SomeDTO> dtos;

我的预期结果将具有如下结构

├── "x"
|    ├── "uigaiun", "guthgi"
|    ├── "rktjuhngit", "ujgthniuertn"
|    └── "nguitren", "ikljugnbe"
|
├── "y"
|    └── "iughnuitn", "eiubgnuie"
|
└── "q"
     ├── "rtiluhn", "iljughbl"
     └── "tkiruln", "jutgnhet"

我认为 Spring Data Repository 界面应该如下所示

@Repository
public interface SomeEntityRepository extends JpaRepository<SomeEntity, Long> 

  @Query(
      "SELECT "
      +  "new SomeDTS "
      +"FROM "
      +  "SomeEntity s "
      +"GROUP BY "
      +  "s.businessValue1")
  public List<SomeDTS> SomeEntityGroupByBusinessValue1();


由于我正在为 JPQL 查询而苦苦挣扎,有人可以帮帮我吗?

更新 1 - 2020 年 11 月 19 日:

@Zorglube 的评论我想我离得更近了

@Repository
public interface SomeEntityRepository extends JpaRepository<SomeEntity, Long> 

  @Query(value =
      "SELECT "+
          " DISTINCT SomeDTS.businessValue1, SomeDTO" +
          " FROM SomeEntity AS SomeDTS" +
          " JOIN SomeEntity AS SomeDTO ON SomeDTS.businessValue1 = SomeDTO.businessValue1")
  Stream<SomeDTS> SomeEntityGroupByBusinessValue1();


这仍然给我的映射带来问题

No converter found capable of converting from type [org.springframework.data.jpa.repository.query.AbstractJpaQuery$TupleConverter$TupleBackedMap] to type [SomeDts]
org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type [org.springframework.data.jpa.repository.query.AbstractJpaQuery$TupleConverter$TupleBackedMap] to type [SomeDts]
    at org.springframework.core.convert.support.GenericConversionService.handleConverterNotFound(GenericConversionService.java:321)
    at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:194)
    at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:174)
    at org.springframework.data.repository.query.ResultProcessor$ProjectingConverter.convert(ResultProcessor.java:297)
    at org.springframework.data.repository.query.ResultProcessor$ChainingConverter.lambda$and$0(ResultProcessor.java:217)
    at org.springframework.data.repository.query.ResultProcessor$ChainingConverter.convert(ResultProcessor.java:228)
    at org.springframework.data.repository.query.ResultProcessor.lambda$processResult$0(ResultProcessor.java:163)
    at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:195)
    at java.base/java.util.Iterator.forEachRemaining(Iterator.java:133)
    at java.base/java.util.Spliterators$IteratorSpliterator.forEachRemaining(Spliterators.java:1801)
    at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484)
    at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474)
    at java.base/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:913)
    at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
    at java.base/java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:578)
    at org.hibernate.query.spi.StreamDecorator.collect(StreamDecorator.java:211)    
.
.
.

那么如何进行映射呢?

更新 2 改用接口

@Repository
public interface SomeEntityRepository extends JpaRepository<SomeEntity, Long> 

  @Query(value =
      "SELECT "+
          " DISTINCT SomeDTSIF.businessValue1 as businessValue1, SomeDTOIF" +
          " FROM SomeEntity AS SomeDTSIF" +
          " JOIN SomeEntity AS SomeDTOIF ON SomeDTSIF.businessValue1 = SomeDTO.businessValue1")
  Stream<SomeDTSIF> SomeEntityGroupByBusinessValue1();


解决了“找不到能够转换的转换器”的问题,但我得到了 6 个对象:

├── "x"
|    └── NULL
|
├── "x"
|    └── NULL
|
├── "x"
|    └── NULL
|
├── "y"
|    └── NULL
|
├── "q"
|    └── NULL
|
└── "q"
     └── NULL

并且 SomeDTSIF 中的 SomeDTOIF 列表没有被映射。

【问题讨论】:

您应该查看Projection 或在您的两个Dts 中添加一些映射信息。 谢谢,我试图搜索谁完成了这样的投影,但没有任何运气......一旦我找到了,不要真正涵盖我正在尝试的内容: baeldung.com/spring-data-jpa-projectionsbytestree.com/spring/…docs.spring.io/spring-data/jpa/docs/current/reference/html/…衣柜好像是thorben-janssen.com/spring-data-jpa-query-projections能不能指点一下攻略。 【参考方案1】:

我最终创建了一个“虚拟”父实体,它的行为有点像视图

@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
@Entity
@EqualsAndHashCode
@Immutable
@Subselect(
    "SELECT"
        + " DISTINCT SomeEntityParent.currency_source "
        + " FROM some_entity SomeEntityParent"
        + " JOIN some_entity SomeEntity"
        + " ON SomeEntityParent.businessValue1 = SomeEntityParent.businessValue1"
)
public class SomeEntityParent 

  private String businessValue1;
  
  private List<SomeEntity> someEntity;

然后是基于它的 Repository 接口

@Repository
public interface SomeEntityParentRepository extends JpaRepository<SomeEntityParent, Long> 


然后可以在服务中使用

@Autowired
private SomeEntityParentRepository repository;
  
List<SomeEntityParent> results = repository.findAll();

平面结构现在是一个分层对象。

【讨论】:

以上是关于Spring数据存储库按列分组,包含其他列的对象列表的主要内容,如果未能解决你的问题,请参考以下文章

使用Python按列分组并汇总另一列的内容

获取分组列的计数

熊猫 groupby 没有将按列分组转换为索引

data.frame 按列分组[重复]

Python - 读取csv并按列分组数据

按列分组并有一列带有 value_counts 字典