Ini bukan perbandingan peka huruf besar kecil di LINQ dengan Entitas:
Thingies.First(t => t.Name == "ThingamaBob");
Bagaimana cara saya mencapai perbandingan case sensitive dengan LINQ ke Entitas?
Ini bukan perbandingan peka huruf besar kecil di LINQ dengan Entitas:
Thingies.First(t => t.Name == "ThingamaBob");
Bagaimana cara saya mencapai perbandingan case sensitive dengan LINQ ke Entitas?
Jawaban:
Itu karena Anda menggunakan LINQ To Entities yang pada akhirnya mengubah ekspresi Lambda Anda menjadi pernyataan SQL. Itu berarti sensitivitas huruf besar / kecil berada di tangan SQL Server Anda yang secara default memiliki Penyusunan SQL_Latin1_General_CP1_CI_AS dan TIDAK peka huruf besar / kecil.
Menggunakan ObjectQuery.ToTraceString untuk melihat kueri SQL yang dihasilkan yang sebenarnya telah dikirim ke SQL Server mengungkap misteri:
string sqlQuery = ((ObjectQuery)context.Thingies
.Where(t => t.Name == "ThingamaBob")).ToTraceString();
Saat Anda membuat kueri LINQ ke Entitas , LINQ ke Entitas memanfaatkan pengurai LINQ untuk mulai memproses kueri dan mengubahnya menjadi pohon ekspresi LINQ. Pohon ekspresi LINQ kemudian diteruskan ke Object Services API, yang mengubah pohon ekspresi menjadi pohon perintah. Ini kemudian dikirim ke penyedia penyimpanan (misalnya SqlClient), yang mengubah pohon perintah menjadi teks perintah database asli. Query dieksekusi di penyimpanan data dan hasilnya direalisasikan menjadi Objek Entitas oleh Object Services. Tidak ada logika yang dimasukkan untuk mempertimbangkan sensitivitas huruf. Jadi, apa pun kasus yang Anda masukkan ke dalam predikat, itu akan selalu diperlakukan sama oleh SQL Server Anda kecuali jika Anda mengubah SQL Server Collates untuk kolom itu.
Oleh karena itu, solusi terbaik adalah dengan mengubah pemeriksaan dari Nama kolom di thingies meja ke Collate Latin1_General_CS_AS yang case sensitive dengan menjalankan ini pada SQL Server Anda:
ALTER TABLE Thingies
ALTER COLUMN Name VARCHAR(25)
COLLATE Latin1_General_CS_AS
Untuk informasi selengkapnya tentang SQL Server Collates , lihat SQL SERVER Collate Case Sensitive SQL Query Search
Satu-satunya solusi yang dapat Anda terapkan di sisi klien adalah dengan menggunakan LINQ ke Objek untuk melakukan perbandingan lain yang tampaknya tidak terlalu elegan:
Thingies.Where(t => t.Name == "ThingamaBob")
.AsEnumerable()
.First(t => t.Name == "ThingamaBob");
Anda dapat menambahkan anotasi [CaseSensitive] untuk EF6 + Code-first
Tambahkan kelas ini
[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());
}
}
Ubah DbContext Anda, tambahkan
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Add(new AttributeToColumnAnnotationConvention<CaseSensitiveAttribute, bool>(
"CaseSensitive",
(property, attributes) => attributes.Single().IsEnabled));
base.OnModelCreating(modelBuilder);
}
Lalu lakukan
Add-Migration CaseSensitive
Perbarui-Database
berdasarkan artikel https://milinaudara.wordpress.com/2015/02/04/case-sensitive-search-using-entity-framework-with-custom-annotation/ dengan beberapa perbaikan bug
WHERE
kondisi di SQL Server tidak membedakan huruf besar / kecil secara default. Buat peka huruf besar kecil dengan mengubah susunan default kolom ( SQL_Latin1_General_CP1_CI_AS
) menjadi SQL_Latin1_General_CP1_CS_AS
.
Cara yang rapuh untuk melakukannya adalah dengan kode. Tambahkan file migrasi baru dan kemudian tambahkan ini di dalam Up
metode:
public override void Up()
{
Sql("ALTER TABLE Thingies ALTER COLUMN Name VARCHAR(MAX) COLLATE SQL_Latin1_General_CP1_CS_AS NOT NULL");
}
Tapi
Anda dapat membuat anotasi khusus yang disebut "CaseSensitive" menggunakan fitur EF6 yang baru dan Anda dapat menghias properti Anda seperti ini:
[CaseSensitive]
public string Name { get; set; }
Posting blog ini menjelaskan bagaimana melakukan itu.
Jawaban yang diberikan oleh @Morteza Manavi menyelesaikan masalah tersebut. Namun, untuk solusi sisi klien , cara yang elegan adalah sebagai berikut (menambahkan tanda centang ganda).
var firstCheck = Thingies.Where(t => t.Name == "ThingamaBob")
.FirstOrDefault();
var doubleCheck = (firstCheck?.Name == model.Name) ? Thingies : null;
Saya menyukai jawaban Morteza, dan biasanya lebih suka memperbaiki di sisi server. Untuk sisi klien saya biasanya menggunakan:
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
Pada dasarnya, pertama-tama periksa apakah ada pengguna dengan kriteria yang disyaratkan, lalu periksa apakah kata sandinya sama. Agak bertele-tele, tetapi saya merasa lebih mudah untuk membaca ketika mungkin ada banyak kriteria yang terlibat.
Tak satu pun dari yang StringComparison.IgnoreCase
berhasil untuk saya. Tapi ini berhasil:
context.MyEntities.Where(p => p.Email.ToUpper().Equals(muser.Email.ToUpper()));
How can I achieve case sensitive comparison
Gunakan string. Sama
Thingies.First(t => string.Equals(t.Name, "ThingamaBob", StringComparison.CurrentCulture);
Selain itu, Anda tidak perlu khawatir tentang null dan hanya mendapatkan kembali informasi yang Anda inginkan.
Gunakan StringComparision.CurrentCultureIgnoreCase untuk Case Insensitive.
Thingies.First(t => string.Equals(t.Name, "ThingamaBob", StringComparison.CurrentCultureIgnoreCase);
Tidak yakin tentang EF4, tetapi EF5 mendukung ini:
Thingies
.First(t => t.Name.Equals(
"ThingamaBob",
System.StringComparison.InvariantCultureIgnoreCase)
StringComparison
enum ini atau yang lainnya untuk membuat perbedaan. Saya telah melihat cukup banyak orang yang menyarankan hal semacam ini harus bekerja untuk berpikir masalahnya ada di suatu tempat di file EDMX (db-first), meskipun stackoverflow.com/questions/841226/…