This isn't a case-sensitive comparison in LINQ to Entities:
Thingies.First(t => t.Name == "ThingamaBob");
How can I achieve case sensitive comparison with LINQ to Entities?
This isn't a case-sensitive comparison in LINQ to Entities:
Thingies.First(t => t.Name == "ThingamaBob");
How can I achieve case sensitive comparison with LINQ to Entities?
That's because you are using LINQ To Entities which is ultimately convert your Lambda expressions into SQL statements. That means the case sensitivity is at the mercy of your SQL Server which by default has SQL_Latin1_General_CP1_CI_AS Collation and that is NOT case sensitive.
Using ObjectQuery.ToTraceString to see the generated SQL query that has been actually submitted to SQL Server reveals the mystery:
string sqlQuery = ((ObjectQuery)context.Thingies
.Where(t => t.Name == "ThingamaBob")).ToTraceString();
When you create a LINQ to Entities query, LINQ to Entities leverages the LINQ parser to begin processing the query and converts it into a LINQ expression tree. The LINQ expression tree is then passed to Object Services API, which converts the expression tree to a command tree. It is then sent to the store provider (e.g. SqlClient), which convert the command tree into the native database command text. Query get executed on the data store and the results are Materialized into Entity Objects by Object Services. No logic has been put in between to take case sensitivity into account. So no matter what case you put in your predicate, it will always treat as the same by your SQL Server unless you change your SQL Server Collates for that column.
Therefore, the best solution would be to change the collation of the Name column in the Thingies table to COLLATE Latin1_General_CS_AS which is case sensitive by running this on your SQL Server:
ALTER TABLE Thingies
ALTER COLUMN Name VARCHAR(25)
COLLATE Latin1_General_CS_AS
For more information on the SQL Server Collates, take a a look at SQL SERVER Collate Case Sensitive SQL Query Search
The only solution that you can apply on client side is to use LINQ to Objects to do yet another comparison which doesn't seem to be very elegant:
Thingies.Where(t => t.Name == "ThingamaBob")
.AsEnumerable()
.First(t => t.Name == "ThingamaBob");
ToTraceString()
extension method. It's not recognized. ? –
Gordan WHERE
conditions in SQL Server are case insensitive by default. Make it case sensitive by changing the column's default collations (SQL_Latin1_General_CP1_CI_AS
) to SQL_Latin1_General_CP1_CS_AS
.
The fragile way to do this is with code. Add a new migration file and then add this inside the Up
method:
public override void Up()
{
Sql("ALTER TABLE Thingies ALTER COLUMN Name VARCHAR(MAX) COLLATE SQL_Latin1_General_CP1_CS_AS NOT NULL");
}
But
You can create custom annotation called "CaseSensitive" using the new EF6 features and you can decorate your properties like this:
[CaseSensitive]
public string Name { get; set; }
This blog post explains how to do that.
You can add [CaseSensitive] annotation for EF6+ Code-first
Add this classes
[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());
}
}
Modify your DbContext, add
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Add(new AttributeToColumnAnnotationConvention<CaseSensitiveAttribute, bool>(
"CaseSensitive",
(property, attributes) => attributes.Single().IsEnabled));
base.OnModelCreating(modelBuilder);
}
Then do
Add-Migration CaseSensitive
Update-Database
based on article https://milinaudara.wordpress.com/2015/02/04/case-sensitive-search-using-entity-framework-with-custom-annotation/ with some bug fix
The answer given by @Morteza Manavi solves the problem. Still, for a client-side solution, an elegant way would be the following (adding a double check).
var firstCheck = Thingies.Where(t => t.Name == "ThingamaBob")
.FirstOrDefault();
var doubleCheck = (firstCheck?.Name == model.Name) ? Thingies : null;
Yes, it is possible and well documented.
https://learn.microsoft.com/en-us/ef/core/miscellaneous/collations-and-case-sensitivity
Option 1 - It is possible to specify collation of a column:
modelBuilder.Entity<Customer>().Property(c => c.Name)
.UseCollation("SQL_Latin1_General_CP1_CS_AS");
Option 2 - or of the whole database:
modelBuilder.UseCollation("SQL_Latin1_General_CP1_CS_AS");
Option 3 - Another option is to specify the collation for a single query:
var customers = context.Customers
.Where(c => EF.Functions.Collate(c.Name, "SQL_Latin1_General_CP1_CS_AS") == "John")
.ToList();
All the options use the SQL_Latin1_General_CP1_CS_AS
collation, which is case sensitive.
I liked Morteza's answer, and would normally prefer to fix on server side. For client-side I normally use:
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
Basically, first checking if there is a user with required criteria, then check if the password is the same. A little bit long-winded, but I feel it is easier to read when there may be a whole bunch of criteria involved.
Use string.Equals
Thingies.First(t => string.Equals(t.Name, "ThingamaBob", StringComparison.CurrentCulture);
Also, you don't have to worry about null and get back only the information you want.
Use StringComparision.CurrentCultureIgnoreCase for Case Insensitive.
Thingies.First(t => string.Equals(t.Name, "ThingamaBob", StringComparison.CurrentCultureIgnoreCase);
Not sure about EF4, but EF5 supports this:
Thingies
.First(t => t.Name.Equals(
"ThingamaBob",
System.StringComparison.InvariantCultureIgnoreCase)
StringComparison
enums to make a difference. I've seen enough people suggesting this kind of thing should work to think the problem is somewhere in the EDMX file (db-first), although #841726 –
Preconceive Neither of the StringComparison.IgnoreCase
worked for me. But this did:
context.MyEntities.Where(p => p.Email.ToUpper().Equals(muser.Email.ToUpper()));
How can I achieve case sensitive comparison
–
Epilate © 2022 - 2024 — McMap. All rights reserved.