2012-01-05 41 views
1

我在我的网页有几个下拉菜单。这些链接并具有类似的双向链接类结构。nhibernate3查询 - 收藏与收藏

换句话说:类Alpha有一个类Beta的列表,而类又有一个类Charlie的列表。每个Beta类也有它自己的Alpha列表(它所属的列表),每个类Charlie都有它自己的Beta列表。

我使用的NHibernate 3与流利的nhibernate和automappings。

现在。如果我只是运行一个

session.CreateCriteria<Alpha>().SetMaxResults(1000).List<Alpha>(); 

我收到N + 1的问题,当我循环的集合。

我看到它的方式如下SQL的应该是所有与查询到数据库

select top 1000 * from Alpha 
select top 1000 * from Beta 
select top 1000 * from Charlie 
select * from Alpha2Beta 
select * from Beta2Charlie 

但是我怎么写这个工作查询?

+0

您在Alpha和Beta,Beta和Charlie之间有双向关系 - 您如何期望只查询这三个表?必须有链接表来实现这个... – 2012-01-05 10:37:43

+0

哦,我很傻,你绝对是对的!我将更新文本 – Ivar 2012-01-05 11:17:48

+0

听起来像您正在使用无状态会话。 StatelessSession没有缓存 - 并且无状态会话中的对象不能延迟加载。这意味着您将无法预取组件并执行组合查询。如果是这种情况 - 您需要在查询中使用.Fetch()以便从Alpha2Beta和Beta2Charlie中加载子对象。你仍然会有一些重复 - 但并不像N + 1那么糟糕。 – Origin 2012-01-05 15:54:02

回答

0

如果您使用的是Criteria,则需要包含方法调用Dyanmic Fetching

+0

据我所知,你不能在多个集合上使用动态抓取。您可以通过这种方式获取多个相关实体和一个集合。 – 2012-01-05 19:14:46

1

Ayende在他的博客中展示了一个不错的窍门。我没有亲自尝试过,因为我决定改变我的BL以避免这个问题,所以请带上一点盐。

你应该可以单独加载集合,让NHibernate使用NHibernate Futures来连接实体。因为它不是一个轻的主题,所以你最好是read his blog post

+0

这是一种时尚,但即使你查询每个Alpha和每个Beta,你仍然会遇到SELECT N + 1,因为NH必须查询Alpha <-> Beta关联。 – Rytmis 2012-01-05 22:57:50

+0

再一次,我没有试过它只是指向资源,但为什么你需要另一个N + 1,如果你加载Alpha和Beta AND连接表?我并不是说只是加载所有东西都可以,但如果不是这样,那是因为它不被支持,并不是因为它不能实现。当然,这需要一些创造性的映射:)(映射连接表) – 2012-01-05 23:22:33

+0

如果您查询Alpha和Betas,身份映射(L1缓存)将确保您在访问关联时不需要加载任何Betas阿尔法。但是,在查询中没有加载的是关联表的内容,所以当你点击关联时会发生什么是“SELECT FROM Alpha_to_Beta WHERE Alpha_Id = n”,而不是“SELECT FROM Alpha_to_Beta INNER JOIN Beta ...” - 也就是说,如果关联尚未加载,则无法预先加载实体本身。这是否澄清了我的观点? :-) – Rytmis 2012-01-06 15:40:48

0

据我所知,按照查询级别进行查询是没有办法的,就像使用连接抓取一样。但是,如果你改变了映射并设置默认获取模式协会是“子查询”,你可能会惊喜:

Hibernate Documentation(同样适用与NHibernate):

对于集合上的fetch =“subselect”,您可以告诉Hibernate不仅在第二个SELECT(懒惰或非懒惰)中加载此集合,还会为所有在您加载的“拥有”实体中加载其他集合 第一个SELECT。这是 获取多个并行集合”

这意味着所要求的第一个关联时,NHibernate的会,而不是装载一个联想,回忆你用得到的根实体的查询特别有用,然后加载查询返回的根实体类型的所有实例的关联数据。

也就是说,如果您正在加载1K个实体并且您希望每个关联的记录数超过一对,那么您'可能只是从(SELECT N + 1)^ 2转到“我只是将整个数据库加载到内存中的圣诞垃圾”.-)

(请注意,如果你这样做,并且有一个场景可以加载Alpha列表,但只需要关联一个Alpha的Betas,你仍然会加载所有这些,并且你无能为力。但实际上,我发现这是一种非常罕见的情况,所以通常对子查询进行适当的调整。)