带有严格In子句的Spring数据

时间:2018-02-20 18:17:39

标签: java spring spring-data spring-data-jpa in-clause

请参阅下面的更新问题

我想查询要求每个元素都具有例如所有给定属性的元素。要归还的一套,不仅仅是一个。

默认的Spring Data Jpa Query,其中一个属性就足够了:

findAllByAttributeIn(Set<Attribute> setAttr)

示例问题

对于这些元素(抽象,没有实际表格)

id | attr
----------
1  | A
2  | A,B
3  | A,B,C

使用此过滤器:

setAttr:[A,B]

默认查询

findAllByAttributeIn(Set<Attribute> setAttr)

返回所有元素(按ID):

[1,2,3]

期望的结果只是第二个元素([A,B])。

是否可以使用给定的Spring Data Jpa查询关键字,或者是创建自定义查询的唯一解决方案?

更新了问题:

有两个实体,媒体和标签。它们具有多对多关系,这在表Media_has_tags中实现。每个媒体都可以有任意数量的标签(0 .. *)。所以在我的Spring应用程序中,媒体有一组标签作为属性,反之亦然。课程:

Media = {
id: string,
Set<Tag> tags,
...
}

Tag = {
id: string,
Set<Media> medias,
...
}

相应的表格是:

Media
-------
id | ...

Tag
-------
id    | ...
title | ...

Media_has_tags
-------
media_id | tag_id

现在我有了一组标签,我想让所有媒体都拥有该套装的每个标签。当然,他们可以拥有更多标签,但他们需要拥有我提供的套装的每个标签。

具体例子:

Media
-------
id | ...
-------
1  |
2  |

Tag
-------
id | title | ...
1  | A     |
2  | B     |

Media_has_tags
-------
media_id | tag_id
1        | 1
2        | 1
2        | 2

给定一组标签[A,B]我只想要ID为2的媒体,因为id为1的媒体没有标签&#39; B&#39;

我可以通过关键字实现这一点吗?我是否,如何或如何构建自己的查询?

1 个答案:

答案 0 :(得分:2)

抱歉,您的问题最初是不正确的。

findAllByAttributeIn(Set<Attribute> setAttr)

生成如下的SQL请求:

select * from <table_name> t where t.attribute in (?,?,?...?)

因此,根据RDBMS规则,您的结果是正确且可预期的。 抽象表的真实结构是什么?

 id | attr
----------
 1  | A
 2  | A,B
 3  | A,B,C

在现实生活中,这将是一个想法:

 id | attr
----------
 1  | A
 2  | A
 2  | B
 3  | A
 3  | B
 3  | C

再次 - 在这种情况下,您获得的结果对于任何RDBMS都是可以的。 请提供您项目中的实例,

因问题更新而更新

好的,问题已经澄清了。 在这种情况下,使用标准的CrudRepository语法没有直接的方法来解决它。但您可以尝试编写@Query请求来管理以实现目标。 在明确的SQL中,必须使用group byhaving来解决此问题。它会是这样的:

select media_id 
From media_has_tags
Where tag_id in(1,2 3)
Group by media_id
Having count(*)=3

就SpringData而言,这意味着您必须创建MediaHasTagsRepository接口和适当的查询方法才能获得外观ID。之后,您可以轻松找到您正在寻找的媒体。 但这种方法看起来并不好恕我直言。我认为最好的方法是通过初始查询找到所有媒体,然后在Java中按给定条件过滤它们。 例如。你有一个List<Media>,其中每个元素至少有一个你正在寻找的标签。然后我们可以循环查找包含所有已查看标签的媒体:

List<Media> list; // here is a filled list of medias
Set<String> titles; // here is a set of title interseptions we a looking for 
final List<Media> result = new ArrayList<>();
for (Media media: list) {
  if (!list.getTags().isEmpty()){
    Set<String> tagTitles = list.getTags().stream().map(item -> item.getTitle()).filter(title -> titles.contains(title)).distinct().collect(Collectors.toSet());
    if (tagTitles.size() == titles.size()) {
      result.add(media);
    }
  }
}