根据 JPA 2.2 支持 Java 8 日期/时间类型 JPA 支持 LocalDate。
查询单行,一切正常。但是当查询多行时,JPA 无法将其转换为列表。
我使用的是最新的 spring 版本 3.3.0
错误日志:
org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.util.ArrayList<?
>] to type [@org.springframework.data.jpa.repository.Query java.util.List<java.time.LocalDate>] for value
[[...]]
Caused by: org.springframework.core.convert.ConverterNotFoundException: No converter found capable of
converting from type [java.sql.Date] to type [@org.springframework.data.jpa.repository.Query
java.time.LocalDate]
at org.springframework.core.convert.support.GenericConversionService.handleConverterNotFound
(GenericConversionService.java:294)
测试实体.java
@Entity
public class TestEntity {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "id")
private Long id;
@Column(name = "TEST_DATE", columnDefinition = "DATE")
private LocalDate testDate;
// Setter Getters omitted for readability
}
TestRepository.java
public interface TestRepository extends CrudRepository<TestEntity, Long> {
@Query(value = "SELECT TEST_DATE FROM TEST_ENTITY", nativeQuery = true)
LocalDate findBy();
}
TestRepositoryList.java
public interface TestRepositoryList extends CrudRepository<TestEntity, Long> {
@Query(value = "SELECT TEST_DATE FROM TEST_ENTITY", nativeQuery = true)
List<LocalDate> findBy();
}
TestApplicationTests.java
// this works perfectly fine
@Test
void testFindBySingle() throws InterruptedException {
testRepository.save(new TestEntity(1L, LocalDate.now()));
log.info(String.valueOf(testRepository.findBy()));
}
// this fails
@Test
void testFindByList() {
testRepositoryList.save(new TestEntity(1L, LocalDate.now()));
testRepositoryList.save(new TestEntity(2L, LocalDate.now()));
log.info(String.valueOf(testRepositoryList.findBy()));
}
众所周知的问题是,当我们使用本机查询时,Spring 有时会抱怨转换器。我们不要讨论为什么会发生这种情况,而是集中讨论如何管理它。问题是我们不想从实体中获取所有字段,而只想获取其中的一部分。这种情况称为“投影”。这类似于使用数据库
view
而不是 select * from table
。有几种解决方案,但我喜欢使用 DTO 作为接口的解决方案。让我们开始。我们创建 DTO 作为带有特定注释的接口
@NamedNativeQuery(name = "TestEntityDTO.getTestDate",
query = "SELECT TEST_DATE FROM TEST_ENTITY",
resultSetMapping = "Mapping.date")
@SqlResultSetMapping(name = "Mapping.TestEntityDTO",
classes = @ConstructorResult(targetClass = TestEntityDTO.class,
columns = {@ColumnResult(name = "date")}))
public interface TestEntityDTO {
LocalDate getTestDate();
}
并修改我们的存储库
public interface TestRepositoryList extends CrudRepository<TestEntity, Long> {
@Query(nativeQuery = true)
List<TestEntityDTO> findBy();
}
注意我们将查询移至 DTO 注释 现在让我们写一个测试
@Test
void testFindByList() {
testRepositoryList.save(new TestEntity(1L, LocalDate.now()));
testRepositoryList.save(new TestEntity(2L, LocalDate.now()));
testRepositoryList.findBy().forEach(
e -> System.out.println(e.getTestDate())
);
}
结果是
2024-06-07
2024-06-07
您可以在 spring 文档和这篇好文章中阅读有关投影的更多信息 https://thorben-janssen.com/spring-data-jpa-dto-native-queries/