Подтвердить что ты не робот

Высокая загрузка с использованием Fluent NHibernate/Nhibernate & Automapping

У меня есть требование загрузить сложный объект с именем Node... ну его не такой сложный... он выглядит следующим образом: -

A 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" )

Когда я запускаю любой из вышеуказанных запросов, они генерируют один и тот же единственный запрос со всеми левыми внешними соединениями, что мне и нужно. Однако по какой-то причине возврат запроса ILIS из запроса не загружается в объекты. Infact возвращаемое количество узлов равно количеству строк запроса, поэтому объекты Nodes повторяются. Кроме того, свойства внутри каждого Node повторяются, а также значения Listvalues.

Итак, я хотел бы знать, как изменить указанный выше запрос, чтобы вернуть все уникальные узлы со свойствами и значениями в них.

Спасибо Набиль

4b9b3361

Ответ 1

Я сам это понял. Ключ должен использовать 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

Ответ 2

каждое отображение должно иметь ленивую загрузку

в Node Карта:

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

в карте EnityType:

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

и т.д.

Кроме того, см. NHibernate Eager загружает многоуровневые дочерние объекты для одноразовой загрузки

Добавлено:

Дополнительная информация о Sql N + 1:

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

Ответ 3

У меня получилось что-то вроде этого:

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

Просто убедитесь, что вы выбрали свой объект таким образом, чтобы избежать дублирования из-за соединения:

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

Ответ 4

SetResultTransformer с DistinctRootEntityResultTransformer будет работать только для основного объекта, но коллекции IList будут умножены.