如何在NHibernate中强制加载代理对象?

时间:2015-09-29 01:57:38

标签: c# sql-server nhibernate orm lazy-evaluation

我现在正在使用NHibernate,并且遇到了一个问题,试图提高我工作的数据带宽效率。

上下文是我正在创建一个数据事件编辑器,它有一个填充了事件的列表视图。这些事件有3种类型,每种都存储在自己的MSSQL表中。

有一个父对象,其中包含这三种事件类型的列表。最初,我只是选择了所有的父母并加载了它下面的事件,但如果你说了20个父母,那么它将运行60个查询左右来加载列表。

我现在更改它只运行3个查询,一个用于选择日期X和日期Y之间的所有事件类型。(此日期在表单上设置了一些日期时间选择器。)

现在,我正在尝试在列表中打印父级的名称,但因为我在nHibernate期间从未访问过父级,所以我只有一个“代理”对象,它会导致崩溃。 Parent对象下面可能有数千个不同的对象,所以我只想加载我需要的东西。

在此期间,为了让它编译,我在nHibernate期间访问该对象。

我获取事件的代码如下:

public IList<MyEvent> GetAllMyEventForAllParentsFromSpecificTimePeriod(
    DateTime startTime, DateTime endTime)
{
    using (var session = SessionFactorySingleton.OpenSession())
    {
        var queryOver = session
               .QueryOver<MyEvent>()
               .Where(re => re.Time <= endTime)
               .And(re => startTime <= re.Time)
               .OrderBy(re => re.Time).Desc;

        var list = queryOver.List();

        if (list.Count > 0)
        {
            foreach (var myEvent in list.Select(myEvent => myEvent.ParentItem.Name)) { }
        }

        return list;
    }
}

到目前为止我发现的是列表加载速度要快得多。

所以我想这里真正的问题是我能做些什么才能实现与访问每个ParentItem.Name以强制它加载它们相同的事情?

更新答案: 由于同事的缘故,我设法提高了效率。

            return session
                .QueryOver<MyEvent>()
                .Where(re => re.Time <= endTime)
                .And(re => startTime <= re.Time)
                .JoinQueryOver(x => x.ParentItem)
                .List();

答案:

foreach (var parent in list.Select(x => x.ParentItem)) { NHibernateUtil.Initialize(parent); }

等同于:

public IList<MyEvent> GetAllMyEventForAllParentsFromSpecificTimePeriod(
    DateTime startTime, DateTime endTime)
{
    using (var session = SessionFactorySingleton.OpenSession())
    {
        var list = session
               .QueryOver<MyEvent>()
               .Where(re => re.Time <= endTime)
               .And(re => startTime <= re.Time)
               .List();

        foreach (var parent in list.Select(x => x.ParentItem)) { NHibernateUtil.Initialize(parent); }            

        return list;
    }
}

2 个答案:

答案 0 :(得分:0)

如果您只是所有ParentItem名称,则可以使用select。

var queryOver = session.QueryOver<Parent>()
               .Select(p => p.Name))
               .List<string>()

答案 1 :(得分:0)

如此处Use NHibernate AliasToBean Transformer launch n+1 query所述,我们有两个选项

  • 使用预测
  • 使用Batch-Fetching

第一个解决方案需要一些自定义转换器:

1)How to partially project a child object with many fields in nHibernate

并保持良好的QueryOver API - 这里是如何创建一些扩展方法来支持完全类型别名:

2)Nhibernate Group By and Alias To Bean

第二解决方案details herethere

  

19.1.5. Using batch fetching

     

NHibernate可以有效地使用批量提取,也就是说,如果访问一个代理(或集合),NHibernate可以加载几个未初始化的代理。批量提取是懒惰选择提取策略的优化。有两种方法可以调整批处理获取:在类和集合级别上。