如何使用JPA criteriaBuilder搜索子属性集合

时间:2016-03-22 14:57:06

标签: jpa collections criteria

我有一个实体,它映射到以这种方式定义的表:

@Entity
@Table(name = "cmmn_calendar_evnt")

public class CommonCalendarEvent implements java.io.Serializable
{
    private Integer                      cevId;
    private Set<CommonCalendarEventPart> commonCalendarEventParts = new HashSet<CommonCalendarEventPart>(0)

@Id
    @GeneratedValue(strategy = IDENTITY)
    @Column(name = "CEV_ID", unique = true, nullable = false)
    public Integer getCevId()
    {
        return this.cevId;
    }

@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "commonCalendarEvent")
    public Set<CommonCalendarEventPart> getCommonCalendarEventParts()
    {
        return this.commonCalendarEventParts;
    }
}

和CommonCalendarEventPart定义如下:

@Entity
@Table(name = "cmmn_calendar_evnt_part")

public class CommonCalendarEventPart implements java.io.Serializable
{

    private static final long   serialVersionUID = 1L;
    private Integer             ceeId;
    private CommonCalendarEvent commonCalendarEvent;
    private PartParticipant     partParticipant;

    @Id
    @GeneratedValue(strategy = IDENTITY)
    @Column(name = "CEE_ID", unique = true, nullable = false)
    public Integer getCeeId()
    {
        return this.ceeId;
    }

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "CEE_CEV_ID", nullable = false)
    public CommonCalendarEvent getCommonCalendarEvent()
    {
        return this.commonCalendarEvent;
    }

        @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "CEE_PPT_ID", nullable = false)
    public PartParticipant getPartParticipant()
    {
        return this.partParticipant;
    }

}

最后:

@Entity
@Table(name = "part_participant")

public class PartParticipant implements java.io.Serializable
{
    private static final long            serialVersionUID         = 1L;
    private Integer                      pptId;

    @Id
    @GeneratedValue(strategy = IDENTITY)
    @Column(name = "PPT_ID", unique = true, nullable = false)
    public Integer getPptId()
    {
        return this.pptId;
    }

}

我想使用CriteriaBuilder生成一个查询,查找特定参与者ID的所有CommonCalendarEvent。

在Hql中它看起来像这样:(虽然我还没有确认这个Hql也是正确的)

"from commonCalendarEvent cce  where :pptId in (cce.commonCalendarEventParts.partParticipant.pptId)"

我已经尝试了一些我认为直接尝试编写criteriaBuilder方法的方法,但我的尝试导致了以下错误: “意外结束子树”只是实现错误。

.....

    CriteriaBuilder builder = getEntityManager().getCriteriaBuilder();

    CriteriaQuery<CommonCalendarEvent> criteria = builder.createQuery(CommonCalendarEvent.class);

    Root<CommonCalendarEvent> root = criteria.from(CommonCalendarEvent.class);

    Fetch<CommonCalendarEvent, CommonCalendarEventPart> evf = root.fetch(CommonCalendarEvent_.commonCalendarEventParts, JoinType.LEFT);

    Join<CommonCalendarEvent, CommonCalendarEventPart> evj = (Join<CommonCalendarEvent, CommonCalendarEventPart>) evf;

    Join<CommonCalendarEventPart, PartParticipant> evpj = evj.join(CommonCalendarEventPart_.partParticipant);
    List<Predicate> pred = new ArrayList<Predicate>();

    pred.add(builder.equal(evpj.get(PartParticipant_.pptId), pptId));
    criteria.where(builder.and(pred.toArray(new Predicate[] {})));
    return getEntityManager().createQuery(criteria).getResultList();

.............
上面的

产生了一个&#34;意外的子树结束&#34;错误。

感谢任何帮助。

2 个答案:

答案 0 :(得分:1)

+1使用延迟初始化。 JPA模型是Object或面向实体的,所以你需要习惯于用这些术语思考。 PartParticipant未在JPA中由id标识,而是由对象本身标识。假设你有参与者名单:

PartParticipant pp = em.find(PartParticipant.class, 2);
List<PartParticipant> pps = new ArrayList<PartParticipant>();
pps.add(pp);

然后将该列表传递给查询。在JPQL中:

TypedQuery<CommonCalendarEvent> cev = em.createQuery("select cev from CommonCalendarEvent cev join fetch cev.commonCalendarEventParts cce where cce.partParticipant in :pps", CommonCalendarEvent.class);
List<CommonCalendarEvent>  cevs = cev.setParameter("pps", pps).getResultList();

请注意,需要提取以防止LazyInitializationExceptions

了解JPQL,CriteriaQuery应该遵循相同的步骤:

CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<CommonCalendarEvent> q = cb.createQuery(CommonCalendarEvent.class);
Root<CommonCalendarEvent> r = q.from(CommonCalendarEvent.class);
Join<CommonCalendarEvent, CommonCalendarEventPart> j = r.join("commonCalendarEventParts");
r.fetch("commonCalendarEventParts");
q.select(r).where(j.get("partParticipant").in(pps));
List<CommonCalendarEvent> rs = em.createQuery(q).getResultList();

除了执行fetch之外,您不需要对fetch执行任何特殊操作。如您所见,查询使用PartParticipant Id。

select 
    commoncale0_.CEV_ID as CEV_ID1_0_0_, 
    commoncale1_.CEE_ID as CEE_ID1_1_1_, 
    commoncale1_.CEE_CEV_ID as CEE_CEV_2_1_1_, 
    commoncale1_.CEE_PPT_ID as CEE_PPT_3_1_1_, 
    commoncale1_.CEE_CEV_ID as CEE_CEV_2_0_0__, 
    commoncale1_.CEE_ID as CEE_ID1_1_0__ 
from cmmn_calendar_evnt commoncale0_ 
    inner join cmmn_calendar_evnt_part commoncale1_ on commoncale0_.CEV_ID=commoncale1_.CEE_CEV_ID 
where commoncale1_.CEE_PPT_ID in (?)

答案 1 :(得分:0)

Join<CommonCalendarEvent, CommonCalendarEventPart> evj = root.join(CommonCalendarEvent_.commonCalendarEventParts); 不是必需的,应该更正第一个连接语句:

coffeescript

查询的其余部分似乎是正确的。