避免N+1选择在NHibernate中使用业务规则
我知道在Hibernate/NHibernate中避免N+1选择问题的基本方法,但是遇到了一个我找不到好的解决方案的问题变体 我映射了以下三个实体:Item、Category和Customer。一个项目将多对多关联到类别,一个类别将多对一映射到客户。到目前为止,没有什么特别的 我的应用程序中的标准查询是获取给定客户的所有项目。我使用以下标准执行此操作,尝试急切地获取项目的类别,以避免在检查项目的categories属性时选择N+1:避免N+1选择在NHibernate中使用业务规则,nhibernate,business-logic,Nhibernate,Business Logic,我知道在Hibernate/NHibernate中避免N+1选择问题的基本方法,但是遇到了一个我找不到好的解决方案的问题变体 我映射了以下三个实体:Item、Category和Customer。一个项目将多对多关联到类别,一个类别将多对一映射到客户。到目前为止,没有什么特别的 我的应用程序中的标准查询是获取给定客户的所有项目。我使用以下标准执行此操作,尝试急切地获取项目的类别,以避免在检查项目的categories属性时选择N+1: ICriteria criteria = mySession.
ICriteria criteria = mySession.CreateCriteria(typeof(Item));
.CreateCriteria("Categories", NHibernate.SqlCommand.JoinType.InnerJoin)
.Add(Expression.Eq("Customer", c));
criteria.SetFetchMode("Categories", FetchMode.Eager);
return criteria.List();
然而,这不起作用,NHibernate仍然会在以后以每项一个select的方式获取类别
我相信,NHibernate知道第一次查询的结果是在Customer上过滤的,并且查询返回的类别可能不完整,因此它以后必须执行单独的查询来获取类别。这个假设正确吗?在我看来,NHibernate必须以这种方式工作以确保正确的结果是合理的
但是,根据我的业务规则或您想称之为的规则,一个项目不能属于多个客户的类别,因此实际上我知道第一次查询的结果实际上是完整的
我的问题是:我能以任何方式告诉NHibernate这个商业规则吗?在这种情况下,是否有其他方法可以避免N+1选择,这似乎很常见?将尝试回答我自己的问题,因为我到目前为止还没有得到任何答案 我的解决方案是将问题分为两个查询:首先获取属于相关客户的项目的ID:
IQuery query = mySession.CreateQuery("select item.Id from Item as item "
+ "join item.Categories as category "
+ "join category.Customer customer "
+ "where customer.id=:id")
.SetInt32("id", c.Id);
IList itemIds = query.List();
然后,我只使用ID获取实际项目,而不涉及对客户的任何限制。通过这种方式,NHibernate知道它可以从一个连接中获得所有类别,从而避免问题中提到的N+1选择:
ICriteria criteria = mySession.CreateCriteria(typeof(MapItem))
.SetFetchMode("Categories", FetchMode.Eager)
.SetResultTransformer(new DistinctRootEntityResultTransformer())
.Add(Expression.In("Id", itemIds));
IList items = criteria.List();
我想不出任何解决方案,可以将这个问题简化为一个有效的单一查询。此外,这种方法迫使程序员对NHibernate的内部工作原理了解得太多,在编写新的查询或条件时很容易遗漏。更普遍的解决办法更可取