【问题标题】:Projections.count() and Projections.countDistinct() both result in the same queryProjections.count() 和 Projections.countDistinct() 都产生相同的查询
【发布时间】:2010-02-23 14:45:02
【问题描述】:

编辑:我已经完全编辑了这篇文章,因此对我的问题的新描述包括所有细节,而不仅仅是我之前认为相关的内容。也许这个新的描述将有助于解决我面临的问题。

我有两个实体类,Customer 和 CustomerGroup。客户和客户群之间的关系是多对多。客户组在 Customer 类中按以下方式注释。

@Entity public class Customer { ... @ManyToMany(mappedBy = "customers", fetch = FetchType.LAZY) public Set<CustomerGroup> getCustomerGroups() { ... } ... public String getUuid() { return uuid; } ... }

客户组类中的客户引用如下注解

@Entity public class CustomerGroup { ... @ManyToMany public Set<Customer> getCustomers() { ... } ... public String getUuid() { return uuid; } ... }

请注意,CustomerGroup 和 Customer 类也有一个 UUID 字段。 UUID 是一个唯一的字符串(数据模型中没有强制唯一性,如您所见,它被当作任何其他普通字符串处理)。

我要做的是获取不属于任何客户组的所有客户,或者客户组是“有效组”。客户组的有效性由有效 UUID 列表定义。

我创建了以下条件查询

Criteria criteria = getSession().createCriteria(Customer.class); criteria.setProjection(Projections.countDistinct("uuid")); criteria = criteria.createCriteria("customerGroups", "groups", Criteria.LEFT_JOIN); List<String> uuids = getValidUUIDs(); Criterion criterion = Restrictions.isNull("groups.uuid"); if (uuids != null && uuids.size() > 0) { criterion = Restrictions.or(criterion, Restrictions.in( "groups.uuid", uuids)); } criteria.add(criterion);

执行查询时,会产生如下SQL查询

select count(*) as y0_ from Customer this_ left outer join CustomerGroup_Customer customergr3_ on this_.id=customergr3_.customers_id left outer join CustomerGroup groups1_ on customergr3_.customerGroups_id=groups1_.id where groups1_.uuid is null or groups1_.uuid in ( ?, ? )

查询正是我想要的,但有一个例外。由于一个客户可以属于多个客户组,左加入客户组将导致重复的客户对象。因此count(*) 将给出一个错误值,因为它只计算有多少结果。我需要获得唯一客户的数量,而我希望通过使用Projections.countDistinct("uuid"); -projection 来实现这一点。出于某种原因,如您所见,投影仍将导致count(*) 查询而不是预期的count(distinct uuid)。将投影countDistinct 替换为仅count("uuid") 将产生完全相同的查询。

是我做错了什么还是这是一个错误?

===

“问题”解决了。原因:PEBKAC(键盘和椅子之间存在问题)。我的代码中有一个分支,但没有意识到该分支已执行。该分支使用 rowCount() 而不是 countDistinct()。

【问题讨论】:

  • 如果您的查询包含左连接,请显示您指定此左连接的其余条件代码。如果您仅使用条件来创建基本查询,然后手动附加左连接:那不是这样做的方法:)
  • 我已编辑问题以包含与我的问题相关的所有代码。
  • 对于遇到同样问题的其他人,请参阅此问题:stackoverflow.com/questions/4616607/…

标签: java hibernate criteria


【解决方案1】:

3.5.1 有 bug

之后

cr.setProjection(Projections.countDistinct("memberId"));

SQL 结果为 count(memberId)

bo 不计数(不同的 memberId)

调试后 ....

public final class Projections {

    public static CountProjection countDistinct(String propertyName) {
        return new CountProjection(propertyName).setDistinct();
    }

distinct 被注意到但未使用。

public class CountProjection extends AggregateProjection {
    private boolean distinct;

    protected CountProjection(String prop) {
        super("count", prop);
    }

    public String toString() {
        if ( distinct ) {
            return "distinct " + super.toString();
        }
        else {
            return super.toString();
        }
    }

    public CountProjection setDistinct() {
        distinct = true;
        return this;
    }
}

and ... 在 AggregateProjection 中 仅使用 getFunctionName() = functionName = "count" !!!

公共类 AggregateProjection 扩展 SimpleProjection {

protected AggregateProjection(String functionName, String propertyName) {
    this.functionName = functionName;
    this.propertyName = propertyName;
}

public String getFunctionName() {
    return functionName;
}

public String getPropertyName() {
    return propertyName;
}

    ...

public String toSqlString(Criteria criteria, int loc, CriteriaQuery criteriaQuery)
        throws HibernateException {
    final String functionFragment = getFunction( criteriaQuery ).render(
            buildFunctionParameterList( criteria, criteriaQuery ),
            criteriaQuery.getFactory()
    );
    return functionFragment + " as y" + loc + '_';
}

protected SQLFunction getFunction(CriteriaQuery criteriaQuery) {
    return getFunction( getFunctionName(), criteriaQuery );
}

【讨论】:

    【解决方案2】:

    “问题”解决了。原因:PEBKAC(键盘和椅子之间存在问题)。我的代码中有一个分支,但没有意识到该分支已执行。该分支使用 rowCount() 而不是 countDistinct()。

    【讨论】:

      【解决方案3】:

      尝试调试 CountProjection 类中的 toSqlString 方法。查看代码,我只能想象出不同的是不真实的;我看不出为什么不包含不同的其他原因:

          public String toSqlString(Criteria criteria, int position, CriteriaQuery criteriaQuery) 
      throws HibernateException {
          StringBuffer buf = new StringBuffer();
          buf.append("count(");
          if (distinct) buf.append("distinct ");
          return buf.append( criteriaQuery.getColumn(criteria, propertyName) )
              .append(") as y")
              .append(position)
              .append('_')
              .toString();
      }
      

      问候,
      斯蒂金

      【讨论】:

        【解决方案4】:

        我猜这是因为你的 'id' 字段是一个独特的字段,hibernate 知道这一点。 当您使用 'distinct' 时,查询会给出不同的结果吗?

        【讨论】:

          【解决方案5】:

          也许字段 ID 无论如何都被定义为唯一的?尝试使用不同的字段,它不是唯一的。

          【讨论】:

          • 尝试使用另一个字段,但仍然导致计数 (*)。事实上,我给 Projections.countDistinct() 提供的参数并不重要,即使是“foobar”也会产生相同的查询。
          猜你喜欢
          • 2016-04-28
          • 1970-01-01
          • 1970-01-01
          • 2011-06-04
          • 2019-07-25
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-01-12
          相关资源
          最近更新 更多