РЕДАКТИРОВАТЬ: я полностью отредактировал этот пост, так что новое описание моей проблемы включает в себя все детали, а не только то, что я ранее считал уместным. Возможно, это новое описание поможет решить проблему, с которой я столкнулся.
У меня есть два класса сущностей, 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 (
?, ?
)
Запрос именно то, что я хотел, но с одним исключением. Поскольку Customer может принадлежать к нескольким группам CustomerGroup, оставленное присоединение к CustomerGroup приведет к дублированию объектов Customer. Следовательно, count(*)
будет давать ложное значение, поскольку оно только подсчитывает, сколько результатов есть. Мне нужно получить количество уникальных клиентов, и этого я ожидал достичь с помощью Projections.countDistinct("uuid");
-проекции. По какой-то причине, как вы можете видеть, проекция все равно приведет к запросу count(*)
вместо ожидаемого count(distinct uuid)
. Замена проекции countDistinct
на count("uuid")
приведет к точно такому же запросу.
Я что-то не так делаю или это ошибка?
===
«Проблема» решена. Причина: PEBKAC (проблема существует между клавиатурой и стулом). В моем коде была ветвь, и я не понимал, что ветвь была выполнена. Эта ветвь использовала rowCount () вместо countDistinct ().