我需要使用以下實體構造一個相交類型的查詢(爲了清楚起見而減少)。JPA Criteria API任意數量的連接/子查詢
@Entity // and other @ stuff
public class Member {
@Id
private Long id;
private String name;
...
}
@Entity
public class Program {
@Id
private Long id;
private Long programName;
private List<ProgramLevel> levels;
...
}
@Entity
public class ProgramLevel {
@Id
private Long id
private String levelName;
}
成員可以屬於一個或多個程序,而且他總有他的計劃層面,這個連接:
public class Membership {
@Id
private Long id;
private Long memberId; // this is the member
private Long programId; // in which program is he
private Long programLevel; // and on what level
...
}
例子:我有三個項目,數學,英語,科學。他們每個人都有一定的層次,如:有代數,幾何,英文有文學,拼寫和語法,科學有實驗和理論。
另外,示例用戶Joe將具有Math:代數,英語:語法程序和級別。用戶示例Max可能會有英文:文學。所以,會員可以有多個節目,但每個節目只有一個級別。
現在我需要計算或獲取匹配幾個程序和其中某些級別的所有成員。 示例:我希望所有擁有數學:代數或幾何的用戶,以及英文:文學或語法和科學:理論。
我並不是真的進入JPA的東西,所以我陷入困境。
在SQL中,我會做一個相交。我如何與JPA做到這一點?
我有這樣的事情:
HashMap<Long, List<ProgramLevel>> levels = new HashMap<Long, List<ProgramLevel>>();
// then I fetch the levels map.
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<Long> criteriaQuery = cb.createQuery(Long.class);
Root<Membership> root = query.from(Membership.class);
// this is the part where I'm stuck.
// I figured I could try with multiple inner joins?
for(Map.Entry<Long, List<ProgramLevel>> curentLevel: levels.entrySet()) {
// cb.equal(root.join ??? what comes here?
// what what what?
// root.get("programId") = currentLevel.getKey()
// AND root.get("programLevelId") IN currentLevel.getValue()
}
...
我該如何獲得呢?
除了做爲多個內部連接,我不知道它是否可以做INTERSECT(db是PostgreSQL,如果它很重要)?
此外,我不知道在那個查詢中,我會把條件只讓我與這些條件不同的成員資格。作爲獎勵,我將不得不創建一個OR查詢。這是我必須匹配所有程序的地方,下一個需要任何程序/級別匹配才能包含在其中。但是一旦我認識到這一點,我希望能夠自己找出一個。
編輯:可能的(僞)SQL選擇會是什麼樣子:
SELECT count(membership) FROM membership m
WHERE (m.program == :program1 and m.programLevel in :programLevels1ArrayOfLevels)
INTERSECT
SELECT count(membership) FROM membership m
WHERE (m.program == :program2 and m.programLevel in :programLevels2ArrayOfLevels)
INTERSECT...
... /* this would go on for as many (Program, List<ProgramLevel>) pairs I have on input. Which is variable).
或者是這樣的:
SELECT count(membership) FROM membership m
JOIN membership m1 ON (m1.program = :program1 AND m1.programLevel IN m1.programLevels1Aray)
JOIN membership m2 ON (m2.program = :program2 AND m2.programLevel IN m1.programLevels2Aray)
/* Continued to as many input pairs I have */
您通常會通過使用不同的別名多次連接同一個表來完成此操作。 JPA應該提供一種方法來做到這一點,但我現在已經有一段時間沒有必要使用它或Criteria API了,所以我會指向大致正確的方向,然後逃離山峯尖叫。 –
嗯。我怎麼去命名這些連接呢?因爲我不知道他們中有多少人。我不知道它是否顯示,但Java是我的第二語言:) – Zlatko
你可以發佈一個[小提琴](http://sqlfiddle.com/)或什麼你想要的SQL?你還需要多少個可能的連接。如果你只是變量的值的列表,你可以通過循環的值列表來實現類似於[this](http://stackoverflow.com/questions/403336/getting-a-query-intersection-in-jpa)的東西使用Criteria API按需創建聯接。這樣你也可以根據需要使用別名(例如'q1','q2','q3','qn')。 –