entity framework net Cómo ejecutar una búsqueda de texto completo usando el framework de entidades 6




mvc entity framework español (2)

Tengo la consulta:

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

El SQL generado es:

SELECCIONE ... DE Fotos AS [Extent1] DONDE [Extent1]. [Pesquisa] LIKE N '% mytem%'

Pero necesito usar:

SELECCIONE ... DE Fotos AS [Extent1] DONDE CONTIENE ([Extent1]. [Pesquisa], 'mi término')

¿Cómo ejecutar una búsqueda de texto completo utilizando Entity Framework 6?


Parece que Entity Framework 6 no admite la búsqueda de texto completo, pero hay una solución alternativa con los interceptores.

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

El enlace de actualización no funciona, así que aquí está el contenido original:

Microsoft TSQL admite consultas de texto completo mediante predicados (CONTAINS y FREETEXT)

Por ejemplo, tienes notas de tabla

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

CREATE FULLTEXT CATALOG [Notes Data]

Cuando busca en esta tabla los registros que contienen la palabra 'John', debe emitir

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

Desafortunadamente, el marco de Enity todavía no admite predicados de búsqueda de texto completo. Para EFv6, puede hacer una solución utilizando la intercepción.

La idea es envolver el texto de búsqueda con alguna palabra mágica durante el interior de la cadena. Contiene código y usa el interceptor para desenvolverlo justo antes de que se ejecute sql en SqlCommand.

Para empezar, vamos a crear la clase interceptor:

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

Utilicé la función de extensión que se puede definir así:

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

Ahora vamos a componer una muestra de cómo usarlo. Necesitamos entidad clase Nota:

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

Configuración de mapeo para ello:

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

Y nuestro ancestro 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());
    }
}

Ahora estamos listos para usarlo. Vamos a buscar 'john':

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();
        }
    }
}

Puede utilizar consultas SQL sin procesar con EF. Por lo tanto, hay otra solución fácil.

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

Se omite la validación de entrada, etc. Edición: El código se modifica de acuerdo a la consulta de OP.





full-text-search