gpt4 book ai didi

c# - EntityFramework StartsWith() 生成的 SQL 包含计划更改 ESCAPE '~'(代字号)

转载 作者:太空狗 更新时间:2023-10-29 18:22:22 25 4
gpt4 key购买 nike

使用 EntityFramework,子句 .OrderBy(x => x.Title.StartsWith("foo")) 导致 SQL WHERE (Title LIKE 'foo%' ESCAPE '~ ')

查看完整查询的执行计划,我发现当我删除 ESCAPE '~' 时,我得到了一个不同的计划(一个利用列的非聚集索引)。

为什么 EF 试图转义不需要它的字符串,我怎样才能让它停止?

最佳答案

多余的 ESCAPE 肯定会改 rebase 数估计并给出不同的计划。虽然很有趣,但我发现它在这次测试中使它更准确而不是更准确!

CREATE TABLE T
(
Title VARCHAR(50),
ID INT IDENTITY,
Filler char(1) NULL,
UNIQUE NONCLUSTERED (Title, ID)
)

INSERT INTO T
(Title)
SELECT TOP 1000 CASE
WHEN ROW_NUMBER() OVER (ORDER BY @@SPID) < 10 THEN 'food'
ELSE LEFT(NEWID(), 10)
END
FROM master..spt_values

没有转义

SELECT *
FROM T
WHERE (Title LIKE 'foo%')

enter image description here

使用Escape

SELECT *
FROM T
WHERE (Title LIKE 'foo%' ESCAPE '~')

enter image description here

如果没有升级到更新版本的 EF 或编写您自己的自定义 DbProviderManifest 实现,我认为您在尝试删除 ESCAPE 时运气不佳。

String.StartsWithString.EndsWithString.Contains 翻译成 LIKE 而不是 CHARINDEXnew in EF 4.0

查看反射器中 System.Data.Entity, Version=4.0.0.0 的定义,相关函数似乎是(在 System.Data.SqlClient.SqlProviderManifest )

public override string EscapeLikeArgument(string argument)
{
bool flag;
EntityUtil.CheckArgumentNull<string>(argument, "argument");
return EscapeLikeText(argument, true, out flag);
}

该方法的签名是

internal static string EscapeLikeText(string text, 
bool alwaysEscapeEscapeChar,
out bool usedEscapeChar)
{

usedEscapeChar = false;
if (((!text.Contains("%") && !text.Contains("_")) && (!text.Contains("[") && !text.Contains("^"))) && (!alwaysEscapeEscapeChar || !text.Contains("~")))
{
return text;
}
StringBuilder builder = new StringBuilder(text.Length);
foreach (char ch in text)
{
switch (ch)
{
case '%':
case '_':
case '[':
case '^':
case '~':
builder.Append('~');
usedEscapeChar = true;
break;
}
builder.Append(ch);
}
return builder.ToString();
}

所以它只是硬编码为始终使用转义并且忽略返回的标志。

因此该版本的 EF 只是将 ESCAPE '~' 附加到所有 LIKE 查询。

这似乎是在最近的代码库中得到改进的东西。

SqlFunctionCallHandler.TranslateConstantParameterForLike的定义是

// <summary>
// Function to translate the StartsWith, EndsWith and Contains canonical functions to LIKE expression in T-SQL
// and also add the trailing ESCAPE '~' when escaping of the search string for the LIKE expression has occurred
// </summary>
private static void TranslateConstantParameterForLike(
SqlGenerator sqlgen, DbExpression targetExpression, DbConstantExpression constSearchParamExpression, SqlBuilder result,
bool insertPercentStart, bool insertPercentEnd)
{
result.Append(targetExpression.Accept(sqlgen));
result.Append(" LIKE ");

// If it's a DbConstantExpression then escape the search parameter if necessary.
bool escapingOccurred;

var searchParamBuilder = new StringBuilder();
if (insertPercentStart)
{
searchParamBuilder.Append("%");
}
searchParamBuilder.Append(
SqlProviderManifest.EscapeLikeText(constSearchParamExpression.Value as string, false, out escapingOccurred));
if (insertPercentEnd)
{
searchParamBuilder.Append("%");
}

var escapedSearchParamExpression = constSearchParamExpression.ResultType.Constant(searchParamBuilder.ToString());
result.Append(escapedSearchParamExpression.Accept(sqlgen));

// If escaping did occur (special characters were found), then append the escape character used.
if (escapingOccurred)
{
result.Append(" ESCAPE '" + SqlProviderManifest.LikeEscapeChar + "'");
}
}

SqlProviderManifest.EscapeLikeText与已经显示的代码相同。请注意,它现在将 false 作为第二个参数传递,并使用输出参数标志仅在必要时附加 ESCAPE

关于c# - EntityFramework StartsWith() 生成的 SQL 包含计划更改 ESCAPE '~'(代字号),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20496098/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com