Esta no es una comparación que distingue entre 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?
Esta no es una comparación que distingue entre 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?
Respuestas:
Esto se debe a que está utilizando LINQ To Entities, que en última instancia convierte sus expresiones Lambda en declaraciones SQL. Eso significa que la distinción entre mayúsculas y minúsculas está a merced de su servidor SQL, que de forma predeterminada tiene SQL_Latin1_General_CP1_CI_AS Collation y que NO distingue entre 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 de LINQ to Entities , LINQ to Entities aprovecha el analizador LINQ para comenzar a procesar la consulta y la convierte en un árbol de expresión LINQ. Luego, el árbol de expresión LINQ se pasa a la API de Object Services , que convierte el árbol de expresión 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 comandos de la base de datos nativa. La consulta se ejecuta en el almacén de datos y los resultados se materializan en objetos de entidad mediante Object Services. No se ha puesto ninguna lógica en el medio para tener en cuenta la distinción entre mayúsculas y minúsculas. Entonces, no importa qué caso ponga en su predicado, su SQL Server siempre lo tratará como el mismo, a menos que cambie su SQL Server Collates para esa columna.
Por lo tanto, la mejor solución sería cambiar la intercalación de la columna Nombre en la tabla Thingies a COLLATE Latin1_General_CS_AS que distingue entre mayúsculas y minúsculas al ejecutar 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 , eche un vistazo a SQL SERVER Collate Búsqueda de consultas SQL sensibles a mayúsculas y minúsculas
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
Agregar 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<CaseSensitiveAttribute, bool>(
"CaseSensitive",
(property, attributes) => attributes.Single().IsEnabled));
base.OnModelCreating(modelBuilder);
}
Entonces hazlo
Agregar-migración sensible a mayúsculas y minúsculas
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
Las condiciones en SQL Server no distinguen entre mayúsculas y minúsculas de forma predeterminada. Hágalo sensible a 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 Up
método:
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 de blog explica cómo hacerlo.
La respuesta de @Morteza Manavi resuelve el problema. Aún así, para una solución del lado del cliente , una forma elegante sería la siguiente (agregando una doble verificación).
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 arreglar 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 verifique si hay un usuario con los criterios requeridos, luego verifique si la contraseña es la misma. Un poco prolijo, pero creo que es más fácil de leer cuando puede haber un montón de criterios involucrados.
Ninguno de los dos StringComparison.IgnoreCase
funcionó para mí. Pero esto hizo:
context.MyEntities.Where(p => p.Email.ToUpper().Equals(muser.Email.ToUpper()));
How can I achieve case sensitive comparison
Utilice string.Equals
Thingies.First(t => string.Equals(t.Name, "ThingamaBob", StringComparison.CurrentCulture);
Además, no tiene que preocuparse por nulos y recuperar solo la información que desea.
Utilice StringComparision.CurrentCultureIgnoreCase para mayúsculas y minúsculas.
Thingies.First(t => string.Equals(t.Name, "ThingamaBob", StringComparison.CurrentCultureIgnoreCase);
No estoy seguro de EF4, pero EF5 lo admite:
Thingies
.First(t => t.Name.Equals(
"ThingamaBob",
System.StringComparison.InvariantCultureIgnoreCase)
StringComparison
distingue entre mayúsculas y minúsculas en la base de datos, no pude hacer que esta o cualquiera de las otras enumeraciones marcaran la diferencia. He visto suficientes personas sugiriendo que este tipo de cosas debería funcionar para pensar que el problema está en algún lugar del archivo EDMX (db-first), aunque stackoverflow.com/questions/841226/…