Hibernate原生查询复杂构造映射:Spring Data JPA结果封装问题
完整实现方案
刚好做过类似的需求,给你整理两种常用持久化框架的完整实现方案,你可以按需选用:
一、MyBatis 实现方式
MyBatis 可以通过注解或者 XML 配置完成结果映射,这里推荐更简洁的注解方式:
1. 完善实体类的 getter/setter 和构造器
确保你的 Source、MyResult 类具备无参构造器和对应的 getter/setter 方法(MyBatis 自动映射需要):
public class Source { private Integer id; private String name; // 无参构造器 public Source() {} // 全参构造器(可选,方便手动创建实例) public Source(Integer id, String name) { this.id = id; this.name = name; } // getter & setter public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } } public class MyResult { private Source source; private Integer itemCount; // 你原有的构造器保留 public MyResult(Source source, Integer itemCount) { this.source = source; this.itemCount = itemCount; } // 新增无参构造器+getter/setter,用于MyBatis自动映射 public MyResult() {} public Source getSource() { return source; } public void setSource(Source source) { this.source = source; } public Integer getItemCount() { return itemCount; } public void setItemCount(Integer itemCount) { this.itemCount = itemCount; } }
2. 编写 Mapper 接口并配置结果映射
通过 @Select 编写原生SQL,用 @Results 配置嵌套对象的映射关系:
@Mapper public interface SourceMapper { @Select("select s.id source_id, s.name source_name, count(i.id) item_count " + "from source s left join item i on s.id = i.source_id " + "group by s.id") @Results({ // 映射到MyResult.source.id @Result(property = "source.id", column = "source_id"), // 映射到MyResult.source.name @Result(property = "source.name", column = "source_name"), // 映射到MyResult.itemCount @Result(property = "itemCount", column = "item_count") }) List<MyResult> getSourceItemCount(); }
3. 调用测试
在Service层注入 SourceMapper,直接调用方法即可得到封装好的结果:
@Service public class SourceService { @Autowired private SourceMapper sourceMapper; public List<MyResult> getSourceItemStats() { return sourceMapper.getSourceItemCount(); } }
二、Spring Data JPA 实现方式
如果你的项目用JPA,分JPQL写法和原生SQL写法两种:
方式1:JPQL 写法(更贴合JPA风格)
JPQL支持直接调用实体类构造器,无需额外映射:
// 先确保Source和Item类已加@Entity注解,对应数据库表 @Entity @Table(name = "source") public class Source { @Id // 标记主键 private Integer id; private String name; // 其余构造器、getter/setter同之前代码 } @Entity @Table(name = "item") public class Item { @Id // 标记主键 private Integer id; private String name; private Integer sourceId; // 其余构造器、getter/setter同之前代码 } // 定义Repository接口 public interface SourceRepository extends JpaRepository<Source, Integer> { @Query(value = "select new com.yourpackage.MyResult(" + "new com.yourpackage.Source(s.id, s.name), count(i.id)) " + "from Source s left join Item i on s.id = i.sourceId " + "group by s.id") List<MyResult> getSourceItemCount(); }
注意:把 com.yourpackage 替换成你实际的包路径,并且 MyResult 需要保留你原来定义的 MyResult(Source source, Integer itemCount) 构造器。
方式2:原生SQL 写法(严格对应你的原生SQL)
如果必须用原生SQL,需要通过 @SqlResultSetMapping 来映射结果:
- 先在任意实体类上定义结果映射(比如放在Source类上):
@Entity @Table(name = "source") @SqlResultSetMapping( name = "MyResultMapping", classes = @ConstructorResult( targetClass = MyResult.class, columns = { @ColumnResult(name = "source_id", type = Integer.class), @ColumnResult(name = "source_name", type = String.class), @ColumnResult(name = "item_count", type = Integer.class) } ) ) public class Source { /* ... 原有代码 ... */ }
- 给
MyResult新增一个适配原生SQL结果的构造器:
public class MyResult { // ... 原有代码 ... // 新增构造器,用于原生SQL结果映射 public MyResult(Integer sourceId, String sourceName, Integer itemCount) { this.source = new Source(sourceId, sourceName); this.itemCount = itemCount; } }
- 在Repository中编写原生查询:
public interface SourceRepository extends JpaRepository<Source, Integer> { @Query(value = "select s.id source_id, s.name source_name, count(i.id) item_count " + "from source s left join item i on s.id = i.source_id " + "group by s.id", nativeQuery = true, resultSetMapping = "MyResultMapping") List<MyResult> getSourceItemCount(); }
调用测试
同样在Service层注入Repository调用即可:
@Service public class SourceService { @Autowired private SourceRepository sourceRepository; public List<MyResult> getSourceItemStats() { return sourceRepository.getSourceItemCount(); } }
内容的提问来源于stack exchange,提问作者Elegant.Obj
相关产品推荐
相关产品推荐

