Nhibernate 使用property ref映射到非键字段时,延迟加载不适用于多对一关系

Nhibernate 使用property ref映射到非键字段时,延迟加载不适用于多对一关系,nhibernate,lazy-loading,icriteria,Nhibernate,Lazy Loading,Icriteria,我有一个使用NHibernate映射的遗留数据库。关注的对象是帐户和通知对象列表。这些对象看起来像: public class Notification { public virtual int Id { get; set; } public virtual DateTime BatchDate { get; set; } /* other properties */ public virtual Account Account { get; set; } }

我有一个使用NHibernate映射的遗留数据库。关注的对象是帐户和通知对象列表。这些对象看起来像:

public class Notification
{
    public virtual int Id { get; set; }
    public virtual DateTime BatchDate { get; set; }
    /* other properties */

    public virtual Account Account { get; set; }
}

public class Account 
{
    public virtual int Id { get; set; }
    public virtual string AccountNumber { get; set; }
    /* other properties */ 
}
映射文件如下所示:

<class name="Account" table="Account" dynamic-update="true">
<id name="Id" column="AccountID">
    <generator class="native" />
</id>
<property name="AccountNumber" length="15" not-null="true" />
    <!-- other properties -->
</class>

<class name="Notification" table="Notification">
    <id name="Id" column="Id">
        <generator class="native" />
    </id>
    <!-- other properties -->
    <many-to-one name="Account" class="Account" property-ref="AccountNumber" lazy="proxy">
        <column name="AcctNum" />
    </many-to-one>

但是,当我创建一个标准时,例如

return session.CreateCriteria(typeof(Notification)).List<Notification>();
return session.CreateCriteria(typeof(Notification)).List();

我得到了一个selectn+1案例,其中每个帐户都被加载,即使该帐户从未被引用。当多对一映射为惰性代理时,为什么要加载所有帐户?

该问题是由
属性ref
引起的。延迟加载仅在
多对一
引用使用另一个对象的主键时起作用,因为NHibernate假定存在强制此类值有效性的外键约束。对于非主键(由属性ref指示),NHibernate不作此假设,因此不假设相关对象必须存在。由于它不想为不存在的对象创建代理(即应该为null而不是代理),因此它急切地获取远程对象。当指定了
not found=“ignore”
时,也会出现同样的问题,因为这表明外键关系没有强制执行,可能会导致空引用

另见:


我也遇到了同样的问题,我确实记得看到一篇帖子说多对一属性引用不能延迟加载,我就是找不到源。NH中的NH 1.2问题似乎在TwoPhaseLoad.cs中-它检查LoadedState并调用IType.ResolveIdentifier将密钥转换为实体或代理。这里涉及的IType是manytone(PK=false,Uniq=true,eager=false)。它最终从基EntityType.cs调用ResolveIdentifier(值、会话、所有者),并检查IsReferenceToPrimaryKey(=false)并调用LoadByUniqueKey()。这一条又有有趣的注释“TODO:实现缓存?代理?”(耶)。然后,session.PersistenceContext.GetEntity(newEntityUniqueKey(…key))与persister.LoadByUniqueKey(…key)的组合获取实体。