gpt4 book ai didi

java - 带有 CONCAT_WS 函数的 JPA CriteriaBuilder 抛出 NullPointerException

转载 作者:行者123 更新时间:2023-12-05 04:56:34 28 4
gpt4 key购买 nike

我有以下用于过滤订单的 CriteriaQuery。

CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<OrderReducedDTO> cq = cb.createQuery(OrderReducedDTO.class);

Root<Order> root = cq.from(Order.class);
Join<Order, Customer> joinCustomer = root.join(Order_.customer);
Join<Order, Shipment> joinShipment = root.join(Order_.shipment);
Join<Shipment, Carrier> joinCarrier = joinShipment.join(Shipment_.carrier);
Join<Order, Payment> joinPayment = root.join(Order_.payment);
Join<Payment, PaymentMethod> joinPaymentMethod = joinPayment.join(Payment_.paymentMethod);
Join<Shipment, Country> joinCountry = joinShipment.join(Shipment_.country);

cq.select(cb.construct(
OrderReducedDTO.class,
root.get(Order_.id),
root.get(Order_.incrementId),
root.get(Order_.state),
root.get(Order_.couponCode),
root.get(Order_.totalDiscount),
root.get(Order_.total),
root.get(Order_.originChannel),
root.get(Order_.branchOffice),
joinCarrier.get(Carrier_.carrierCode),
cb.function("CONCAT_WS", String.class,
cb.literal(","),
joinShipment.get(Shipment_.streetName),
joinShipment.get(Shipment_.streetNumber),
joinShipment.get(Shipment_.city),
joinCountry.get(Country_.name),
joinShipment.get(Shipment_.zipCode)
),
joinPaymentMethod.get(PaymentMethod_.code),
joinPayment.get(Payment_.paymentDate),
root.get(Order_.createdAt),
root.get(Order_.updatedAt),
root.get(Order_.externalId),
joinCustomer.get(Customer_.fullName)
));
... filters and predicates...

给我带来麻烦并导致抛出 NPE 的部分是这个

cb.function("CONCAT_WS", String.class,
cb.literal(","),
joinShipment.get(Shipment_.streetName),
joinShipment.get(Shipment_.streetNumber),
joinShipment.get(Shipment_.city),
joinCountry.get(Country_.name),
joinShipment.get(Shipment_.zipCode)
)

更具体地说,当我使用 CONCAT_WS 函数时。如果我使用 CONCAT,它会起作用。这是我得到的堆栈跟踪:

java.lang.NullPointerException: null
at org.hibernate.hql.internal.NameGenerator.generateColumnNames(NameGenerator.java:27)
at org.hibernate.hql.internal.ast.util.SessionFactoryHelper.generateColumnNames(SessionFactoryHelper.java:434)
at org.hibernate.hql.internal.ast.tree.SelectClause.initializeColumnNames(SelectClause.java:270)
at org.hibernate.hql.internal.ast.tree.SelectClause.finishInitialization(SelectClause.java:260)
at org.hibernate.hql.internal.ast.tree.SelectClause.initializeExplicitSelectClause(SelectClause.java:255)
at org.hibernate.hql.internal.ast.HqlSqlWalker.useSelectClause(HqlSqlWalker.java:1026)
...

这是我的 OrderReducedDTO

@Getter
public class OrderReducedDTO {

@JsonProperty("order_id")
private Integer orderId;

@JsonProperty("increment_id")
private String incrementId;

private OrderStates state;

@JsonProperty("coupon_code")
private String couponCode;

@JsonProperty("total_discount")
private BigDecimal totalDiscount;

private BigDecimal total;

@JsonProperty("origin_channel")
private String originChannel;

@JsonProperty("branch_office")
private String branchOffice;

@JsonProperty("shipping_method")
private String shippingMethod;

@JsonProperty("shipping_address")
private String shippingAddress;

@JsonProperty("payment_method")
private String paymentMethod;

@JsonProperty("payment_date")
private Timestamp paymentDate;

@JsonProperty("created_at")
private Timestamp createdAt;

@JsonProperty("updated_at")
private Timestamp updatedAt;

@JsonProperty("external_id")
private String externalId;

@JsonProperty("customer_full_name")
private String customerFullName;

@Setter
private List<OrderProductReducedDTO> products;

public OrderReducedDTO(Integer orderId,
String incrementId,
OrderStates state,
String couponCode,
BigDecimal totalDiscount,
BigDecimal total,
String originChannel,
String branchOffice,
String shippingMethod,
String shippingAddress,
String paymentMethod,
Object paymentDate,
Object createdAt,
Object updatedAt,
String externalId,
String customerFullName) {
this.orderId = orderId;
this.incrementId = incrementId;
this.state = state;
this.couponCode = couponCode;
this.totalDiscount = totalDiscount;
this.total = total;
this.originChannel = originChannel;
this.branchOffice = branchOffice;
this.shippingMethod = shippingMethod;
this.shippingAddress = shippingAddress;
this.paymentMethod = paymentMethod;
this.paymentDate = (Timestamp) paymentDate;
this.createdAt = (Timestamp) createdAt; //https://hibernate.atlassian.net/browse/HHH-4179
this.updatedAt = (Timestamp) updatedAt;
this.externalId = externalId;
this.customerFullName = customerFullName;
}
}

我主要想知道我是否正确使用了function 方法。我想我是因为 CONCAT 有效。

最佳答案

在 Hibernate 中调试了几个小时后,我终于找到了问题的根源:

org/hibernate/hql/internal/ast/tree/ConstructorNode.java

private Type[] resolveConstructorArgumentTypes() throws SemanticException {
SelectExpression[] argumentExpressions = this.collectSelectExpressions();
if (argumentExpressions == null) {
return new Type[0];
} else {
Type[] types = new Type[argumentExpressions.length];

for(int x = 0; x < argumentExpressions.length; ++x) {
types[x] = argumentExpressions[x].getDataType();
}

return types;
}
}

argumentExpressions[x].getDataType() 正在返回 null

我用谷歌搜索,发现这可能是由于 Hibernate 不知道给定 SQL 函数的实际返回类型(显然它只知道最常见的)。然后我关注了this answer并像这样实现了自定义 MetadataBuilderContributor:

public class SqlFunctionsMetadataBuilderContributor implements MetadataBuilderContributor {

@Override
public void contribute(MetadataBuilder metadataBuilder) {
metadataBuilder.applySqlFunction(
"concat_ws",
new StandardSQLFunction("concat_ws", StandardBasicTypes.STRING)
);
}
}

然后在我的 application.properties 中添加:

spring.jpa.properties.hibernate.metadata_builder_contributor=ar.com.glamit.glamitoms.config.hibernate.SqlFunctionsMetadataBuilderContributor

重新启动应用后,argumentExpressions[x].getDataType() 现在返回一个 StringType 并且 NullPointerException 消失了。

关于java - 带有 CONCAT_WS 函数的 JPA CriteriaBuilder 抛出 NullPointerException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64882431/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com