如何在Hibernate查询Project时仅获取关联Category的id和name字段
解决方案
下面提供3种常用的实现方式,可根据你的业务场景选择:
方案1:HQL投影查询 + 自定义DTO(最推荐,可控性最高)
直接定义只包含你需要字段的传输对象,HQL查询时直接指定要查询的字段并构造DTO对象,不会产生多余查询:
- 先定义两个DTO类
// 仅包含id和name的简化Category类 public class SimpleCategory { private Integer id; private String name; // 必须提供全参数构造方法 public SimpleCategory(Integer id, String name) { this.id = id; this.name = name; } // 此处补充getter、setter方法 } // 仅包含所需字段的简化Project类 public class SimpleProject { private String id; private String name; private String description; private SimpleCategory category; // 必须提供全参数构造方法 public SimpleProject(String id, String name, String description, SimpleCategory category) { this.id = id; this.name = name; this.description = description; this.category = category; } // 此处补充getter、setter方法 }
- 编写HQL查询语句
// 注意DTO类要写完整的包路径 String hql = "select new com.your.package.SimpleProject(" + "p.id, p.name, p.description, " + "new com.your.package.SimpleCategory(c.id, c.name)" + ") from Project p left join p.category c"; Session currentSession = entityManager.unwrap(Session.class); Query<SimpleProject> theQuery = currentSession.createQuery(hql, SimpleProject.class); List<SimpleProject> projects = theQuery.getResultList();
方案2:使用实体图(无需新增DTO,复用原有实体类)
通过JPA实体图指定仅加载需要的关联属性,查询出来的Category除id、name外其余属性均为未加载状态,只要不主动调用getProjects()就不会触发额外查询:
- 给Project实体类添加实体图配置
@NamedEntityGraph( name = "Project.onlyCategoryIdAndName", attributeNodes = @NamedAttributeNode(value = "category", subgraph = "simpleCategory"), subgraphs = @NamedSubgraph( name = "simpleCategory", attributeNodes = { @NamedAttributeNode("id"), @NamedAttributeNode("name") } ) ) @Entity @Table(name="project") public class Project { // 原有代码保持不变 }
- 查询时应用实体图
String hql = "from Project"; Session currentSession = entityManager.unwrap(Session.class); Query<Project> theQuery = currentSession.createQuery(hql, Project.class); theQuery.setHint("javax.persistence.fetchgraph", currentSession.getEntityGraph("Project.onlyCategoryIdAndName")); List<Project> projects = theQuery.getResultList();
方案3:仅需屏蔽序列化时多余字段的极简方案
如果你只是在序列化(比如转JSON返回给前端)时不想要Category的projects属性,不需要控制查询逻辑,可以直接在Category的projects属性上添加序列化忽略注解即可:
@OneToMany(mappedBy = "category") @JsonIgnore // Jackson序列化时忽略该字段,不会触发懒加载查询 private List<Project> projects;
同时可以把@ManyToOne的加载策略改为懒加载,减少不必要的关联查询:
@ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name="category", referencedColumnName = "id") private Category category;
内容的提问来源于stack exchange,提问作者prasadmsvs
相关产品推荐
相关产品推荐

