带有 QueryDSL 的 Postgresql 数组函数

Postgresql Array Functions with QueryDSL

我使用 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>));

由于您不能使用自定义运算符,因此您将不得不使用它们的等效函数。您可以使用 \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);

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

方法的替代方法是编译数组的转义字符串格式并将其作为第二个参数传递。如果您不将双引号视为可选,则打印起来会更容易。在这种情况下,您必须在

上方的 ParameterExpression 行中将 String[] 替换为 String
  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,值由 ,

分隔

对于 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)