How to make a query through LINQ ignoring accents?

9

I would like to know if you can do a query with LINQ that compares two strings and ignores their accents.

That's not my Collation in the database is set to AI and that I do not need to replace in the strings to exit by removing their accents.

For example, when trying to fetch an item by the name "Orchid", it should return both the items that are saved in the database as "Orchid", "Orchid", "Orchid" and any other variation. >

I've tried using

string.Compare(string1, string2, CultureInfo.GetCultureInfo("pt-BR"), 
               CompareOptions.IgnoreNonSpace | CompareOptions.IgnoreCase) == 0

inside the LINQ query, but it does not work.

    
asked by anonymous 12.05.2017 / 04:10

3 answers

7

You only get this if you set the COLLATION of the column (or the table, or the bank) before. There are a few ways to do this.

One of these is defining a base initializer , like this:

public class CollationInitializer : CreateDatabaseIfNotExists<MeuContexto>
{
    public override void InitializeDatabase(MeuContextocontext)
    {
        if(!context.Database.Exists())
        {
            using (SqlConnection connection = new SqlConnection("DefaultConnection"))
            {
                connection.Open();
                using(SqlCommand command = new SqlCommand(string.Format("CREATE DATABASE {0} COLLATE Latin1_General_CI_AI", "MinhaBaseDeDados"), connection))
                {
                    command.ExecuteNonQuery();
                }
            }

            SqlConnection.ClearAllPools();
         }

         base.InitializeDatabase(context);
    }
}

E:

public class MeuContexto: DbContext
{
    public MeuContexto() : base("DefaultConnection", throwIfV1Schema: false)
    {
        Database.SetInitializer(new CollationInitializer<MeuContexto>());
        if(!Database.Exists())
        {
            Database.Initialize(true);
         }
     } 
}

Another is setting up a migration interceptor to set COLLATION to the time the database is being updated:

public class CreateDatabaseCollationInterceptor : IDbCommandInterceptor
{
    private readonly string _collation;

    public CreateDatabaseCollationInterceptor(string collation)
    {
        _collation = collation;
    }

    public void NonQueryExecuted(DbCommand command, DbCommandInterceptionContext<int> interceptionContext) { }
    public void NonQueryExecuting(DbCommand command, DbCommandInterceptionContext<int> interceptionContext)
    {
        // Apenas para SQL Server
        if (Regex.IsMatch(command.CommandText, @"^create database \[.*]$"))
        {
            command.CommandText += " COLLATE " + _collation;
        }
    }

    public void ReaderExecuted(DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext) { }
    public void ReaderExecuting(DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext) { }
    public void ScalarExecuted(DbCommand command, DbCommandInterceptionContext<object> interceptionContext) { }
    public void ScalarExecuting(DbCommand command, DbCommandInterceptionContext<object> interceptionContext) { }
}
    
12.05.2017 / 04:19
3

In SQL Server it is possible to change the collation of a column " on the fly" during a Select .

Something like:

Select *
From Entidades
Where (Coluna Collate SQL_Latin1_General_CP1_CI_AI) Like 'Tê%'

This query returns all rows where the Nome column starts with "Te" regardless of whether or not casing accents or differences in>. For example: " Test ", " Test ", " Test ". Note also that the parameter uses an accent, I did this to illustrate that it is also inconsiderate.

Obviously you will need to write the query to execute it, but I think this is not a problem.

I made an example running this query with Entity Framework.

const string collation = "SQL_Latin1_General_CP1_CI_AI";

using (var db = new Contexto())
{
    var resultado = db.Database.SqlQuery<Entidade>($"Select * From Entidades
                                                     Where (Nome Collate {collation}) 
                                                     Like '%{param}%'").ToList();
}
    
12.05.2017 / 18:58
0

A simple way I found was like this. I use entity framework with mysql and utf8 -default collation,

using (controle_estoqueEntities entity = new controle_estoqueEntities())
        {
            return (from a in entity.clientes
                    where ( (a.nome_cliente == nome || a.nome_cliente.Contains(nome)))  
                    orderby a.nome_cliente
                    select new ClienteDTO
                    {IdCliente = a.idcliente,
                        NomeCliente = a.nome_cliente}).toList();

}

    
20.02.2018 / 08:24