hibernate 我想使用String_agg()postrges数据库函数,并使用Criterial API的order By Clause

4urapxun  于 2023-04-30  发布在  其他
关注(0)|答案(2)|浏览(180)

我有一个postgres数据库,它有两个表:电影和演员每部电影可以有多个演员,每个演员可以在多部电影中工作。即多对多关系),
我想从电影表中返回每部电影的演员名单。演员的名字应该在列表中以升序排列
我可以写本机查询,就像下面

SELECT
    f.title,
    STRING_AGG (
    a.first_name,
        ','
       ORDER BY
        a.first_name,
    ) actor
FROM
    film f
INNER JOIN film_actor fa USING (film_id)
INNER JOIN actor a USING (actor_id)
GROUP BY
    f.title;

下面是我的示例实体

@Entity
class Film{

@Id
int film_id;

String title;

@ManyToMany(targetEntity = Actor.class,)
    @JoinTable(name = "film_actor"
            joinColumns = { @JoinColumn(name = "film_id") }, inverseJoinColumns = { @JoinColumn(name = "actor_id") })
List<Actors> actors

}

@Entity
class Actors{

@Id
int actor_id;

String first_name;

String last_name;

}

我尝试编写查询条件生成器如下

CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
        CriteriaQuery<Object> criteriaQuery = criteriaBuilder.createQuery();

        Root<Film> filmRoot = criteriaQuery.from(Film.class);
        Join<Film, Actor> filmActorJoin = filmRoot.join("actors", JoinType.LEFT);

        Expression<String> filmActorExpression = criteriaBuilder.function("string_agg", String.class,
                filmActorJoin.get("first_name"), criteriaBuilder.literal(", ") 
                
        );
        
        criteriaQuery.groupBy(filmRoot.get("film_id")).orderBy(criteriaBuilder.asc(filmActorExpression));

但是上面的criteria查询不是按照ASC顺序聚合first_name的字符串。有人能帮我吗

5t7ly7z5

5t7ly7z51#

在Hibernate 6中,HibernateCriteriaBuilder接口声明了listagg()函数。当然,你需要进行类型转换才能得到它,i即(HibernateCriteriaBuilder) entityManager.getCriteriaBuilder()
https://docs.jboss.org/hibernate/orm/6.2/javadocs/org/hibernate/query/criteria/HibernateCriteriaBuilder。html#listagg(org.hibernate.query.jpaOrder,jakarta.坚持不懈criteria.Expression,雅加达.坚持不懈标准。表达式)
请注意,您可以在此处找到受支持的聚合函数列表:
www.example. com

slwdgvem

slwdgvem2#

如果你能够在DB中定义新的函数,我会考虑这样的东西:
PostgreSQL部分:

CREATE OR REPLACE FUNCTION sort_asc(ar text[]) returns text[]
AS
$$
SELECT array((SELECT unnest(ar) ORDER BY 1))
$$
    LANGUAGE SQL
    STABLE;

休眠部分:

cb.function("array_to_string", Object.class,
  cb.function("sort_asc", Object.class,
    cb.function("array_agg", Object.class,
      filmActorJoin.get("first_name")
    )
  ),
  cb.literal(", ")
).as(String.class)

另一个“选项”(从我的Angular 看更像是技巧)是register sql function in Hibernate,在这种情况下,解决方案看起来像这样:

public class StringAggFunction extends SQLFunctionTemplate {

    public static final String FUNCTION_NAME = "string_agg";

    public StringAggFunction() {
        super(StringType.INSTANCE, "string_agg(?1, ?2 order by ?3)");
    }

}
cb.function("string_agg", Object.class,
        filmActorJoin.get("first_name"),
        cb.literal(", "),
        filmActorJoin.get("first_name")
).as(String.class)

相关问题