避免N+1选择在NHibernate中使用业务规则

避免N+1选择在NHibernate中使用业务规则,nhibernate,business-logic,Nhibernate,Business Logic,我知道在Hibernate/NHibernate中避免N+1选择问题的基本方法,但是遇到了一个我找不到好的解决方案的问题变体 我映射了以下三个实体:Item、Category和Customer。一个项目将多对多关联到类别,一个类别将多对一映射到客户。到目前为止,没有什么特别的 我的应用程序中的标准查询是获取给定客户的所有项目。我使用以下标准执行此操作,尝试急切地获取项目的类别,以避免在检查项目的categories属性时选择N+1: ICriteria criteria = mySession.

我知道在Hibernate/NHibernate中避免N+1选择问题的基本方法,但是遇到了一个我找不到好的解决方案的问题变体

我映射了以下三个实体:Item、Category和Customer。一个项目将多对多关联到类别,一个类别将多对一映射到客户。到目前为止,没有什么特别的

我的应用程序中的标准查询是获取给定客户的所有项目。我使用以下标准执行此操作,尝试急切地获取项目的类别,以避免在检查项目的categories属性时选择N+1:

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的内部工作原理了解得太多,在编写新的查询或条件时很容易遗漏。更普遍的解决办法更可取