是否有可能使用全文search(FTS)和LINQ?

我想知道是否有可能使用.NET Framework 3.5使用LINQ的FTS。 我正在search我没有find任何有用的文档。

有没有人有这方面的经验?

是。 但是,你必须先创buildSQL服务器function,并调用,因为默认情况下LINQ将使用一个像。

这个博客文章将解释细节,但这是摘录:

为了得到它的工作,你需要创build一个表值函数,它只根据你传入的关键字来做一个CONTAINSTABLE查询,

create function udf_sessionSearch (@keywords nvarchar(4000)) returns table as return (select [SessionId],[rank] from containstable(Session,(description,title),@keywords)) 

然后,将这个函数添加到您的LINQ 2 SQL模型中,他现在可以编写像这样的查询了。

  var sessList = from s in DB.Sessions join fts in DB.udf_sessionSearch(SearchText) on s.sessionId equals fts.SessionId select s; 

否。全文search不支持LINQ To SQL。

也就是说,你可以使用一个使用FTS的存储过程,并使LINQ To SQL查询从中提取数据。

我不这么认为。 您可以在字段上使用“包含”,但仅生成LIKE查询。 如果你想使用全文,我会build议使用存储过程做查询,然后将其传回给LINQ

如果你不想创build连接并想简化你的C#代码,你可以创buildSQL函数并在“from”子句中使用它:

 CREATE FUNCTION ad_Search ( @keyword nvarchar(4000) ) RETURNS TABLE AS RETURN ( select * from Ad where (CONTAINS(Description, @keyword) OR CONTAINS(Title, @keyword)) ) 

更新你的DBML之后,在linq中使用它:

 string searchKeyword = "word and subword"; var result = from ad in context.ad_Search(searchKeyword) select ad; 

这将产生如下简单的SQL:

 SELECT [t0].ID, [t0].Title, [t0].Description FROM [dbo].[ad_Search](@p0) AS [t0] 

从ad_Search函数实现中可以看出,这可以通过多个列进行search。

不,全文search是非常特定于sql server的东西(文本是通过单词索引的,查询命中这个索引而不是遍历一个字符数组)。 Linq不支持这一点,任何.Contains()调用将打击未pipe理的string函数,但不会从索引中受益。

我做了一个工作原型,只有SQL Server的CONTAINS和没有通配符列。 它实现的是你像使用普通的LINQ函数一样使用CONTAINS

 var query = context.CreateObjectSet<MyFile>() .Where(file => file.FileName.Contains("pdf") && FullTextFunctions.ContainsBinary(file.FileTable_Ref.file_stream, "Hello")); 

你会需要:

1.代码和EDMX中的函数定义支持CONTAINS关键字。

2.通过EFProviderWrapperToolkit / EFTracingProvider重写EF SQL,因为CONTAINS不是一个函数,默认情况下生成的SQL将其结果视为

但:

1.Contains不是一个真正的函数,你不能从中select布尔结果。 它只能在条件下使用。

2.如果查询包含具有特殊字符的非参数化string,则下面的SQL重写代码可能会中断。

我的原型的来源

function定义:(EDMX)

在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:使用不同的参数types(varbinary和nvarchar)来启用相同的函数,

function定义:(代码)

 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”与edmx中的值相同:StorageModels / Schema / @ Namespace

重写EF SQL :(通过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) { // TODO: handle escape chars between parens/squares/quotes var lvlParan = 0; var lvlSquare = 0; var lvlQuoteS = 0; var lvlQuoteD = 0; for (var i = startIndex; i < commandText.Length; i++) { var c = commandText[i]; if (c == endChar && lvlParan == 0 && lvlSquare == 0 && (lvlQuoteS % 2) == 0 && (lvlQuoteD % 2) == 0) return i; switch (c) { case '(': ++lvlParan; break; case ')': --lvlParan; break; case '[': ++lvlSquare; break; case ']': --lvlSquare; break; case '\'': ++lvlQuoteS; break; case '"': ++lvlQuoteD; break; } } return -1; } } 

启用EFProviderWrapperToolkit:

如果你通过nuget得到它,它应该添加这些行到你的app.config或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>