我会稍微简化一下任务,但问题如下,我有一个包含 id、名称和标签的实体。
@Entity
public class MyEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@ElementCollection
private List<String> tags;
}
我需要在存储库中实现一个方法,该方法将搜索标签中包含传递给该方法的标签列表的所有实体,例如有 3 个实体。
№1(id=1,name=“name1”,标签={“tag1”,“tag2”,“tag3”})
№2(id=2,name=“name2”,标签={“tag1”“tag3”,“tag4”})
№3(id=3,name=“name3”,标签={“tag2”,“tag3”})
传输的带有标签的列表看起来像这样{“tag2”,“tag3”}。那么这个方法应该返回实体№1和№3。
我尝试以不同的方式实现存储库,这里有一些选项。
@Query("SELECT e FROM Entity e WHERE :tags MEMBER OF e.tags")
List<Entity> findByTagsContaining(@Param("tags") List<String> tags);
在这种情况下,解析查询时会出现问题。
还尝试通过 nativeQuery 和 @> 与 PostgreSQL
@Query(value = "SELECT * FROM my_entity_table WHERE tags @> :tags", nativeQuery = true)
List<MyEntity> findByTagsContaining(@Param("tags") List<String> tags);
尝试使用
String[] tags
,像这样转换为ARRAY。
@Query(value = "SELECT * FROM my_entity_table WHERE tags @> ARRAY(:tags)", nativeQuery = true)
List<MyEntity> findByTagsContaining(@Param("tags") List<String> tags);
没有帮助。
我知道可以使用
tags.containsAll(tags_list)
直接从实体获取,但它会比通过查询慢。
好吧,我自己修好了。 这是解决方案。
@Query(value = "SELECT * FROM sample WHERE tags @> CAST(ARRAY[:tags] AS TEXT[])", nativeQuery = true)
public List<Sample> findByTags(@Param("tags") String[] tags);
是的,我知道这是一种反模式,因为当切换到另一个没有这样的
@>
运算符的数据库时,此代码将不起作用,没有针对 SQL 注入的完整保护。
但是它有效,我只是想展示一个简单的示例解决方案。