我有两个实体类,Customer和CustomerGroup。客户和客户群之间的关系是ManyToMany。客户组在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 (
?, ?
)
查询正是我想要的,但有一个例外。由于客户可以属于多个CustomerGroup,因此加入CustomerGroup将导致重复的Customer对象。因此,count(*)
将给出错误值,因为它只计算有多少结果。我需要获得独特客户的数量,这是我希望通过Projections.countDistinct("uuid");
- 投影实现的。出于某种原因,正如您所看到的,投影仍然会导致count(*)
查询而不是预期的count(distinct uuid)
。仅使用countDistinct
替换投影count("uuid")
将导致完全相同的查询。
我做错了什么还是这个错误?
===
“问题”解决了。原因:PEBKAC(键盘和椅子之间存在问题)。我的代码中有一个分支,并没有意识到分支已执行。该分支使用rowCount()而不是countDistinct()。
答案 0 :(得分:4)
这是3.5.1中的错误
之后
cr.setProjection(Projections.countDistinct( “MEMBERID”));
SQL结果是count(memberId)
bo not count(distinct memberId)
调试后....
public final class Projections {
public static CountProjection countDistinct(String propertyName) {
return new CountProjection(propertyName).setDistinct();
}
注意到不同但未使用。
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;
}
}
和...在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 );
}
答案 1 :(得分:3)
“问题”解决了。原因:PEBKAC(键盘和椅子之间存在问题)。我的代码中有一个分支,并没有意识到分支已执行。该分支使用rowCount()而不是countDistinct()。
答案 2 :(得分:1)
尝试在CountProjection类中调试方法toSqlString。看看代码,我只能想象那种截然不同的代码;我没有看到为什么不包括distinct的原因:
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();
}
的问候,
斯泰恩
答案 3 :(得分:0)
我想这是因为你的'id'字段是一个唯一的字段,而hibernate知道这一点。 当您使用'distinct'时,查询是否会给出不同的结果?
答案 4 :(得分:0)
也许字段ID被定义为唯一?尝试使用不同的字段,这不是唯一的。