如果跟随 Skip(..) LINQ 部分,则 XML 字段上的自定义 SQLFunctionTemplate 会导致转义错误
Posted
技术标签:
【中文标题】如果跟随 Skip(..) LINQ 部分,则 XML 字段上的自定义 SQLFunctionTemplate 会导致转义错误【英文标题】:Custom SQLFunctionTemplate on XML field causes escaping error if a Skip(..) LINQ section follows 【发布时间】:2016-12-06 15:31:09 【问题描述】:我创建了一个自定义 SQLFunctionTemplate 来查询特定名称/值对的 XML 字段:
RegisterFunction("_ExistInCaratteristiche",
new SQLFunctionTemplate(NHibernateUtil.Boolean,
"?1.exist('/L/I/C[N=sql:variable(\"?2\") and V=sql:variable(\"?3\")]') = 1"));
我是这样使用的:
private IQueryable<MyEntity> _xmlFilter(IQueryable<MyEntity> input, string element, string value)
if (String.IsNullOrEmpty(element) || String.IsNullOrEmpty(value))
return input;
return input.Where(m => m.XMLField.XMLContains(element.ToUpper(),value));
所以,我可以做到:
..
IQueryable<MyEntity> result = Session.Query<MyEntity>();
result = _xmlFilter(result, filter.element, filter.value);
return result.ToList();
..
这工作正常。
不幸的是,如果我在此自定义过滤器之后添加一个跳过 LINQ 部分,如下所示:
..
IQueryable<MyEntity> result = Session.Query<MyEntity>();
result = _xmlFilter(result, filter.element, filter.value);
result = result.Skip(3);
return result.ToList();
..
调用 result.ToList() 时出现以下错误:
找不到引用文本的终止 ''' 字符。
我认为我正面临一个转义问题,但我真的不知道为什么只有添加一个 Skip LINQ 部分才会发生这种情况。我在 SQLFunctionTemplate 中尝试了各种引号和单引号组合,但我无法解决问题。
按照 Oskar Berggren 的要求,这是异常的完整堆栈跟踪,当 nhibernate
尝试将 iqueryable
转换为适当的查询时(即 .ToList()
是调用)
NHibernate.Exceptions.SqlParseException: Cannot find terminating ''' character for quoted text.
at NHibernate.SqlCommand.Parser.SqlParserUtils.ReadDelimitedText(String text, Int32 maxOffset, Int32 offset)
at NHibernate.SqlCommand.Parser.SqlTokenizer.<GetEnumerator>d__0.MoveNext()
at NHibernate.SqlCommand.Parser.SqlTokenizerExtensions.TryParseUntil(IEnumerator`1 tokenEnum, String keyword)
at NHibernate.SqlCommand.Parser.SqlTokenizerExtensions.TryParseUntilFirstOrderColumn(IEnumerator`1 tokenEnum, SqlToken& orderToken)
at NHibernate.SqlCommand.Parser.MsSqlSelectParser..ctor(SqlString sql)
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.Hql.Ast.ANTLR.SqlGenerator.GetSqlStringWithLimitsIfNeeded(QueryWriter queryWriter)
at NHibernate.Hql.Ast.ANTLR.SqlGenerator.EndQuery()
at NHibernate.Hql.Ast.ANTLR.SqlGenerator.selectStatement()
at NHibernate.Hql.Ast.ANTLR.SqlGenerator.statement()
at NHibernate.Hql.Ast.ANTLR.HqlSqlGenerator.Generate()
at NHibernate.Hql.Ast.ANTLR.QueryTranslatorImpl.DoCompile(IDictionary`2 replacements, Boolean shallow, String collectionRole)
at NHibernate.Hql.Ast.ANTLR.QueryTranslatorImpl.Compile(IDictionary`2 replacements, Boolean shallow)
at NHibernate.Hql.Ast.ANTLR.ASTQueryTranslatorFactory.CreateQueryTranslators(IASTNode ast, String queryIdentifier, String collectionRole, Boolean shallow, IDictionary`2 filters, ISessionFactoryImplementor factory)
at NHibernate.Hql.Ast.ANTLR.ASTQueryTranslatorFactory.CreateQueryTranslators(IQueryExpression queryExpression, String collectionRole, Boolean shallow, IDictionary`2 filters, ISessionFactoryImplementor factory)
at NHibernate.Engine.Query.QueryExpressionPlan.CreateTranslators(IQueryExpression queryExpression, String collectionRole, Boolean shallow, IDictionary`2 enabledFilters, ISessionFactoryImplementor factory)
at NHibernate.Engine.Query.QueryExpressionPlan..ctor(IQueryExpression queryExpression, Boolean shallow, IDictionary`2 enabledFilters, ISessionFactoryImplementor factory)
at NHibernate.Engine.Query.QueryPlanCache.GetHQLQueryPlan(IQueryExpression queryExpression, Boolean shallow, IDictionary`2 enabledFilters)
at NHibernate.Impl.AbstractSessionImpl.GetHQLQueryPlan(IQueryExpression queryExpression, Boolean shallow)
at NHibernate.Impl.AbstractSessionImpl.CreateQuery(IQueryExpression queryExpression)
at NHibernate.Linq.DefaultQueryProvider.PrepareQuery(Expression expression, IQuery& query, NhLinqExpression& nhQuery)
at NHibernate.Linq.DefaultQueryProvider.Execute(Expression expression)
at NHibernate.Linq.DefaultQueryProvider.Execute[TResult](Expression expression)
at Remotion.Linq.QueryableBase`1.GetEnumerator()
at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
at TRIM.Chibro.Services.Base.Operations.ListOdPOperation.Execute(ListOdPDto filter) in c:\Progetti.SVN.Cloud\Chibro\ChibroMES\src\TRIM.Chibro.Services\Base\Operations\ListOdPOperation.cs:line 30
at TRIM.Chibro.Services.Implementations.ListOdPService.Execute(ListOdPDto filter) in c:\Progetti.SVN.Cloud\Chibro\ChibroMES\src\TRIM.Chibro.Services\Implementations\ListOdPService.cs:line 20
at TRIM.Chibro.Web.Controllers.ListOdPController.Index(ListOdPModel model) in c:\Progetti.SVN.Cloud\Chibro\ChibroMES\src\TRIM.Chibro.Web\Controllers\ListOdPController.cs:line 75
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.Async.AsyncControllerActionInvoker.ActionInvocation.InvokeSynchronousActionMethod()
at System.Web.Mvc.Async.AsyncControllerActionInvoker.<BeginInvokeSynchronousActionMethod>b__39(IAsyncResult asyncResult, ActionInvocation innerInvokeState)
at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResult`2.CallEndDelegate(IAsyncResult asyncResult)
at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResultBase`1.End()
at System.Web.Mvc.Async.AsyncResultWrapper.End[TResult](IAsyncResult asyncResult, Object tag)
at System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeActionMethod(IAsyncResult asyncResult)
at System.Web.Mvc.Async.AsyncControllerActionInvoker.AsyncInvocationWithFilters.<InvokeActionMethodFilterAsynchronouslyRecursive>b__3d()
at System.Web.Mvc.Async.AsyncControllerActionInvoker.AsyncInvocationWithFilters.<>c__DisplayClass46.<InvokeActionMethodFilterAsynchronouslyRecursive>b__3f()
at System.Web.Mvc.Async.AsyncControllerActionInvoker.<>c__DisplayClass33.<BeginInvokeActionMethodWithFilters>b__32(IAsyncResult asyncResult)
at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResult`1.CallEndDelegate(IAsyncResult asyncResult)
at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResultBase`1.End()
at System.Web.Mvc.Async.AsyncResultWrapper.End[TResult](IAsyncResult asyncResult, Object tag)
at System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeActionMethodWithFilters(IAsyncResult asyncResult)
at System.Web.Mvc.Async.AsyncControllerActionInvoker.<>c__DisplayClass21.<>c__DisplayClass2b.<BeginInvokeAction>b__1c()
at System.Web.Mvc.Async.AsyncControllerActionInvoker.<>c__DisplayClass21.<BeginInvokeAction>b__1e(IAsyncResult asyncResult)
【问题讨论】:
对,那么你从哪里得到异常,它到底在抱怨哪个字符串? @OskarBerggren 抱歉回复晚了,但我一直在度假。我包含了异常的完整堆栈跟踪,一旦 Nhibernate 尝试将 IQueryable“转换”为实际查询(即调用 ToList() 时),该异常就会出现。如果您可能需要任何其他信息,请告诉我如何检索它。非常感谢。 【参考方案1】:在堆栈跟踪中,您可以看到问题来自 GetLimitString() 及其助手,这回答了您关于为什么它仅在存在 Skip() 时发生的问题。如果没有跳过/采取,则没有理由对 SQL 应用限制/偏移量,因此永远不会调用该方法。
至于问题本身,这有点困难。 NHibernate 必须对 SQL 做一些魔术,以便在 2012 年之前对 MSSQL 方言应用限制/偏移,因为它们缺乏针对此功能的直接 SQL 语法。
我不知道您的代码中是否存在转义问题,或者您是否遇到了 NHibernate 的 MsSqlSelectParser 未设计的情况。
如果您获取 NHibernate 源代码和 pdb 文件,您可以尝试向下调试到堆栈跟踪的前 5 行,并逐步查看它到底哪里出错了。
【讨论】:
以上是关于如果跟随 Skip(..) LINQ 部分,则 XML 字段上的自定义 SQLFunctionTemplate 会导致转义错误的主要内容,如果未能解决你的问题,请参考以下文章
PagedList 使用 LINQ Skip and Take,但使用 Count of results 显示分页