2016-09-15 61 views
0

我使用EclipseLink作爲JPA實現,我需要使用主鍵(數字ID)獲取多個對象。但我也需要維護給定的id順序。JPA EclipseLink - 通過主鍵維護訂單獲取多個對象

使用本機MySQL的這種行爲可以使用ORDER BY FIELD

SELECT id FROM table WHERE id IN(9,5,2,6) ORDER BY FIELD(id,9,5,2,6); 

我現在試圖複製使用JPA實施此查詢得到。從this thread已經建立,ORDER BY FIELD不支持,所以我去了一個更低層次的方法使用JPA native query

我嘗試使用參數查詢來實現此目標,而不是使用原始語句。第一個實現是這樣

Class<?> clazz = ...; 
List<Long> ids = ...; 

EntityManagerFactory emf = ...; 
EntityManager em = emf.createEntityManager(); 
String statement = "SELECT * FROM table WHERE id IN (?)"; 

Query createNativeQuery = em.createNativeQuery(statement, clazz); 
createNativeQuery.setParameter(1, ids); 
List resultList = createNativeQuery.getResultList(); 

正如你可以看到ORDER條款現在還沒有,第一步,我只是想用ids列表與IN操作人員進行參數查詢工作。在setParameter方法中,我嘗試提供List對象,逗號分隔列表(字符串),但它們都不起作用。最後,他們都完成了一個SQL語法錯誤。 我也試圖玩括號,有或沒有,但沒有任何作品。

這裏的一些測試我做

String statement = "SELECT * FROM " + tableName + " WHERE id IN (?)"; 
Query createNativeQuery = emJpa.createNativeQuery(statement, this.em.getClassObject()); 
createNativeQuery.setParameter(1, ids); 

查詢不給任何錯誤,但沒有結果給出。

String statement = "SELECT * FROM " + tableName + " WHERE id IN (?)"; 
Query createNativeQuery = emJpa.createNativeQuery(statement, this.em.getClassObject()); 
createNativeQuery.setParameter(1, Joiner.on(",").join(ids)); 

只有一個結果給出,但7個IDS是查詢

this topic我使用?1代替?也試過,但沒有改變提供。有沒有辦法使nativeQuery與ID列表工作?

就目前我使用的是完整的原始SQL語句

String joinedId = Joiner.on(",").join(ids); 
String statement = "SELECT * FROM " + tableName + " WHERE id IN (" + joinedId + ") ORDER BY FIELD(id," + joinedId + ")"; 
Query createNativeQuery = emJpa.createNativeQuery(statement, this.em.getClassObject()); 
createNativeQuery.getResultList(); 

但起初我開始與參數查詢,每次陳述解析的相關優化和性能。


編輯

隨着克里斯的建議,我嘗試使用FUNCTION操作(這是可用,因爲我使用的是最新的EclipseLink)一TypedQuery。在執行這個代碼

Local Exception Stack: 
Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.6.3.v20160428-59c81c5): org.eclipse.persistence.exceptions.DatabaseException 
Internal Exception: java.sql.SQLException: Operand should contain 1 column(s) 
Error Code: 1241 
Call: SELECT ... all the fields ... FROM webcontent_type WHERE (ID IN ((?,?,?,?,?,?,?))) ORDER BY FIELD(ID, (?,?,?,?,?,?,?)) 
    bind => [14 parameters bound] 
Query: ReadAllQuery(referenceClass=WebContentType sql="SELECT ... all the fields ... FROM webcontent_type WHERE (ID IN (?)) ORDER BY FIELD(ID, ?)") 

EDIT 2

嘗試沒有括號,但仍然有一個錯誤

這裏是生成的代碼

List<Long> ids = ...; 
Class<?> clazz = ...; 
String statement = "SELECT e FROM " + clazz.getSimpleName() + " e WHERE e.id IN (:idList) ORDER BY FUNCTION('FIELD', e.id, :idList)"; 

EntityManagerFactory emf = ...; 
EntityManager em = emf.createEntityManager(); 

TypedQuery<?> query = em.createQuery(statement, clazz); 
query.setParameter("idList", ids); 

List resultList = query.getResultList(); 

這裏是錯誤

SELECT e FROM FrameWorkUser e WHERE e.id IN :idList ORDER BY FUNCTION('FIELD', e.id, :idList) 

我必須說,有一個元素代碼工作的名單,但有10種元素的另一個列表有錯誤

javax.persistence.PersistenceException: Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.6.3.v20160428-59c81c5): org.eclipse.persistence.exceptions.DatabaseException 
Internal Exception: java.sql.SQLException: Operand should contain 1 column(s) 
Error Code: 1241 
Call: SELECT .... FROM webcontent_type WHERE (ID IN (?,?,?,?,?,?,?)) ORDER BY FIELD(ID, (?,?,?,?,?,?,?)) 
    bind => [14 parameters bound] 
Query: ReadAllQuery(referenceClass=WebContentType sql="SELECT .... FROM webcontent_type WHERE (ID IN ?) ORDER BY FIELD(ID, ?)") 
    at org.eclipse.persistence.internal.jpa.QueryImpl.getDetailedException(QueryImpl.java:382) 
    at org.eclipse.persistence.internal.jpa.QueryImpl.executeReadQuery(QueryImpl.java:260) 
    at org.eclipse.persistence.internal.jpa.QueryImpl.getResultList(QueryImpl.java:473) 

看來,即使W/O括號,所產生的語句有他們

+0

JPA本機查詢不支持集合,在這裏看到http://stackoverflow.com/questions/21484176/how-to-use-a-dynamic-parameter-in-a-in-子句的一個jpa命名查詢 – Guenther

+0

有沒有辦法將它作爲字符串加入列表綁定之前傳遞它作爲參數? –

回答

1

如果您打算使用本機查詢,您必須完全按照您爲數據庫構成SQL的方式來執行此操作 - 這意味着您必須將列表分解爲其組件參數,因爲JPA提供程序不需要更改SQL您。儘管大多數提供程序處理JPQL中的列表,所以「從e.id in(:idList)」中的Entity e中選擇e將在EclipseLink中工作。

你的缺失是'FIELD'不是JPQL結構。爲此,您將不得不使用JPQL 2.1 FUNCTION運算符。喜歡的東西:

"Select e from Entity e where e.id in :idList order by FUNCTION('FIELD', e.id, :idList)" 
+0

我試過你建議的代碼(我不知道'FUNCTION'子句)。您可以在主要問題中閱讀結果,我在底部添加新章節 –

+0

我的錯誤和我已經稍微更正了答案:請勿在JPQL中使用()。它應該是「in:idList」。您可能仍然需要分解FUNCTION調用的列表,或者查看EclipseLink的調用來解決它的問題 - 我不再使用源代碼了,所以我建議您查看錯誤看看是否有可能有解決方法。 – Chris

+0

我刪除了括號,但有相同的錯誤(請參閱主要問題上的EDIT2)。正如你所建議的,FUNCTION調用中的列表不起作用。你有沒有發現與這件事有關的任何錯誤?我試圖找到一些東西,但沒有得到結果 –