هل من الممكن استخدام بحث النص الكامل (FTS) مع LINQ؟

StackOverflow https://stackoverflow.com/questions/224475

سؤال

وأنا أتساءل عما إذا كان من الممكن أن تستخدم FTS مع LINQ باستخدام الإطار الصافي 3.5. أنا في البحث حول الوثائق التي لم أجد أي شيء مفيد حتى الان.

هل لديها أي خبرة في هذا؟

هل كانت مفيدة؟

المحلول

نعم. ولكن لديك لإنشاء وظيفة الخادم SQL أولا، وندعو أنه افتراضيا سوف LINQ استخدام مثل.

وهذا <وأ href = "http://sqlblogcasts.com/blogs/simons/archive/2008/12/18/LINQ-to-SQL---Enabling-Fulltext-searching.aspx" يختلط = "noreferrer" > بلوق وظيفة الذي سوف يشرح بالتفصيل ولكن هذه هي خلاصة:

<اقتباس فقرة>   

ليحصل على عمل تحتاج إلى إنشاء وظيفة الجدول تقدر أن يفعل   لا شيء أكثر من استعلام CONTAINSTABLE على أساس الكلمات الرئيسية التي تمر   في،

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

وثم إضافة هذه الوظيفة لSQL نموذج LINQ 2 وكان المعزوفة لك   ويمكن الآن إرسال الاستفسارات مثل.

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

نصائح أخرى

ولا. غير معتمد البحث عن النص الكامل LINQ إلى SQL.

وقال ذلك، كنت <م> يمكن استخدام الإجراء المخزن الذي يستخدم FTS ولها LINQ إلى البيانات سحب الاستعلام SQL من ذلك.

وأنا لا أعتقد ذلك. يمكنك استخدام "يحتوي" على الميدان، ولكنه يولد إلا استعلام LIKE. إذا كنت ترغب في استخدام النص الكامل أوصي باستخدام بروك المخزنة للقيام الاستعلام ثم تمريرها إلى LINQ

وإذا كنت لا تريد إنشاء الصلات وترغب في تبسيط الخاص بك C # رمز، يمكنك إنشاء وظيفة SQL واستخدامها في "من" شرط:

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.

لا، البحث عن النص الكامل هو شيء محدد جدا لمزود خدمة (التي تتم فهرسة النص عن طريق الكلمات، وضرب هذا المؤشر الاستفسارات مقابل عبور مجموعة أحرف). ينق لا يدعم هذا، أي .Contains () يدعو سوف تصل الى وظائف سلسلة تديرها الامم المتحدة ولكن لن تستفيد من فهرسة.

وأنا قدمت نموذج العمل، ل SQL Server في على فقط وليس أعمدة البدل. ما يحقق هو بالنسبة لك لاستخدام <م> على مثل وظائف LINQ العادية:

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

سوف تحتاج:

والتعاريف 1.Function في رمز وEDMX لدعم <م> على الكلمة.

و2.Rewrite EF SQL التي كتبها EFProviderWrapperToolkit / EFTracingProvider، لأن CONTAINS ليس وظيفة وافتراضيا SQL ولدت يعامل نتيجته ك <م> قليلا .

ولكن:

و1.Contains ليست في الحقيقة وظيفة ولا يمكنك تحديد النتائج المنطقية من ذلك. ويمكن أن تستخدم إلا في الظروف.

و2.THE SQL كود إعادة كتابة هو عرضة للكسر إذا احتوت الاستفسارات سلاسل غير ذات معلمات مع أحرف خاصة أدناه.

مصدر بلدي النموذج

تعاريف وظيفة: (EDMX)

وتحت EDMX: StorageModels / مخطط

<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>

ملاحظة: يتم استخدام حالات غريبة من حرف لتمكين نفس الوظيفة مع أنواع مختلفة المعلمة (ثنائي متغير وNVARCHAR)

تعاريف وظيفة: (رمز)

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 / مخطط / @ النطاق

اعادة صياغة 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>
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top