Java 使用Spring数据JpaRepositories按ElementCollections中的值查询实体

Java 使用Spring数据JpaRepositories按ElementCollections中的值查询实体,java,spring,spring-data-jpa,spring-data,Java,Spring,Spring Data Jpa,Spring Data,是否可以使用查询方法根据附加的@ElementCollection中存储的值查询JPA存储库中的实体 设置 我的Spring Boot 2/Spring 5应用程序有一个实体(Artwork),可以附加任意元数据。 元数据是通过使用@ElementCollection和@CollectionTable的简单键值映射实现的,因为元数据只是纯文本键/值对,不存在于其实体的范围之外 实体如下所示: @Entity @Table(name = "artwork") public class Artwor

是否可以使用查询方法根据附加的
@ElementCollection
中存储的值查询JPA存储库中的实体

设置

我的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
}
一般来说,查询似乎是可能的。但我在StackOverflow上找到的大多数答案都是关于,而不是在地图上

所以我的问题是

如何使用查询方法根据附加的
@ElementCollection
中存储的值查询JPA存储库中的实体?或者我需要使用JPA的一对多映射在对象级别转换这种关系吗

更新

  • 因为我们在artist表中有数万条记录,所以我希望在数据库级别进行筛选,而不是在应用程序中进行筛选
  • 按元数据查询将变得很常见,因此引入辅助标志(如
    hasLicense
    )或将艺术家移动到主实体不是一个选项

谢谢

JPA2.0允许使用
KEY()
VALUE()
引用JPQL中基于地图的
@ElementCollection
中的键和值

通常,您可以使用它们来解决您的问题。但是,如中所述,对于
VALUES()
…,Hibernate似乎是一种奇怪的行为。。。。。。幸运的是,它做到了

无论如何,您的问题可以通过以下
@Query
(假设您使用的是Hibernate。如果您使用其他提供程序,您可以尝试
VALUES()
):

要查找特定艺术家的所有艺术品,请执行以下操作:

artworkRepository.findArtworkByMetadata("artist" , "someName");

在应用程序级别上提取所有的过滤器?因为我们有数万个记录,这将是不有效的。如果您的标准可以根据未来的需求发展,其他方法可能会更合适(例如,ElasticSearch for metdata+DB for entities)。如果您在JPA实体中引入“hasLicense”列,那么第一个用例就可以解决,并且抓取会很快,但是在元数据中搜索匹配项-如果您想将其保留在DB中,这应该是一个单独的表,其中FK是主实体。谢谢,但我不打算过早优化。元数据位于一个单独的表中,表中有一个外键,如上所述,我希望根据此信息进行查询。谢谢,这看起来很有希望。我假设,
VALUES()
中是可选的(KEY(meta)=:name和meta=:value)
?目前我遇到了一些延迟初始化问题,但是生成的sql看起来不错。在
(KEY(meta)=:name和meta=:value)
中,我没有使用
VALUES()
,因为正如我提到的,它在Hibernate中有问题。
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");