Загруженное дерево NHibernate попадает в базу данных при обходе Automapper - PullRequest
2 голосов
/ 26 июля 2011

Я столкнулся со странной проблемой NHibernate и Automapper. Я не уверен, кто виноват, но я борюсь за целый день, и я не могу понять, почему.

Вот мои файлы отображения Nhibernate:

Navigation.hbm.xml

<id name="ID" column="NavigationID">
  <generator class="identity"></generator>
</id>

<property name="IsDefault"/>
<property name="RoleType" column="RoleTypeID" />

<bag  name="Items" cascade="save-update" inverse="true" lazy="false" fetch="join">
  <key column="NavigationID"/>
  <one-to-many class="NavigationItem"/>
</bag>

NavigationItem.hbm.xml

 <class name="NavigationItem" table="NavigationItem">

<id name="ID" column="NavigationItemID">
  <generator class="identity"></generator>
</id>

<property name="ShowInMenu"/>
<property name="Order" column="[Order]" />

<many-to-one name="Page" column="PageID" lazy="false" fetch="join" />
<many-to-one name="Navigation" column="NavigationID" />
<many-to-one name="Parent" column="ParentNavigationItemID" />

<bag  name="Items" cascade="save-update" inverse="true">
  <key column="ParentNavigationItemID"/>
  <one-to-many class="NavigationItem"/>
</bag>

Вот как я заполняю объект навигации:

ISession session = SessionProvider.Instance.CurrentSession;

            using (transaction = session.BeginTransaction())
            {
                var navigation = session.QueryOver<Navigation>()
                    .Where(x => x.IsDefault && x.RoleType == null)
                    .TransformUsing(new NHibernate.Transform.RootEntityResultTransformer())
                    .SingleOrDefault();

                transaction.Commit();
                return navigation;
            }

Так как для пакета элементов в объекте навигации установлено значение lazy = "false", я получаю только один запрос к базе данных, чтобы получить объект навигации, и левое соединение, чтобы получить также все элементы навигации.

Все идеально до сих пор.

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

Затем у меня есть модель пользовательского интерфейса, которую я сопоставляю с Automapper.

Вот модели UI:

public class NavigationModel
{
    public List<NavigationItemModel> Items { get; set; }

    public NavigationModel()
    {
        Items = new List<NavigationItemModel>();
    }
}

public class NavigationItemModel
{
    public string PageName { get; set; }
    public string Url { get; set; }
    public bool Selected { get; set; }

    public NavigationItemModel Parent { get; set; }
    public List<NavigationItemModel> Items { get; set; }
}

И сопоставления с автоматом:

AutoMapper.Mapper
            .CreateMap<NavigationItem, NavigationItemModel>()
 // IF I REMOVE THE NEXT LINE, IT HITS THE DATABASE FOR EACH SUB-ITEM of the NavigationItem.Items
            .ForMember(m => m.Items, o => o.Ignore()); 

        AutoMapper.Mapper
            .CreateMap<Navigation, NavigationModel>();

Хорошо, теперь поведение выглядит так:

  • Если я игнорирую член NavigationItem.Items в отображении, все идет хорошо, но отображается только навигация и ее элементы. Никакая коллекция подпунктов элементов навигации не отображается. НО база данных больше не попала. Но я хочу сопоставить и другие элементы ...
  • Если я удаляю строку под комментарием, база данных попадает для каждого элемента Navigation.Items, запрашивая его подэлементы (где ParentID = Item.ID).

Есть идеи, что я делаю не так?

Извините за стену текста, но я подумал, что лучше описать это более подробно, я потратил на это целый день и перепробовал все виды запросов с Future и JoinQueryOver и т. Д. Проблема, похоже, не заключается в с NHibernate, так как он загружается нормально, и я могу выполнять итерации без дополнительных вызовов в базу данных.


Я забыл включить генерируемый SQL:

Сначала есть этот запрос:

SELECT this_.NavigationID             as Navigati1_7_2_,
   this_.IsDefault                as IsDefault7_2_,
   this_.RoleTypeID               as RoleTypeID7_2_,
   items2_.NavigationID           as Navigati5_4_,
   items2_.NavigationItemID       as Navigati1_4_,
   items2_.NavigationItemID       as Navigati1_4_0_,
   items2_.ShowInMenu             as ShowInMenu4_0_,
   items2_.[Order]                as column3_4_0_,
   items2_.PageID                 as PageID4_0_,
   items2_.NavigationID           as Navigati5_4_0_,
   items2_.ParentNavigationItemID as ParentNa6_4_0_,
   page3_.PageID                  as PageID8_1_,
   page3_.Name                    as Name8_1_,
   page3_.Title                   as Title8_1_,
   page3_.Description             as Descript4_8_1_,
   page3_.URL                     as URL8_1_
FROM   Navigation this_
   left outer join NavigationItem items2_
     on this_.NavigationID = items2_.NavigationID
   left outer join Page page3_
     on items2_.PageID = page3_.PageID
WHERE  (this_.IsDefault = 1 /* @p0 */
    and this_.RoleTypeID is null)

Затем, когда Automapper вступает в игру, создается список этих запросов, отличается только параметр p0 (от 1 до 12 ... количество элементов без родителей)

SELECT items0_.ParentNavigationItemID as ParentNa6_2_,
   items0_.NavigationItemID       as Navigati1_2_,
   items0_.NavigationItemID       as Navigati1_4_1_,
   items0_.ShowInMenu             as ShowInMenu4_1_,
   items0_.[Order]                as column3_4_1_,
   items0_.PageID                 as PageID4_1_,
   items0_.NavigationID           as Navigati5_4_1_,
   items0_.ParentNavigationItemID as ParentNa6_4_1_,
   page1_.PageID                  as PageID8_0_,
   page1_.Name                    as Name8_0_,
   page1_.Title                   as Title8_0_,
   page1_.Description             as Descript4_8_0_,
   page1_.URL                     as URL8_0_
FROM   NavigationItem items0_
   left outer join Page page1_
     on items0_.PageID = page1_.PageID
WHERE  items0_.ParentNavigationItemID = 1 /* @p0 */

Это взято из приложения NHProf, надеюсь, это поможет.

Спасибо, Космин

1 Ответ

4 голосов
/ 26 июля 2011

Я думаю, что AutoMapper рекурсивно отображает ваши классы.Если это так, то вы можете указать максимальную глубину для ваших отображений, используя

Mapper.CreateMap<TSource, TDestination>().MaxDepth(2); // or 1, or 3, or whatever
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...