Hibernate Query 将映射实体集合与给定集合中的至少一个元素匹配,并且不能在另一个多对多关系中匹配

Posted

技术标签:

【中文标题】Hibernate Query 将映射实体集合与给定集合中的至少一个元素匹配,并且不能在另一个多对多关系中匹配【英文标题】:Hibernate Query to match mapped entity collection with at least one element in given collection,and must not match in another, ManyToMany relationship 【发布时间】:2021-09-18 14:33:55 【问题描述】:

我的所有者实体:

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

这实现了我的目标,即获取在ReaderEntity.subscriptionssubscriptionList 中至少有一个共同点的读者。

我想要达到的目标:

现在,我有一个restrictedSubscriptionList,它是SubscriptionEntity 的集合(可以是SubscriptionEntity.name)。现在我想扩展上面的查询,这样,如果读者订阅了restrictedSubscriptionList 中的任何一个,那么它就不会被获取。这意味着,如果ReaderEntity.subscriptionsrestrictedSubscriptionList 之间的交集不为空,则不应获取 Reader。

到目前为止我尝试了什么: 我尝试将AND NOT IN (:restrictedSubscriptionList) 添加到该查询中,但它似乎有错误的逻辑,并且仍然会填充所有订阅了至少一个restrictedSubscriptionList 的读者。

我手动获取属于restrictedSubscriptionList 的读者并将它们添加到排除为:

WHERE r.username NOT IN (:restrictedSubscriptionList)

但是当这样的读者越来越多时,查询会变大,导致效率降低。

如果有人可以帮助我制定查询,将不胜感激。

非常感谢您抽出宝贵时间阅读我的问题。

【问题讨论】:

【参考方案1】:

由于各种原因,您不能也不应该过滤实体的集合。您能做的最好的事情就是只选择那些符合您要求的ReaderEntity 对象。您可以使用以下查询,这在结果集基数方面更好:

from ReaderEntity r 
where exists (
  select 1 
  from r.subscriptions s 
  where s.subscriptionName in :subscriptionList 
  and s.subscriptionName not in :restrictedSubscriptionList
)

【讨论】:

以上是关于Hibernate Query 将映射实体集合与给定集合中的至少一个元素匹配,并且不能在另一个多对多关系中匹配的主要内容,如果未能解决你的问题,请参考以下文章

如何将多个值类型集合映射到 Hibernate 中的一个表?

hibernate注解配置

(转)Hibernate框架基础——一对多关联关系映射

hibernate 映射总结

hibernate的映射之四(多对多双向关联)

重复收集角色映射实体Hibernate,我不知道有什么问题