Dies ist kein Vergleich zwischen Groß- und Kleinschreibung in LINQ und Entitäten:
Thingies.First(t => t.Name == "ThingamaBob");
Wie kann ich einen Vergleich zwischen Groß- und Kleinschreibung mit LINQ to Entities erzielen?
Dies ist kein Vergleich zwischen Groß- und Kleinschreibung in LINQ und Entitäten:
Thingies.First(t => t.Name == "ThingamaBob");
Wie kann ich einen Vergleich zwischen Groß- und Kleinschreibung mit LINQ to Entities erzielen?
Antworten:
Dies liegt daran, dass Sie LINQ To Entities verwenden, mit dem Ihre Lambda-Ausdrücke letztendlich in SQL-Anweisungen konvertiert werden. Dies bedeutet, dass die Groß- und Kleinschreibung Ihrem SQL Server ausgeliefert ist, der standardmäßig über die SQL_Latin1_General_CP1_CI_AS-Kollatierung verfügt und bei der NICHT zwischen Groß- und Kleinschreibung unterschieden wird.
Die Verwendung von ObjectQuery.ToTraceString zum Anzeigen der generierten SQL-Abfrage, die tatsächlich an SQL Server gesendet wurde , enthüllt das Rätsel:
string sqlQuery = ((ObjectQuery)context.Thingies
.Where(t => t.Name == "ThingamaBob")).ToTraceString();
Wenn Sie eine LINQ to Entities- Abfrage erstellen , nutzt LINQ to Entities den LINQ-Parser, um mit der Verarbeitung der Abfrage zu beginnen und sie in einen LINQ-Ausdrucksbaum zu konvertieren. Der LINQ-Ausdrucksbaum wird dann an die Object Services- API übergeben, die den Ausdrucksbaum in einen Befehlsbaum konvertiert. Es wird dann an den Speicheranbieter (z. B. SqlClient) gesendet, der den Befehlsbaum in den nativen Datenbankbefehlstext konvertiert. Die Abfrage wird im Datenspeicher ausgeführt und die Ergebnisse werden von Object Services in Entitätsobjekte materialisiert. Dazwischen wurde keine Logik eingefügt, um die Groß- und Kleinschreibung zu berücksichtigen. Unabhängig davon, in welchem Fall Sie Ihr Prädikat eingeben, wird es von Ihrem SQL Server immer als gleich behandelt, es sei denn, Sie ändern Ihre SQL Server-Sortierungen für diese Spalte.
Daher besteht die beste Lösung darin, die Sortierung der Spalte Name in der Thingies- Tabelle in COLLATE Latin1_General_CS_AS zu ändern. Dabei wird zwischen Groß- und Kleinschreibung unterschieden, indem Sie dies auf Ihrem SQL Server ausführen :
ALTER TABLE Thingies
ALTER COLUMN Name VARCHAR(25)
COLLATE Latin1_General_CS_AS
Weitere Informationen zu den SQL Server-Sortierungen finden Sie unter SQL Server-Sortierung Groß- und Kleinschreibung beachten
Die einzige Lösung, die Sie auf der Clientseite anwenden können, besteht darin, LINQ to Objects zu verwenden, um einen weiteren Vergleich durchzuführen, der nicht sehr elegant zu sein scheint:
Thingies.Where(t => t.Name == "ThingamaBob")
.AsEnumerable()
.First(t => t.Name == "ThingamaBob");
Sie können eine [CaseSensitive] -Anmerkung für EF6 + Code-first hinzufügen
Fügen Sie diese Klassen hinzu
[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());
}
}
Ändern Sie Ihren DbContext, fügen Sie hinzu
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Add(new AttributeToColumnAnnotationConvention<CaseSensitiveAttribute, bool>(
"CaseSensitive",
(property, attributes) => attributes.Single().IsEnabled));
base.OnModelCreating(modelBuilder);
}
Dann mach
Add-Migration CaseSensitive
Datenbank auf den neusten Stand bringen
basierend auf Artikel https://milinaudara.wordpress.com/2015/02/04/case-sensitive-search-using-entity-framework-with-custom-annotation/ mit einigen Fehlerkorrekturen
WHERE
Bei Bedingungen in SQL Server wird standardmäßig die Groß- und Kleinschreibung nicht berücksichtigt. Ändern Sie die Groß- und Kleinschreibung, indem Sie die Standardkollatierungen ( SQL_Latin1_General_CP1_CI_AS
) der Spalte in ändern SQL_Latin1_General_CP1_CS_AS
.
Der fragile Weg, dies zu tun, ist mit Code. Fügen Sie eine neue Migrationsdatei hinzu und fügen Sie diese dann in die Up
Methode ein:
public override void Up()
{
Sql("ALTER TABLE Thingies ALTER COLUMN Name VARCHAR(MAX) COLLATE SQL_Latin1_General_CP1_CS_AS NOT NULL");
}
Aber
Mit den neuen EF6-Funktionen können Sie benutzerdefinierte Anmerkungen mit dem Namen "CaseSensitive" erstellen und Ihre Eigenschaften wie folgt dekorieren:
[CaseSensitive]
public string Name { get; set; }
In diesem Blogbeitrag wird erklärt, wie das geht.
Die Antwort von @Morteza Manavi löst das Problem. Für eine clientseitige Lösung wäre ein eleganter Weg jedoch der folgende (Hinzufügen einer doppelten Prüfung).
var firstCheck = Thingies.Where(t => t.Name == "ThingamaBob")
.FirstOrDefault();
var doubleCheck = (firstCheck?.Name == model.Name) ? Thingies : null;
Ich mochte Mortezas Antwort und würde es normalerweise vorziehen, sie auf der Serverseite zu reparieren. Für die Client-Seite verwende ich normalerweise:
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
Überprüfen Sie zunächst, ob es einen Benutzer mit den erforderlichen Kriterien gibt, und prüfen Sie dann, ob das Kennwort identisch ist. Ein bisschen langatmig, aber ich denke, es ist einfacher zu lesen, wenn es eine ganze Reihe von Kriterien gibt.
Keiner von beiden StringComparison.IgnoreCase
hat für mich funktioniert. Aber das tat:
context.MyEntities.Where(p => p.Email.ToUpper().Equals(muser.Email.ToUpper()));
How can I achieve case sensitive comparison
Verwenden Sie string.Equals
Thingies.First(t => string.Equals(t.Name, "ThingamaBob", StringComparison.CurrentCulture);
Außerdem müssen Sie sich keine Sorgen um Null machen und nur die gewünschten Informationen zurückerhalten.
Verwenden Sie StringComparision.CurrentCultureIgnoreCase für Groß- und Kleinschreibung.
Thingies.First(t => string.Equals(t.Name, "ThingamaBob", StringComparison.CurrentCultureIgnoreCase);
Ich bin mir bei EF4 nicht sicher, aber EF5 unterstützt dies:
Thingies
.First(t => t.Name.Equals(
"ThingamaBob",
System.StringComparison.InvariantCultureIgnoreCase)
StringComparison
Aufzählungen nicht dazu bringen, einen Unterschied zu machen. Ich habe genug Leute gesehen, die vorgeschlagen haben, dass so etwas funktionieren sollte, um zu glauben, dass das Problem irgendwo in der EDMX-Datei (db-first) liegt, obwohl stackoverflow.com/questions/841226/…