如何使用Spring JPA/Hibernate将单表查询的1列映射到集合?

huangapple go评论80阅读模式
英文:

How do I map 1 column of a SINGLE table query to a COLLECTION using Spring JPA/Hibernate

问题

我想知道是否有一种类似于Stream API中的groupingBy Collector的方法。我知道如何选择一列(问题被标记为重复,但我不认为是重复的),我想要进行分组(类似于Java Stream API中的groupingBy collector),而不是使用group By。

假设您有一个表(一个表)如下:

+---------------------+
+       myTable       +
+----------+----------+
+ column_A | column_B +
+----------+----------+
+        1 |        1 +
+        1 |        2 +
+        1 |        3 +
+        2 |        1 +
+----------+----------+

我想要类似于以下内容的结果:

@Entity
@Table("MyTable")
public class MyEntity {
  @Column("column_A")
  private int a;
  
  @Column("column_B")
  private List<Integer> b; //通常这只是int b,但我想要所有具有相同a的b的列表
}

以及一个仓库类似于:

public interface MyCrudRepo extends CrudRepository<MyEntity, Integer> {
  List<MyEntity> findByA();
} 

或者

public interface MyCrudRepo extends CrudRepository<MyEntity, Integer> {
  @Query("SELECT m.a, m.b FROM MyEntity m")
  List<MyEntity> customFind();
}

这不一定是最终的样子,任何与此类似的方法都可以。我已经研究了投影,但所有示例都使用了两个不同的表。

英文:

Id like to know if there's a way of doing something like the Stream API groupingBy Collector. I know how to select one column (the question was marked as duplicated and I don't belive it is) I want to do a grouping (like the groupingBy collector of the java Stream API) not a group By.
Suppose you have a table (ONE table) like:

+---------------------+
+       myTable       +
+----------+----------+
+ column_A | column_B +
+----------+----------+
+        1 |        1 +
+        1 |        2 +
+        1 |        3 +
+        2 |        1 +
+----------+----------+

And I would like to have something like

@Entity
@Table(&quot;MyTable&quot;)
public class MyEntity {
  @Column(&quot;column_A&quot;)
  private int a;
  
  @Column(&quot;column_B&quot;) ?
  private List&lt;Integer&gt; b; //normanly this wuould just be int b, butI want a list of all b&#39;s that have the same a
}

with a repo like

public interface MyCrudRepo extends CrudRepository&lt;MyEntity,Integer&gt;{
  List&lt;MyEntity&gt; findByA();
} 

or

public interface MyCrudRepo extends CrudRepository&lt;MyEntity,Integer&gt;{
  @Query(&quot;SELECT m.a,m.b FROM MyEntity m&quot;)
  List&lt;MyEntity&gt; customFind();
} 

This is not necessarily how it should look at the end, anything that works similar to this is fine. I have looked into projections but all examples use 2 different tables.

答案1

得分: 1

没有一种特定的方法可以使用JPQL来实现您所需的内容。相反,您可以使用Hibernate的ResultTransformer,它允许您将查询结果转换为任何您需要的格式。这是一个代码解决方案,类似于在列表结果中使用Stream API实现分组,并返回包含聚合数据的映射。

英文:

There is no a specific way to do what you need using JPQL. Instead, you can use a Hibernate ResultTransformer, that allows yo to transform the query results to whatever you need. This is a code solution, and is similar to implementing the grouping using the Stream API in the list result and return a map containing the aggregated data.

答案2

得分: 0

使用注解可以引用相同的表格(一种类似于hack的方式):

@ElementCollection
@CollectionTable(name = "table_name")

示例:

@Data
@Entity
@Table(name = "parent")
public class Parent {
    @Id
    private long id;

    private String name;

    @ElementCollection
    @CollectionTable(
        name = "parent",
        joinColumns = @JoinColumn(name = "id"))
    private List<Child> children;

    @Data
    @Embeddable
    public static class Child {
        @Column(name = "child_id")
        private long id;

        @Column(name = "child_name")
        private String name;
    }
}

表中的列:

id,name,child_id,child_name

但是... 你会从存储库中获得多个副本(一行一个对象),所以使用Set来摆脱它们 Set.copyOf(repository.findAll())

Hibernate 将查询数据库以获取每个父对象的子对象。

附注:如果为同一个表格创建了两个实体,则应该也适用于 @OneToMany 注解,可能会适用,没有验证过。

英文:

It's possible to refer the same table using annotations (some kind of hack):

@ElementCollection  
@CollectionTable(name = &quot;table_name&quot;)

Example:

@Data
@Entity
@Table(name = &quot;parent&quot;)
public class Parent {
    @Id
    private long id;

    private String name;

    @ElementCollection
    @CollectionTable(
        name = &quot;parent&quot;,
        joinColumns = @JoinColumn(name = &quot;id&quot;))
    private List&lt;Child&gt; children;


    @Data
    @Embeddable
    public static class Child {
        @Column(name = &quot;child_id&quot;)
        private long id;

        @Column(name = &quot;child_name&quot;)
        private String name;
    }
}

columns in the table:

id, name, child_id, child_name

But... you'll get several copies from repository (one object for row), so use Set to get rid of them Set.copyOf(repository.findAll())

Hibernate will be quering database to get children for each parent.

P.S. Should work with @OneToMany annotation too, possibly, if create two entities for one table, didn't check that

huangapple
  • 本文由 发表于 2020年8月25日 13:30:41
  • 转载请务必保留本文链接:https://go.coder-hub.com/63572568.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定