当Automapper走过时,NHibernate渴望加载的树会命中数据库

时间:2011-07-26 18:01:52

标签: nhibernate lazy-loading automapper hierarchy eager-loading

我遇到了一个奇怪的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>

这就是我填写Navigation对象的方式:

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;
            }

由于Navigation对象上的Items包设置为lazy =“false”,因此我只获得一个查询数据库以获取Navigation对象,并且左连接也获得所有导航项目。

直到现在,一切都很完美。

我做了一个测试,遍历所有项目,子项目递归,不再对数据库进行点击。

然后,我有一个用Automapper映射的UI模型。

以下是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 个答案:

答案 0 :(得分:4)

我认为AutoMapper正在递归地映射你的类。如果是这种情况,则可以使用

指定映射的最大深度
Mapper.CreateMap<TSource, TDestination>().MaxDepth(2); // or 1, or 3, or whatever