문제

.NET 프레임 워크 3.5를 사용하여 LINQ와 함께 FTS를 사용할 수 있는지 궁금합니다. 아직 유용한 것을 찾지 못한 문서를 검색하고 있습니다.

누구든지 이것에 대한 경험이 있습니까?

도움이 되었습니까?

해결책

예. 그러나 먼저 SQL Server 기능을 작성하고 기본적으로 LINQ가 LIKE를 사용하는 것처럼 호출해야합니다.

이것 블로그 게시물 세부 사항을 설명하지만 이것은 추출물입니다.

작동하도록하려면 전달한 키워드를 기반으로 포함 가능한 쿼리에 불과한 테이블 값 기능을 만들어야합니다.

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;

다른 팁

아니요. 전체 텍스트 검색은 LINQ에서 SQL에서 지원하지 않습니다.

즉, 당신 ~할 수 있다 FTS를 사용하고 LINQ에서 SQL 쿼리 데이터를 사용하여 저장된 프로 시저를 사용하십시오.

나는 그렇게 믿지 않는다. 필드에서 '포함'을 사용할 수는 있지만 LIKE 질문. 전체 텍스트를 사용하려면 저장된 Proc를 사용하여 쿼리를 수행 한 다음 LINQ로 다시 전달하는 것이 좋습니다.

결합을 만들고 싶지 않고 C# 코드를 단순화하려면 SQL 기능을 작성하여 "Clause에서"에서 사용할 수 있습니다.

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 기능 구현에서 볼 수 있듯이 여러 열에서 검색하는 작업입니다.

아니요, 전체 텍스트 검색은 SQL Server에 매우 특화되어 있습니다 (텍스트는 단어로 인덱싱되고 쿼리는이 색인에 맞는 것보다 문자 배열을 가로 지릅니다). LINQ는이를 지원하지 않으며 .crontains () 호출은 관리되지 않은 문자열 함수에 도달하지만 인덱싱의 이점은 없습니다.

SQL Server의 작업 프로토 타입을 만들었습니다. 포함 와일드 카드만이 없습니다. 그것이 달성하는 것은 당신이 사용하는 것입니다 포함 일반 LINQ 기능과 마찬가지로 :

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

필요할 것이예요:

1. 코드 및 EDMX의 기능을 지원합니다 포함 예어.

2. efproviderWrapperToolKit/efTracingProvider의 2.Rewrite EF SQL은 함수가 아니고 기본적으로 생성 된 SQL은 결과를 다음과 같이 처리합니다. 조금.

하지만:

1. 함수는 실제로 기능이 아니며 부울 결과를 선택할 수 없습니다. 조건에서만 사용할 수 있습니다.

2. 쿼리에 특수 문자가있는 비모수 문자열이 포함되어 있으면 아래의 SQL 재 작성 코드가 파손될 수 있습니다.

내 프로토 타입의 소스

함수 정의 : (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>

추신 : char의 이상한 사례는 다른 매개 변수 유형 (Varbinary 및 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.");
    }
}

추신: "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>
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top