使用QueryDSL的Postgresql数组函数

问题描述 投票:1回答:3

我使用Vlad Mihalcea的库来将SQL数组(在我的情况下为Postgresql)映射到JPA。然后让我们想象我有一个实体,例如。

@TypeDefs(
{@TypeDef(name = "string-array", typeClass = 
StringArrayType.class)}
)
@Entity
public class Entity {
    @Type(type = "string-array")
    @Column(columnDefinition = "text[]")
    private String[] tags;
}

适当的SQL是:

CREATE TABLE entity (
    tags text[]
);

使用QueryDSL我想获取标签包含所有给定标签的行。原始SQL可以是:

SELECT * FROM entity WHERE tags @> '{"someTag","anotherTag"}'::text[];

(摘自:https://www.postgresql.org/docs/9.1/static/functions-array.html

是否可以使用QueryDSL执行此操作?下面的代码有点像?

predicate.and(entity.tags.eqAll(<whatever>));
java sql postgresql hibernate querydsl
3个回答
3
投票
  1. 第一步是生成正确的sql:WHERE tags @> '{"someTag","anotherTag"}'::text[];
  2. 第二步由coladict描述(非常感谢!):弄清楚被调用的函数:@>是arraycontains而:: text []是string_to_array
  3. 第三步是正确调用它们。经过几个小时的调试,我发现HQL不会将函数视为函数,除非我添加了一个表达式符号(在我的例子中:... = true),所以最终解决方案如下所示:predicate.and(Expressions.booleanTemplate("arraycontains({0}, string_to_array({1}, ','))=true", entity.tags, tagsStr));其中tagsStr - 是一个String与由,分隔的值

0
投票

由于您无法使用自定义运算符,因此必须使用其功能等价物。您可以使用\doS+在psql控制台中查找它们。对于\doS+ @>,我们得到了几个结果,但这是你想要的结果:

                                          List of operators
   Schema   | Name | Left arg type | Right arg type | Result type |      Function       | Description 
------------+------+---------------+----------------+-------------+---------------------+-------------
 pg_catalog | @>   | anyarray      | anyarray       | boolean     | arraycontains       | contains

它告诉我们使用的函数叫做arraycontains,所以现在我们使用\df arraycontains查找该函数来查看它的参数

                              List of functions
   Schema   |     Name      | Result data type | Argument data types |  Type  
------------+---------------+------------------+---------------------+--------
 pg_catalog | arraycontains | boolean          | anyarray, anyarray  | normal

从这里,我们将您的目标查询转换为:

SELECT * FROM entity WHERE arraycontains(tags, '{"someTag","anotherTag"}'::text[]);

然后,您应该能够使用构建器的function调用来创建此条件。

ParameterExpression<String[]> tags = cb.parameter(String[].class);
Expression<Boolean> tagcheck = cb.function("Flight_.id", Boolean.class, Entity_.tags, tags);

虽然我使用不同的阵列解决方案(可能会很快发布),但我相信它应该可行,除非底层实现中存在错误。

方法的替代方法是编译数组的转义字符串格式并将其作为第二个参数传递。如果不将双引号视为可选,则更容易打印。在那种情况下,玩具必须在上面的String[]排中用String替换ParameterExpression


0
投票

对于EclipseLink,我创建了一个函数

CREATE OR REPLACE FUNCTION check_array(array_val text[], string_comma character varying ) RETURNS bool AS $$
        BEGIN
                RETURN arraycontains(array_val, string_to_array(string_comma, ','));
        END;
$$ LANGUAGE plpgsql;

正如Serhii所指出的那样,你可以使用Expressions.booleanTemplate("FUNCTION('check_array', {0}, {1}) = true", entity.tags, tagsStr)

© www.soinside.com 2019 - 2024. All rights reserved.