I created a working prototype for SQL Server CONTAINS only and without wildcard columns. What it achieves is to use CONTAINS, like normal LINQ functions:
var query = context.CreateObjectSet<MyFile>() .Where(file => file.FileName.Contains("pdf") && FullTextFunctions.ContainsBinary(file.FileTable_Ref.file_stream, "Hello"));
You will need:
1. Function definitions in code and EDMX to support the CONTAINS keyword.
2.Rewrite EF SQL using EFProviderWrapperToolkit / EFTracingProvider, because CONTAINS is not a function, and by default the generated SQL treats its result as a bit.
BUT:
1.Contains is not really a function, and you cannot choose logical results from it. It can only be used in conditions.
2. The SQL rewrite code below is likely to break if the queries contain non-parameterized strings with special characters.
Source of my prototype
Function Definitions: (EDMX)
In edmx: StorageModels / Schema
<Function Name="conTAINs" BuiltIn="true" IsComposable="true" ParameterTypeSemantics="AllowImplicitConversion" ReturnType="bit" Schema="dbo"> <Parameter Name="dataColumn" Type="varbinary" Mode="In" /> <Parameter Name="keywords" Type="nvarchar" Mode="In" /> </Function> <Function Name="conTAInS" BuiltIn="true" IsComposable="true" ParameterTypeSemantics="AllowImplicitConversion" ReturnType="bit" Schema="dbo"> <Parameter Name="textColumn" Type="nvarchar" Mode="In" /> <Parameter Name="keywords" Type="nvarchar" Mode="In" /> </Function>
PS: strange cases of characters are used to enable the same function with different types of parameters (varbinary and nvarchar)
Function Definitions: (code)
using System.Data.Objects.DataClasses; public static class FullTextFunctions { [EdmFunction("MyModel.Store", "conTAINs")] public static bool ContainsBinary(byte[] dataColumn, string keywords) { throw new System.NotSupportedException("Direct calls are not supported."); } [EdmFunction("MyModel.Store", "conTAInS")] public static bool ContainsString(string textColumn, string keywords) { throw new System.NotSupportedException("Direct calls are not supported."); } }
PS: "MyModel.Store" is the same as the value in edmx: StorageModels / Schema / @ Namespace
Rewrite EF SQL: (using EFProviderWrapperToolkit)
using EFProviderWrapperToolkit; using EFTracingProvider; public class TracedMyDataContext : MyDataContext { public TracedMyDataContext() : base(EntityConnectionWrapperUtils.CreateEntityConnectionWithWrappers( "name=MyDataContext", "EFTracingProvider")) { var tracingConnection = (EFTracingConnection) ((EntityConnection) Connection).StoreConnection; tracingConnection.CommandExecuting += TracedMyDataContext_CommandExecuting; } protected static void TracedMyDataContext_CommandExecuting(object sender, CommandExecutionEventArgs e) { e.Command.CommandText = FixFullTextContainsBinary(e.Command.CommandText); e.Command.CommandText = FixFullTextContainsString(e.Command.CommandText); } private static string FixFullTextContainsBinary(string commandText, int startIndex = 0) { var patternBeg = "(conTAINs("; var patternEnd = ")) = 1"; var exprBeg = commandText.IndexOf(patternBeg, startIndex, StringComparison.Ordinal); if (exprBeg == -1) return commandText; var exprEnd = FindEnd(commandText, exprBeg + patternBeg.Length, ')'); if (commandText.Substring(exprEnd).StartsWith(patternEnd)) { var newCommandText = commandText.Substring(0, exprEnd + 2) + commandText.Substring(exprEnd + patternEnd.Length); return FixFullTextContainsBinary(newCommandText, exprEnd + 2); } return commandText; } private static string FixFullTextContainsString(string commandText, int startIndex = 0) { var patternBeg = "(conTAInS("; var patternEnd = ")) = 1"; var exprBeg = commandText.IndexOf(patternBeg, startIndex, StringComparison.Ordinal); if (exprBeg == -1) return commandText; var exprEnd = FindEnd(commandText, exprBeg + patternBeg.Length, ')'); if (exprEnd != -1 && commandText.Substring(exprEnd).StartsWith(patternEnd)) { var newCommandText = commandText.Substring(0, exprEnd + 2) + commandText.Substring(exprEnd + patternEnd.Length); return FixFullTextContainsString(newCommandText, exprEnd + 2); } return commandText; } private static int FindEnd(string commandText, int startIndex, char endChar) {
Enable EFProviderWrapperToolkit:
If you get it via nuget, it should add these lines to your app.config or web.config:
<system.data> <DbProviderFactories> <add name="EFTracingProvider" invariant="EFTracingProvider" description="Tracing Provider Wrapper" type="EFTracingProvider.EFTracingProviderFactory, EFTracingProvider, Version=1.0.0.0, Culture=neutral, PublicKeyToken=def642f226e0e59b" /> <add name="EFProviderWrapper" invariant="EFProviderWrapper" description="Generic Provider Wrapper" type="EFProviderWrapperToolkit.EFProviderWrapperFactory, EFProviderWrapperToolkit, Version=1.0.0.0, Culture=neutral, PublicKeyToken=def642f226e0e59b" /> </DbProviderFactories> </system.data>