Подтвердить что ты не робот

Как выполнить полнотекстовый поиск с использованием сущности framework 6

У меня есть запрос:

var query = DataContext.Fotos.Where(x => x.Pesquisa.Contais("myTerm")

Сгенерированный SQL:

SELECT... FROM Fotos AS [Extent1] WHERE [Extent1]. [Pesquisa] LIKE N '% mytem%'

Но мне нужно использовать:

SELECT... FROM Fotos AS [Extent1] ГДЕ СОДЕРЖИТ ([Extent1]. [Pesquisa], 'мой термин')

Как выполнить полнотекстовый поиск с использованием сущности framework 6?

4b9b3361

Ответ 1

Кажется, что Entity Framework 6 не поддерживает полнотекстовый поиск, но есть обходной путь с перехватчиками.

http://www.entityframework.info/Home/FullTextSearch

Ссылка на обновление не работает, поэтому вот оригинальный контент:

Microsoft TSQL поддерживает полнотекстовый запрос с помощью предикатов (CONTAINS и FREETEXT)

Например, у вас есть таблица Notes

Create table Notes (
    Id int Identity not null,
    NoteText text 
)

CREATE FULLTEXT CATALOG [Notes Data]

При поиске в этой таблице записей, содержащих слово "Джон", вам необходимо выполнить

SELECT TOP (10) 
* from gps.NOTES
WHERE contains(NoteText, '(john)') 

К сожалению, платформа Enity пока не поддерживает предикаты полнотекстового поиска. Для EFv6 вы можете сделать обходной путь, используя перехват.

Идея состоит в том, чтобы обернуть искомый текст каким-то волшебным словом во время простого String. Содержит код и использовать перехватчик, чтобы развернуть его непосредственно перед выполнением sql в SqlCommand.

Для начала давайте создадим класс перехватчика:

public class FtsInterceptor : IDbCommandInterceptor
{
    private const string FullTextPrefix = "-FTSPREFIX-";
    public static string Fts(string search)
    {
    return string.Format("({0}{1})", FullTextPrefix, search);
    }
    public void NonQueryExecuting(DbCommand command, DbCommandInterceptionContext<int> interceptionContext)
    {
    }
    public void NonQueryExecuted(DbCommand command, DbCommandInterceptionContext<int> interceptionContext)
    {
    }
    public void ReaderExecuting(DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext)
    {
        RewriteFullTextQuery(command);
    }
    public void ReaderExecuted(DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext)
    {
    }
    public void ScalarExecuting(DbCommand command, DbCommandInterceptionContext<object> interceptionContext)
    {
        RewriteFullTextQuery(command);
    }
    public void ScalarExecuted(DbCommand command, DbCommandInterceptionContext<object> interceptionContext)
    {
    }
    public static void RewriteFullTextQuery(DbCommand cmd)
    {
        string text = cmd.CommandText;
        for (int i = 0; i < cmd.Parameters.Count; i++)
        {
            DbParameter parameter = cmd.Parameters[i];
            if (parameter.DbType.In(DbType.String, DbType.AnsiString, DbType.StringFixedLength, DbType.AnsiStringFixedLength))
            {
                if (parameter.Value == DBNull.Value)
                    continue;
                var value = (string)parameter.Value;
                if (value.IndexOf(FullTextPrefix) >= 0)
                {
                    parameter.Size = 4096;
                    parameter.DbType = DbType.AnsiStringFixedLength;
                    value = value.Replace(FullTextPrefix, ""); // remove prefix we added n linq query
                    value = value.Substring(1, value.Length - 2); // remove %% escaping by linq translator from string.Contains to sql LIKE
                    parameter.Value = value;
                    cmd.CommandText = Regex.Replace(text,
                    string.Format(
                    @"\[(\w*)\].\[(\w*)\]\s*LIKE\s*@{0}\s?(?:ESCAPE
                    N?'~')",parameter.ParameterName),
                    string.Format(@"contains([$1].[$2], @{0})",parameter.ParameterName));
                    if (text == cmd.CommandText)
                        throw new Exception("FTS was not replaced on: " + text);
                    text = cmd.CommandText;
                }
            }
        }
    }
}

Я использовал функцию расширения В, которую можно определить так:

static class LanguageExtensions
{
    public static bool In<T>(this T source, params T[] list)
    {
        return (list as IList<T>).Contains(source);
    }
}

Теперь давайте составим пример, как его использовать. Нам нужен класс сущности Примечание:

public class Note
{
    public int Id { get; set; }
    public string NoteText { get; set; }
}

Конфигурация сопоставления для него:

public class NoteMap : EntityTypeConfiguration<Note>
{
    public NoteMap()
    {
        // Primary Key
        HasKey(t => t.Id);
    }
}

И наш предок DbContext:

public class MyContext : DbContext
{
    static MyContext()
    {
        DbInterception.Add(new FtsInterceptor());
    }
    public MyContext(string nameOrConnectionString) : base(nameOrConnectionString)
    {
    }
    public DbSet<Note> Notes { get; set; }
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Configurations.Add(new NoteMap());
    }
}

Теперь мы готовы его использовать. Давайте искать "Джон":

class Program
{
    static void Main(string[] args)
    {
        var s = FtsInterceptor.Fts("john");
        using (var db = new MyContext("CONNSTRING"))
        {
            var q = db.Notes.Where(n => n.NoteText.Contains(s));
            var result = q.Take(10).ToList();
        }
    }
}

Ответ 2

Вы можете использовать необработанные SQL-запросы с EF. Итак, есть еще одно облегченное решение.

        using (DBContext context = new DBContext())
        {
            string query = string.Format("Select Id, Name, Description From Fotos Where CONTAINS(Pesquisa, '\"{0}\"')", textBoxStrToSearch.Text);
            var data = context.Database.SqlQuery<Fotos>(query).ToList();
            dataGridView1.DataSource = data;
        }

Проверка ввода и т.д. опущена. Изменить: код изменяется в соответствии с запросом OP.