NHibernate IN 表达式/限制达到 2100 参数限制 SQL 服务器
NHibernate IN Expression / Restrictions Hitting 2100 Parameter Limit SQL Server
有没有办法强制 NHibernate 运行 查询而不将其作为参数化查询执行。基本上,我 运行 遇到了一个问题,我遇到了 SQL 服务器的 2100 参数限制。
由于我的查询受到 "IN" 限制,我达到了极限。由于某些原因,我不会详细说明我需要在查询中使用 NHibernate In Restriction。
Query.Add(Restrictions.In("df.ID", myList));
我在查询中使用了 运行 NHibernate 探查器,NHibernate 将每个 "In" 值作为参数而不是文字值传递。
myList 是一个包含超过 5201 个值的数组。我在网上研究过,您可以传递给 SQL 的 IN 值没有限制,所以如果我能让 NHibernate 将这些值作为文字值而不是参数传递,那么应该可以解决我的问题。
如有任何帮助,我们将不胜感激。另外请不要评论我对 IN 语句的使用,我已经 运行 遇到一个问题,我的查询要求我以这种方式使用 IN 语句,而我无法以任何其他方式处理它。
我能够通过使用添加到我的查询中的 SQL 条件语句并结合使用 table-valued 参数来解决这个问题。
而不是这个:
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
如果您对文字值没问题,您可以使用以下 class:
/// <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
与 table 别名和列名一起使用。
有没有办法强制 NHibernate 运行 查询而不将其作为参数化查询执行。基本上,我 运行 遇到了一个问题,我遇到了 SQL 服务器的 2100 参数限制。
由于我的查询受到 "IN" 限制,我达到了极限。由于某些原因,我不会详细说明我需要在查询中使用 NHibernate In Restriction。
Query.Add(Restrictions.In("df.ID", myList));
我在查询中使用了 运行 NHibernate 探查器,NHibernate 将每个 "In" 值作为参数而不是文字值传递。
myList 是一个包含超过 5201 个值的数组。我在网上研究过,您可以传递给 SQL 的 IN 值没有限制,所以如果我能让 NHibernate 将这些值作为文字值而不是参数传递,那么应该可以解决我的问题。
如有任何帮助,我们将不胜感激。另外请不要评论我对 IN 语句的使用,我已经 运行 遇到一个问题,我的查询要求我以这种方式使用 IN 语句,而我无法以任何其他方式处理它。
我能够通过使用添加到我的查询中的 SQL 条件语句并结合使用 table-valued 参数来解决这个问题。
而不是这个:
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
如果您对文字值没问题,您可以使用以下 class:
/// <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
与 table 别名和列名一起使用。