簡體   English   中英

JPA Criteria API - 使用 ElementCollection 外鍵的 WHERE 條件加入 ElementCollection

[英]JPA Criteria API - joining ElementCollection with WHERE condition on ElementCollection foreign key

我有一個實體 Document 和 enum Label (不是我的真實案例,我使用類比)。 文檔可以有一組標簽。 標簽的映射如下:

@Entity
public class Document {
    ...

    @ElementCollection(fetch = FetchType.EAGER)
    @Enumerated(EnumType.STRING)
    @Column(name = "labels")
    private Set<Label> labels = new HashSet<>();

    ...
}

這意味着標簽被映射到具有兩列(document_id,value)的單獨表中,但在 Java 中它只是枚舉

我需要選擇沒有任何列出標簽的文檔。 在 SQL 中它看起來像這樣:

select D.id 
from document D left join label L 
on D.id = L.document_id and L.value in('label1','label2',...)
where L.document_id is null

但我不知道如何在 JPA Criteria API 中編寫它。 我不知道如何在標簽表中表達外鍵。 JPA 謂詞應該是這樣的

CriteriaBuilder cd = ...
SetJoin<Object, Object> labelsJoin = root.joinSet("labels", JoinType.LEFT);
cb.and(labelsJoin .in("label1","label2"), cb.isNull(...???...)));

這是我的相關 SQL 問題

預先感謝您的建議。 盧卡斯

這應該返回預期的結果,但查詢語句有點不同

CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<Document> query = cb.createQuery(Document.class);
Root<Document> root = query.from(Document.class);

Subquery<Long> subquery = query.subquery(Long.class);
Root<Document> subRoot = subquery.from(Document.class);
Join<Document, Label> label = subRoot.join("labels", JoinType.INNER);

List<Label> labels = Arrays.asList(Label.LABEL_1, Label.LABEL_2);
subquery.select(subRoot.get("id")).where(
    cb.equal(root.get("id"), subRoot.get("id")), 
    label.in(labels)
);

query.select(root).where(cb.exists(subquery).not());

List<Document> result = entityManager.creteQuery(query).getResultList();

您應該可以輕松翻譯 NOT IN 選項

select *
from document
where document.id not in (
    select document_id
    from label 
    where value in ('label1', 'label2')
)

進入標准 API

CriteriaQuery<Document> query = cb.createQuery(Document.class);
Root<Document> root = query.from(Document.class);
query.select(root);

Subquery<Long> subquery = query.subquery(Long.class);
Root<Document> subRoot = subquery.from(Document.class);
subquery.select(subRoot.<Long>get("id"));
Join<Document, Label> labelsJoin = subRoot.join("labels");  
subquery.where(labelsJoin.get("value").in("label1", "label2"));

query.where(cb.not(cb.in(root.get("id")).value(subquery)));

不過,您可能需要調整DocumentLabel之間的連接。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM