JPA - 使用组合标准查找嵌套实体

时间:2015-09-25 12:55:03

标签: jpa criteria-api

我有一个名为FileEntity的实体,其中包含ReportEntity类型的报告列表。

FileEntity有一个字段,用于确定哪个用户创建了包含多个报告的文件。

@Entity
public class FileEntity {

    @Id
    private Long id;

    @JoinColumn(name = "user")
    @ManyToOne(optional = true)
    @NotNull
    private User user;

    @OneToMany(cascade = CascadeType.ALL,
           fetch = FetchType.EAGER,
           orphanRemoval = true)
    @NotNull
    private List<Report> reports = new ArrayList<>(5);

    ...
}

@Entity
public class Report {

    @Id
    private Long id;

    ...
}

我目前正在尝试使用给定的报告ID和发布包含该报告的文件的人员的ID来获取单个报告。该组合是唯一的,因此它只应为报告和用户ID的特定组合返回一个报告。但我无法使用以下标准检索单个结果:

public Report findReportByUserAndReportId(Long reportId, Long userId) {
    Objects.nonNull(reportId);
    Objects.nonNull(userId);
    try {
        final CriteriaBuilder cb = entityManager.getCriteriaBuilder();
        final CriteriaQuery<Report> cq = cb.createQuery(Report.class);
        final Root<FileEntity> fileEntity = cq.from(FileEntity.class);
        final Root<Report> report = cq.from(Report.class);
        final Join<FileEntity, Report> join = fileEntity.join(FileEntity_.reports);
        final Predicate[] predicates = new Predicate[]{
            cb.equal(join.get("id"),
                     userId),
            cb.equal(join.get(Report_.id),
                     reportId)};
        cq.select(report).where(predicates);
        return entityManager.createQuery(cq).getSingleResult();
    } catch (NoResultException |
             NonUniqueResultException ne) {
        LOG.log(Level.WARNING,
                "Could not find report: {0}",
                ne.getMessage());
    }
    return null;
}

有人知道我做错了吗?

1 个答案:

答案 0 :(得分:1)

首先,不要在这里使用多个根,因为它们生成所有元素的carthesian产品,而不加入它们。请改用联接或Path。第二,在第一个谓词中。 join对象表示Path个报告,而不是用户,因此在那里查找userid没有意义。

Root<FileEntity> fileEntity = cq.from(FileEntity.class);
Path<User> user = fileEntity.get(FileEntity_.user);
Join<FileEntity, Report> reports = fileEntity.join(FileEntity_.reports);
Predicate[] predicates = new Predicate[]{
        cb.equal(user.get(User_.id),
                 userId),
        cb.equal(reports.get(Report_.id),
                 reportId)};