Spring 使用 Projection 的 JPA 本机查询给出 "ConverterNotFoundException"
Spring JPA native query with Projection gives "ConverterNotFoundException"
我正在使用 Spring JPA,我需要一个本机查询。通过该查询,我只需要从 table 中获取两个字段,因此我尝试使用 Projections。它不起作用,这是我收到的错误:
org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type [org.springframework.data.jpa.repository.query.AbstractJpaQuery$TupleConverter$TupleBackedMap] to type [com.example.IdsOnly]
我试图严格按照我链接的那个页面的说明进行操作,我试图让我的查询成为非本地的(顺便说一句,如果我使用投影,我真的需要它是本地的吗?),但我总是明白错误。
如果我使用一个接口,它可以工作,但结果是代理,我真的需要它们是 "normal results",我可以把它们变成 json。
所以,这是我的代码。实体:
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@Entity
@Table(name = "TestTable")
public class TestTable {
@Id
@Basic(optional = false)
@GeneratedValue(strategy = GenerationType.SEQUENCE)
@Column(name = "Id")
private Integer id;
@Column(name = "OtherId")
private String otherId;
@Column(name = "CreationDate")
@Temporal(TemporalType.TIMESTAMP)
private Date creationDate;
@Column(name = "Type")
private Integer type;
}
投影的class:
import lombok.Value;
@Value // This annotation fills in the "hashCode" and "equals" methods, plus the all-arguments constructor
public class IdsOnly {
private final Integer id;
private final String otherId;
}
存储库:
public interface TestTableRepository extends JpaRepository<TestTable, Integer> {
@Query(value = "select Id, OtherId from TestTable where CreationDate > ?1 and Type in (?2)", nativeQuery = true)
public Collection<IdsOnly> findEntriesAfterDate(Date creationDate, List<Integer> types);
}
以及尝试获取数据的代码:
@Autowired
TestTableRepository ttRepo;
...
Date theDate = ...
List<Integer> theListOfTypes = ...
...
Collection<IdsOnly> results = ttRepo.findEntriesAfterDate(theDate, theListOfTypes);
感谢您的帮助。我真的不明白我做错了什么。
查询应该使用 constructor expression:
@Query("select new com.example.IdsOnly(t.id, t.otherId) from TestTable t where t.creationDate > ?1 and t.type in (?2)")
而且我不了解 Lombok,但请确保有一个将这两个 ID 作为参数的构造函数。
JPA 2.1 引入了一个有趣的 ConstructorResult 特性,如果您想保留它 native。
使用 spring 数据,您可以切断中间人并简单地定义
public interface IdsOnly {
Integer getId();
String getOtherId();
}
并使用像这样的本机查询;
@Query(value = "Id, OtherId from TestTable where CreationDate > ?1 and Type in (?2)", nativeQuery = true)
public Collection<IdsOnly> findEntriesAfterDate(Date creationDate, List<Integer> types);
查看 https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#projections
您可以 return 对象数组 (List) 列表作为存储库 class 中本机查询方法的 return 类型。
@Query(
value = "SELECT [type],sum([cost]),[currency] FROM [CostDetails] " +
"where product_id = ? group by [type],[currency] ",
nativeQuery = true
)
public List<Object[]> getCostDetailsByProduct(Long productId);
for(Object[] obj : objectList){
String type = (String) obj[0];
Double cost = (Double) obj[1];
String currency = (String) obj[2];
}
@Query(value = "select isler.saat_dilimi as SAAT, isler.deger as DEGER from isler where isler.id=:id", nativeQuery = true)
List<Period> getById(@Param("id") Long id);
public interface Period{
Long getDEGER();
Long getSAAT();
}
如上面给出的本机查询的示例代码所示,将 return 值转换为任何值,如“SAAT”、“DEGER”,然后定义具有 getDEGER() 和 getSAAT 的接口“period” ().即使我不明白为什么 get 之后的参数必须是大写的,但在小写的情况下它不能正常工作。 IE。与 getDeger()、getSaat() 的接口在我的情况下无法正常工作。
我正在使用 Spring JPA,我需要一个本机查询。通过该查询,我只需要从 table 中获取两个字段,因此我尝试使用 Projections。它不起作用,这是我收到的错误:
org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type [org.springframework.data.jpa.repository.query.AbstractJpaQuery$TupleConverter$TupleBackedMap] to type [com.example.IdsOnly]
我试图严格按照我链接的那个页面的说明进行操作,我试图让我的查询成为非本地的(顺便说一句,如果我使用投影,我真的需要它是本地的吗?),但我总是明白错误。
如果我使用一个接口,它可以工作,但结果是代理,我真的需要它们是 "normal results",我可以把它们变成 json。
所以,这是我的代码。实体:
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@Entity
@Table(name = "TestTable")
public class TestTable {
@Id
@Basic(optional = false)
@GeneratedValue(strategy = GenerationType.SEQUENCE)
@Column(name = "Id")
private Integer id;
@Column(name = "OtherId")
private String otherId;
@Column(name = "CreationDate")
@Temporal(TemporalType.TIMESTAMP)
private Date creationDate;
@Column(name = "Type")
private Integer type;
}
投影的class:
import lombok.Value;
@Value // This annotation fills in the "hashCode" and "equals" methods, plus the all-arguments constructor
public class IdsOnly {
private final Integer id;
private final String otherId;
}
存储库:
public interface TestTableRepository extends JpaRepository<TestTable, Integer> {
@Query(value = "select Id, OtherId from TestTable where CreationDate > ?1 and Type in (?2)", nativeQuery = true)
public Collection<IdsOnly> findEntriesAfterDate(Date creationDate, List<Integer> types);
}
以及尝试获取数据的代码:
@Autowired
TestTableRepository ttRepo;
...
Date theDate = ...
List<Integer> theListOfTypes = ...
...
Collection<IdsOnly> results = ttRepo.findEntriesAfterDate(theDate, theListOfTypes);
感谢您的帮助。我真的不明白我做错了什么。
查询应该使用 constructor expression:
@Query("select new com.example.IdsOnly(t.id, t.otherId) from TestTable t where t.creationDate > ?1 and t.type in (?2)")
而且我不了解 Lombok,但请确保有一个将这两个 ID 作为参数的构造函数。
JPA 2.1 引入了一个有趣的 ConstructorResult 特性,如果您想保留它 native。
使用 spring 数据,您可以切断中间人并简单地定义
public interface IdsOnly {
Integer getId();
String getOtherId();
}
并使用像这样的本机查询;
@Query(value = "Id, OtherId from TestTable where CreationDate > ?1 and Type in (?2)", nativeQuery = true)
public Collection<IdsOnly> findEntriesAfterDate(Date creationDate, List<Integer> types);
查看 https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#projections
您可以 return 对象数组 (List) 列表作为存储库 class 中本机查询方法的 return 类型。
@Query(
value = "SELECT [type],sum([cost]),[currency] FROM [CostDetails] " +
"where product_id = ? group by [type],[currency] ",
nativeQuery = true
)
public List<Object[]> getCostDetailsByProduct(Long productId);
for(Object[] obj : objectList){
String type = (String) obj[0];
Double cost = (Double) obj[1];
String currency = (String) obj[2];
}
@Query(value = "select isler.saat_dilimi as SAAT, isler.deger as DEGER from isler where isler.id=:id", nativeQuery = true)
List<Period> getById(@Param("id") Long id);
public interface Period{
Long getDEGER();
Long getSAAT();
}
如上面给出的本机查询的示例代码所示,将 return 值转换为任何值,如“SAAT”、“DEGER”,然后定义具有 getDEGER() 和 getSAAT 的接口“period” ().即使我不明白为什么 get 之后的参数必须是大写的,但在小写的情况下它不能正常工作。 IE。与 getDeger()、getSaat() 的接口在我的情况下无法正常工作。