#用Fetch解决Select N+1

多层次结构ComponentCode

ComponentCode 是一个自指向的多层次类,伪代码定义如下:

class ComponentCode
{
    ComponentCode Parent;
    IEnumerabl<ComponentCode> Children;
}

灵活设计带来的副作用

我们用到的ComponentCode多达4层,而且很多时候是要全部取出来。直接依靠他本身的映射,就会出现Select N+1 的问题,我的案例就有1600次到数据库的读取。 部分影射代码如下:

class ComponentCodeMap: ClassMap<ComponentCode>
{
    public ComponentCodeMap()
        {
            Id(x => x.Id);           
            References(x => x.Parent);
            HasMany(x => x.Children).Cascade.All();
        }
}

QueryOver中的Fetch

幸运的是, nHibernate的QueryOver有一个方法 fetch可以在一个查询中通过join把子对象同时查询出来。

QueryOver.Of<ComponentCode>()
    .Where(x=>...)
    .Fetch(x=>x.Children).Eager

Fetch的级联

但是,我们有4级,可以持续使用Fetch,不过有点小技巧:

QueryOver.Of<ComponentCode>()
    .Where(x=>...)
    .Fetch(x=>x.Children).Eager
    .Fetch(x=>x.Children.First().Children).Eager
    .Fetch(x=>x.Children.First().Children.First().Children).Eager

重复记录

使用Join(Eager)来Fetch数据库,存在重复记录的问题: http://nhibernate.info/doc/howto/various/get-unique-results-from-joined-queries.html http://www.andriybuday.com/2010/08/understanding-fetchmode-and-fetchtype.html

( 本文版权属于© 2015 卓逸天成 | 转载请注明作者和出处:卓逸知识文库 http://kb.skight.com )