@ManyToMany关系中表的JPA 2.0 CriteriaQuery

我在@ManyToMany关系中有两个实体。

 // Output has 4 other @ManyToOne relationships if that matters @Entity @Table public class Output { @Id public String address; @ManyToMany(targetEntity = Interval.class, cascade = CascadeType.ALL, fetch = FetchType.LAZY) @JoinTable(name = "output_has_interval", joinColumns = {@JoinColumn(name = "output_address", referencedColumnName = "address")}, inverseJoinColumns = {@JoinColumn(name = "interval_start", referencedColumnName = "start"), @JoinColumn(name = "interval_end", referencedColumnName = "end")}) Collection intervals; @IdClass(IntervalPK.class) // I'll omit this one. @Entity @Table public class Interval { @Id public Calendar start; @Id public Calendar start; @ManyToMany(targetEntity = Output.class, mappedBy = "intervals", cascade = CascadeType.ALL, fetch = FetchType.LAZY) public Collection outputs; 

连接表在outputinterval之间称为output_has_interval

我如何做这样的CriteriaQuery

 SELECT `output`.`address` FROM `output`, `output_has_interval`, `interval` WHERE `output`.`address` = `output_has_interval`.`output_address` AND `interval`.`start` = `output_has_interval`.`interval_start` AND `interval`.`end` = `output_has_interval`.`interval_end` AND `interval`.`start` >= '2011-04-30' 

如果我在MySQL中发布它,这可以按预期工作。

(我也有相应的静态元模型类,根据要求我可以发布它们 – 没什么好看的。)

 CriteriaBuilder cb = em.getCriteriaBuilder(); CriteriaQuery cq = cb.createQuery(Output.class); Root root= cq.from(Output.class); CollectionJoin join = root.join(Output_.intervals); Expression start = join.get(Interval_.start); Predicate pred = cb.greaterThanOrEqualTo(start, /* calendar for '2011-04-30' */); cq.where(pred); TypedQuery tq = em.createQuery(cq); 

但是tq.getResultList返回数据库中的每个output行。 任何想法?

(旁注:Hibernate(我正在使用的提供程序)在发出此查询时生成许多select语句,每个关系Output一个,有时更多。)

编辑:我写道:

tq.getResultList返回数据库中的每个output

澄清它:它返回的不仅仅是数据库中的每个output行。 它实际上使用outputinterval但是谓词:

 `interval`.`start` >= '2011-04-30' 

不满意。

好吧,我会设法自己解决我的谜语。

首先:整个问题源于我是一个糟糕的程序员。 我迭代了TypedQuery.getResultList()并以递归方式访问Output.intervals中的每个Interval ,因此Output.intervals懒惰地加载所请求的对象,生成一些select语句。

但是我不得不以某种方式控制那些Interval 。 对我的CriteriaQuery进行了以下更改。

 CriteriaBuilder cb = em.getCriteriaBuilder(); CriteriaQuery cq = cb.createTupleQuery(); // or createQuery(Tuple.class) Root root= cq.from(Output.class); // from clause CollectionJoin join = root.join(Output_.intervals); Path addressPath = root.get(Output_.address); // mind these Path objects Path startPath = join.get(Interval_.start); // these are the key to success! cq.multiselect(addressPath, startPath); // select clause Expression start = join.get(Interval_.start); Predicate pred = cb.greaterThanOrEqualTo(start, /* calendar for '2011-04-30' */); cq.where(pred); // where clause TypedQuery tq = em.createQuery(cq); // holds Tuples for (Tuple tuple : tq.getResultsList()) { String address = tuple.get(addressPath); Calendar start = tuple.get(startPath); ... 

编辑

我刚刚意识到我可以使用Path对象而不是Expression对象(反之亦然),因为Path扩展了Expression 。 好吧…