java - 使用 Spring Data JpaRepositories 通过 ElementCollections 中的值查询实体
问题描述
是否可以使用查询方法根据存储在附件中的值来查询 JpaRepository 中的实体@ElementCollection
?
设置
我的 Spring Boot 2 / Spring 5 应用程序有一个实体 ( Artwork
) 可以附加任意元数据。元数据是通过一个简单的键值映射使用@ElementCollection
and实现的@CollectionTable
,因为元数据只是纯文本键/值对并且不存在于它的实体范围之外。
实体如下所示:
@Entity
@Table(name = "artwork")
public class Artwork implements Serializable {
@Id
@GeneratedValue(strategy = IDENTITY)
private Long id;
// more propperties
@ElementCollection
@MapKeyColumn(name = "name")
@Column(name = "value")
@CollectionTable(name = "artwork_metadata", joinColumns = @JoinColumn(name = "artwork_id"))
private Map<String, String> metadata = new HashMap<>();
// more code
}
问题
我有两个用例,我需要根据元数据映射中存储的信息查询实体。
- 一个用例是查找所有
Artwork
带有许可证的 s(metadata.name = license
无论 value 列中的内容是什么) - 另一种是查找一位特定艺术家的所有实体(具有精确的键/值对
metadata.name = artist
andmetadata.value = someName
)
我尝试使用下划线表示法进行手动属性路径描述;但我的数据类型是地图,而不是真正的带有字段name
/的对象value
。
public interface ArtworkRepository extends JpaRepository<Artwork, Long> {
List<Artwork> findAllByReleaseDateAfter(Instant after);
// Not working
List<Artwork> findAllByMetadata_NameAndMetadata_value
一般查询似乎是可能的。但我在 StackOverflow 上找到的大多数答案都是关于在 Lists 中搜索,而不是在地图中搜索。
所以我的问题是
如何@ElementCollection
使用查询方法根据存储在附件中的值查询 JpaRepository 中的实体?或者我是否需要使用 JPA 的一对多映射在对象级别转换这种关系。
更新
- 由于我们在艺术家表中有数万条记录,因此我想在数据库级别而不是在应用程序中进行过滤。
- 通过元数据进行查询将变得普遍,因此引入辅助标志
hasLicense
或将艺术家移动到主要实体不是一种选择。
谢谢。
解决方案
JPA 2.0 允许在 JPQL中使用KEY()
和VALUE()
引用基于映射的键和值。@ElementCollection
通常,您可以使用它们来解决您的问题。但是,正如本文所述,Hibernate 似乎是一种奇怪的行为VALUES()
......幸运的是,它有解决方法。
无论如何,您的问题可以通过以下方式解决@Query
(假设您使用的是 Hibernate。如果您使用其他提供商,您可以尝试VALUES()
)。:
public interface ArtworkRepository extends JpaRepository<Artwork, Long> {
@Query(value = "select a from Artwork a join a.metadata meta where (KEY(meta) = :name)")
public List<Artwork> findArtworkByMetadata(@Param("name") String name);
@Query(value = "select a from Artwork a join a.metadata meta where (KEY(meta) = :name and meta = :value)")
public List<Artwork> findArtworkByMetadata(@Param("name") String name, @Param("value") String value);
}
要查找所有具有许可证的艺术品:
artworkRepository.findArtworkByMetadata("license");
要查找特定艺术家的所有艺术品:
artworkRepository.findArtworkByMetadata("artist" , "someName");
推荐阅读
- r - 使用 Rshiny 同时选择多个变量
- python - 使用 SQLalchemy ORM 仅从 excel 加载唯一数据(例如“get_or_add”功能)时最小化“接触”数据库?
- javascript - 带有自定义过滤器错误的智能表:未捕获的类型错误:无法读取未定义的属性“替换”
- c# - 尝试在 c# 中获取令牌时出现 AdalSilentTokenAcquisitionException
- html - 将两个内容与 flex-container 对齐
- javascript - 如何允许用户在 ISV 应用程序中创建报告?
- python - 在多个频道中创建一个不和谐的机器人类型
- python - 了解熊猫 groupby().agg() 值
- docker - 将数据写回已挂载的 kubernetes 卷(configmap 或任何其他类型)
- c# - 将 float[] 列表转换为 double[] 列表