【问题标题】:NHibernate IN Expression / Restrictions Hitting 2100 Parameter Limit SQL ServerNHibernate IN 表达式/限制达到 2100 参数限制 SQL Server
【发布时间】:2019-10-20 13:09:27
【问题描述】:

有没有办法强制 NHibernate 运行查询而不将其作为参数化查询执行。基本上我遇到了一个问题,即我达到了 SQL Server 的 2100 参数限制。

由于对我的查询的“IN”限制,我达到了限制。由于某些原因,我不会详细说明我需要在查询中使用 NHibernate In Restriction。

Query.Add(Restrictions.In("df.ID", myList));

我在查询上运行了 NHibernate 分析器,并且 NHibernate 将每个“In”值作为参数而不是文字值传递。

myList 是一个包含超过 5201 个值的数组。我在网上进行了研究,对于可以传递给 SQL 的 IN 值的数量没有限制,所以如果我可以让 NHibernate 将值作为文字值而不是应该解决我的问题的参数传递。

任何帮助将不胜感激。另外请不要评论我对 IN 语句的使用,我遇到了一个问题,我的查询要求我以这种方式使用 IN 语句,而我无法以任何其他方式处理它。

【问题讨论】:

标签: sql asp.net sql-server nhibernate nhibernate-criteria


【解决方案1】:

我能够通过使用添加到我的查询中的 SQL 标准语句并结合使用表值参数来解决这个问题。

而不是这样:

Query.Add(Restrictions.In("df.ID", myList));

我用过这个:

Query.Add(new SQLCriterion(new SqlString(string.Format("this_.ID NOT IN (SELECT * FROM [dbo].[Explode] ('{0}'))", siteProdIds)), new object[0], new IType[0]))

然后我在我的数据库上创建了这个函数:

CREATE FUNCTION [dbo].[Explode](
    @string    varchar(MAX) -- '1,2,3,5,6,7'
)
RETURNS @table TABLE(element int)
AS
BEGIN
DECLARE @temp varchar(MAX), @delimPos AS tinyint = 0         
SET @temp= LTRIM(RTRIM(@string))
WHILE CHARINDEX(',',@temp) > 0 
BEGIN 
SET @delimPos = CHARINDEX(',',@temp)
INSERT INTO @table(element) VALUES (CAST((LEFT(@temp,@delimPos-1)) AS int))
SET @temp= RTRIM(LTRIM(SUBSTRING(@temp,@delimPos+1,LEN(@temp)-@delimPos))) 
END 
INSERT INTO @table(element) VALUES (CAST((@temp) AS int))
RETURN
END

【讨论】:

    【解决方案2】:

    如果你对文字值没问题,你可以使用以下类:

        /// <summary>
        /// IN expression with inlined parameters like  "Id IN (1, 2, 3)"   
        /// </summary>
        public class InlineInExpression : SimpleExpression
        {
            //Note!!! this works properly only for numeric types. String list requires escaping and wrapping each value in `[escapedValue]`
            public static InlineInExpression For<T>(string propertyPath, IEnumerable<T> list)
            {
                return new InlineInExpression(propertyPath, string.Join(", ", list));
            }
    
            /// <summary>
            /// IN expression ctor
            /// </summary>
            /// <param name="propertyPath">Property path</param>
            /// <param name="inExpression">Coma-delimited parameters like "1, 2, 3"</param>
            private InlineInExpression(string propertyPath, string inExpression)
                :base(propertyPath, null, inExpression)
            {
            }
    
            public override SqlString ToSqlString(ICriteria criteria, ICriteriaQuery criteriaQuery)
            {
                SqlString[] columnNames =
                    CriterionUtil.GetColumnNamesForSimpleExpression(PropertyName, null, criteriaQuery, criteria, this, Value);
    
                if (columnNames.Length != 1)
                    throw new HibernateException("This expression supports only single column properties.");
    
                return new SqlString(columnNames[0], " IN (", Op, ")");
            }
        }
    

    及用法示例:

    Query.Add(InlineInExpression.For("df.ID", myList));
    

    请注意,它仅适用于数值(int、long 等)。如果需要字符串处理 - 你应该自己实现它。

    您还可以将此方法应用于您的解决方案,以避免将 SQLCriterion 与表别名和列名一起使用。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-11-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-10-14
      相关资源
      最近更新 更多