Frage

Ich frage mich, wenn möglich ist FTS mit LINQ zu verwenden .NET 3.5 Framework. Ich bin rund um die Dokumentation zu suchen, die ich noch nicht nützlich etwas gefunden hat.

Hat jemand Erfahrung auf diesem?

War es hilfreich?

Lösung

Ja. Allerdings müssen Sie SQL-Server-Funktion zuerst und rufen Sie erstellen, die als standardmäßig wird LINQ ein ähnliches verwenden.

Das Blog-Post, die das Detail, aber das ist der Extrakt wird erklärt:

  

es zum Laufen bringen Sie eine Tabelle bewertet Funktion erstellen müssen, tut   nichts anderes als eine CONTAINS Abfrage auf der Basis der Keywords, die Sie weitergeben   in,

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

Sie dann diese Funktion, um SQL-Modell LINQ 2 hinzufügen und er presto Sie   können nun Anfragen wie schreiben.

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

Andere Tipps

Nein. Volltextsuche wird nicht von LINQ to SQL unterstützt.

Das heißt, Sie können eine gespeicherte Prozedur, die FTS und haben die LINQ to SQL-Abfrage Pull Daten aus, dass verwendet.

Ich glaube nicht. Sie können ‚enthält‘ auf einem Feld verwenden, aber es erzeugt nur eine LIKE Abfrage. Wenn Sie Volltext verwenden möchten, würde ich die Abfrage mit einem gespeicherten proc empfehlen zu tun, dann ist es zu LINQ geben zurück

Wenn Sie nicht wollen, schließt sich erstellen und möchten Ihre C # -Code vereinfachen, können Sie SQL-Funktion erstellen und verwenden Sie es in „von“ Klausel:

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

Nach dem DBML aktualisieren, verwenden Sie es in Linq:

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

Dies wird produzieren einfache SQL wie folgt aus:

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

Dies ist Werk auf der Suche nach mehreren Spalten, wie Sie aus der ad_Search Funktion Implementierung sehen können.

Nein, Volltextsuche ist etwas sehr spezifisch für SQL Server (in diesem Text wird durch Worte indiziert und Abfragen schlugen diesen Index einen Zeichen-Array im Vergleich zu durchqueren). Linq dies nicht unterstützt, werden alle .Contains () ruft werden die un-verwalteten String-Funktionen schlagen, aber nicht von der Indizierung profitieren.

Ich habe einen funktionierenden Prototyp, für SQL Server ENTHÄLT nur und keine Wildcard-Spalten. Was sie erreicht, ist für Sie zu nutzen ENTHÄLT wie gewöhnliche LINQ Funktionen:

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

Sie benötigen:

1.Function Definitionen in Code und EDMX die Unterstützung ENTHÄLT Stichwort.

2.Rewrite EF SQL durch EFProviderWrapperToolkit / EFTracingProvider, weil ENTHÄLT keine Funktion und wird standardmäßig die erzeugte SQL behandelt sein Ergebnis als Bit .

ABER:

1.Contains ist nicht wirklich eine Funktion und man kann nicht boolean Ergebnisse auswählen. Es kann nur unter Bedingungen verwendet werden.

2. SQL Umschreiben Code unten ist wahrscheinlich zu brechen, wenn Abfragen enthalten nichtparametrisierter Strings mit Sonderzeichen.

Quelle meines Prototyp

Funktionsdefinitionen: (EDMX)

Unter 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: die seltsamen Fälle von Zeichen verwendet werden, um die gleiche Funktion mit verschiedenen Parametertypen (varbinary und nvarchar)

aktivieren

Funktionsdefinitionen: (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" ist das gleiche wie der Wert in edmx: StorageModels / Schema / @ Namespace

Rewrite EF SQL: (von 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;
    }
}

Aktivieren EFProviderWrapperToolkit:

Wenn Sie es nuget bekommen, sollte es diese Zeilen in Ihre app.config oder web.config hinzufügen

<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>
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top