Les Projections.count() et des Projections.countDistinct() fois de suite dans la même requête

EDIT: j'ai édité ce post complètement, de sorte que la nouvelle description de mon problème comprend tous les détails et pas seulement ce que j'ai déjà considérés comme pertinents. Peut-être que cette nouvelle description pour aider à résoudre le problème, je suis confronté à.

J'ai deux classes d'entité, de la Clientèle et CustomerGroup. La relation entre les clients et groupes de clients est ManyToMany. Les groupes de clients sont annotés de la manière suivante dans la classe de la Clientèle.


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

Le client de référence dans les groupes de clients de la classe est annotée de la façon suivante


@Entity
public class CustomerGroup {
  ...
  @ManyToMany
  public Set<Customer> getCustomers() {
    ...
  }

  ...

  public String getUuid() {
    return uuid;
  }
  ...
}

Il est à noter que la CustomerGroup et les catégories de Clients ont également un UUID champ. L'UUID est une chaîne unique (unicité n'est pas forcé dans le modèle de données, comme vous pouvez le voir, il est traité comme tout autre normal de la chaîne).

Ce que je suis en train de faire, est de récupérer tous les clients qui n'appartiennent à aucun groupe de clients OU le client est un groupe "groupe valide". La validité d'un groupe de clients est défini par une liste de validité des Uuid.

J'ai créé les critères suivants requête


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);

Lors de l'exécution de la requête, la requête SQL suivante


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 (
        ?, ?
    )

La requête est exactement ce que je voulais, mais avec une exception. Depuis un Client peut appartenir à plusieurs CustomerGroups, à gauche rejoindre la CustomerGroup résultat sera dupliqué objets de Client. D'où la count(*) donnera une valeur fausse, car elle ne prend en compte que le nombre de résultats. J'ai besoin d'obtenir le montant de unique clients et ce, je m'attendais à atteindre à l'aide de la Projections.countDistinct("uuid"); -projection. Pour une raison quelconque, comme vous pouvez le voir, la projection sera toujours un count(*) requête à la place de l' count(distinct uuid). Remplacement de la projection countDistinct avec juste count("uuid") résultat sera exactement le même requête.

Je fais quelque chose de mal ou est-ce un bug?

===

"Problème" résolu. Raison: PEBKAC (Problème Existe Entre le Clavier Et la Chaise). J'ai eu une branche dans mon code et je ne savais pas que la branche a été exécuté. Cette branche utilisée rowCount() au lieu de countDistinct().

Si votre requête contient une jointure gauche, s'il vous plaît montrer le reste de vos critères de code dans lequel vous spécifiez cette jointure gauche. Si vous êtes en utilisant des critères uniquement pour créer la requête de base et ensuite ajouter le left join manuellement: ce n'est pas la façon de le faire 🙂
J'ai édité la question pour contenir tout le code lié à mon problème.
Pour d'autres, aux prises avec le même problème, reportez-vous à cette question: stackoverflow.com/questions/4616607/...

OriginalL'auteur Kim L | 2010-02-23