问题描述
public Optional<byte[]> findShipmentLabelByClientIdAndAwb(String clientId,String awb) {
String queryString = "select g.shipmentLabel as shipmentLabel from GenericShipment g where g.client.id = :clientId and g.shipmentId = :awb " +
" AND (g.processingStatus is null or g.processingStatus <> 'DELETED') AND g.shipmentLabel is not null";
val query = entityManager.createquery(queryString,byte[].class);
query.setParameter("clientId",clientId);
query.setParameter("awb",awb);
return query.getResultStream().findFirst();
}
如您所见,我试图获取 shipmentLabel 列(在我的Postgres模式中定义为 bytea )作为字节数组。 运行时会发生以下异常:
java.lang.classCastException:[无法将B强制转换为[Ljava.lang.Object ; 在org.hibernate.internal.ScrollableResultsImpl.prepareCurrentRow(ScrollableResultsImpl.java:203) 在org.hibernate.internal.ScrollableResultsImpl.next(ScrollableResultsImpl.java:101) 在org.hibernate.query.internal.ScrollableResultsIterator.hasNext(ScrollableResultsIterator.java:33) 在java.util.Spliterators $ IteratorSpliterator.tryAdvance(Spliterators.java:1811) 在java.util.stream.ReferencePipeline.forEachWithCancel(ReferencePipeline.java:126) 在java.util.stream.AbstractPipeline.copyIntoWithCancel(AbstractPipeline.java:499) 在java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:486) 在java.util.stream.AbstractPipeline.wrapAndcopyInto(AbstractPipeline.java:472) 在java.util.stream.FindOps $ FindOp.evaluateSequential(FindOps.java:152) 在java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) 在java.util.stream.ReferencePipeline.findFirst(ReferencePipeline.java:531) 在 org.hibernate.query.spi.StreamDecorator.findFirst(StreamDecorator.java:260)
我想知道这是否是预期的行为,在此先感谢您的回答。
目前,解决方法是使用JPA 2.1变体:
返回query.getResultList()。stream()。findFirst();
作为环境,我正在使用 Spring Boot 2.3.3 ,休眠版本是 5.4.20 。
解决方法
首先尝试使用getResultList
,然后查看是否有效:
public Optional<Byte[]> findShipmentLabelByClientIdAndAwb(
String clientId,String awb) {
return entityManager.createQuery("""
select
g.shipmentLabel as shipmentLabel
from GenericShipment g
where
g.client.id = :clientId and
g.shipmentId = :awb and
(
g.processingStatus is null or
g.processingStatus <> 'DELETED'
) and
g.shipmentLabel is not null
""")
.setParameter("clientId",clientId)
.setParameter("awb",awb)
.setMaxResults(1)
.getResultList()
.stream()
.findFirst();
}
请注意,仅使用fidFirst
仅选择N条记录作为第一条记录是没有效率的。如果该查询返回100条记录怎么办?您仍然需要从数据库中选择所有100个。
这就是为什么我添加了setMaxResults
呼叫的原因。
如果这不起作用,请尝试调试Hibernate BinaryType
,并查看为什么它不返回byte[]
。
没有用于字节的原始流,您可以在调试器中检查可能正在使用Stream<Byte[]>
或Stream<Object[]>
的哪种类型的流。这可以解释您遇到的异常。使用Byte []应该可以解决您的问题。
public Optional<Byte[]> findShipmentLabelByClientIdAndAwb(String clientId,String awb) {
String queryString = "select g.shipmentLabel as shipmentLabel from GenericShipment g where g.client.id = :clientId and g.shipmentId = :awb " +
" AND (g.processingStatus is null or g.processingStatus <> 'DELETED') AND g.shipmentLabel is not null";
val query = entityManager.createQuery(queryString,Byte[].class);
query.setParameter("clientId",clientId);
query.setParameter("awb",awb);
return query.getResultStream().findFirst();
}