Comparación de mayúsculas y minúsculas de LINQ to Entities

Esta no es una comparación sensible a mayúsculas y minúsculas en LINQ to Entities:

Thingies.First(t => t.Name == "ThingamaBob"); 

¿Cómo puedo lograr una comparación sensible a mayúsculas y minúsculas con LINQ to Entities?

Esto se debe a que está utilizando LINQ To Entities que finalmente convierte sus expresiones Lambda en declaraciones SQL. Eso significa que la sensibilidad de mayúsculas y minúsculas está a merced de su SQL Server, que de forma predeterminada tiene SQL_Latin1_General_CP1_CI_AS Collation y que NO es sensible a mayúsculas y minúsculas.

El uso de ObjectQuery.ToTraceString para ver la consulta SQL generada que se ha enviado realmente a SQL Server revela el misterio:

 string sqlQuery = ((ObjectQuery)context.Thingies .Where(t => t.Name == "ThingamaBob")).ToTraceString(); 

Cuando crea una consulta LINQ to Entities , LINQ to Entities aprovecha el analizador LINQ para comenzar a procesar la consulta y la convierte en un árbol de expresiones LINQ. El árbol de expresiones LINQ se pasa luego a la API de servicios de objetos , que convierte el árbol de expresiones en un árbol de comandos. Luego se envía al proveedor de la tienda (por ejemplo, SqlClient), que convierte el árbol de comandos en el texto de comando de la base de datos nativa. La consulta se ejecuta en el almacén de datos y los resultados se materializan en Objetos de la entidad mediante los Servicios de objetos . No se ha puesto ninguna lógica entre en cuenta para tomar en cuenta la sensibilidad de caso. Así que no importa en qué caso coloque su predicado, siempre tratará como lo mismo su SQL Server a menos que cambie los SQL Server Collates para esa columna.

Solución del lado del servidor:

Por lo tanto, la mejor solución sería cambiar la intercalación de la columna Nombre en la tabla Thingies para COLLATE Latin1_General_CS_AS, que distingue entre mayúsculas y minúsculas ejecutando esto en su SQL Server:

 ALTER TABLE Thingies ALTER COLUMN Name VARCHAR(25) COLLATE Latin1_General_CS_AS 

Para obtener más información sobre SQL Server Collates , consulte a aa SERVER SQL Intercalar mayúsculas y minúsculas SQL Query Search

Solución del lado del cliente:

La única solución que puede aplicar en el lado del cliente es usar LINQ to Objects para hacer otra comparación que no parece ser muy elegante:

 Thingies.Where(t => t.Name == "ThingamaBob") .AsEnumerable() .First(t => t.Name == "ThingamaBob"); 

Puede agregar la anotación [CaseSensitive] para EF6 + Code-first

Agrega estas clases

 [AttributeUsage(AttributeTargets.Property, AllowMultiple = true)] public class CaseSensitiveAttribute : Attribute { public CaseSensitiveAttribute() { IsEnabled = true; } public bool IsEnabled { get; set; } } public class CustomSqlServerMigrationSqlGenerator : SqlServerMigrationSqlGenerator { protected override void Generate(AlterColumnOperation alterColumnOperation) { base.Generate(alterColumnOperation); AnnotationValues values; if (alterColumnOperation.Column.Annotations.TryGetValue("CaseSensitive", out values)) { if (values.NewValue != null && values.NewValue.ToString() == "True") { using (var writer = Writer()) { //if (System.Diagnostics.Debugger.IsAttached == false) System.Diagnostics.Debugger.Launch(); // https://github.com/mono/entityframework/blob/master/src/EntityFramework.SqlServer/SqlServerMigrationSqlGenerator.cs var columnSQL = BuildColumnType(alterColumnOperation.Column); //[nvarchar](100) writer.WriteLine( "ALTER TABLE {0} ALTER COLUMN {1} {2} COLLATE SQL_Latin1_General_CP1_CS_AS {3}", alterColumnOperation.Table, alterColumnOperation.Column.Name, columnSQL, alterColumnOperation.Column.IsNullable.HasValue == false || alterColumnOperation.Column.IsNullable.Value == true ? " NULL" : "NOT NULL" //todo not tested for DefaultValue ); Statement(writer); } } } } } public class CustomApplicationDbConfiguration : DbConfiguration { public CustomApplicationDbConfiguration() { SetMigrationSqlGenerator( SqlProviderServices.ProviderInvariantName, () => new CustomSqlServerMigrationSqlGenerator()); } } 

Modifique su DbContext, agregue

 protected override void OnModelCreating(DbModelBuilder modelBuilder) { modelBuilder.Conventions.Add(new AttributeToColumnAnnotationConvention( "CaseSensitive", (property, attributes) => attributes.Single().IsEnabled)); base.OnModelCreating(modelBuilder); } 

Entonces hazlo

Add-Migration CaseSensitive

Actualizar base de datos

basado en el artículo https://milinaudara.wordpress.com/2015/02/04/case-sensitive-search-using-entity-framework-with-custom-annotation/ con algunas correcciones de errores

WHERE condiciones en SQL Server son insensibles a mayúsculas / minúsculas por defecto. Haga que distinga entre mayúsculas y minúsculas cambiando las intercalaciones predeterminadas de la columna ( SQL_Latin1_General_CP1_CI_AS ) a SQL_Latin1_General_CP1_CS_AS .

La forma frágil de hacer esto es con código. Agregue un nuevo archivo de migración y luego agregue esto dentro del método Up :

 public override void Up() { Sql("ALTER TABLE Thingies ALTER COLUMN Name VARCHAR(MAX) COLLATE SQL_Latin1_General_CP1_CS_AS NOT NULL"); } 

Pero

Puede crear una anotación personalizada llamada “CaseSensitive” utilizando las nuevas funciones de EF6 y puede decorar sus propiedades de esta manera:

 [CaseSensitive] public string Name { get; set; } 

Esta publicación del blog explica cómo hacerlo.

La respuesta dada por @Morteza Manavi resuelve el problema. Aún así, para una solución del lado del cliente , una manera elegante sería la siguiente (agregando un doble control).

 var firstCheck = Thingies.Where(t => t.Name == "ThingamaBob") .FirstOrDefault(); var doubleCheck = (firstCheck.Name == model.Name) ? Thingies : null; 

Me gustó la respuesta de Morteza, y normalmente preferiría solucionarlo en el lado del servidor. Para el lado del cliente normalmente uso:

 Dim bLogin As Boolean = False Dim oUser As User = (From c In db.Users Where c.Username = UserName AndAlso c.Password = Password Select c).SingleOrDefault() If oUser IsNot Nothing Then If oUser.Password = Password Then bLogin = True End If End If 

Básicamente, primero verifica si hay un usuario con los criterios requeridos, luego verifica si la contraseña es la misma. Un poco largo, pero creo que es más fácil de leer cuando puede haber un montón de criterios involucrados.

Ninguno de StringComparison.IgnoreCase funcionó para mí. Pero esto hizo:

 context.MyEntities.Where(p => p.Email.ToUpper().Equals(muser.Email.ToUpper())); 

Use string.Equals

 Thingies.First(t => string.Equals(t.Name, "ThingamaBob", StringComparison.CurrentCulture); 

Además, no tiene que preocuparse por nulo y obtener solo la información que desea.

Utilice StringComparision.CurrentCultureIgnoreCase para distinguir entre mayúsculas y minúsculas.

 Thingies.First(t => string.Equals(t.Name, "ThingamaBob", StringComparison.CurrentCultureIgnoreCase); 

No estoy seguro acerca de EF4, pero EF5 lo admite:

 Thingies .First(t => t.Name.Equals( "ThingamaBob", System.StringComparison.InvariantCultureIgnoreCase)