java - JPA EclipseLink - 通过主键维护顺序获取多个对象

标签 java mysql sql jpa eclipselink

我使用 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/

相关文章:

java - 你如何在java中初始化一个字符串?

php - PHP 日期中的 SQL 查询

sql - Teradata 错误 3782 联接表的搜索条件中的列引用不正确

SQL Server 执行模拟

sql - 将查询中的数据插入表时,查询是否针对插入的每条记录运行?

Java加载文本文件

Java Robot MousePress() 在 Windows 任务管理器上不起作用

java - 在目录android中保存图像时出现空指针异常

mysql - 使用几乎相同的子查询优化 mySQL 查询

php - 如何计算表中的行数 (phpMyAdmin)