如何在NHibernate中加载关联而不重复?
我需要加载一个非常大的对象列表,有很多孩子和孩子的孩子。 最好的方法是什么?
我正在使用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(); }
提取集合是一个困难的操作。 它有许多副作用(如你意识到,当有更多的collections) 。 但是即使拿到一个集合,我们也会加载很多重复的行。
一般来说,对于集合加载,我build议使用批处理。 这将执行更多的SQL查询…但不是那么多,更重要的是,您可以在根列表ARNomination
上进行分页。
参见: 19.1.5。 使用批量提取可以find更多的细节。
您必须使用属性batch-szie="25"
来标记您的集合和/或实体。
XML:
<bag name="Contacts" ... batch-size="25"> ...
stream利:
HasMany(x => x.Contacts) ... .BatchSize(25)
请在这里检查几个参数:
- NHibernate的QueryOver与提取导致多个SQL查询和数据库命中
- 这是在NHibernate中加载子集合的正确方法
- https://stackoverflow.com/q/18419988/1679310
只要你急于加载多个集合,我就会同意@ RadimKhlerler,那么笛卡尔的产品总是会发生的。 为了select一个合适的批量大小,那么我可能会select这个与page size
相同,因为它只是觉得正确…(没有证据为什么)
还有另外一种技术,你可能觉得更合适,那就是阅读Ayende的博客文章,告诉你如何在同一时间发送两个未来的查询,以便加载多个集合,灵魂工作是单独加载每个集合。
然而,无论您select哪条路线,我build议您在结果中添加一个分析器,以查看哪个更适合您