如何使用字符串在 SQL Server 2008+ 中使用 Linq to Entities 搜索 varbinary 列

How to use a string to search varbinary columns in SQL Server 2008+ using Linq to Entities

我的环境是 .NET Framework 4.5.1、C#、Entity Framework 6.1.3(对象上下文)、SQL Server 2008+、ASP.NET MVC5。

我在 SQL 服务器中有一个 table,文档对象开始存储在 varbinary(max) 列中。

我正在重写一个现有的网络应用程序,我们让用户能够通过文本框输入搜索字符串 ~ 然后搜索 table 和 returns 列表中的每条记录包含用户输入搜索字符串的记录。

目前 SQL 查询,包括用户指定的搜索字符串被构建为字符串命令,然后通过 ADO.NET 数据适配器执行并传递给 SQL 服务器并且完美运行.

这是构建的完整 SQL 查询的测试示例,包括当前运行的用户指定的搜索字符串(取自 SQL 服务器分析器)

SELECT TOP 1000000 * 
FROM 
    (SELECT DISTINCT docInfo.docInfoID 
     FROM docFile 
     INNER JOIN docInfo ON docInfo.docFileID = docFile.docFileID
     INNER JOIN SOInfoArchive ON SOInfoArchive.docInfoID = docInfo.docInfoID
     WHERE (docInfo.docType LIKE 'SYSOUT')
       AND (SOInfoArchive.serverInfoID IN (1)) 
       AND CONTAINS(docFileObject, 'REM')
   )

以上查询成功returns89576条记录。

我想通过使用 LINQ to Entities 将当前构建 SQL 查询的过程替换为我的 C# 代码中的字符串命令。

我在整个项目中对所有 SQL 服务器交互使用 LINQ to Entities。

但是,我无法将用户提供的字符串传递给我的 LINQ 查询,这样我就可以替换 SQL 命令字符串查询,如上所示。

起初(错误地)我认为我可以使用 .Contains() 方法并将用户提交的字符串转换为字节传递给它,示例如下:

string input = "orderno=012p92"; //passed from the user via textbox
var bytes = System.Text.Encoding.Unicode.GetBytes(input); // convert the string to binary ready for searching the varbinary fields

using (SysviewEntities context = new SysviewEntities())
{
    var docs = from df in context.docFile
               where df.docFileObject.Contains('bytes')
               select df;
}

但这甚至无法编译,因为我收到错误

'byte[]' does not contain a definition for 'Contains' and the best extension method overload 'System.Linq.ParallelEnumerable.Contains(System.Linq.ParallelQuery, TSource)' has some invalid arguments

然后我研究了一些在 SO 上提出的类似问题,并认为解决方案是使用等于评估运算符替换 .Contains() 方法,如下所示:

string theString = "orderno=*012p92";
byte[] theBytes = Encoding.Unicode.GetBytes(theString);

using (SysviewEntities context = new SysviewEntities())
{
    string input = "orderno=012p92";
    var bytes = System.Text.Encoding.Unicode.GetBytes(input);

    var docs = (from df in context.docFile
                where df.docFileObject == bytes
                select df).ToList();                
}   

现在查询编译但 returns 没有结果 ~ 结果 SQL 从我的 LINQ 查询传递到 SQL 服务器(来自 SQL Profiler)的查询是

exec sp_executesql N'SELECT 
    [Extent1].[docFileID] AS [docFileID], 
    [Extent1].[docFileHash] AS [docFileHash], 
    [Extent1].[docFileObject] AS [docFileObject], 
    [Extent1].[docFilterType] AS [docFilterType]
    FROM [dbo].[docFile] AS [Extent1]
    WHERE [Extent1].[docFileObject] = @p__linq__0',N'@p__linq__0 varbinary(8000)',@p__linq__0=0x6F0072006400650072006E006F003D00300031003200700039003200 

所以我对搜索字符串的二进制转换显然没有奏效。

我在这里读到的所有其他问题看起来很相似,但似乎不适用于我在这里想要实现的目标 ~ 尽管我承认我很可能只是没有正确理解推荐和建议的解决方案。

所以总结一下我的问题是

  1. 是否可以使用 LINQ to Entities 轻松复制此 SQL 查询?

    SELECT TOP 1000000 * 
    FROM 
        (SELECT DISTINCT docInfo.docInfoID 
         FROM docFile 
         INNER JOIN docInfo ON docInfo.docFileID = docFile.docFileID
         INNER JOIN SOInfoArchive ON SOInfoArchive.docInfoID = docInfo.docInfoID
         WHERE (docInfo.docType LIKE 'SYSOUT')
           AND (SOInfoArchive.serverInfoID IN (1)) 
           AND CONTAINS(docFileObject, 'REM')
        )
    
  2. SQL 这部分如何/为什么查询

    AND CONTAINS(docFileObject, 'REM')
    

    获取字符串(在本例中为 REM)并搜索 table 中的所有 varbinary docFileObjects 以查找与搜索字符串 REM 匹配的记录?

    一定是某处正在进行某种转换?

  3. 如何成功复制此转换,以便我可以将转换后的字符串值传递给我的 LINQ 查询?

  4. 我最好使用当前进程而不是使用 LINQ to Entities 来实现此特定功能。

如果您能用简单的语言向我解释我做错了什么,尝试使用 LINQ to Entities 执行此操作的问题是什么以及任何简单的建议,我将不胜感激至于我能做些什么来获得解决方案。

底线是我不能使用 LINQ to Entities .Contains 方法将字符串变量传递给 SQL Contains 语句,其中 SQL 列是 Varbinary 格式。

我的解决方案是在 SQL 中创建一个存储过程,并在我的存储过程中将字符串变量作为输入 nvarchar 传递。

我第一次尝试使用临时 SQL 表执行此操作失败(存储过程有效 ~ 但我无法使用 EF 中的数据,因为 EF 无法 'see' 列的元数据我的存储过程试图 return)。

我最终使用 SQL 临时变量解决了这个问题。

下面的 SO post

中记录了我失败的过程和我解决该问题的方式