休眠查询以匹配映射实体集合与给定集合中的至少一个元素,多对多关系

Posted

技术标签:

【中文标题】休眠查询以匹配映射实体集合与给定集合中的至少一个元素,多对多关系【英文标题】:Hibernate Query to match mapped entity collection with at least one element in given collection, ManyToMany relationship 【发布时间】:2021-08-25 19:28:58 【问题描述】:

我的所有者实体:

@Entity(name = "SubscriptionEntity")
@Table(name = "SUBSCRIPTION", uniqueConstraints = 
        @UniqueConstraint(columnNames = "ID"))
 
public class SubscriptionEntity implements Serializable 

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "ID", unique = true, nullable = false)
    private Integer subscriptionId;
 
    @Column(name = "SUBS_NAME", unique = true, nullable = false, length = 100)
    private String subscriptionName;
     
    @ManyToMany(cascade=CascadeType.ALL)
    @JoinTable(name="READER_SUBSCRIPTIONS", joinColumns=@JoinColumn(referencedColumnName="ID")
                                        , inverseJoinColumns=@JoinColumn(referencedColumnName="ID"))
    private Set<ReaderEntity> readers;
 
    //Getters and setters

映射实体:

@Entity(name = "ReaderEntity")
@Table(name = "READER", uniqueConstraints = 
        @UniqueConstraint(columnNames = "ID"),
        @UniqueConstraint(columnNames = "EMAIL"),
        @UniqueConstraint(columnNames = "USERNAME")
 
public class ReaderEntity implements Serializable 

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "ID", unique = true, nullable = false)
    private Integer readerId;
 
    @Column(name = "EMAIL", unique = true, nullable = false, length = 100)
    private String email;
 
    @Column(name = "USERNAME", unique = false, nullable = false, length = 100)
    private String username;
 
    @ManyToMany(mappedBy="readers") 
    private Set<SubscriptionEntity> subscriptions;
 
    //Getters and setters

现在,我有一个 subscriptionList,其中包含很少的订阅。我想要一个ReaderEntity 对象的分页列表,其订阅至少属于subscriptionList 中的一个。即ReaderEntity.subscriptionssubscriptionList 的交集应该至少是一个。

我参考了这篇文章并写了一个查询: Hibernate or SQL Query M-N member of with collections?

@Query("SELECT r FROM ReaderEntity r LEFT JOIN r.subscriptions s WHERE (s.subscriptionName in (:subscriptionList))")
Page<User> findAllBySubscriptions(@Param("subscriptionList") Set<String> subscriptionList, Pageable pageable);

但如果subscriptionList 中的多个元素与实际ReaderEntity.subscriptions 匹配,则此查询会填充重复条目。

我不能使用Distinct,因为可分页包含排序顺序,它按用户名对列表进行排序,不区分大小写。所以它在末尾附加order by lower(username) 并抛出错误:

ORDER BY items must appear in the select list if SELECT DISTINCT is specified.

谁能帮我制定这个查询或指导我如何实现这一目标?

【问题讨论】:

【参考方案1】:

使用提示pass distinct through

@QueryHints(@QueryHint(name = org.hibernate.annotations.QueryHints.PASS_DISTINCT_THROUGH, value = "false"))
@Query("SELECT distinct r FROM ReaderEntity r LEFT JOIN r.subscriptions s WHERE (s.subscriptionName in (:subscriptionList))")
Page<User> findAllBySubscriptions(@Param("subscriptionList") Set<String> subscriptionList, Pageable pageable);

【讨论】:

以上是关于休眠查询以匹配映射实体集合与给定集合中的至少一个元素,多对多关系的主要内容,如果未能解决你的问题,请参考以下文章

@OneToMany 映射休眠中的集合

如何配置 Hibernate Envers 以避免实体修订查询中的某些集合(连接表)

查询具有两个一对多集合的休眠实体

什么算法将集合 A 中的每个元素映射到集合 B 中的最佳匹配?

Mybatis resultMap 嵌套集合

JPA 一个实体中的两个惰性集合 - 如何运行 JPA 查询以获取实体和只有一个集合