2010-02-23 22 views
2

編輯:我已經完全編輯了這篇文章,以便我的問題的新描述包括所有的細節,而不僅僅是我之前認爲的相關內容。也許這個新的描述將有助於解決我面臨的問題。Projections.count()和Projections.countDistinct()都會導致相同的查詢

我有兩個實體類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 (
     ?, ? 
    ) 
 

查詢正是我想要的,但是有一個例外。由於客戶可以屬於多個CustomerGroups,因此加入CustomerGroup會導致重複的Customer對象。因此count(*)會給出一個錯誤的值,因爲它只計算有多少結果。我需要獲得大量的獨特客戶,而我期望通過使用Projections.countDistinct("uuid");投影來實現這一點。出於某種原因,如您所見,投影仍然會導致count(*)查詢,而不是預期的count(distinct uuid)。用count("uuid")替換投影countDistinct將導致完全相同的查詢。

我做錯了什麼或者這是一個錯誤?

===

「問題」已解決。原因:PEBKAC(鍵盤和椅子之間存在問題)。我在我的代碼中有一個分支,並沒有意識到分支已被執行。該分支使用rowCount()而不是countDistinct()。

+0

。如果你正在使用的標準只有創造了基本查詢事後追加左側手動加入:那就是不要做:) – Fortega 2010-02-23 14:52:00

+0

的方式我已經編輯到包含與我的問題所有代碼的問題。 – 2010-02-24 06:26:44

+0

對於其他有同樣問題的掙扎,看到了這個問題:http://stackoverflow.com/questions/4616607/projections-countdistinct-with-hibernate-produces-unexpected-result – simon 2011-01-07 11:59:22

回答

3

「問題」得到解決。原因:PEBKAC(鍵盤和椅子之間存在問題)。我在我的代碼中有一個分支,並沒有意識到分支已被執行。該分支使用rowCount()而不是countDistinct()。

0

我想這是因爲你的'id'字段是一個獨特的字段,休眠知道這一點。 當您使用'distinct'時,查詢是否會給出不同的結果?

0

也許字段ID被定義爲唯一嗎?嘗試使用不同的字段,這不是唯一的。

+0

使用另一場試了,但還是造成了計數(*)。實際上,我將它作爲Projections.countDistinct()的參數並不重要,即使是「foobar」結果也會出現在同一個查詢中。 – 2010-02-23 14:51:48

0

- >以下的answar是不正確的......我會在這裏留下一段時間,雖然......

你應該做的

criteria = criteria.setProjection(Projections.countDistinct("id")); 

代替

criteria.setProjection(Projections.countDistinct("id")); 

(或本不需要?)

1

嘗試調試類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

THRE是錯誤在3.5.1

cr.setProjection(Projections.countDistinct( 「MEMBERID」));

SQL結果數(MEMBERID)

博不計(不同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 = 「計數」 使用!

公共類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); 
} 
相關問題