首页 > 解决方案 > 使用 Spring Data JpaRepositories 通过 ElementCollections 中的值查询实体

问题描述

是否可以使用查询方法根据存储在附件中的值来查询 JpaRepository 中的实体@ElementCollection

设置

我的 Spring Boot 2 / Spring 5 应用程序有一个实体 ( Artwork) 可以附加任意元数据。元数据是通过一个简单的键值映射使用@ElementCollectionand实现的@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
}

问题

我有两个用例,我需要根据元数据映射中存储的信息查询实体。

我尝试使用下划线表示法进行手动属性路径描述;但我的数据类型是地图,而不是真正的带有字段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 的一对多映射在对象级别转换这种关系。

更新

谢谢。

标签: javaspringspring-data-jpaspring-data

解决方案


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");

推荐阅读