JPA - 多对多集合的分页查询返回错误数量的实体

Posted

技术标签:

【中文标题】JPA - 多对多集合的分页查询返回错误数量的实体【英文标题】:JPA - Paginated query with ManyToMany collection returns wrong number of entities 【发布时间】:2013-12-14 09:37:07 【问题描述】:

我有这两个实体(这里是简化版本):

主题:

@Entity
public class Topic implements Serializable 
    @Id
    @GeneratedValue( strategy = GenerationType.IDENTITY )
    private Long         id;

    @ManyToMany
    @JoinTable(
            name = "topic_member",
            joinColumns = @JoinColumn( name = "topic" ),
            inverseJoinColumns = @JoinColumn( name = "member" ) )
    @JoinFetch
    private List<Member> participants   = new ArrayList<Member>();

    ...

会员:

@Entity
public class Member implements Serializable 
    @Id
    @GeneratedValue( strategy = GenerationType.IDENTITY )
    private Long                id;

    ...

这些通过连接表 topic_member(member, topic) 关联,通过单向 @ManyToMany 关系。

当我插入东西时一切正常,这里没问题。

但是当我想选择东西时,它变得更加棘手。假设我想选择与特定成员相关的所有主题。我编写了以下 JPQL 查询:

SELECT t FROM Topic t WHERE :member MEMBER OF t.participants ORDER BY t.id DESC

然后我写了这个:

TypedQuery<Topic> query = em.createQuery( MY_JPQL_REQUEST, Topic.class );
query.setParameter( PARAM_MEMBER, member );
return query.getResultList();

而且效果很好。

但是有些奇怪的错误:似乎我不能在这个查询上使用分页! 例如,当我尝试这个时:

TypedQuery<Topic> query = em.createQuery( MY_JPQL_REQUEST, Topic.class );
query.setParameter( PARAM_MEMBER, member );
query.setFirstResult( 0 );
query.setMaxResults( 5 );
return query.getResultList();

它返回错误的实体数量。比如前一个返回5的时候,就只返回3...

我在这里缺少什么?我不明白会出什么问题。

我读过this page,我认为这里可能有些东西,但我不知道是什么。

[编辑] 如果有帮助,这是我在数据库中的连接表中的内容:

+-------------+-------------+ |会员 |话题 | +-------------+-------------+ | 1 | 1 | | 1 | 2 | | 1 | 3 | | 1 | 4 | | 1 | 5 | | 2 | 1 | | 2 | 2 | | 2 | 3 | | 2 | 4 | | 2 | 5 | +-------------+-------------+

[解决方案] 感谢 Chris,我得到了它的工作。我不得不在@ManyToMany 字段上用@BatchFetch( BatchFetchType.JOIN ) 替换@JoinFetch,并查询SELECT DISTINCT(t) FROM ... 而不是SELECT t FROM ...

【问题讨论】:

【参考方案1】:

这是设计使然。分页在数据库级别工作以过滤返回的行数。在集合上使用 fetch 连接时,它需要多行来构建单个实体,因此返回的实体数将与最大结果不匹配。最重要的是,为确保返回 Bly 完整实体,可能会丢弃第一个和最后一个实体,因为无法验证它们是否完整。

尝试使用带有 IN 策略的批量获取。

【讨论】:

感谢您的信息。就我而言,我应该如何使用 IN 策略来选择与特定成员相关的所有主题?我试过了,但我从来没有让它正常工作。 eclipse.org/eclipselink/documentation/2.4/jpa/extensions/… 是我所指的,而不是 join fetch 注释。您显示的映射从主题到成员,因此类似于“select m from topic t join t.participants m where t = :t” 不幸的是,这个请求似乎是错误的。在我的简单设计中,每个主题都有一个成员列表,并且我想要给定成员的所有主题(= 给定成员在其参与者列表中的每个主题)。我一定遗漏了一些明显的东西,但如果没有 MEMBER OF...,我看不到如何做到这一点 批量提取适用于您的原始查询。正是使用 join fetch 导致了分页问题。如果仍然有问题,请尝试使用 DISTINCT。 好的,非常感谢!最后,JPQL 查询中 @ManyToMany 字段 + DISTINCT 上的 @BatchFetch(IN 或 JOIN 类型,两者都可以正常工作)成功了。

以上是关于JPA - 多对多集合的分页查询返回错误数量的实体的主要内容,如果未能解决你的问题,请参考以下文章

JPA 多对多JPQL查询语句怎么写?

Spring,JPA:如何使用多对多关系桥表设置查询另一个实体下的实体

多对多表的增删改查与drf的分页

弹簧数据 JPA。子实体的分页

Spring Data JPA:查询多对多

Spring Data JPA 中的分页(限制和偏移)