首页 文章

使用Fluent NHibernate / Nhibernate和Automapping进行预先加载

提问于
浏览
23

我需要加载一个名为 Node 的复杂对象......好吧,它不是那么复杂......看起来如下: -

Node 引用了 EntityType ,其中有一对多 Property ,而 PorpertyListValue 又有一对多 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对象 . 没有延迟加载 . 原因是我在数据库中有数千个Node对象,我必须使用WCF服务通过线路发送它们 . 我遇到了类SQL N 1问题 . 我正在使用Fluent Nhibernate和Automapping,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不会将属性加载到对象中 . 事实上,返回的节点数等于查询的行数,因此重复节点对象 . 此外,每个节点内的属性都会重复,Listvalues也是如此 .

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

谢谢Nabeel

4 回答

  • 22

    每个映射都必须关闭延迟

    在节点映射中:

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

    在EnityType Map中:

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

    等等...

    另外,请参阅NHibernate Eager loading multi-level child objects一次性加载

    添加:

    有关Sql N 1的其他信息:

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

  • 9

    我自己搞清楚了 . 关键是使用 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

  • 13

    我最终得到了这样的东西:

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

    只需确保选择这样的实体,以避免因连接而重复:

    session.CreateCriteria(typeof(T)).SetResultTransformer(Transformers.DistinctRootEntity).List<T>();
    
  • 4

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

相关问题