使用非实体 class 作为本机查询的结果 class

use a non-entity class as a result class for native query

网络上的每个 example/tutorials 都处理实体 classes,当涉及存储过程(函数)时,SP 仅从该实体收集数据。虽然这很常见,但我们有一个涉及多个表的复杂查询,并且我们希望返回一些列。为此,我们可以在 postgresql 中使用带或不带任何参数的函数。

我有这段调用这样一个函数的代码:

@Component
public class CapPlanningItemPerCapGroupImpl implements CapPlanningItemPerCapGroupRepository {
    private final EntityManager em;

    public CapPlanningItemPerCapGroupImpl(EntityManager em) {
        this.em = em;
    }

    @Override
    public List<CapPlanningItemPerCapGroup> getCapPlanningItems(Long companyId, Long plantId, int year, Long costAccTypeId) {
        Session session = em.unwrap(Session.class);
        NativeQuery<CapPlanningItemPerCapGroup> query = session.createNativeQuery(
                "SELECT * FROM get_cap_planning_items(:year, :companyId, :plantId, :costAccTypeId)", CapPlanningItemPerCapGroup.class);
        query.setParameter("year", year);
        query.setParameter("companyId", companyId);
        query.setParameter("plantId", plantId);
        query.setParameter("costAccTypeId", costAccTypeId);

        return query.getResultList();
    }
}

CapPlanningItemPerCapGroup class 没有用 @Entity 注释,因为我不想将它作为数据表存储在数据库中。这就像一个自定义类型。但是使用这个设置,上面的查询失败了,说 CapPlanningItemPerCapGroup 是一个未知的实体。

如果我从查询调用中删除此 CapPlanningItemPerCapGroup.class,我会在邮递员中得到结果,但当然没有任何字段名称,只有原始数据。

所以,我的问题是:我真的需要手动将结果列表转换为 appr. class 类型,或者是否有开箱即用的自动映射,我不必列出所有返回的列名和类型?

谢谢。

您可以使用 @SqlResultSetMapping 来描述 Hibernate 将对结果集中的每条记录执行的构造函数调用。我在我的博客 Result Set Mapping: Constructor Result Mappings 中详细解释了这一点。

大意很简单:

您的 CapPlanningItemPerCapGroup 需要一个设置所有属性的构造函数。

@SqlResultSetMapping 中,您通过引用 class 来描述构造函数调用,并按照您希望将它们提供给构造函数的顺序列出结果集中的列,例如:

@SqlResultSetMapping(
        name = "BookValueMapping",
        classes = @ConstructorResult(
                targetClass = BookValue.class,
                columns = {
                    @ColumnResult(name = "id", type = Long.class),
                    @ColumnResult(name = "title"),
                    @ColumnResult(name = "version", type = Long.class),
                    @ColumnResult(name = "authorName")}))

定义映射后,您可以将其名称作为第二个参数提供给 createNativeQuery 方法。

List<BookValue> results = this.em.createNativeQuery("SELECT b.id, b.title, b.version, a.firstName || a.lastName as authorName FROM Book b JOIN Author a ON b.author_id = a.id", "BookValueMapping").getResultList();