如何在NHibernate中没有重复的情况下加载加载关联?

时间:2014-01-07 11:39:22

标签: nhibernate orm future eager-loading cartesian-product

我需要加载一个非常大的对象列表,其中有很多孩子和孩子的孩子。什么是最好的方法?

我正在使用Oracle 11g数据库,我编写了以下方法,但它产生了笛卡尔积(重复结果):

 public IList<ARNomination> GetByEventId(long eventId)
        {
            var session = this._sessionFactory.Session;

            var nominationQuery = session.Query<ARNomination>().Where(n => n.Event.Id == eventId);

            using (var trans = session.Transaction)
            {
                trans.Begin();

                // this will load the Contacts in one statement
                nominationQuery
                    .FetchMany(n => n.Contacts)
                    .ToFuture();

                // this will load the CustomAttributes in one statement
                nominationQuery
                    .FetchMany(n => n.CustomAttributes)
                    .ToFuture();

                // this will load the nominations but joins those two tables in one statement which results in cartesian product
                nominationQuery
                    .FetchMany(n => n.CustomAttributes)
                    .FetchMany(n => n.Contacts)
                    .ToFuture();

                trans.Commit();
            }

            return nominationQuery.ToList();
        }

2 个答案:

答案 0 :(得分:9)

获取集合是一项艰难的操作。它有很多副作用(正如你所知,当有更多的集合时)。但即使提取了一个集合,我们也会加载许多重复的行。

通常,对于集合加载,我建议使用批处理。这将执行更多SQL查询...但不是很多,更重要的是,您可以在根列表ARNomination上进行分页。

请参阅:19.1.5. Using batch fetching您可以找到更多详细信息。

您必须使用属性batch-szie="25"标记您的馆藏和/或实体。

的xml:

<bag name="Contacts" ... batch-size="25">
...

流利:

HasMany(x => x.Contacts)
  ...
  .BatchSize(25)

请在这里查看一些参数:

答案 1 :(得分:1)

当您急切地加载多个集合时,我同意@RadimKöhler,然后总会出现笛卡尔积。为了选择合适的批量大小,我可能会选择它与page size相同,因为它感觉正确...(虽然没有证据)

还有另一种技术,你可能觉得更合适,那就是阅读这篇博客post by Ayende,它告诉你如何同时发送两个未来的查询来急切加载灵魂工作的多个集合。单独加载每个集合。

无论你采取哪种方式,我都建议在结果中投放一个分析器,看看哪种方式对你有好处......