给定以下实体:
@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<>();
}
因此,订阅可以有零个或多个它感兴趣的mainCode或otherCode。我可以获取经过的某个对象的mainCode和otherCode。代码本身是可嵌入的,只有单个String字段。
如何创建一个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,如果没有任何其他Code,它也会失败。
在您的示例中,情况正好相反。例如,如果代码具有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