我有一个Spring-Boot应用程序,它有一些使用内容投影的本机查询。它在生产中运行Postgres并且工作正常。我正在尝试使用@DataJpaTest
和h2内存数据库为存储库设置集成测试,但是我使用内容投影的查询因驱动程序中的JdbcSQLException而失败:
org.h2.jdbc.JdbcSQLException:列数不匹配
我成功保存到TestEntityManager,因此数据库中有记录,但我无法通过存储库方法调用SELECT。它在Postgres的生产中正常工作 - 这是对h2的限制,是否有我可以应用的解决方法,所以我可以正确测试这个?
存储库方法看起来像这样(一个内连接,where子句中的两个参数,更改了表名和列以保护有罪):
public interface OrderRepository extends PagingAndSortingRepository<Order, Long> {
@Query(nativeQuery = true,
value = "SELECT order.id, order.total, pizza.name " +
"FROM example.order " +
"INNER JOIN example.pizza USING (pizza_id) " +
"WHERE order.customer_id = :custId " +
"AND order.order_date = :orderDate ",
countQuery = "SELECT count(order.id) " +
"FROM example.order " +
"INNER JOIN example.pizza USING (pizza_id) " +
"WHERE order.customer_id = :custId " +
"AND order.order_date = :orderDate")
<T> Page<T> findAllByCustIdAndOrderDate(String custId, OffsetDateTime orderDate, Pageable paging, Class<T> type);
}
投影看起来像这样:
public interface PizzaOrderProjection {
Long getId();
Double getTotal();
String getName();
}
当我调用findAllByCustIdAndOrderDate
时会触发异常,并且它打印的SQL语句导致它是SELECT。它打印的SELECT看起来非常正常:
Hibernate:
/* dynamic native SQL query */ SELECT
order.id,
order.total,
pizza.name
FROM
example.order
INNER JOIN
example.pizza USING (pizza_id)
WHERE
order.customer_id = ?
AND order.order_date = ? limit ?
2019-04-09 12:42:18.704 WARN 17568 --- [ main] o.h.engine.jdbc.spi.SqlExceptionHelper : SQL Error: 21002, SQLState: 21S02
2019-04-09 12:42:18.708 ERROR 17568 --- [ main] o.h.engine.jdbc.spi.SqlExceptionHelper : Column count does not match; SQL statement:
事实证明,错误消息实际上与底层问题无关。
H2数据库不支持using
子句中的inner join
关键字,仅支持on
关键字。
通过将内部联接更改为使用on
来解决此问题,如下所示:
public interface OrderRepository extends PagingAndSortingRepository<Order, Long> {
@Query(nativeQuery = true,
value = "SELECT order.id, order.total, pizza.name " +
"FROM example.order " +
"INNER JOIN example.pizza ON order.pizza_id = pizza.pizza_id " +
"WHERE order.customer_id = :custId " +
"AND order.order_date = :orderDate ",
countQuery = "SELECT count(order.id) " +
"FROM example.order " +
"INNER JOIN example.pizza ON order.pizza_id = pizza.pizza_id " +
"WHERE order.customer_id = :custId " +
"AND order.order_date = :orderDate")
<T> Page<T> findAllByCustIdAndOrderDate(String custId, OffsetDateTime orderDate, Pageable paging, Class<T> type);
}
此更改使查询在postgres和h2中都有效。