powered by simpleCommunicator - 2.0.59     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / ADO.NET, LINQ, Entity Framework, NHibernate, DAL, ORM [игнор отключен] [закрыт для гостей] / NHibernate - loading trees
19 сообщений из 19, страница 1 из 1
NHibernate - loading trees
    #37094772
Pregamil
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Всем доброго времени суток. Вопрос вот такой вот. Решил оптимизировать работу с деревом категорий. С одной стороны, хотелось бы для отдельных случаев оставить возможность работать с деревом через ленивую загрузку. Но в ситуациях с редактированием деревьев нужно загружать их полностью. Самый простой вариант, который пришел, выключить ленивую загрузку подкатегорий и установить batch="очень много", тогда запросов на БД (при загрузке деревьев категорий) идет очень мало. Но при этом возможность работать лениво (даже при установке в запросах _session.QueryOver<Category>().Where(category => category.Id == id).Fetch(x => x.ChildCategories).Lazy ) пропадает... Таким образом, подумал, LazyLoad отключать нельзя, но нужно попробовать загрузить все категории одним запросом, прописанным на TSQL вручную. Нашел статью , в которой говорится, что есть такая возможность в NHibernate. Обрадовался, реализовал:

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
public class Category : DomainObject<long>
{
    public Category()
    {
        ChildCategories = new List<Category>();
    }

    public virtual string Name { get; set; }

    public virtual Category Parent { get; set; }
    public virtual IList<Category> ChildCategories { get; private set; }

    public virtual void AddChild(Category category)
    {
        if (category.Parent !=null && category.Parent != this)
        {
            category.Parent.RemoveChild(category);
        }

        ChildCategories.Add(category);
        category.Parent = this;
    }

    public virtual void RemoveChild(Category category)
    {
        if (ChildCategories.Contains(category))
        {
            ChildCategories.Remove(category);
            category.Parent = null;
        }
    }
}

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="NHibernateLab.Domain" namespace="NHibernateLab.Domain" default-lazy="true">

  <class name="Category" table="Category">
   
    <id name="Id" column="CategoryID" type="long">
      <generator class="native"/>
    </id>
    
    <property name="Name" column="Name" type="string"/>

    <many-to-one name="Parent" class="Category" column="ParentId"/>
    
    <bag name="ChildCategories" cascade="all" inverse="true">
      <key column="ParentId"/>
      <one-to-many class="Category"/>  
    </bag>
    
  </class>
  
</hibernate-mapping>

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
public Category GetFullTree(long Id)
{
    string query = @"WITH Hierachy(CategoryId, Name, Level)
                        AS
                        (
	                        SELECT CategoryID, Name, 0 AS Level
	                        FROM Category c
	                        WHERE c.CategoryID = :id
	
	                        UNION ALL
	
	                        SELECT cat.CategoryId, cat.Name, hier.Level + 1
	                        FROM Category cat
	                        INNER JOIN Hierachy hier
	                        ON cat.ParentId = hier.CategoryId
                        )
                        SELECT CategoryId, Name
                        FROM Hierachy
                        WHERE Level >= 0";


    List<Category> list = _session.CreateSQLQuery(query)
                    .AddEntity(typeof (Category))
                    .SetInt64("id", Id)
                    //.SetCacheable(true)
                    .List<Category>().ToList();

    Category result = list.Where(cat => cat.Parent == null).First();

    return result;
}

Метод GetFullTree реально инициализирует громадную коллекцию объектов, и возвращает root клиентскому коду. Но при первом обращении клиентского кода к любому rootCategory.ChildCategories[x], на базу данных уходит запрос на получение этого Child'а. Это, видимо, потому, что NHibernate-то создал кучу объектов при TSQL-запросе, но не связал их, и обернул проксиками. Таким образом проблема: lazy отключать нельзя, потому, что из кода его включить не удается, а загружать через custom-tsql нельзя, так как объекты не связываются друг с другом, оборачиваются в прокси, и при первом обращении к подобъектам будут сгенерированы запросы на базу данных. Игрался уже с second-level cache

Код: plaintext
1.
2.
3.
4.
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="NHibernateLab.Domain" namespace="NHibernateLab.Domain" default-lazy="true">

  <class name="Category" table="Category">
    <cache usage="read-write"/>  
.......

Код: plaintext
1.
2.
3.
4.
5.
<hibernate-configuration  xmlns="urn:nhibernate-configuration-2.2" >
  <session-factory name="NHibernate.Test">
.........
    <property name="cache.provider_class">NHibernate.Cache.HashtableCacheProvider</property>
    <property name="cache.use_second_level_cache">true</property>
.........

...не помогло, так как, по-видимому, он кеширует именно запросы, а TSQL-запрос сильно отличается от тех, что генерит NHibernate. Подскажите, как тут быть? Спасибо :)
...
Рейтинг: 0 / 0
NHibernate - loading trees
    #37095832
Pregamil
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Если я не понятно сформулировал вопрос, скажите пожалуйста, я переформулирую. Спасибо.
...
Рейтинг: 0 / 0
NHibernate - loading trees
    #37096885
ViPRos
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Pregamil,

да нахрен эти нибернейты нужны? у них ж ума нету
...
Рейтинг: 0 / 0
NHibernate - loading trees
    #37096888
Pregamil
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
ViPRosда нахрен эти нибернейты нужны? у них ж ума нету
Если к NHibernate с умом подойти, то очень нужны. А по теме есть какие-нибудь идеи?
...
Рейтинг: 0 / 0
NHibernate - loading trees
    #37096900
ViPRos
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Pregamil,

идея одна - простая
в БД нафиг не нужны деревя, потому что Родитель и Потомок разного типа (попроще, из разных таблиц), так что имеем n типов и их агрегатов (юнион) и скоко надо ограничений - Может состоять(агрегатный типI, агрегатный тип J,....) одноуревновые и отношений Состоит(элементагрегатный типI, элементагрегатный тип J,....)
мозгов у хибера не хватит выбрать их по уму
...
Рейтинг: 0 / 0
NHibernate - loading trees
    #37096940
Pregamil
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
ViPRosPregamil,

идея одна - простая
в БД нафиг не нужны деревя, потому что Родитель и Потомок разного типа (попроще, из разных таблиц), так что имеем n типов и их агрегатов (юнион) и скоко надо ограничений - Может состоять(агрегатный типI, агрегатный тип J,....) одноуревновые и отношений Состоит(элементагрегатный типI, элементагрегатный тип J,....)
мозгов у хибера не хватит выбрать их по уму
Ну, во-первых, в моём случае родитель и потомок одного типа (попроще, в одной таблице живут). Во-вторых, если имеем n типов, то не факт, что агрегатов будет тоже n, по крайней мере не всегда так. В NHibernate для выборки таких связанных коллекций можно указать Fetch(x=>x.Collection).Eager, тогда он выберет подколлекцию сразу же, через left outer join. С выборками из разных таблиц, в общем-то, более-менее понятно, но здесь имеем дело с одной таблицей и рекурсивной выборкой всего дерева. Fetch(x=>x.Collection).Eager выбирает только один подуровень (коллекцию Children первого уровня). Но нужно всё дерево. Можно отключить ленивую загрузку и установить batchsize="много", тогда он сделает пару-тройку запросов на базу, и выберет всё дерево, но как тогда включить lazyLoading для других запросов? Из кода включить не удалось. Далее, попалась под руку статья, где указывается, что можно самому прописать рекурсивный TSQL-запрос, и подсунуть хиберу в session.CreateSQLQuery. Прописал, подсунул, получил несколько тысяч категорий в коллекции. Но друг с другом они не связаны, и в каждой категории Children'ы обёрнуты в проксики, поэтому при первом обращении к любой коллекции сразу же следует вызов на БД. А россыпью мне эти несколько тыщ категорий не нужны. Какие идеи? (кроме реализации на чистом ado.net)
...
Рейтинг: 0 / 0
NHibernate - loading trees
    #37097045
ViPRos
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Pregamil,

во первых :) я не сказал что будет n агрегатов, скорееих будет >= n так как типы сами выступают в роли агрегата тоже
во вторых, неужто этот batchsize действует на всю сессиию, скорее есть возможность указать это для отдельного графа (подсхемы)
вощем это все теория, счас пацаны проснуться и скажут
...
Рейтинг: 0 / 0
NHibernate - loading trees
    #37097323
SolYUtor
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ViPRosсчас пацаны проснуться и скажут
Проснулся, вот ответ .
...
Рейтинг: 0 / 0
NHibernate - loading trees
    #37098156
Pregamil
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
SolYUtorViPRosсчас пацаны проснуться и скажут
Проснулся, вот ответ .

Здорово, работает :) Спасибо!

Опробовал этот вариант, вот код:

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
public void GetCategory(long id)
{
    Category category = _session.CreateQuery(
        "select cat from Category cat join fetch cat.ChildCategories")
        .SetResultTransformer(new DistinctRootEntityResultTransformer())
        .List<Category>()
        .Where(x => x.Id == id)
        .First();
}

И вот SQL, который пошел на базу данных при выполнении этого метода:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
select category0_.CategoryID  as CategoryID1_0_,
       category1_.CategoryID  as CategoryID1_1_,
       category0_.Name        as Name1_0_,
       category0_.ParentId    as ParentId1_0_,
       category1_.Name        as Name1_1_,
       category1_.ParentId    as ParentId1_1_
from   Category category0_
       inner join Category category1_
         on category0_.ParentId = category1_.CategoryID

В результате получил проинициализированное дерево. Только есть одно но: вне сессии его использовать нельзя, так как Children-коллекции листьев этого дерева (которые, по сути, должны быть пустыми коллекциями), NHibernate оформил в виде своих проксиков, которые, опять таки, ломятся в базу.
Можно-ли каким-то образом заставить его генерировать пустые коллекции, которые при первом доступе к ним не будут ломиться в базу? Спасибо.
...
Рейтинг: 0 / 0
NHibernate - loading trees
    #37101848
SolYUtor
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Pregamil,

Вы немного не то делаете. Надо грузить в список все категории, а уже корневые выбирать из этого загруженного списка.
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
        [Test]
        public void LoadFullTree()
        {
            var parent = new Category {Caption = "Parent"};
            var child1 = new Category {Caption = "Child1"};
            var child2 = new Category {Caption = "Child2"};
            var subchild = new Category {Caption = "SubChild"};
            
            parent.AddChild(child1);
            parent.AddChild(child2);
            child2.AddChild(subchild);

            CurrentSession.PersistFlushClear(parent);

            var tree = CurrentSession
                .CreateQuery("select c from Category c join fetch c.Children")
                .SetResultTransformer(new DistinctRootEntityResultTransformer())
                .List<Category>();


            foreach (var category in tree.Where(category => category.HasChildren))
            {
                foreach (var child in category.Children)
                {
                    Trace.TraceInformation(child.Caption);
                }
            }

В результатет ни одного дополнительного запроса в базу:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
NHibernate: 
    select
        category0_.Id as Id9_0_,
        children1_.Id as Id9_1_,
        category0_.Caption as Caption9_0_,
        category0_.ParentId as ParentId9_0_,
        children1_.Caption as Caption9_1_,
        children1_.ParentId as ParentId9_1_,
        children1_.ParentId as ParentId0__,
        children1_.Id as Id0__ 
    from
        dbo_Category category0_ 
    inner join
        dbo_Category children1_ 
            on category0_.Id=children1_.ParentId

Information: 0 : Child1
Information: 0 : Child2
Information: 0 : SubChild
...
Рейтинг: 0 / 0
NHibernate - loading trees
    #37104604
Pregamil
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
SolYUtorВы немного не то делаете. Надо грузить в список все категории, а уже корневые выбирать из этого загруженного списка.
Спасибо, проверил. И что самое интересное: если идти по алгоритму:

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
Category tree;

using (ISession session = CreateSession())
{
    int Id = CreateAndPersistCategoryTree();
    tree = LoadCategoryTree(Id);
}

WriteTreeRecursive(tree);

т.е. в одной сессии и создать, и прочитать категории, то вне сессии (после её закрытия), всё отрабатывает по-человечески, без проксиков и поползновений в базу.

Но если сохранить дерево в одной сессии, а прочитать в совершенно другой, то NHibernate тут же обернет чайлдов категорий-листьев дерева в проксики, и попытается полезть в базу.

Написал тестовый пример. SQL базы:

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
USE [master]
GO

IF EXISTS(SELECT name FROM sys.databases
     WHERE name = 'NHCategories')
     BEGIN
		 DROP DATABASE NHCategories
	 END
GO

CREATE DATABASE NHCategories
GO

USE [NHCategories]
GO
/****** Object:  Table [dbo].[Categories]    Script Date: 02/08/2011 14:25:20 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Categories](
	[Id] [int] IDENTITY( 1 , 1 ) NOT NULL,
	[Name] [nvarchar](max) NOT NULL,
	[ParentId] [int] NULL,
 CONSTRAINT [PK_Categories] PRIMARY KEY CLUSTERED 
(
	[Id] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
USE [master]
GO

Вывод на консоль в рамках одной сессииNHibernate: INSERT INTO Categories (Name, ParentId) VALUES (@p0, @p1); select SC
OPE_IDENTITY();@p0 = 'Parent' [Type: String (4000)], @p1 = NULL [Type: Int32 (0)
]
NHibernate: INSERT INTO Categories (Name, ParentId) VALUES (@p0, @p1); select SCOPE_IDENTITY();@p0 = 'Child1' [Type: String (4000)], @p1 = 33 [Type: Int32 (0)]
NHibernate: INSERT INTO Categories (Name, ParentId) VALUES (@p0, @p1); select SCOPE_IDENTITY();@p0 = 'Child2' [Type: String (4000)], @p1 = 33 [Type: Int32 (0)]
NHibernate: INSERT INTO Categories (Name, ParentId) VALUES (@p0, @p1); select SCOPE_IDENTITY();@p0 = 'SubChild' [Type: String (4000)], @p1 = 35 [Type: Int32 (0)
]
NHibernate: select category0_.Id as Id0_0_, children1_.Id as Id0_1_, category0_.Name as Name0_0_, category0_.ParentId as ParentId0_0_, children1_.Name as Name0_1_, children1_.ParentId as ParentId0_1_, children1_.ParentId as ParentId0__, children1_.Id as Id0__ from Categories category0_ inner join Categories children1_on category0_.Id=children1_.ParentId
----
33 - Parent
34 - Child1
35 - Child2
36 - SubChild
Вывод на консоль в рамках разных сессийNHibernate: INSERT INTO Categories (Name, ParentId) VALUES (@p0, @p1); select SCOPE_IDENTITY();@p0 = 'Parent' [Type: String (4000)], @p1 = NULL [Type: Int32 (0)]
NHibernate: INSERT INTO Categories (Name, ParentId) VALUES (@p0, @p1); select SCOPE_IDENTITY();@p0 = 'Child1' [Type: String (4000)], @p1 = 25 [Type: Int32 (0)]
NHibernate: INSERT INTO Categories (Name, ParentId) VALUES (@p0, @p1); select SCOPE_IDENTITY();@p0 = 'Child2' [Type: String (4000)], @p1 = 25 [Type: Int32 (0)]
NHibernate: INSERT INTO Categories (Name, ParentId) VALUES (@p0, @p1); select SCOPE_IDENTITY();@p0 = 'SubChild' [Type: String (4000)], @p1 = 27 [Type: Int32 (0)]
NHibernate: select category0_.Id as Id0_0_, children1_.Id as Id0_1_, category0_.Name as Name0_0_, category0_.ParentId as ParentId0_0_, children1_.Name as Name0_1_, children1_.ParentId as ParentId0_1_, children1_.ParentId as ParentId0__, chi
ldren1_.Id as Id0__ from Categories category0_ inner join Categories children1_on category0_.Id=children1_.ParentId
-----
25 - Parent
26 - Child1
NHibernate: SELECT children0_.ParentId as ParentId1_, children0_.Id as Id1_, children0_.Id as Id0_0_, children0_.Name as Name0_0_, children0_.ParentId as ParentId0_0_ FROM Categories children0_ WHERE children0_.ParentId=@p0;@p0 = 26 [Type:Int32 (0)]
27 - Child2
28 - SubChild
NHibernate: SELECT children0_.ParentId as ParentId1_, children0_.Id as Id1_, children0_.Id as Id0_0_, children0_.Name as Name0_0_, children0_.ParentId as ParentId0_0_ FROM Categories children0_ WHERE children0_.ParentId=@p0;@p0 = 28 [Type:Int32 (0)]

Контрольный пример приложил в аттаче. Параметр метода SessionManager.OpenSession(true/false) меняет видимость сессии (возвращает новую сессию, или старую, уже использованую ранее).

Заранее благодарен, если есть идет, почему так происходит и как с этим работать.
...
Рейтинг: 0 / 0
NHibernate - loading trees
    #37104795
SolYUtor
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Pregamil,

NHibernate всегда старается грузить как можно меньше данных из бд. Рецепт стар как мир - ленивая загрузка. Поэтому ему и нужны прокси - для автоматической ленивой загрузки, без дополнительных телодвижений. Сессия всегда возвращает прокси-объекты (если включена ленивая загрузка). Даже когда вы грузите всё дерево целиком с DistinctRootEntityResultTransformer, всё равно возвращаются прокси, только уже инициализированные. Прокси-объект всегда связан с той сессией, в которой он открыт, потому после закрытия сессии становится почти безполезен.
Использование сессии для одной операции, и последующие ее закрытие (как в вашем примере) - это антишаблон. Если вы работаете с деревом - то держите сессию открытой, и уже по окончании работы с деревом сбрасывайте изменения в БД ( Session.Flush() ).
...
Рейтинг: 0 / 0
NHibernate - loading trees
    #37104860
Pregamil
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
SolYUtorЕсли вы работаете с деревом - то держите сессию открытой, и уже по окончании работы с деревом сбрасывайте изменения в БД ( Session.Flush() ).
Изменять категории мне не нужно, нужно только читать. Как в принципе работать с сессиями и NH мне понятно. Задача, в общем-то, немного другая: в приложении выгрузить все категории и отобразить на странице. Выгрузить одним запросом. Т.е. в базе уже есть категории, и если выгрузить их одним запросом и начать рекурсивно конвертировать автомаппером на [Category -> CategoryViewModel], то автомаппер будет обходить всё дерево. И когда дойдет до листьев, NH будет делать запросы на БД из-за проксиков. Чтобы всё работало и не падало, надо держать сессию открытой, тогда при доступе автомаппера к самым конечным подкатегориям он отправит запрос на базу. В итоге, при выборе всех категорий NH шлет один запрос на базу, и при конвертировании категории в CategoryViewModel будет еще несколько запросов на базу (в примере выше - +2 запроса, из-за Lazy Loading-а). Категорий много, поэтому мелких запросов на сервер больше тысячи, что убивает производительность. Да и попытка выкачать все категории одним махом ради одного запроса на базу и была. Если выключить LazyLoading, то не получится работать с категориями лениво. Вот и вопрос: каким именно образом выгрузить категории из базы и сконвертировать их в иерархию других классов (CategoryViewModel), чтобы при этом пошел ровно один запрос на базу данных, а не 1001 (при конвертировании)? Согласен и сессию держать открытой, и что угодно. Но как?
...
Рейтинг: 0 / 0
NHibernate - loading trees
    #37104903
SolYUtor
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Pregamil,

речь идёт об ASP.NET приложении?
...
Рейтинг: 0 / 0
NHibernate - loading trees
    #37104917
Pregamil
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
да, об ASP.NET MVC.
...
Рейтинг: 0 / 0
NHibernate - loading trees
    #37105991
SolYUtor
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Pregamil,

решение ваших проблем есть тут . Гугл вам поможет :)
...
Рейтинг: 0 / 0
NHibernate - loading trees
    #37106303
KirillMedvedev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Практически всё правильно, за исключением одной маленькой ошибки:

session.CreateQuery("from Category cat left join fetch cat.Children")

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
public static Category LoadCategory(long Id)
{
    using (ISession session = SessionManager.OpenSession(true))
    {
        Category category = session.CreateQuery("from Category cat left join fetch cat.Children")
                                    .List<Category>()
                                    .Where(cat=>cat.Id == Id)
                                    .First();

        return category;
    }
}

Таким образом при закрытой сессии можно работать со всем деревом, в базу больше лезть не будет.
...
Рейтинг: 0 / 0
NHibernate - loading trees
    #37106505
KirillMedvedev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
А вот, по сути, и разница:

Первый вариант:
from Category cat inner join fetch cat.Children

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
select category0_.Id       as Id0_0_,
       children1_.Id       as Id0_1_,
       category0_.Name     as Name0_0_,
       category0_.ParentId as ParentId0_0_,
       children1_.Name     as Name0_1_,
       children1_.ParentId as ParentId0_1_,
       children1_.ParentId as ParentId0__,
       children1_.Id       as Id0__
from   Categories category0_
       inner join Categories children1_
         on category0_.Id = children1_.ParentId

SQL output:
Id0_0Id0_1Name0_0ParentId0_0Name0_1ParentId0_0ParentId_0Id0_12ParentNULLChild111213ParentNULLChild211334Child21SubChild334


Второй вариант:
from Category cat left join fetch cat.Children
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
select category0_.Id       as Id0_0_,
       children1_.Id       as Id0_1_,
       category0_.Name     as Name0_0_,
       category0_.ParentId as ParentId0_0_,
       children1_.Name     as Name0_1_,
       children1_.ParentId as ParentId0_1_,
       children1_.ParentId as ParentId0__,
       children1_.Id       as Id0__
from   Categories category0_
       left outer join Categories children1_
         on category0_.Id = children1_.ParentId

SQL output:
Id0_0Id0_1Name0_0ParentId0_0Name0_1ParentId0_0ParentId_0Id0_12ParentNULLChild111213ParentNULLChild21132NULLChild11NULLNULLNULLNULL34Child21SubChild3344NULLSubChild3NULLNULLNULLNULL

Поэтому при inner-join при доступе к самым вложенным категориям NHibernate лезет в базу, так как у него нет информации о Child-ах: есть они или нет. При left outer join лезть в базу смысла нет, так как он теперь явно понимает, что коллекция пуста.
...
Рейтинг: 0 / 0
NHibernate - loading trees
    #37106819
Pregamil
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Thanx, всё прояснилось :)
...
Рейтинг: 0 / 0
19 сообщений из 19, страница 1 из 1
Форумы / ADO.NET, LINQ, Entity Framework, NHibernate, DAL, ORM [игнор отключен] [закрыт для гостей] / NHibernate - loading trees
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]