首页 > 解决方案 > @Formula 字段未被客户端代码识别

问题描述

相关:如何在多列上计数不同

我有一个包含许多字段的实体类,其中三个longitudelatitudeupdate_time。我正在尝试添加一个@Formula连接三个字段的字段:

@Formula("concat(longitude, latitude, update_time)")
public String fix; 

然后我想将该字段用作countDistinct查询的一部分:

@SuppressWarnings( {"unchecked", "rawtypes"} )
public long getCountDistinctPositions() {
    Session session = sessionFactory.openSession();

    CriteriaBuilder criteriaBuilder = session.getCriteriaBuilder();

    CriteriaQuery criteriaQuery = criteriaBuilder.createQuery();
    Root<Position> position = criteriaQuery.from(Position.class);
    Expression fix = position.get("fix");
    Expression countDistinct = criteriaBuilder.countDistinct(fix);
    criteriaQuery.select(countDistinct);
    Query query = session.createQuery(criteriaQuery);
    Long result = (Long)query.getSingleResult();

    session.close();

    return result;
}

但我不断收到一个例外:

java.lang.IllegalArgumentException: Unable to locate Attribute  with the the given name [fix] on this ManagedType [aaa.Position]

标签: hibernatejpaaggregate

解决方案


@Formula不能查询一个字段,它基本上是一个合成字段,Hibernate 将在仅执行选择查询时填充。

对于您的用例,您需要执行:

SELECT DISTINCT longitude, latitude, update_time FROM Entity

从 JPA 查询的角度来看,您需要#countDistinct在所有 3 个单独的列上执行,而不是在公式列上执行。

考虑公式列的最佳方式是您已在您的实体上有效地翻译了以下方法

@Transient
public String getFix() {
  return this.longitude + this.latitude + this.update_time;
}

到数据库在查询时为您连接的属性。

更新

CriteriaQuery<Long> countQuery = cb.createQuery( Long.class );
Root<TheEntity> root = countQuery.from( TheEntity.class );

countQuery.select( cb.count( root.get( "id" ) ) );

Subquery<Integer> subQuery = countQuery.subquery( Integer.class );
Root<TheEntity> subRoot = subQuery.from( TheEntity.class );
subQuery.select( cb.min( subRoot.get( "id" ) ) );
subQuery.groupBy( subRoot.get( "longitude" ), 
   subRoot.get( "latitude" ), 
   subRoot.get( "updateTime" ) );

countQuery.where( root.get( "id" ).in( subQuery ) );

Long count = entityManager.createQuery( countQuery ).getSingleResult();

推荐阅读