带有 QueryDSL 的 Postgresql 数组函数

Ser*_*nov 1 java sql postgresql hibernate 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;
}
Run Code Online (Sandbox Code Playgroud)

合适的 SQL 是:

CREATE TABLE entity (
    tags text[]
);
Run Code Online (Sandbox Code Playgroud)

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

SELECT * FROM entity WHERE tags @> '{"someTag","anotherTag"}'::text[];
Run Code Online (Sandbox Code Playgroud)

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

是否可以使用 QueryDSL 来做到这一点?类似于下面的代码?

predicate.and(entity.tags.eqAll(<whatever>));
Run Code Online (Sandbox Code Playgroud)

Ser*_*nov 7

  1. 第一步是生成正确的sql: WHERE tags @> '{"someTag","anotherTag"}'::text[];
  2. 第 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有值相隔,


col*_*ict 6

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

                                          List of operators
   Schema   | Name | Left arg type | Right arg type | Result type |      Function       | Description 
------------+------+---------------+----------------+-------------+---------------------+-------------
 pg_catalog | @>   | anyarray      | anyarray       | boolean     | arraycontains       | contains
Run Code Online (Sandbox Code Playgroud)

它告诉我们所使用的函数被调用arraycontains,所以现在我们使用以下命令查找该函数以查看它的参数\df arraycontains

                              List of functions
   Schema   |     Name      | Result data type | Argument data types |  Type  
------------+---------------+------------------+---------------------+--------
 pg_catalog | arraycontains | boolean          | anyarray, anyarray  | normal
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

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

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