2016-09-15 85 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调用中的列表不起作用。你有没有发现与这件事有关的任何错误?我试图找到一些东西,但没有得到结果 –