【问题标题】:Simple NHibernate Eager Loading confusion简单的 NHibernate Eager Loading 混淆
【发布时间】:2013-06-01 07:24:19
【问题描述】:

我有一个非常简单的主子模型:

WorkflowEscalationPolicy。

WorkflowEscalations 可从WorkflowEscalationPolicy.Escalations 属性访问。

当我收到WorkflowEscalationPolicy 项目时,我想急切地获取升级。

我有一个获取所有升级策略的方法。我试过用这个:

IEnumerable<IWorkflowEscalationPolicy> results = 
  Session
 .Query<WorkflowEscalationPolicy>()
 .Fetch(x=>x.Escalations)
 .Where(q=>q.ApplicationKey==applicationKey);

还有这个:

IEnumerable<IWorkflowEscalationPolicy> results = 
 Session
 .CreateCriteria<WorkflowEscalationPolicy>()
 .SetFetchMode("Escalations", FetchMode.Eager)
 .List<WorkflowEscalationPolicy>();

要完成此操作,但两者都不起作用 - 因为子 Escalations 集合仍然为空。我知道数据库中有WorkflowEscalations

我的映射文件:

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
                   assembly="FB.SimpleWorkflow.NHibernate"
                   namespace="FB.SimpleWorkflow.NHibernate.Model" >
    <class name="WorkflowEscalationPolicy" table="SW_WorkflowEscalationPolicy" >
        <id name="Id">
            <generator class="native" />
        </id>
        <property name="ApplicationKey" />
        <property name="ActivityKey" />
        <property name="InstanceKey" />     
        <property name="State" />
        <property name="EscalateAfterSeconds" />
        <property name="MaximumEscalationsPerTransition" />

        <set name="Escalations" table="SW_WorkflowEscalation" cascade="all-delete-orphan" inverse="true">
            <key column="WorkflowEscalationPolicyId" />
            <one-to-many class="WorkflowEscalation" />
        </set>
    </class>


</hibernate-mapping>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
                   assembly="FB.SimpleWorkflow.NHibernate"
                   namespace="FB.SimpleWorkflow.NHibernate.Model" >
    <class name="WorkflowEscalation" table="SW_WorkflowEscalation" >
        <id name="Id">
            <generator class="native" />
        </id>
        <property name="EscalatedTimeStamp" />
        <property name="EscalatedByUserName" />
        <property name="EscalatedOnHost" />

        <many-to-one name="WorkflowEscalationPolicy" column="WorkflowEscalationPolicyID" />
        <many-to-one name="WorkflowActivityInstanceTransition" column="WorkflowActivityInstanceTransitionId" />
    </class>


</hibernate-mapping>

两者之间有什么区别,我在这里缺少什么?我以为NHibernate首先是指加载策略的映射文件?

NHibernate 是 v3.1

更新:2013 年 6 月 6 日

感谢@cremor 进一步调查...

我已经分析了查询执行的生成的 SQL,我得到了:

SELECT this_.Id as Id4_1_, 
    this_.ApplicationKey as Applicat2_4_1_, 
    this_.ActivityKey as Activity3_4_1_, 
    this_.InstanceKey as Instance4_4_1_, 
    this_.State as State4_1_, 
    this_.EscalateAfterSeconds as Escalate6_4_1_, 
    this_.MaximumEscalationsPerTransition as MaximumE7_4_1_, 
    escalation2_.WorkflowEscalationPolicyID as Workflow5_3_, 
    escalation2_.Id as Id3_, 
    escalation2_.Id as Id2_0_, 
    escalation2_.EscalatedTimeStamp as Escalate2_2_0_, 
    escalation2_.EscalatedByUserName as Escalate3_2_0_, 
    escalation2_.EscalatedOnHost as Escalate4_2_0_, 
    escalation2_.WorkflowEscalationPolicyID as Workflow5_2_0_, 
    escalation2_.WorkflowActivityInstanceTransitionID as Workflow6_2_0_ 
    FROM SW_WorkflowEscalationPolicy this_ 
    left outer join SW_WorkflowEscalation escalation2_ on this_.Id=escalation2_.WorkflowEscalationPolicyID

这是我所期望的。

这会生成正确的 SQL,在主 EscalationPolicy 记录的右侧有单个详细升级记录。因此,数据库很好,T-SQL 很好,因此在 NHibernate 内部存在误解。

【问题讨论】:

  • 究竟是什么不起作用?急切加载仅意味着升级列表直接在 WorkflowEscalationPolicy 对象之后加载,并不意味着执行了某些连接。
  • 抱歉,已添加说明。即使数据库中有记录,(WorkflowEscalation 的)Escalations 属性也是空的。也许这就是我不清楚的地方?但是,我以前看过这段代码!有些事情发生了变化,我接受我已经打破了它,但需要弄清楚如何:)

标签: nhibernate


【解决方案1】:

如果Escalations 集合在不应该为空的情况下为空,则急切加载没有问题。因为如果你不急于加载一个集合,NHibernate 只会在你第一次访问它时加载它,所以你永远不会看到它是空的。唯一的区别是急切加载在同一个 SQL 查询中加入集合,而延迟加载执行一个(或多个,称为 select n+1 问题)单独的查询。

我不知道它是否会对您使用的数据库产生影响,但是您的键列在映射中是不同的,尽管它们应该相同(一个以大写“D”结尾,一个以小写结尾)。

您确定返回的WorkflowEscalationPolicy 对象不在任何NHibernate 缓存中吗?如果是,NHibernate 可能会丢弃 SQL 查询的结果,只返回现有对象。尝试为您的查询创建一个新会话。

PS:与您的问题无关,但在查询许多父对象时急切加载集合时要小心。示例:如果您有 100 个父级并且每个父级在集合中有 100 个元素,则您的 SQL 查询将返回 10000 行。您不会从 NHibernate 获得 10000 个对象,但所有这些行仍然必须从数据库发送到您的客户端。在这种情况下最好使用延迟加载,并使用子选择获取或批处理映射集合以防止选择 n+1 问题。

【讨论】:

  • 谢谢@cremor。您帮助我理解了急切的加载并不一定等于急切的人口,这就是我所追求的。也感谢你的 PS,我很感激。有趣的是,这只是一个单元测试,API 将会从中增长,这将有助于实现这一点——尽管我对目前的创纪录水平感到高兴。

    关于区分大小写的有趣点,我不知道这一点,也没有看到任何提及它。我已经更正了这个

    但是它仍然无法填充子集合。我已经更新了我的问题以澄清。

  • @Program.X 您确定返回的WorkflowEscalationPolicy 对象不在任何NHibernate 缓存中吗?如果是,NHibernate 可能会丢弃 SQL 查询的结果,只返回现有对象。尝试为您的查询创建一个新会话。
  • 就是这样。毫无疑问,我需要熟悉 NHibernate 的许多隐藏方面。非常感谢。
  • @Program.X 很高兴知道。我已将其添加到答案中,因此遇到相同问题的其他用户不必阅读 cmets。
猜你喜欢
  • 2011-03-14
  • 1970-01-01
  • 2018-11-16
  • 1970-01-01
  • 2011-05-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-22
相关资源
最近更新 更多