使用Spring Data JpaRepositories通过ElementCollections中的值查询实体

时间:2019-02-15 15:08:50

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

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

设置

我的Spring Boot 2 / Spring 5应用程序有一个实体(Artwork),可以将任意元数据附加到该实体。 元数据是使用@ElementCollection@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(无论值列中有metadata.name = license
  • 另一种方法是查找一位特定艺术家的所有实体(具有metadata.name = artistmetadata.value = someName的键/值对)

我曾尝试使用下划线表示手动属性路径;但我的数据类型是地图,而不是具有字段name / value的对象。

public interface ArtworkRepository extends JpaRepository<Artwork, Long> {
    List<Artwork> findAllByReleaseDateAfter(Instant after);

    // Not working
    List<Artwork> findAllByMetadata_NameAndMetadata_value 

一般来说,查询是可能的。但是我在StackOverflow上找到的大多数答案都是关于searching in Lists,而不是地图。

我的问题是

如何使用查询方法基于附件@ElementCollection中存储的值查询JpaRepository中的实体?还是我需要使用JPA的一对多映射在对象级别转换这种关系。

更新

  • 由于我们在artist表中有成千上万的记录,因此我想在数据库级别而不是在应用程序中进行过滤。
  • 通过元数据进行查询将变得很普遍,因此,不能引入诸如hasLicense之类的帮助器标记,或者将艺术家移至主要实体。

谢谢。

1 个答案:

答案 0 :(得分:2)

JPA 2.0允许使用KEY()VALUE()来引用JPQL中基于地图的@ElementCollection中的键和值。

通常,您可以使用它们来解决问题。但是,如this中所述,对于VALUES()来说,休眠似乎是一种奇怪的行为……幸运的是,它具有workaround

无论如何,可以通过以下@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");