【发布时间】:2022-08-14 22:34:33
【问题描述】:
我正在尝试使用 Spring Data Specification 构建选择查询。有问题的查询如下:
SELECT * FROM product WHERE id IN (SELECT product_id FROM product_tags WHERE tags IN (\'GRADUATION\', \'BIRTHDAY\'));
用户应该提供一组标签以与子查询中的IN 运算符匹配,BIRTHDAY 和 GRADUATION 是一些示例。我已经尝试根据this 答案构建我的解决方案,但遇到了一些麻烦。
public static Specification<Product> withTags(Set<Tags> tags) {
return tags == null ?
null :
(root, query, criteriaBuilder) -> {
List<Predicate> predicates = new ArrayList<>();
Subquery<Tags> subquery = query.subquery(Tags.class);
Root<Tags> subqueryRoot = subquery.from(Tags.class);
subquery.select(subqueryRoot.get(\"product_tags\").get(\"product_id\"));
subquery.where(criteriaBuilder.trim(subqueryRoot.get(\"product\").get(\"id\")).in(tags));
predicates.add(subqueryRoot.get(\"*\").in(subquery));
return criteriaBuilder.and(predicates.toArray(new Predicate[0]));
};
}
这里的问题是我试图从Tags 创建一个子查询,它没有注册为实体,而是一个枚举。因此,执行代码会给我一个错误(这是我迄今为止遇到的唯一错误,请指出可能导致其他错误的部分代码)。
public enum Tags {
BIRTHDAY(\"birthday\"),
GRADUATION(\"graduation\"),
GET_WELL_SOON(\"get well soon\"),
RIBBON(\"ribbon\"),
WRAPPING_PAPER(\"wrapping paper\");
final String tagName;
private Tags(String tagName) {
this.tagName = tagName;
}
public String getTagName() {
return tagName;
}
}
不确定这是否有帮助,但在Product 类中有一个字段tags 用@ElementCollection 表示。 Spring 自动创建一个名为 \'product_tags\' 的表,子查询从这个表中选择。
@ElementCollection(fetch = FetchType.EAGER)
@Enumerated(EnumType.STRING)
private Set<Tags> tags;
如果可能的话,我想翻译这个查询而不是第一个
SELECT * FROM product WHERE id IN (SELECT product_id FROM product_tags WHERE tags = ANY(ARRAY[\'GRADUATION\', \'GET_WELL_SOON\']));
更新
我已经编辑了我的代码
public static Specification<Product> withTags(Set<Tags> tags) {
return tags == null ?
null :
(root, query, criteriaBuilder) -> {
List<Predicate> predicates = new ArrayList<>();
Subquery<Long> subquery = query.subquery(Long.class);
Root<Product> subroot = subquery.from(Product.class);
subquery.select(subroot.get(\"id\").get(\"tags\"));
subquery.where(criteriaBuilder.trim(subroot.join(\"tags\").get(\"id\")).in(tags));
predicates.add(root.get(\"id\").in(subquery));
return criteriaBuilder.and(predicates.toArray(new Predicate[0]));
};
}
但是现在我收到了这个错误
java.lang.IllegalStateException: Illegal attempt to dereference path source [null.id] of basic type
作为参考,我的表是这样定义的
产品:
Column | Type | Collation | Nullable | Default
-------------+------------------------+-----------+----------+---------
id | bigint | | not null |
category | character varying(255) | | |
date_added | date | | |
description | character varying(255) | | |
name | character varying(255) | | |
price | double precision | | not null |
产品标签:
Column | Type | Collation | Nullable | Default
------------+------------------------+-----------+----------+---------
product_id | bigint | | not null |
tags | character varying(255) | | |
-
嗯...也许您可以尝试使用从标签 getTagName() 构建的 Set<String>?
-
那是一个很好的选择,但如果可能的话,我更喜欢使用标签。当我们讨论集合的主题时,url 参数是否可以接受对象集合?我收到了这个新错误:
Parameter value [] did not match expected type [java.util.Set (n/a)]; -
如果我要使用一组字符串,你会建议我如何构建查询?
标签: java sql spring-data-jpa