Spring Data JPA 规范 - @OneToMany 依赖

9

我在使用Spring data JPA规范获取实体Person的List时遇到了问题(由于分页)。我需要通过person获取所有notes,但这两个实体之间的依赖关系在Person方面。我不知道如何创建我的Predicate,因为Note不包含与Person相关的任何属性。

我可以简单地使用Persons getter获取List,但我无法使用此方法,因为我需要返回分页数据。

@Entity
public class Person implements Serializable {

    @Id
    private Long personId;

    @OneToMany
    @JoinColumn(name = "personId")
    private List<Note> notes;

}

@Entity
public class Note implements Serializable {

    @Id
    private Long noteId;
}

通常情况下,我会像这样写,但是在“Note”中没有“person”属性,且数据库无法在此阶段被重新映射。

public static Specification<Note> notesByPerson(final Long personId) {
        return new Specification<Note>() {
            @Override
            public Predicate toPredicate(final Root<Note> root, final CriteriaQuery<?> query,
                    final CriteriaBuilder builder) {

                final Path<Person> per = root.<Person> get("person");

                return builder.equal(per.<Long> get("personId"), personId);

            }
        };
    }

谢谢,Zdend。
2个回答

13

问题已解决。

public static Specification<Note> notesByPerson(final Long personId) {
        return new Specification<Note>() {

            @Override
            public Predicate toPredicate(final Root<Note> noteRoot, final CriteriaQuery<?> query,
                    final CriteriaBuilder cb) {

                final Subquery<Long> personQuery = query.subquery(Long.class);
                final Root<Person> person = personQuery.from(Person.class);
                final Join<Person, Note> notes = person.join("notes");
                personQuery.select(notes.<Long> get("noteId"));
                personQuery.where(cb.equal(person.<Long> get("personId"), personId));

                return cb.in(noteRoot.get("noteId")).value(personQuery);
            }
        };
    }

1
你能进一步解释一下解决方案吗?(详细说明步骤) - levtatarov
3
一定有比使用那个in子句更好的方法...你应该考虑在你的Note类中添加@ManyToOne Person person;,这样你就可以进行简单的Join操作了。 - rwyland
我知道这是很久以前的事了。但首先解释一下他们的答案。在具有关联映射的侧面创建一个子查询。即Person,而子查询的类型为Long,因为它只获取notes行的pk,以便将其作为IN子句返回用于Notes根主查询的id列表。2)关于我的上面的评论添加ManyToOne映射,我同意,但要小心,因为ManyToOne默认为急切获取,这样即使另一个用例不需要该数据,它也将始终返回。 - bytor99999

1

我不确定如何使用谓词来实现这个,因为我通常不使用它们,但在JPQL(或类似的HQL)中,您可以像这样做:

SELECT Note n FROM Person.notes WHERE XXXX

基本上就相当于在SQL中执行此操作

SELECT n.noteId FROM person as p JOIN persons_notes pn ON pn.person=p.personId JOIN notes as n ON n.noteId=pn.noteId

我猜测Predicate方法具有与上述描述相似的能力。

那就是问题所在...我不能使用这样的查询,因为我需要对其进行分页处理,而我们的实现只能处理作为查询参数的规范。此外,我对谓词不熟悉,不知道它们能做什么。 - Zdend
对于分页,您需要获取生成的TypedQuery,可以使用上述方法或通过CriteriaBuilder(读取Predicates)生成,然后调用setFistResult()来分页*returnCount,并调用setMaxResults()来返回Count。如果您需要总数,我认为大多数人只需调用相同的查询两次,一次获取数据,另一次执行“count()”。 - CodeChimp

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接