使用 NHibernate Criteria API 选择特定的数据集和计数

发布于 2024-08-06 05:09:54 字数 5263 浏览 8 评论 0原文

我为 NHibernate 的持久性设置了以下域: Domain

我使用 PaperConfiguration 作为根聚合。

我想选择给定 Tier 和 AcademyYearConfiguration 的所有 PaperConfiguration 对象。根据以下示例,这非常有效:(

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

不过也许有更好的方法来做到这一点)。

但还需要知道每个 PaperConfiguration 有多少 ReferenceMaterials,我想在同一个调用中获取它。避免 HQL - 我已经有一个 HQL 解决方案。

我知道这就是预测的目的,这个问题提出了一个想法,但我无法理解让它工作。

我有一个 PaperConfigurationView,而不是 IList; 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>

I have the following domain set up for persistence with NHibernate:
Domain

I am using the PaperConfiguration as the root aggregate.

I want to select all PaperConfiguration objects for a given Tier and AcademicYearConfiguration. This works really well as per the following example:

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

(Perhaps there is a better way of doing this though).

Yet also need to know how many ReferenceMaterials there are for each PaperConfiguration and I would like to get it in the same call. Avoid HQL - I already have an HQL solution for it.

I know this is what projections are for and this question suggests an idea but I can't get it to work.

I have a PaperConfigurationView that has, instead of IList<ReferenceMaterial> ReferenceMaterials the ReferenceMaterialCount and was thinking along the lines of

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

unfortunately this does not work. What am I doing wrong?

The following simplified query:

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

creates this rather unexpected 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

The above query fails with ADO.NET error as it obviously is not a correct SQL since it is missing a group by or the count being count(referencem1_.Id) rather than (this_.Id).

NHibernate mappings:

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

情场扛把子 2024-08-13 05:09:54

您应该使用 Projections.GroupProperty() 而不是 Projections.Property()。

You should use Projections.GroupProperty() instead of Projections.Property().

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文