使用Fluent NHibernate / Nhibernate&自动映射

时间:2010-06-29 16:48:32

标签: nhibernate fluent-nhibernate eager-loading automapping

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

节点引用了 EntityType ,其中一对多 属性,而属性一个一对多 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也是如此。

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

由于 纳比尔

4 个答案:

答案 0 :(得分: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

答案 1 :(得分:13)

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

答案 2 :(得分:9)

我最终得到了类似的东西:

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

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

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

答案 3 :(得分:4)

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