我知道我可以在JPA中将列表传递给命名查询,但NamedNativeQuery怎么样?我尝试了很多方法,但仍然无法将列表传递给NamedNativeQuery。任何人都知道如何将列表传递给NamedNativeQuery中的in子句?非常感谢你!
NamedNativeQuery如下:
@NamedNativeQuery(
name="User.findByUserIdList",
query="select u.user_id, u.dob, u.name, u.sex, u.address from user u "+
"where u.user_id in (?userIdList)"
)
就像这样调用:
List<Object[]> userList = em.createNamedQuery("User.findByUserIdList").setParameter("userIdList", list).getResultList();
然而,结果并不像我预期的那样。
System.out.println(userList.size()); //output 1
Object[] user = userList.get(0);
System.out.println(user.length); //expected 5 but result is 3
System.out.println(user[0]); //output MDAVERSION which is not a user_id
System.out.println(user[1]); //output 5
System.out.println(user[2]); //output 7
答案 0 :(得分:16)
列表不是本机SQL查询的有效参数,因为它不能绑定在JDBC中。您需要为列表中的每个参数设置一个参数。
其中u.user_id在(?id1,?id2)
这是通过JPQL支持的,但不支持SQL,因此您可以使用JPQL而不是本机查询。
某些JPA提供商可能会支持此功能,因此您可能希望记录提供商的错误。
答案 1 :(得分:6)
以上接受的答案不正确,让我偏离了很多天!!
JPA和Hibernate都使用Query接受本机查询中的集合。
你只需要做
String nativeQuery = "Select * from A where name in :names"; //use (:names) for older versions of hibernate
Query q = em.createNativeQuery(nativeQuery);
q.setParameter("names", l);
同时参考这里提出相同的答案(我从其中一个中选择了上面的例子)
答案 2 :(得分:3)
根据您的数据库/提供程序/驱动程序/等,您实际上可以将列表作为绑定参数传递给JPA本机查询。
例如,使用Postgres和EclipseLink,以下工作(返回true),演示多维数组以及如何获得双精度数组。 (对于其他类型,请SELECT pg_type.* FROM pg_catalog.pg_type
;可能是_
的那些类型,但在使用之前将其删除。)
Array test = entityManager.unwrap(Connection.class).createArrayOf("float8", new Double[][] { { 1.0, 2.5 }, { 4.1, 5.0 } });
Object result = entityManager.createNativeQuery("SELECT ARRAY[[CAST(1.0 as double precision), 2.5],[4.1, 5.0]] = ?").setParameter(1, test).getSingleResult();
强制转换就在那里,因此文字数组是双精度数而不是数字数。
更多问题的关键点 - 我不知道您是否可以执行命名查询;我认为这取决于,也许。但我认为以下内容适用于Array的内容。
Array list = entityManager.unwrap(Connection.class).createArrayOf("int8", arrayOfUserIds);
List<Object[]> userList = entityManager.createNativeQuery("select u.* from user u "+
"where u.user_id = ANY(?)")
.setParameter(1, list)
.getResultList();
我没有与OP相同的架构,所以我没有完全检查过这个,但我认为它应该可行 - 至少在Postgres&amp;的EclipseLink。
此外,密钥位于:http://tonaconsulting.com/postgres-and-multi-dimensions-arrays-in-jdbc/
答案 3 :(得分:1)
在JPA2中尝试使用Hibernate作为提供程序,似乎hibernate确实支持列入“IN”并且它可以工作。 (至少对于命名查询,我相信它与命名的NATIVE查询类似) 内部hibernate在内部生成动态参数,在IN内部与传入列表中的元素数相同。
所以在上面的例子中
List<Object[]> userList = em.createNamedQuery("User.findByUserIdList").setParameter("userIdList", list).getResultList();
如果list包含2个元素,则查询将如下所示
select u.user_id, u.dob, u.name, u.sex, u.address from user u "+
"where u.user_id in (?, ?)
如果它有3个元素,它看起来像
select u.user_id, u.dob, u.name, u.sex, u.address from user u "+
"where u.user_id in (?, ?, ?)
答案 4 :(得分:0)
使用hibernate,JPA 2.1和deltaspike数据我可以在包含IN子句的查询中将列表作为参数传递。我的询问如下。
@Query(value = "SELECT DISTINCT r.* FROM EVENT AS r JOIN EVENT AS t on r.COR_UUID = t.COR_UUID where " +
"r.eventType='Creation' and t.eventType = 'Reception' and r.EVENT_UUID in ?1", isNative = true)
public List<EventT> findDeliveredCreatedEvents(List<String> eventIds);
答案 5 :(得分:0)
当前,我在Hibernate中使用JPA 2.1
我还对本地查询使用IN条件。我的查询示例
SELECT ... WHERE table_name.id IN (?1)
我注意到由于James
所述的限制,无法传递“ id_1,id_2,id_3”之类的字符串但是当您使用jpa 2.1 +休眠模式时,可以传递字符串值列表。就我而言,下一个代码有效:
List<String> idList = new ArrayList<>();
idList.add("344710");
idList.add("574477");
idList.add("508290");
query.setParameter(1, idList);
答案 6 :(得分:0)
在我的情况下(EclipseLink,PostGreSQL),此方法有效:
ServerSession serverSession = this.entityManager.unwrap(ServerSession.class);
Accessor accessor = serverSession.getAccessor();
accessor.reestablishConnection(serverSession);
BigDecimal result;
try {
Array jiraIssues = accessor.getConnection().createArrayOf("numeric", mandayWorkLogQueryModel.getJiraIssues().toArray());
Query nativeQuery = this.entityManager.createNativeQuery(projectMandayWorkLogQueryProvider.provide(mandayWorkLogQueryModel));
nativeQuery.setParameter(1,mandayWorkLogQueryModel.getPsymbol());
nativeQuery.setParameter(2,jiraIssues);
nativeQuery.setParameter(3,mandayWorkLogQueryModel.getFrom());
nativeQuery.setParameter(4,mandayWorkLogQueryModel.getTo());
result = (BigDecimal) nativeQuery.getSingleResult();
} catch (Exception e) {
throw new DataAccessException(e);
}
return result;
查询中也不能使用IN(?),因为您会得到类似:
的错误由以下原因引起:org.postgresql.util.PSQLException:错误:运算符不存在:数字=数字[]
'IN(?)'必须交换为'= ANY(?)'
我的解决方案基于Erhannis概念。
答案 7 :(得分:0)
可以很简单:
@Query(nativeQuery =true,value = "SELECT * FROM Employee as e WHERE e.employeeName IN (:names)")
List<Employee> findByEmployeeName(@Param("names") List<String> names);
答案 8 :(得分:0)
在 jpa 中,它对我有用
@Query(nativeQuery =true,value = "SELECT * FROM Employee as e WHERE e.employeeName IN (:names)")
List<Employee> findByEmployeeName(@Param("names") List<String> names);
答案 9 :(得分:0)
你应该这样做:
String userIds ="1,2,3,4,5";
List<String> userIdList= Stream.of(userIds.split(",")).collect(Collectors.toList());
然后,在您的查询中传递类似参数,如下所示:
@NamedNativeQuery(name="User.findByUserIdList", query="select u.user_id, u.dob, u.name, u.sex, u.address from user u where u.user_id in (?userIdList)")
答案 10 :(得分:-1)
使用标准JPA是不可能的。 Hibernate提供了专有方法setParameterList()
,但是它仅适用于Hibernate会话,在JPA的EntityManager
中不可用。
我想出了以下针对Hibernate的解决方法,该解决方法并不理想,但几乎是标准的JPA代码,并且具有一些不错的属性。
对于初学者,您可以将命名的本机查询很好地分隔在orm.xml
文件中:
<named-native-query name="Item.FIND_BY_COLORS" result-class="com.example.Item">
<query>
SELECT i.*
FROM item i
WHERE i.color IN ('blue',':colors')
AND i.shape = :shape
</query>
</named-native-query>
占位符用单引号引起来,因此它是有效的本机JPA查询。它运行时无需设置参数列表,并且在其周围设置了其他匹配的颜色参数后仍会返回正确的结果。
在您的DAO或存储库类中设置参数列表:
@SuppressWarnings("unchecked")
public List<Item> findByColors(List<String> colors) {
String sql = getQueryString(Item.FIND_BY_COLORS, Item.class);
sql = setParameterList(sql, "colors", colors);
return entityManager
.createNativeQuery(sql, Item.class)
.setParameter("shape", 'BOX')
.getResultList();
}
没有手动构造查询字符串。您可以像往常一样设置任何其他参数。
Helper方法:
String setParameterList(String sql, String name, Collection<String> values) {
return sql.replaceFirst(":" + name, String.join("','", values));
}
String getQueryString(String queryName, Class<?> resultClass) {
return entityManager
.createNamedQuery(queryName, resultClass)
.unwrap(org.hibernate.query.Query.class) // Provider specific
.getQueryString();
}
因此,基本上,我们是从orm.xml
中读取查询字符串,手动设置参数列表,然后创建本机JPA查询。不幸的是,createNativeQuery().getResultList()
返回了无类型查询和无类型列表,即使我们向其传递了结果类也是如此。因此,@SuppressWarnings("unchecked")
。
缺点:对于非Hibernate的JPA提供程序,不执行查询就展开查询可能会更复杂或更不可能。例如,以下可能适用于EclipseLink(未经测试,取自Can I get the SQL string from a JPA query object?):
Session session = em.unwrap(JpaEntityManager.class).getActiveSession();
DatabaseQuery databaseQuery = query.unwrap(EJBQueryImpl.class).getDatabaseQuery();
databaseQuery.prepareCall(session, new DatabaseRecord());
Record r = databaseQuery.getTranslationRow();
String bound = databaseQuery.getTranslatedSQLString(session, r);
String sqlString = databaseQuery.getSQLString();
另一种选择是将查询存储在文本文件中,然后添加代码以从中读取查询。
答案 11 :(得分:-3)
您可以尝试使用:userIdList 而不是(?userIdList)
@NamedNativeQuery(
name="User.findByUserIdList",
query="select u.user_id, u.dob, u.name, u.sex, u.address from user u "+
"where u.user_id in :userIdList"
)