Проблема в HQL при попытке получить счетчик свойства (то есть объекта) и его значения - PullRequest
0 голосов
/ 26 апреля 2011

В моем проекте у меня есть две сущности: первая PaperEntity содержит несколько свойств (состоящих из типов значений, а также ссылочных типов - ссылки на другие сущности-), а вторая - PaperStatusEntity. PaperEntity имеет свойство с именем Result типа PaperStatusEntity (а также свойство с именем заблокированного типа bool)

Представьте, что у вас есть около 500 бумаг и только 8 статусов, определенных в базе данных. Я хочу узнать, сколько используется каждый статус? например, status1 используется 58 раз, а status2 используется 130 раз и так далее. Ниже пишу HQL

select paper.Result, Count(paper.Result) from PaperEntity paper group by paper.Result

это hql генерирует ниже ошибки:

Column 'Conference_PaperStatusesTable.Id' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause. 

генерируется sql:

select paperentit0_.Result as col_0_0_, count(paperentit0_.Result) as col_1_0_, paperstatu1_.Id as Id48_, paperstatu1_.Version as Version48_, paperstatu1_.CreationTime as Creation3_48_, paperstatu1_.Portal as Portal48_, paperstatu1_.TitleCodeName as TitleCod5_48_, paperstatu1_.Enabled as Enabled48_, paperstatu1_.RefereeChoice as RefereeC7_48_, paperstatu1_.OrderIndex as OrderIndex48_, paperstatu1_.ContactMessageTemplate as ContactM9_48_ from Conference_PapersTable paperentit0_ inner join Conference_PaperStatusesTable paperstatu1_ on paperentit0_.Result=paperstatu1_.Id, Conference_PaperStatusesTable paperstatu2_ where paperentit0_.Result=paperstatu2_.Id group by paperentit0_.Result 

Если я попытаюсь сгруппировать данные с помощью свойства типа значения, такого как 'Locked' (то есть bool), проблем не будет, и все в порядке

также Если я использую Критерии вместо HQL, работает верно:

IList result = NHibernateSessionManager.Instance.CurrentSession.CreateCriteria(typeof(PaperEntity))
                .SetProjection(Projections.ProjectionList().Add(Projections.RowCount()).Add(Projections.GroupProperty("Result"))).List();

foreach (var item in result) {
        object[] value = item as object[];
        yield return new Pair<PaperStatusEntity, int>(value[1] as PaperStatusEntity, (int)value[0]);
    }

Ответы [ 3 ]

0 голосов
/ 26 апреля 2011

HQL group by недостаточно умен, чтобы проецировать все свойства объекта при группировании по нему.Вам необходимо:

  • Указать все свойства
  • Выбрать только те, которые вам нужны (идентификатор, описание, что угодно)
  • Использовать подзапрос, чтобы получить количество

Причина, по которой он работает с критериями, заключается в том, что он выбирает только идентификатор при использовании Projections.GroupProperty, создавая неинициализированные прокси.

Это может создать ВЫБРАТЬ N + 1 проблема.

0 голосов
/ 27 апреля 2011

Вы можете попробовать:

SELECT paper.Result, Count(paper.Result) 
FROM PaperEntity paper
JOIN paper.Result as status
GROUP BY paper.Result

Обратите внимание, что вы бы предпочли использовать "ОТ PaperStatusEntity" и присоединиться к документам Поскольку с тем, что вы пытаетесь сделать, вы не можете получить счет для PaperStatusEntity, если ни одна бумага не использует этот статус (это означает, что вы не получаете счет = 0, вы просто не получаете счет)

Вы также можете использовать аннотацию @Formula, чтобы для заданного статуса вы могли выполнить paperStatusEntity.getPaperNumber ()

Просто добавьте что-то вроде

@Formula("select count() from PaperEntity paper where paper.result_id = id");
public int getPaperNumber();

(следует адаптировать)

(я использую Hibernate, но он должен быть таким же?)

0 голосов
/ 26 апреля 2011

Вам необходимо указать простой тип данных, по которому ядро ​​базы данных будет группироваться.Если paper.Result - это другая сущность, вам, вероятно, потребуется присоединиться к таблице PaperStatusEntity.

Что-то вроде:

select paper.Result, Count(paper.Result) 
from PaperEntity as paper 
join paper.Result as status
group by status.Id

Если PaperStatus отображается как компонент, вы также можете получить доступ к Result.Идентификатор напрямую.

...