NHIbernate 延迟加载一个父对象

NHIbernate lazy load a parent object

我有两个对象,CaseNote。一个 Case 可以有成百上千的 Notes。我们正在尝试异步、分批加载它们,并将它们流式传输到 UI,这样就不会延迟等待它们全部加载。

class/mappings是

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

加载案例 123 的前 10 个注释,加载案例对象,这需要大约 30 秒,因为上面还有很多其他东西,加载时还有其他逻辑,等等,none 其中我 need/want 此时。我want/need都是10个音符

我尝试了此映射的各种变体,其中 none 已经奏效。我在这里做错了什么?

您如何使用此查询?是 UI 的东西吗?喜欢在网格中显示还是什么?还是在组件中执行业务逻辑?

你想投影到另一个对象的任何一种方式。您现在的查询 returns 一个注释列表,然后将根据映射加载该父对象。

因此,如果您使用此查询将信息发送到 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();

这将阻止加载父对象。它还具有额外的好处,即您只查询所需的信息,因为查询仅限于您正在投影的数据。

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

这是真正的映射(这不是它只是一个明显的摘录)

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

这是class(再次提取无ID)

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

这将是一个用于加载注释的单元测试语句:

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 属性) 必须是明确的。

主要是:

there is usage of the Case object somewhere. E.g. in override of the GetHashCode() the Case.ID is used

或者:

there is a serialization or DTO conversion which does touch the Case property

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

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