25

我需要加载一个名为Node的复杂对象......它并不复杂......它看起来如下: -

节点具有对EntityType的引用,该引用与Property具有一对多关系,而Property又与PorpertyListValue具有一对多关系

public class Node
{
    public virtual int Id
    {
        get;
        set;
    }

    public virtual string Name
    {
        get;
        set;
    }

    public virtual EntityType Etype
    {
        get;
        set;
    }

}


public class EntityType
{
    public virtual int Id
    {
        get;
        set;
    }

    public virtual string Name
    {
        get;
        set;
    }

    public virtual IList<Property> Properties
    {
        get;
        protected set;
    }

    public EntityType()
    {
        Properties = new List<Property>();
    }
}

public class Property
{
    public virtual int Id
    {
        get;
        set;
    }

    public virtual string Name
    {
        get;
        set;
    }        

    public virtual EntityType EntityType
    {
        get;
        set;
    }

    public virtual IList<PropertyListValue> ListValues
    {
        get;
        protected set;
    }

    public virtual string DefaultValue
    {
        get;
        set;
    }

    public Property()
    {
        ListValues = new List<PropertyListValue>();
    }
}


public class PropertyListValue
{
    public virtual int Id
    {
        get;
        set;
    }

    public virtual Property Property
    {
        get;
        set;
    }

    public virtual string Value
    {
        get;
        set;
    }

    protected PropertyListValue()
    {
    }
}

我试图做的是一次加载所有子对象的 Node 对象。没有延迟加载。原因是我在数据库中有数千个节点对象,我必须使用 WCF 服务通过网络发送它们。我遇到了类 SQL N+1 问题。我正在使用带有 Automapping 的 Fluent Nhibernate,而 NHibernate Profiler 建议我使用FetchMode.Eager一次加载整个对象。我正在使用以下 qyuery

     Session.CreateCriteria(typeof (Node))
            .SetFetchMode( "Etype", FetchMode.Join )
            .SetFetchMode( "Etype.Properties", FetchMode.Join )
            .SetFetchMode( "Etype.Properties.ListValues", FetchMode.Join )

或使用 NHibernate LINQ

        Session.Linq<NodeType>()
         .Expand( "Etype")
         .Expand( "Etype.Properties" )
         .Expand( "Etype.Properties.ListValues" )

当我运行上述任何查询时,它们都会生成一个带有所有左外连接的相同查询,这正是我所需要的。但是,由于某种原因,查询返回的 IList 没有被加载到对象中。实际上返回的Nodes计数等于查询的行数,因此Nodes对象是重复的。此外,每个Node中的属性都是重复的,Listvalues也是如此。

所以我想知道如何修改上述查询以返回所有具有属性和列表值的唯一节点。

4

4 回答 4

23

每个映射都必须有延迟加载

在节点图中:

Map(x => x.EntityType).Not.LazyLoad();

在 EnityType 地图中:

Map(x => x.Properties).Not.LazyLoad();

等等...

另请参阅NHibernate Eager loading multi-level child objects for one time eager loading

添加:

关于 Sql N+1 的附加信息:

http://nhprof.com/Learn/Alerts/SelectNPlusOne

于 2010-06-29T18:27:27.873 回答
14

我自己想办法。关键是使用SetResultTransformer()将DistinctRootEntityResultTransformer的对象作为参数传递。所以查询现在如下所示

Session.CreateCriteria(typeof (Node))
   .SetFetchMode( "Etype", FetchMode.Join )
   .SetFetchMode( "Etype.Properties", FetchMode.Join )
   .SetFetchMode( "Etype.Properties.ListValues", FetchMode.Join )
   .SetResultTransformer(new DistinctRootEntityResultTransformer());

我通过这些链接找到了我的问题的答案:

http://www.mailinglistarchive.com/html/nhusers@googlegroups.com/2010-05/msg00512.html

http://ayende.com/Blog/archive/2010/01/16/eagerly-loading-entity-associations-efficiently-with-nhibernate.aspx

于 2010-08-18T09:50:57.253 回答
9

我最终得到了这样的结果:

HasMany(x => x.YourList).KeyColumn("ColumnName").Inverse().Not.LazyLoad().Fetch.Join()

只需确保像这样选择您的实体,以避免由于加入而导致重复:

session.CreateCriteria(typeof(T)).SetResultTransformer(Transformers.DistinctRootEntity).List<T>();
于 2011-10-12T19:09:38.480 回答
4

带有 DistinctRootEntityResultTransformer 的 SetResultTransformer 仅适用于 Main 对象,但 IList 集合将成倍增加。

于 2010-12-21T20:16:34.903 回答