Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/73.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# EntityFramework StartsWith()生成的SQL包含计划更改转义'~';(瓷砖)_C#_Sql_.net_Sql Server_Entity Framework - Fatal编程技术网

C# EntityFramework StartsWith()生成的SQL包含计划更改转义'~';(瓷砖)

C# EntityFramework StartsWith()生成的SQL包含计划更改转义'~';(瓷砖),c#,sql,.net,sql-server,entity-framework,C#,Sql,.net,Sql Server,Entity Framework,使用EntityFramework,子句.OrderBy(x=>x.Title.StartsWith(“foo”))生成SQLWHERE(标题类似“foo%”ESCAPE“~”) 查看完整查询的执行计划,当我删除ESCAPE'~'时,我看到了一个不同的计划(一个使用列的非聚集索引) 为什么EF试图转义一个不需要它的字符串,我如何使它停止 多余的ESCAPE肯定会改变基数估计并给出不同的计划。虽然有趣的是,我发现它在这次测试中更准确,而不是更少 CREATE TABLE T ( Title VAR

使用EntityFramework,子句
.OrderBy(x=>x.Title.StartsWith(“foo”))
生成SQL
WHERE(标题类似“foo%”ESCAPE“~”)

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


为什么EF试图转义一个不需要它的字符串,我如何使它停止

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

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 

使用
Escape

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

除了升级到EF的最新版本或编写自己的自定义
DbProviderManifest
实现之外,我认为您在尝试删除
ESCAPE
时运气不佳

String.StartsWith
String.EndsWith
String.Contains
转换为
类似的
,而不是
CHARINDEX

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

因此,它只是硬编码为始终使用escape,而返回的标志被忽略

因此,EF的版本只是将
转义“~”
附加到所有
类似的
查询中

这似乎在最近的代码库中得到了改进

信息系统的定义是

//
//函数转换StartWith、EndsWith,并包含T-SQL中类似表达式的规范函数
//并在对类似表达式的搜索字符串进行转义时添加尾部转义“~”
// 
私有静态void TranslateConstantParameterForLike(
SqlGenerator sqlgen、DbExpression targetExpression、DbConstantExpression ConstSearchParameterExpression、SqlBuilder结果、,
bool insertPercentStart,bool insertPercentEnd)
{
Append(targetExpression.Accept(sqlgen));
结果。追加(“类似”);
//如果是DbConstantExpression,则在必要时转义搜索参数。
发生布尔逃逸;
var searchParamBuilder=新的StringBuilder();
如果(插入百分比开始)
{
searchParamBuilder.Append(“%”);
}
searchParamBuilder.Append(
SqlProviderManifest.EscapeLiketText(constSearchParameterExpression.Value为字符串,false,out escapingOccurred);
如果(插入百分比结束)
{
searchParamBuilder.Append(“%”);
}
var escapedSearchParamExpression=constSearchParamExpression.ResultType.Constant(searchParamBuilder.ToString());
Append(EscapedSearchParameterExpression.Accept(sqlgen));
//如果确实发生转义(找到特殊字符),则追加使用的转义字符。
如果(转义发生)
{
result.Append(“ESCAPE'”+SqlProviderManifest.LikeEscapeChar+“”);
}
}

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

从Entity Framework 6.2开始,添加了对
.Like()
的支持,作为
DbFunctions
的一部分

现在你可以这样做了:

var query = db.People.Where(p => DbFunctions.Like(p.Name, "w%"));

有关更多信息:

请完全按照SQL Profiler截取的内容发布完整查询。这里有些不对劲。从逻辑上讲,ESCAPE子句不应影响优化器的决策。我也无法复制:
SELECT*FROM sys.objects,其中的名称为'obj%'ESCAPE'~'
。顺便说一句,ESCAPE子句允许您正确执行StartsWith(“%”)。这是必需的。@usr-
在存在用户定义的转义字符时,我们不支持精确的基数估计。所以我们可能得到一个糟糕的估计和一个糟糕的计划。我们将考虑在将来的版本中解决这个问题。< /代码>问题也在这里回答:@ MartinSmith很好知道。另一方面,估计者似乎忽略了免责条款。对于这个精确的查询,这应该会产生相同的结果。@AndiKrusch,你的链接项不包含这个问题的答案(或者可以说是它自己的答案)。你有博客吗,Martin?@usr-没有。我只是有时候写很长的答案@马丁史密斯,再次感谢你的回答。
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();
}
// <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 + "'");
        }
    }
var query = db.People.Where(p => DbFunctions.Like(p.Name, "w%"));