2

我的 Spring Data repository 方法的代码如下:

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();

}

如您所见,我试图以字节数组的形式获取shippingLabel列,该列在我的 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。org.hibernate.query.spi.StreamDecorator.findFirst(StreamDecorator.java:260)

我想知道这是否是这里的预期行为,提前感谢您的回答。

目前,解决方法是使用 JPA 2.1 变体:

返回 query.getResultList().stream().findFirst();

作为环境,我使用的是Spring Boot 2.3.3Hibernate版本是5.4.20

4

2 回答 2

3

先试试看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();
}

请注意,仅选择 N 条记录以使用fidFirst. 如果此查询返回 100 条记录怎么办?您仍然会从数据库中选择所有 100 个。

这就是我添加setMaxResults调用的原因。

如果这不起作用,请尝试调试 HibernateBinaryType并查看它为什么不返回byte[]

于 2020-09-25T07:39:57.533 回答
0

字节没有原始流,您可以在调试器中检查您获得的流类型可能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();

}

于 2020-09-25T07:36:02.383 回答