我正在尝试使用Spring Data 规范构建一个选择查询。所涉及的查询如下: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
类中有一个用@ElementCollection
表示的字段tags
。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 |
产品标签(_T):
Column | Type | Collation | Nullable | Default
------------+------------------------+-----------+----------+---------
product_id | bigint | | not null |
tags | character varying(255) | | |
1条答案
按热度按时间3npbholx1#
我似乎已经找到了答案。
Tags.class
显然可以工作,从那里我只需要调整我的查询成为一个连接选择。虽然不是我最初希望完成的,但它工作了。