我正在尝试获取查询结果的第2页,这是我的代码构建的预处理语句SQL查询:
SELECT DISTINCT Contents.*
FROM Contents
INNER JOIN ContentsFilter ON ContentsFilter.ContentId = Contents.ContentId
INNER JOIN Filter ON Filter.Id = ContentsFilter.FilterId
WHERE Contents.[Key] LIKE 'kh_%'
AND Filter.Name IN (:filters)
ORDER BY Contents.Created DESC
然后进行参数化,并在构造的SetFetchSize()
上调用SetFirstResult()
和IQuery
。在第1页,这工作正常,但在第2页我得到这个例外:
NHibernate.HibernateException: The dialect was unable to perform paging of a statement that requires distinct results, and is ordered by a column that is not included in the result set of the query.
at NHibernate.Dialect.MsSql2005DialectQueryPager.BuildFromClauseForPagingDistinctQuery(MsSqlSelectParser sqlQuery, SqlStringBuilder result)
at NHibernate.Dialect.MsSql2005DialectQueryPager.PageByLimitAndOffset(SqlString offset, SqlString limit)
at NHibernate.Dialect.MsSql2005DialectQueryPager.PageBy(SqlString offset, SqlString limit)
at NHibernate.Dialect.MsSql2005Dialect.GetLimitString(SqlString queryString, SqlString offset, SqlString limit)
at NHibernate.Dialect.Dialect.GetLimitString(SqlString queryString, Nullable`1 offset, Nullable`1 limit, Parameter offsetParameter, Parameter limitParameter)
at NHibernate.Loader.Loader.TryGetLimitString(Dialect dialect, SqlString queryString, Nullable`1 offset, Nullable`1 limit, Parameter offsetParameter, Parameter limitParameter, SqlString& result)
at NHibernate.Loader.Loader.AddLimitsParametersIfNeeded(SqlString sqlString, ICollection`1 parameterSpecs, QueryParameters queryParameters, ISessionImplementor session)
at NHibernate.Loader.Loader.CreateSqlCommand(QueryParameters queryParameters, ISessionImplementor session)
at NHibernate.Loader.Loader.PrepareQueryCommand(QueryParameters queryParameters, Boolean scroll, ISessionImplementor session)
at NHibernate.Loader.Loader.DoQuery(ISessionImplementor session, QueryParameters queryParameters, Boolean returnProxies, IResultTransformer forcedResultTransformer)
at NHibernate.Loader.Loader.DoQueryAndInitializeNonLazyCollections(ISessionImplementor session, QueryParameters queryParameters, Boolean returnProxies, IResultTransformer forcedResultTransformer)
at NHibernate.Loader.Loader.DoList(ISessionImplementor session, QueryParameters queryParameters, IResultTransformer forcedResultTransformer)
at NHibernate.Loader.Loader.DoList(ISessionImplementor session, QueryParameters queryParameters)
at NHibernate.Loader.Loader.ListIgnoreQueryCache(ISessionImplementor session, QueryParameters queryParameters)
at NHibernate.Loader.Loader.List(ISessionImplementor session, QueryParameters queryParameters, ISet`1 querySpaces, IType[] resultTypes)
at NHibernate.Loader.Custom.CustomLoader.List(ISessionImplementor session, QueryParameters queryParameters)
at NHibernate.Impl.SessionImpl.ListCustomQuery(ICustomQuery customQuery, QueryParameters queryParameters, IList results)
at NHibernate.Impl.AbstractSessionImpl.List(NativeSQLQuerySpecification spec, QueryParameters queryParameters, IList results)
at NHibernate.Impl.AbstractSessionImpl.List(NativeSQLQuerySpecification spec, QueryParameters queryParameters)
at NHibernate.Impl.SqlQueryImpl.List()
at MySite.Data.NHibernate.Shell.KnowledgeHubRepository.ExecuteKnowledgeHubQuery(IQuery query) in C:\Work\MySite\src\app\MySite.Data.NHibernate\Shell\KnowledgeHubRepository.cs:line 194
at MySite.Data.NHibernate.Shell.KnowledgeHubRepository.FindByFilter(String[] filters, Int32 page) in C:\Work\MySite\src\app\MySite.Data.NHibernate\Shell\KnowledgeHubRepository.cs:line 174
at Castle.Proxies.Invocations.IKnowledgeHubRepository_FindByFilter.InvokeMethodOnTarget()
at Castle.DynamicProxy.AbstractInvocation.Proceed()
at MySite.Core.App.Ioc.Interceptors.StopwatchInterceptor.Intercept(IInvocation invocation) in C:\Work\MySite\src\app\MySite.Core\App\Ioc\Interceptors\StopwatchInterceptor.cs:line 11
at Castle.DynamicProxy.AbstractInvocation.Proceed()
at Castle.Proxies.IKnowledgeHubRepositoryProxy.FindByFilter(String[] filters, Int32 page)
at MySite2.Web.Controllers.KnowledgeHubController.Get(Int32 page, String filters) in C:\Work\MySite\src\app\Website\Controllers\KnowledgeHubController.cs:line 119
at lambda_method(Closure , ControllerBase , Object[] )
at System.Web.Mvc.ActionMethodDispatcher.Execute(ControllerBase controller, Object[] parameters)
at System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext, IDictionary`2 parameters)
at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary`2 parameters)
at System.Web.Mvc.ControllerActionInvoker.<>c__DisplayClass15.<InvokeActionMethodWithFilters>b__12()
at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodFilter(IActionFilter filter, ActionExecutingContext preContext, Func`1 continuation)
at System.Web.Mvc.ControllerActionInvoker.<>c__DisplayClass15.<>c__DisplayClass17.<InvokeActionMethodWithFilters>b__14()
at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodWithFilters(ControllerContext controllerContext, IList`1 filters, ActionDescriptor actionDescriptor, IDictionary`2 parameters)
at MySite.Core.App.Ioc.WindsorActionInvoker.InvokeActionMethodWithFilters(ControllerContext controllerContext, IList`1 filters, ActionDescriptor actionDescriptor, IDictionary`2 parameters) in C:\Work\MySite\src\app\MySite.Core\App\Ioc\WindsorActionInvoker.cs:line 21
at System.Web.Mvc.ControllerActionInvoker.InvokeAction(ControllerContext controllerContext, String actionName)
我非常清楚地选择*
因此我认为异常消息不正确,如果我将其更改为SELECT DISTINCT Contents.*, Contents.Created
,我肯定会得到System.Data.SqlClient.SqlException: The column 'Created' was specified multiple times for 'q_'.
那么这个错误信息究竟意味着什么?
我正在使用NHibernate 4.0.4.4000和SQL Server Express 2008 64位10.0.6。
答案 0 :(得分:1)
我猜你使用ISession.CreateSqlQuery
。我甚至不知道NHibernate会尝试解析任意SQL查询以在其中注入分页,但它确实这样做。
不幸的是,你的案子不在案。第一页的作用是因为它不必应用偏移量,它只需要在select之后注入一个top语句。这是一个非常简单的解析和改变查询的问题。案例,没有很多检查要执行。请参阅MsSql2005DialectQueryPager.cs中的PageByLimitOnly
。
第二页和下一页因为必须注入一个row_number() over (order by yourOrderBy)
where
条件语句以便与SQL Server 2008/2005进行抵消而被吹走了,因为它非常复杂。
NHibernate必须重写顺序,并且当前实现通过依赖于distinct中不存在的列来防止重写无效顺序。旧的SQL Server版本,支持由未选择的列排序的不同查询,这种情况会导致SQL Server 2005/2008的NHibernate分页逻辑失败。 (SQL Server 2000支持这种截然不同的情况,但我认为它已经在SQL Server 2005中被删除了,所以也许NHibernate确实有其他原因。)
但目前支票的实施并未考虑*
。
请参阅MsSql2005DialectQueryPager.cs中的BuildFromClauseForPagingDistinctQuery
。
那么,既然您已经提供了自己的SQL,为什么不在其中插入自己的分页语句呢?
否则你需要尝试在NHibernate上使用pull-request支持你的情况并等待它的合并和释放。
或者升级到SQL 2012并将NHibernate方言设置为MsSql2012Dialect
:它支持offset fetch
SQL语句,这些SQL语句在任意SQL查询中都可以更简单地注入。