C# NHibernate非故意惰性属性加载

C# NHibernate非故意惰性属性加载,c#,performance,nhibernate,lazy-loading,C#,Performance,Nhibernate,Lazy Loading,我为业务对象引入了一个映射,其中包含一个名为“Name”的属性: 出于某种原因,当我获取“Foo”对象时,NHibernate似乎应用了惰性属性加载(对于简单属性,而不是关联): 下面的代码段生成n+1个SQL语句,其中第一个语句只获取ID,其余的n个语句获取每条记录的名称: ISession session = ...IQuery query = session.CreateQuery(queryString); ITransaction tx = session.BeginTransacti

我为业务对象引入了一个映射,其中包含一个名为“Name”的属性:

出于某种原因,当我获取“Foo”对象时,NHibernate似乎应用了惰性属性加载(对于简单属性,而不是关联):

下面的代码段生成n+1个SQL语句,其中第一个语句只获取ID,其余的n个语句获取每条记录的名称:

ISession session = ...IQuery query = session.CreateQuery(queryString);
ITransaction tx = session.BeginTransaction();

List<Foo> result = new List<Foo>();
foreach (Foo foo in query.Enumerable())
{
    result.Add(foo);
}

tx.Commit();
session.Close();
类似地,以下代码在会话关闭后导致LazyLoadingException:

ISession session = ...
ITransaction tx = session.BeginTransaction();
Foo result = session.Load<Foo>(id);
tx.Commit();
session.Close();

Console.WriteLine(result.Name);

顺便说一句:抽象的“BusinessObjectBase”基类封装了用作内部标识符的ID属性。

我不认为这是由于延迟属性加载造成的。这是因为使用了
Enumerable
Load

请查看关于
可枚举的

。。。迭代器将在上加载对象 请求,使用返回的标识符 通过初始SQL查询(n+1) 总数)

或者使用批处理获取来减少查询的数量(在类的映射中)

注意:
Enumerable
只有在您不希望需要整个结果,或者在不希望同时将它们全部存储在内存中的特殊情况下才有意义(然后您需要
execute
删除它们)。在大多数情况下,
List
是您所需要的


Load
的情况下,只创建一个代理(不执行查询)。在第一次访问它时,它被加载。(例如,在查询中使用此代理作为筛选参数或将其链接到另一个实体而无需加载其内容时,此功能非常强大。)如果需要其内容,请使用
Get

using (ISession session = ...)
using (ITransaction tx = session.BeginTransaction())
{
    Foo result = session.Get<Foo>(id);

    tx.Commit();
}
// could still fail in case of lazy loaded references
Console.WriteLine(result.Name);
使用(ISession会话=…)
使用(ITransaction tx=session.BeginTransaction())
{
Foo result=session.Get(id);
tx.Commit();
}
//在延迟加载引用的情况下仍可能失败
Console.WriteLine(result.Name);
。。。或者更好的方法是,仅在会话打开时使用实体

using (ISession session = ...)
using (ITransaction tx = session.BeginTransaction())
{
    Foo result = session.Load<Foo>(id);
    // should always work fine
    Console.WriteLine(result.Name);

    tx.Commit();
}
使用(ISession会话=…)
使用(ITransaction tx=session.BeginTransaction())
{
Foo result=session.Load(id);
//应该一直都很好
Console.WriteLine(result.Name);
tx.Commit();
}

您使用的是哪个NHibernate版本?2.1.2.4000;嗯,那是<3。猜这个版本甚至不支持惰性属性?不管怎样,正如Stefan指出的,这个问题并不是由于延迟属性加载造成的。用代码示例和进一步的建议更新了我的答案。非常准确和有用的答案,谢谢。根据链接的参考文档,第一个问题的解决方案是:IList result=query.List(),或者如果我需要一个列表,则List result=query.List().ToList();-如果是这样,您可能希望在答案中包含此代码,以供将来的读者参考?我现在已经实现了.List(),它的性能比以前要好得多!(当然,因为现在与数据库的通信负载是O(1)而不是O(n)
<class name="Foo" table="V1_FOO">
    ...
    <property name="Name" column="NAME"/>
</class>
<class name="Foo" table="V1_FOO" batch-size="20">
IQuery query = session.CreateQuery(queryString);
List<Foo> result query.List<Foo>();
using (ISession session = ...)
using (ITransaction tx = session.BeginTransaction())
{
    Foo result = session.Get<Foo>(id);

    tx.Commit();
}
// could still fail in case of lazy loaded references
Console.WriteLine(result.Name);
using (ISession session = ...)
using (ITransaction tx = session.BeginTransaction())
{
    Foo result = session.Load<Foo>(id);
    // should always work fine
    Console.WriteLine(result.Name);

    tx.Commit();
}