如何使用多个ElementCollections进行搜索

时间:2015-04-14 12:40:04

标签: jpa criteria jpql embeddable

鉴于以下实体:

@Entity
@Table(name = "subscription")
public class Subscription implements Serializable {

  private static final long serialVersionUID = 1L;

  @ElementCollection
  @CollectionTable(joinColumns= @JoinColumn(name="subscription"))
  private Set<Code> mainCodes = new HashSet<>();

  @ElementCollection
  @CollectionTable(joinColumns= @JoinColumn(name="subscription"))
  private Set<Code> otherCodes = new HashSet<>();

}

因此,订阅可以包含零个或多个它感兴趣的mainCodes或其他代码。我可以获取经过的某个对象的mainCode和otherCode。代码本身是可嵌入的,只有一个字符串字段。

如何创建一个JPA查询(或CriteriaBuilder),使用“OR”机制在这些集合中搜索?

所以基本上我正在寻找这样的查询:

select s from subscription s where :myMainCode IN s.mainCodes OR :otherCode IN s.otherCodes

使用CriteriaBuilder是可行的,还是需要使用更明确的查询?如果是这样,查询是什么样的?

编辑:尝试使用CriteriaBuilder:

final CriteriaBuilder cb = this.entityManager.getCriteriaBuilder();
final CriteriaQuery<Subscription> cq = cb.createQuery(Subscription.class);
final Root<Subscription> root = cq.from(Subscription.class);

final Expression<Collection<Code>> mainCodes = root.get("mainCodes");
final Predicate containsMainCode = cb.isMember(obj.getClassCode(), mainCodes);

final Expression<Collection<Code>> otherCodes = root.get("otherCodes");
final Predicate containsOtherCode = cb.isMember(obj.getOtherCode(), otherCodes);

final Predicate searchPredicate = cb.or(containsMainCode, containsOtherCode);
cq.select(root).where(searchPredicate);

但是,这会创建两个涉及的集合的内部联接,这意味着如果mainCode有一行,它将不返回任何结果,但是对于数据库中的otherCode则不会返回结果,它会生成此查询:

SELECT t0.ID FROM Subscription_OTHERCODES t2, Subscription_MAINCODES t1, subscription t0 WHERE ((t1.CODESYSTEM = ?) AND (t1.CODE = ?)) OR ((t2.CODESYSTEM = ?) AND (t2.CODE = ?))) AND ((t1.subscription = t0.ID) AND (t2.subscription = t0.ID))

因此即使找到匹配的mainCode,如果它没有任何其他的代码也会失败。

1 个答案:

答案 0 :(得分:0)

在你的例子中,这是另一种方式。 例如,如果代码具有name属性):

select s from Subscription s left join s.mainCodes m left join s.otherCodes o 
where m.name IN :myMainCode or o.name IN :myOtherCode