使用QueryDSL的Postgresql数组函数

时间:2018-01-16 11:40:03

标签: java sql postgresql hibernate querydsl

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

script-loader

适当的SQL是:

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

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

CREATE TABLE entity (
    tags text[]
);

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

是否可以使用QueryDSL执行此操作?像代码一样的东西?

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

2 个答案:

答案 0 :(得分:3)

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

答案 1 :(得分: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