web-dev-qa-db-ja.com

Fluent NHibernate / Nhibernate&Automappingを使用した積極的な読み込み

Node ...という複雑なオブジェクトをロードする必要があります。それほど複雑ではありません...次のようになります:-

NodeにはEntityTypeへの参照があり、これには1対多プロパティこれは1対多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の問題が発生しました。自動マッピングでFluentNhibernateを使用しており、NHibernate Profilerで使用するように提案されましたFetchMode.Eager =オブジェクト全体を一度にロードする次のSQLを使用しています

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

またはNHibernateLINQを使用する

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

上記のクエリのいずれかを実行すると、両方とも、すべての左側の外部結合を含む1つの同じ単一のクエリを生成します。これが必要です。ただし、何らかの理由で、クエリから返されるIListがオブジェクトにプロパティをロードされていません。実際、返されるノード数はクエリの行数と等しいため、ノードオブジェクトが繰り返されます。さらに、各Node内のプロパティが繰り返され、リスト値も繰り返されます。

したがって、上記のクエリを変更して、プロパティとリスト値を含むすべての一意のノードを返す方法を知りたいと思います。

24
nabeelfarid

私はそれを自分で理解します。重要なのは、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/[email protected]/2010-05/msg00512.html

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

13
nabeelfarid

各マッピングでは遅延読み込みをオフにする必要があります

in Node Map:

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

enityTypeマップ内:

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

等々...

また、 NHibernate Eagerがマルチレベルの子オブジェクトをロードする を参照してください。

追加:

SQL N + 1に関する追加情報:

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

23
Tim Hoolihan

私は次のようなものになりました:

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

結合による重複を避けるために、必ず次のようにエンティティを選択してください。

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

DistinctRootEntityResultTransformerを指定したSetResultTransformerは、メインオブジェクトに対してのみ機能しますが、IListコレクションは乗算されます。

4
awattar