NHibernate-HQL“;加入“获取”;使用SetMaxResults时抛出错误

NHibernate-HQL“;加入“获取”;使用SetMaxResults时抛出错误,nhibernate,nhibernate-mapping,hql,Nhibernate,Nhibernate Mapping,Hql,我正在尝试运行最简单的查询: string queryStr = "select b " + "from Blog b " + "left outer join fetch b.BlogComments bc"; IList<Blog> blogs = Session.CreateQuery(queryStr) .SetMaxResults(10) .List<Blog>(); 但

我正在尝试运行最简单的查询:

string queryStr = "select b " +
                  "from Blog b " +
                  "left outer join fetch b.BlogComments bc";

IList<Blog> blogs = Session.CreateQuery(queryStr)
    .SetMaxResults(10)
    .List<Blog>();
但是,如果我从HQL中删除“fetch”,它就可以正常工作。另外,如果我保留fetch in但删除SetMaxResults,它也可以正常工作。这与fetch+SetMaxResults组合有关

我正在尝试加载子集合,以优化查询并防止SELECT N+1问题。我正在使用NHibernate 3.3.1.4000和MySQL数据库


我的映射:

public class BlogMap : ClassMapping<Blog>
{
    public BlogMap ()
    {
        // other properties (snip)....

        Set(x => x.BlogComments, x =>
        {
            x.Inverse(true);
            x.Cascade(Cascade.All | Cascade.DeleteOrphans);
            x.Lazy(CollectionLazy.Extra);
            x.Key(k => { k.Column("BlogId"); });
        }, x => x.OneToMany());
    }
}


public class BlogCommentMap : ClassMapping<BlogComment>
{
    public BlogCommentMap ()
    {
        // other properties (snip)....

        ManyToOne(x => x.Blog, x =>
        {
            x.Column("BlogId");
            x.NotNullable(true);
        });
    }
}
公共类BlogMap:ClassMapping
{
公共博客地图()
{
//其他属性(snip)。。。。
设置(x=>x.blogcoments,x=>
{
x、 逆(真);
x、 级联(Cascade.All | Cascade.deleteOlivers);
x、 懒惰(CollectionLazy.Extra);
x、 键(k=>{k.Column(“BlogId”);});
},x=>x.OneToMany());
}
}
公共类映射:类映射
{
公共博客评论地图()
{
//其他属性(snip)。。。。
多通(x=>x.Blog,x=>
{
x、 专栏(“博客ID”);
x、 不可为空(true);
});
}
}

Stacktrace(按要求):

[ArgumentNullException: Value cannot be null.
Parameter name: source]
   System.Linq.Enumerable.ToList(IEnumerable`1 source) +4206743
   NHibernate.Engine.QueryParameters.CreateCopyUsing(RowSelection selection) +178
   NHibernate.Hql.Ast.ANTLR.QueryTranslatorImpl.List(ISessionImplementor session, QueryParameters queryParameters) +210
   NHibernate.Engine.Query.HQLQueryPlan.PerformList(QueryParameters queryParameters, ISessionImplementor session, IList results) +369
   NHibernate.Impl.SessionImpl.List(String query, QueryParameters queryParameters, IList results) +301

[GenericADOException: Could not execute query[SQL: SQL not available]]
   NHibernate.Impl.SessionImpl.List(String query, QueryParameters queryParameters, IList results) +351
   NHibernate.Impl.SessionImpl.List(String query, QueryParameters parameters) +282
   NHibernate.Impl.QueryImpl.List() +162
   WebApp.Repositories.BlogRepository.SearchBlogs(SearchBlogs search) in C:\...path...\BlogRepository.cs:43
   WebApp.Controllers.HomepageController.Index(Int32 page) in C:\...path...\Controllers\HomepageController.cs:54
   lambda_method(Closure , ControllerBase , Object[] ) +101
   System.Web.Mvc.ActionMethodDispatcher.Execute(ControllerBase controller, Object[] parameters) +17
   System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext, IDictionary`2 parameters) +208
   System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary`2 parameters) +27
   System.Web.Mvc.<>c__DisplayClass15.<InvokeActionMethodWithFilters>b__12() +55
   System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodFilter(IActionFilter filter, ActionExecutingContext preContext, Func`1 continuation) +263
   System.Web.Mvc.<>c__DisplayClass17.<InvokeActionMethodWithFilters>b__14() +19
   System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodWithFilters(ControllerContext controllerContext, IList`1 filters, ActionDescriptor actionDescriptor, IDictionary`2 parameters) +191
   System.Web.Mvc.ControllerActionInvoker.InvokeAction(ControllerContext controllerContext, String actionName) +343
   System.Web.Mvc.Controller.ExecuteCore() +116
   System.Web.Mvc.ControllerBase.Execute(RequestContext requestContext) +97
   System.Web.Mvc.ControllerBase.System.Web.Mvc.IController.Execute(RequestContext requestContext) +10
   System.Web.Mvc.<>c__DisplayClassb.<BeginProcessRequest>b__5() +37
   System.Web.Mvc.Async.<>c__DisplayClass1.<MakeVoidDelegate>b__0() +21
   System.Web.Mvc.Async.<>c__DisplayClass8`1.<BeginSynchronous>b__7(IAsyncResult _) +12
   System.Web.Mvc.Async.WrappedAsyncResult`1.End() +62
   System.Web.Mvc.<>c__DisplayClasse.<EndProcessRequest>b__d() +50
   System.Web.Mvc.SecurityUtil.<GetCallInAppTrustThunk>b__0(Action f) +7
   System.Web.Mvc.SecurityUtil.ProcessInApplicationTrust(Action action) +22
   System.Web.Mvc.MvcHandler.EndProcessRequest(IAsyncResult asyncResult) +60
   System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.EndProcessRequest(IAsyncResult result) +9
   System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +8970061
   System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +184
[ArgumentNullException:值不能为null。
参数名称:源]
System.Linq.Enumerable.ToList(IEnumerable`1源)+4206743
NHibernate.Engine.QueryParameters.CreateCopyUsing(行选择)+178
NHibernate.Hql.Ast.ANTLR.QueryTranslatorImpl.List(ISessionImplementor会话,QueryParameters QueryParameters)+210
NHibernate.Engine.Query.HQLQueryPlan.PerformList(QueryParameters QueryParameters,ISessionImplementor会话,IList结果)+369
NHibernate.Impl.SessionImpl.List(字符串查询、QueryParameters QueryParameters、IList结果)+301
[GenericADOException:无法执行查询[SQL:SQL不可用]]
NHibernate.Impl.SessionImpl.List(字符串查询、QueryParameters QueryParameters、IList结果)+351
NHibernate.Impl.SessionImpl.List(字符串查询,QueryParameters参数)+282
NHibernate.Impl.QueryImpl.List()+162
C:\…路径…\BlogRepository.cs:43中的WebApp.Repositories.BlogRepository.SearchBlogs(SearchBlogs搜索)
C:\…path…\Controllers\HomepageController.cs:54中的WebApp.Controllers.HomepageController.Index(Int32页)
lambda_方法(闭包、控制器库、对象[])+101
System.Web.Mvc.ActionMethodDispatcher.Execute(ControllerBase控制器,对象[]参数)+17
System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext ControllerContext,IDictionary`2参数)+208
System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext ControllerContext,ActionDescriptor ActionDescriptor,IDictionary`2参数)+27
System.Web.Mvc.c__显示类15.b__12()+55
System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodFilter(IActionFilter筛选器、ActionExecutingContext预文本、Func`1 continuation)+263
System.Web.Mvc.c__显示类17.b__14()+19
System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodWithFilters(ControllerContext ControllerContext,IList`1筛选器,ActionDescriptor ActionDescriptor,IDictionary`2参数)+191
System.Web.Mvc.ControllerActionInvoker.InvokeAction(ControllerContext ControllerContext,String actionName)+343
System.Web.Mvc.Controller.ExecuteCore()+116
System.Web.Mvc.ControllerBase.Execute(RequestContext-RequestContext)+97
System.Web.Mvc.ControllerBase.System.Web.Mvc.IController.Execute(RequestContext RequestContext)+10
System.Web.Mvc.c__显示类b.b__5()+37
System.Web.Mvc.Async.c__显示类1.b__0()+21
System.Web.Mvc.Async.c_uuudisplayClass8`1.b_uuu7(IAsyncResult)+12
System.Web.Mvc.Async.WrappedAsyncResult`1.End()+62
System.Web.Mvc.c_uuudisplayClasse.b_uuud()+50
System.Web.Mvc.SecurityUtil.b___0(操作f)+7
System.Web.Mvc.SecurityUtil.ProcessInApplicationTrust(操作)+22
System.Web.Mvc.MvcHandler.EndProcessRequest(IAsyncResult asyncResult)+60
System.Web.Mvc.MvcHandler.System.Web.IHTTPassynchandler.EndProcessRequest(IAsyncResult结果)+9
System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()+8970061
System.Web.HttpApplication.ExecuteStep(IExecutionStep步骤,布尔值&同步完成)+184

这看起来像是QueryParameters.CreateCopyUsing()中的一个bug,或者其他一些东西没有正确创建原始QueryParameters。无论如何,在集合联接中使用SetMaxResults()将强制在客户端而不是数据库中应用分页,这可能不是您想要的


你可能想重写它,在产生10个blog id的子查询中使用IN,并在外部查询中使用join抓取。

你遇到的是一个bug。。。但在这种情况下,这可能是一个好兆头因为在获取父项及其集合的查询上进行分页(
SetFirstResult()
SetMaxResults()
)将返回意外结果。比如说

DB表格包含以下内容:

  • 布洛加
    • 博客评论1
    • 博客评论2
    • 博客评论3
  • 博客
    • 博客评论B1
    • 博客评论2
QueryOver
语法(正在运行)执行与上述HQL相同的操作:

var blogs = session.QueryOver<Blog>()
  .Fetch(c => c.BlogComment).Eager // collection in one SQL
  .Skip(0).Take(2) // paging, but weird...
  .List<Blog>();
var blogs=session.QueryOver()
.Fetch(c=>c.blogcoment).Eager//在一个SQL中收集
.Skip(0).Take(2)//分页,但是很奇怪。。。
.List();
.Skip(0)。选择(2)
-第一页,选择结果是这两行,但只有一个BlogA:

|BlogA| BlogCommentA1
|BlogA | BlogCommentA2

.Skip(2)。采取(2)
-下一页,怪异。。。又是BlogA

|BlogA| BlogCommentA3
|BlogB | blogb1

这很可能不是我们想要的

建议:选择1+1 在这种情况下,最可靠的方法是只在
var blogs = session.QueryOver<Blog>()
  .Fetch(c => c.BlogComment).Eager // collection in one SQL
  .Skip(0).Take(2) // paging, but weird...
  .List<Blog>();