NHIbernate延迟加载父对象

时间:2016-02-04 15:50:22

标签: nhibernate lazy-loading nhibernate-mapping

我有两个对象CaseNote。一个案例可以有成千上万的笔记,就像成千上万。我们试图以批量方式异步加载它们,并将它们流式传输到UI,这样就没有延迟等待它们全部加载。

类/映射是

public class Case
{
        public virtual IList<Note> Notes { get; protected set; }
}

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="SCMS.TAMS.BusinessEntities" namespace="SCMS.TAMS.BusinessEntities">
    <class name="Case" table="Cases">
        <bag name="Notes" inverse="true" cascade="all" lazy="true">
            <key column="CaseID" />
            <one-to-many class="Note" />
        </bag>
    </class>
</hibernate-mapping>

public class Note
{
    public virtual Case Case {get; set;}
    public virtual long CaseId {get; set;}
}

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="SCMS.TAMS.BusinessEntities" namespace="SCMS.TAMS.BusinessEntities" default-lazy="true">
    <class name="Note" table="CaseNotes">
        <many-to-one name="Case" column="CaseID"/>
        <property name="CaseId" column="CaseID" />
    </class>
</hibernate-mapping>

现在,当我打电话

NHibernateSession.Query<Note>().Where(n => n.CaseId == 123).Skip(0).Take(10).ToList();

加载Case 123的前10个Notes,这个东西加载了Case对象,大约需要30秒,因为它上面有很多其他东西,加载时还有其他逻辑等等,我都不需要/想要在这个时候。我想要/需要的只是10个笔记。

我已尝试过这种映射的各种变体,但没有一种变得有效。我在这里做错了什么?

2 个答案:

答案 0 :(得分:1)

您是如何使用此查询的?用户界面有什么用?喜欢在网格中显示什么?或者您是在组件中执行业务逻辑?

无论哪种方式,您都希望投射到另一个对象中。您的查询现在返回一个注释列表,然后按照映射加载该父对象。

因此,如果您使用此查询将信息发送到asp.net mvc应用程序的UI,请直接投影到您的视图模型中

NHibernateSession.Query<Note>().Where(n => n.CaseId == 123).Select(n => new SomeViewModel { Prop1 = n.Prop1, Prop2 = n.Prop2 ...}).Skip(0).Take(10).ToList();

或创建匿名对象

NHibernateSession.Query<Note>().Where(n => n.CaseId == 123).Select n => new { n.Prop1, n.Prop2, ...}).Skip(0).Take(10).ToList();

这将使父对象无法加载。它还有一个额外的好处,即您只需要查询所需的信息,因为查询仅限于您预测的数据。

答案 1 :(得分:0)

重要的是要知道如果以上都是真的......

这是真正的映射(这不是一个明显的提取)

<class name="Note" table="CaseNotes">
    <many-to-one name="Case" column="CaseID"/>
    ...

这是类(再次提取没有ID)

public class Note
{
    public virtual Case Case {get; set;}
    public virtual long CaseId {get; set;}
}

这将是一个加载笔记的UNIT TEST语句:

var list = NHibernateSession
  .Query<Note>()
  .Where(n => n.CaseId == 123)
  .Skip(0).Take(10)
  .ToList();

然后 NHibernate永远不会加载Case 对象。 <强>从不即可。这是因为:

NHibernate is lazy, just live with it

原因是,加载相关引用Case属性)的触发器必须是明确的。

晴:

  

在某处使用了Case对象。 E.g。在覆盖GetHashCode()时使用Case.ID

或者:

  

有序列化或DTO转换,它触及Case属性

在这种情况下,NHibernate必须加载......

因此,使用基本查询创建一些单元测试,并确保您的实际上如上所示。然后它将按预期工作