我使用 EclipseLink 作为 JPA 实现,并且需要使用主键(数字 ID)获取多个对象。但我还需要维护给定的 id 顺序。
使用 native 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 查询
的更底层方法。
我尝试使用参数查询来实现此目标,而不是使用原始语句。第一次实现是这样的
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)
似乎即使没有括号,结果语句也有它们
最佳答案
如果您要使用 native 查询,则必须像为数据库形成 SQL 一样进行操作 - 这意味着您必须将列表分解为其组件参数,因为 JPA 提供程序不会更改 SQL你。不过,大多数提供程序都在 JPQL 中处理列表,因此“从实体 e 中选择 e,其中 (:idList) 中的 e.id”将在 EclipseLink 中工作。
您缺少的一点是“FIELD”不是 JPQL 构造。为此,您必须使用 JPQL 2.1 FUNCTION运算符(operator)。类似于:
"Select e from Entity e where e.id in :idList order by FUNCTION('FIELD', e.id, :idList)"
关于java - JPA EclipseLink - 通过主键维护顺序获取多个对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39506853/