带有Projection的Spring JPA原生查询给出了"ConverterNotFoundException"

non*_*rej 11 java spring projection spring-data-jpa

我正在使用Spring JPA,我需要一个原生查询.有了这个查询,我只需要从表中获得两个字段,所以我正在尝试使用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]
Run Code Online (Sandbox Code Playgroud)

我试图准确地遵循我链接的那个页面的说明,我试图让我的查询非原生(我实际上需要它是原生的,如果我使用投影,顺便说一句?),但我总是得到那个错误.
如果我使用一个接口它可以工作,但结果是代理,我真的需要它们是"正常结果",我可以变成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;
}
Run Code Online (Sandbox Code Playgroud)

投影类:

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;
}
Run Code Online (Sandbox Code Playgroud)

存储库:

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);
}
Run Code Online (Sandbox Code Playgroud)

以及试图获取数据的代码:

@Autowired
TestTableRepository ttRepo;
...
    Date theDate = ...
    List<Integer> theListOfTypes = ...
    ...
    Collection<IdsOnly> results = ttRepo.findEntriesAfterDate(theDate, theListOfTypes);  
Run Code Online (Sandbox Code Playgroud)

谢谢您的帮助.我真的不明白我做错了什么.

Rob*_*roj 10

查询应该使用构造函数表达式:

@Query("select new com.example.IdsOnly(t.id, t.otherId) from TestTable t where t.creationDate > ?1 and t.type in (?2)")
Run Code Online (Sandbox Code Playgroud)

我不知道Lombok,但确保有一个构造函数将两个ID作为参数.

  • 评论:解决方案不适用于nativeQuery (6认同)
  • 问题是针对本机查询的 (2认同)

sha*_*haf 10

借助弹簧数据,您可以削减中间人并简单地定义

public interface IdsOnly {
  Integer getId();
  String getOtherId();
}
Run Code Online (Sandbox Code Playgroud)

并使用本机查询,例如;

@Query(value = "Id, OtherId from TestTable where CreationDate > ?1 and Type in (?2)", nativeQuery = true)
    public Collection<IdsOnly> findEntriesAfterDate(Date creationDate, List<Integer> types);
Run Code Online (Sandbox Code Playgroud)

查看https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#projections


Mon*_*éhi 6

如果您想保持原生, JPA 2.1 引入了一个有趣的ConstructorResult特性。

  • 除了在 JPA 实体上提供提到的“SqlResultSetMapping”和“ConstructorResult”,然后直接在“EntityManager”上执行查询之外,我还发现没有办法让我的本机 SQL 查询结果映射到自定义类型。因此不幸的是,鉴于这些约束(本机查询 + 自定义投影),无法使用 Spring Data 的 `@Query` 注释。 (3认同)

小智 5

您可以返回对象数组(列表)列表作为存储库类中本机查询方法的返回类型。

@Query(
            value = "SELECT [type],sum([cost]),[currency] FROM [CostDetails] " +
                    "where product_id = ? group by [type],[currency] ",
            nativeQuery = true
    )
    public List<Object[]> getCostDetailsByProduct(Long productId);
Run Code Online (Sandbox Code Playgroud)
for(Object[] obj : objectList){
     String type = (String) obj[0];
     Double cost = (Double) obj[1];
     String currency = (String) obj[2];
     }
Run Code Online (Sandbox Code Playgroud)