Использование NHibernate Criteria API для выбора определенного набора данных вместе с количеством

У меня есть следующий домен, настроенный для сохранения с помощью NHibernate: Domain

Я использую PaperConfiguration в качестве корневого агрегата.

Я хочу выбрать все объекты PaperConfiguration для данного уровня и AcademicYearConfiguration. Это действительно хорошо работает, как показано в следующем примере:

ICriteria criteria =
session.CreateCriteria<PaperConfiguration>()
    .Add(Restrictions.Eq("AcademicYearConfiguration", configuration))
    .CreateCriteria("Paper")
    .CreateCriteria("Unit")
    .CreateCriteria("Tier")
        .Add(Restrictions.Eq("Id", tier.Id))

return criteria.List<PaperConfiguration>();

(Возможно, есть лучший способ сделать это).

Но также необходимо знать, сколько ReferenceMaterials существует для каждой PaperConfiguration, и я хотел бы получить его в одном и том же вызове. Избегайте HQL - у меня уже есть решение HQL для этого.

Я знаю, для чего нужны прогнозы, и этот вопрос предлагает идею, но я не могу понять это работать.

У меня есть PaperConfigurationView, который имеет вместо IList<ReferenceMaterial> ReferenceMaterials ReferenceMaterialCount и мыслит в духе

ICriteria criteria =
session.CreateCriteria<PaperConfiguration>()
    .Add(Restrictions.Eq("AcademicYearConfiguration", configuration))
    .CreateCriteria("Paper")
    .CreateCriteria("Unit")
    .CreateCriteria("Tier")
        .Add(Restrictions.Eq("Id", tier.Id))
    .SetProjection(
        Projections.ProjectionList()
           .Add(Projections.Property("IsSelected"), "IsSelected")
           .Add(Projections.Property("Paper"), "Paper")
            // and so on for all relevant properties
           .Add(Projections.Count("ReferenceMaterials"), "ReferenceMaterialCount")
    .SetResultTransformer(Transformers.AliasToBean<PaperConfigurationView>());

return criteria.List< PaperConfigurationView >();

к сожалению, это не работает. Что я делаю неправильно?

Следующий упрощенный запрос:

ICriteria criteria =
session.CreateCriteria<PaperConfiguration>()
.CreateCriteria("ReferenceMaterials")
.SetProjection(
Projections.ProjectionList()
.Add(Projections.Property("Id"), "Id")
.Add(Projections.Count("ReferenceMaterials"), "ReferenceMaterialCount")
).SetResultTransformer(Transformers.AliasToBean<PaperConfigurationView>());
 return criteria.List< PaperConfigurationView >();

создает этот довольно неожиданный SQL:

SELECT 
  this_.Id as y0_, 
  count(this_.Id) as y1_ 
FROM Domain.PaperConfiguration this_ 
  inner join Domain.ReferenceMaterial referencem1_ 
    on this_.Id=referencem1_.PaperConfigurationId

Вышеупомянутый запрос не выполняется с ошибкой ADO.NET, поскольку это, очевидно, неправильный SQL, поскольку в нем отсутствует группа по или счетчик, являющийся count (referencem1_.Id), а не (this_.Id).

Отображения NHibernate:

  <class name="PaperConfiguration" table="PaperConfiguration">
    <id name="Id" type="Int32">
      <column name="Id" sql-type="int" not-null="true" unique="true" index="PK_PaperConfiguration"/>
      <generator class="native" />
    </id>
    <!-- IPersistent -->
    <version name="VersionLock" />
    <!-- IAuditable -->
    <property name="WhenCreated" type="DateTime" />
    <property name="CreatedBy" type="String" length="50" />
    <property name="WhenChanged" type="DateTime" />
    <property name="ChangedBy" type="String" length="50" />

    <property name="IsEmeEnabled" type="boolean" not-null="true" />

    <property name="IsSelected" type="boolean" not-null="true" />

    <many-to-one name="Paper" column="PaperId" class="Paper" not-null="true" access="field.camelcase"/>

    <many-to-one name="AcademicYearConfiguration" column="AcademicYearConfigurationId" class="AcademicYearConfiguration" not-null="true" access="field.camelcase"/>

    <bag name="ReferenceMaterials" generic="true" cascade="delete" lazy="true" inverse="true">
      <key column="PaperConfigurationId" not-null="true" />
      <one-to-many class="ReferenceMaterial" />
    </bag>
  </class>

  <class name="ReferenceMaterial" table="ReferenceMaterial">
    <id name="Id" type="Int32">
      <column name="Id" sql-type="int" not-null="true" unique="true" index="PK_ReferenceMaterial"/>
      <generator class="native" />
    </id>
    <!-- IPersistent -->
    <version name="VersionLock" />
    <!-- IAuditable -->
    <property name="WhenCreated" type="DateTime" />
    <property name="CreatedBy" type="String" length="50" />
    <property name="WhenChanged" type="DateTime" />
    <property name="ChangedBy" type="String" length="50" />

    <property name="Name" type="String" not-null="true" />
    <property name="ContentFile" type="String" not-null="false" />
    <property name="Position" type="int" not-null="false" />
    <property name="CommentaryName" type="String" not-null="false" />
    <property name="CommentarySubjectTask" type="String" not-null="false" />
    <property name="CommentaryPointScore" type="String" not-null="false" />
    <property name="CommentaryContentFile" type="String" not-null="false" />

    <many-to-one name="PaperConfiguration" column="PaperConfigurationId" class="PaperConfiguration" not-null="true"/>
  </class>

person mfloryan    schedule 28.09.2009    source источник
comment
Почему не работает второй критерий запроса? Есть сообщения об ошибках? (Я предполагаю, что отсутствует предложение group by, но хочу быть уверенным, с чем вы столкнулись.)   -  person Stefan Steinegger    schedule 28.09.2009
comment
Не могли бы вы опубликовать свои сопоставления?   -  person John Rayner    schedule 29.09.2009
comment
Я включу сопоставления завтра, чтобы убедиться, что я их правильно запечатлел. Что касается сообщения об ошибке - вы можете видеть из запроса SQL, что это было бы неправильно - но на данный момент это кажется неуместным, поскольку я ожидал, что счет будет из подзапроса, но там даже нет JOIN или подзапроса.   -  person mfloryan    schedule 29.09.2009
comment
Я не могу здесь помочь, за исключением того, что вы можете попробовать опубликовать свой вопрос в группе пользователей NH (groups.google.com/group/nhusers?hl=en). Многие из разработчиков NHib работают там.   -  person John Rayner    schedule 30.09.2009


Ответы (1)


Вы должны использовать Projection.GroupProperty () вместо Projection.Property ().

person Canton    schedule 29.09.2009
comment
Спасибо. Я действительно экспериментировал с этим подходом, пробуя как Property, так и GroupProperty, но ни один из них не дал результатов. - person mfloryan; 29.09.2009