【问题标题】:Map Query result to dto将查询结果映射到 dto
【发布时间】:2021-08-13 11:48:52
【问题描述】:

我有这 3 个独立的表,即学生、教师和主题。这里的独立是指这些表之间没有关系。

我想要所有这些表的计数。 SQL 查询看起来像 -

SELECT
  (SELECT COUNT(*) FROM Student as ST, 
  (SELECT COUNT(*) FROM Teacher as TE,
  (SELECT COUNT(*) FROM Subject as SU

现在我想将此结果映射到 dto 。 DTO 看起来像

public class CountDto{
        Integer student;
        Integer teacher;
        Integer subject;
        }

存储库调用看起来像 -

@Query(value = "SELECT\r\n"
        + "  (SELECT COUNT(*) FROM Student) as ST, \r\n"
        + "  (SELECT COUNT(*) FROM Teacher) as TE,\r\n"
        + "  (SELECT COUNT(*) FROM Subject) as SU", nativeQuery = true)
public CountDto getCount();

调用此函数时出现以下错误提示

"message": "Failed to convert from type [java.lang.Object[]] to type [com.rbl.mdm.dto.CountDto ] for value '{16, 16 , 34}'; nested exception is org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type [java.lang.Integer] to type [com.rbl.mdm.dto.CountDto]"

我应该如何将我的响应转换为所需的 DTO?

【问题讨论】:

  • 也许this 会有所帮助。

标签: java spring-boot dto


【解决方案1】:

您可以将CountDto 声明为公共接口,它应该可以工作。就Spring 而言,它被称为Projection。或者,您可以将SqlResultSetMappingConstructorResult 与您的班级一起使用。

您不必通过任何实体类来实现它,只需像在存储库文件中一样创建一个独立的接口即可:

public interface StudentRepository extends CrudRepository<Student, Long> {

    @Query(value = "SELECT\r\n"
            + "  (SELECT COUNT(*) FROM Student) as ST, \r\n"
            + "  (SELECT COUNT(*) FROM Teacher) as TE,\r\n"
            + "  (SELECT COUNT(*) FROM Subject) as SU", nativeQuery = true)
    Counts getCount();
    
    public static interface Counts {
        Integer getST();        
        Integer getTE();
        Integer getSU();
    }

}

【讨论】:

  • 当 repo 调用从 3 个独立的表中返回数据时,我应该制作哪种类型的 Projection。根据我对 Projections 的理解,它们反映了实体的方法,这里我们有 3 个不同的实体!
【解决方案2】:

所以这是要做的答案 - DTO 看起来像

public CountDto{
    private Integer studentTotal;
    private Integer teacherTota;
    private Integer subjectTotal;
}

存储库调用 -

@Query(value = "SELECT\r\n"
        + "  (SELECT COUNT(*) FROM Student) as ST, \r\n"
        + "  (SELECT COUNT(*) FROM Teacher) as TE,\r\n"
        + "  (SELECT COUNT(*) FROM Subject) as SU", nativeQuery = true)
public Map<String,Integer> getCount();

最后是serviceImpl--

public CountDto getCount{
        CountDto CountValue = new CountDto();
        Map<String,Integer> map =  repository.getCount();
        for (Map.Entry<String,Integer> entry : map.entrySet())   {
            if(entry.getKey().equals("ST"))
                CountValue.setStudentTotal( entry.getValue());
            if(entry.getKey().equals("TE"))
                CountValue.setTeacherTotal( entry.getValue());
            if(entry.getKey().equals("SU"))
                CountValue.setSubjectTotal( entry.getValue());
        }
        return CountValue ;
}
     

但解决方案对我来说似乎相当复杂。需要任何更简单的方法。

【讨论】:

    【解决方案3】:

    在纯 Hibernate/JPA 使用中,这是一个简单的动态实例化查询(JPA 称之为“构造函数结果”):

    select new CountDTO( 
       (SELECT COUNT(*) FROM Student) as ST,
       ...
    )
    

    这里没有关于 Spring 的概念,虽然有一个警告......在试图变得有用时,它经常“妨碍”。不确定这里是不是这种情况...您是否尝试过直接的 Hibernate/JPA?

    【讨论】:

    • 如果您只是想使用 Spring API,您应该删除“hibernate”标签。如果只是使用 Spring,那么这里没有任何与 Hibernate 相关的内容。
    • 此方法仅适用于非本地 (JPQL) 查询,而 OP 使用本地。
    • 不知道@Query 是什么。它显然是一个 Spring 注释 :shrug: 对于本机查询,甚至更容易...@NamedNativeQuery 使用@ConstructorResult 结果进行结果映射
    • 如果用户只想要 Spring 特定的功能,那么 hibernate 应该作为标签删除
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-07-15
    • 2019-07-25
    • 2022-01-11
    • 1970-01-01
    • 2020-12-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多