JPQL 中带有 JPA 的本机查询的“GROUP_CONCAT”是不是有替代方案?

Posted

技术标签:

【中文标题】JPQL 中带有 JPA 的本机查询的“GROUP_CONCAT”是不是有替代方案?【英文标题】:Is there an alternative for native query's 'GROUP_CONCAT' in JPQL with JPA?JPQL 中带有 JPA 的本机查询的“GROUP_CONCAT”是否有替代方案? 【发布时间】:2019-12-15 00:57:37 【问题描述】:

我正在尝试使用 jpql 和 JPA 获取配置文件的配置文件菜单。我的“个人资料”和“个人资料菜单”实体具有多对一的关系。

我已尝试研究这些答案,但找不到任何可行的解决方案。

How to add non-standardized sql functions in Spring Boot application?

Registering a SQL function with JPA and Hibernate

https://vladmihalcea.com/hibernate-sql-function-jpql-criteria-api-query/

我也浏览了这个链接,似乎和我的问题一样, How to register non-standarized SQL functions manually in Spring Boot application?

使用本机查询时,我可以使用以下查询获取我的数据:

"SELECT
 GROUP_CONCAT(pm.user_menu_id SEPARATOR ',')
 AS profile_menu_ids,
 p.description
 FROM profile p
 LEFT JOIN profile_menu pm ON p.id = pm.profile_id
 WHERE
 p.id =:profileId
 AND
 pm.status = 'Y'
 GROUP BY p.id"

上面的查询为我提供了数据,

|profile_menu_ids|description  |
|----------------|-------------|
|4,5             |admin profile|

jpql 中是否有任何方法或替代方案与 JPA 获得上述结果?

【问题讨论】:

GROUP_CONCATmysql(和 SQLite)特定的函数,所以我怀疑 JPQL 会支持它。您可能必须在 Java 端处理这个问题,可能使用流。 ***.com/questions/7005354/… 我实际上想使用 JPQL 来处理它。 JPQL 中没有替代方案吗? @TimBiegeleisen 不,我不认为有,主要是因为每个数据库供应商都有不同的处理组连接的方式(可能有一种 ANSI SQL 的方式,但我的猜测是很少/没有供应商真正支持它)。 【参考方案1】:

您可以考虑使用FluentJPA,它支持任何自定义功能:

public ProfileMenuGroup getMenuIdsByProfile(int profileId) 
    FluentQuery query = FluentJPA.SQL((Profile p,
                                       ProfileMenu pm) -> 
        String menuIds = alias(GROUP_CONCAT(pm.getUserMenuId(), ","),
                                            ProfileMenuGroup::getProfileMenuIds);
        String description = alias(p.getDescription(), ProfileMenuGroup::getDescription);

        SELECT(menuIds, description);
        FROM(p).LEFT_JOIN(pm).ON(p == pm.getProfile());
        WHERE(p.getId() == profileId && pm.getStatus() == "Y");
        GROUP(BY(p.getId()));
    );
    return query.createQuery(em, ProfileMenuGroup.class).getSingleResult();

查询产生以下 SQL(profileId 是自动绑定的):

SELECT GROUP_CONCAT(t1.user_menu_id SEPARATOR ',') AS profile_menu_ids,
                                    t0.description AS description 
FROM profile t0  LEFT JOIN profile_menu t1  ON (t0.id = t1.profile_id) 
WHERE ((t0.id = ?1) AND (t1.status = 'Y')) 
GROUP BY  t0.id

给定以下类型声明:

@Entity
@Data // lombok
@Table(name = "profile")
public class Profile 
    @Id
    private int id;

    private String description;


@Entity
@Data // lombok
@Table(name = "profile_menu")
public class ProfileMenu 
    @Id
    private int id;

    @ManyToOne
    @JoinColumn(name = "profile_id")
    private Profile profile;

    private int userMenuId;

    private String status;


@Tuple
@Data // lombok
public class ProfileMenuGroup 

    private String profileMenuIds;

    private String description;

【讨论】:

以上是关于JPQL 中带有 JPA 的本机查询的“GROUP_CONCAT”是不是有替代方案?的主要内容,如果未能解决你的问题,请参考以下文章

JPA 中的传递列表命名本机查询

JPA中带有IN子句的位置参数

如何从 Spring Data JPA GROUP BY 查询中返回自定义对象

是否有 JPA / JPQL 查询来搜索春季作为 JSON 传递的实体子集?

如何以编程方式验证 JPQL(JPA 查询)

JPA 多对多JPQL查询语句怎么写?