我使用EclipseLink作为JPA实现,我需要使用主键(数字id)获取多个对象。但我还需要保持给定的id顺序。
使用本机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个ID
从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();
但首先我开始使用参数查询进行优化,并在每次语句解析时都与性能相关。
修改
根据 Chris 的建议,我使用FUNCTION
运算符尝试了一个TypedQuery(因为我使用了最新的EclipseLink
,所以可以使用它)。这是结果代码
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();
这是执行此代码时的错误
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, ?)")
编辑2
尝试没有括号,但仍然有错误
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)
似乎即使没有括号,结果语句也有它们
答案 0 :(得分:1)
如果要使用本机查询,则必须完全像为数据库构建SQL一样 - 这意味着必须将列表拆分为其组件参数,因为JPA提供程序不应更改SQL您。大多数提供者处理JPQL中的列表,因此&#34;从实体e中选择e,其中e.id在(:idList)&#34;将在EclipseLink中工作。
你遗漏的是&#39; FIELD&#39;不是JPQL构造。为此,您必须使用JPQL 2.1 FUNCTION运算符。类似的东西:
"Select e from Entity e where e.id in :idList order by FUNCTION('FIELD', e.id, :idList)"