นี่ไม่ใช่การเปรียบเทียบแบบคำนึงถึงขนาดตัวพิมพ์ใน LINQ กับเอนทิตี:
Thingies.First(t => t.Name == "ThingamaBob");
ฉันจะเปรียบเทียบกรณีที่สำคัญกับ LINQ กับเอนทิตีได้อย่างไร
นี่ไม่ใช่การเปรียบเทียบแบบคำนึงถึงขนาดตัวพิมพ์ใน LINQ กับเอนทิตี:
Thingies.First(t => t.Name == "ThingamaBob");
ฉันจะเปรียบเทียบกรณีที่สำคัญกับ LINQ กับเอนทิตีได้อย่างไร
คำตอบ:
นั่นเป็นเพราะคุณใช้LINQ To Entitiesซึ่งท้ายที่สุดแล้วจะแปลงนิพจน์ Lambda ของคุณเป็นคำสั่ง SQL นั่นหมายความว่าความไวของตัวพิมพ์จะขึ้นอยู่กับความเมตตาของ SQL Server ของคุณซึ่งโดยค่าเริ่มต้นมีการเรียงลำดับSQL_Latin1_General_CP1_CI_ASและไม่คำนึงถึงขนาดตัวพิมพ์
ใช้ObjectQuery ToTraceStringเพื่อดูแบบสอบถาม SQL ที่สร้างขึ้นซึ่งถูกส่งไปยัง SQL Server จริงเผยให้เห็นความลึกลับ:
string sqlQuery = ((ObjectQuery)context.Thingies
.Where(t => t.Name == "ThingamaBob")).ToTraceString();
เมื่อคุณสร้างไฟล์ LINQ เพื่อองค์กรแบบสอบถามLINQ กับหน่วยงานยกระดับ parser LINQ ที่จะเริ่มต้นการประมวลผลแบบสอบถามและแปลงเป็นต้นไม้แสดงออก LINQ จากนั้นแผนภูมินิพจน์ LINQ จะถูกส่งไปยังObject Services API ซึ่งแปลงโครงสร้างนิพจน์เป็นแผนผังคำสั่ง จากนั้นจะส่งไปยังผู้ให้บริการร้านค้า (เช่น SqlClient) ซึ่งจะแปลงโครงสร้างคำสั่งเป็นข้อความคำสั่งฐานข้อมูลดั้งเดิม แบบสอบถามได้รับการดำเนินการในการจัดเก็บข้อมูลและผลจะMaterializedเข้าEntity วัตถุโดยบริการวัตถุ. ไม่มีการใส่ตรรกะระหว่างเพื่อพิจารณาความอ่อนไหวของตัวพิมพ์ ดังนั้นไม่ว่าคุณจะใส่เพรดิเคตในกรณีใดก็จะถือว่า SQL Server ของคุณเหมือนกันเสมอเว้นแต่คุณจะเปลี่ยน SQL Server Collates สำหรับคอลัมน์นั้น
ดังนั้นทางออกที่ดีที่สุดคือการเปลี่ยนการเรียงชื่อคอลัมน์ในตารางThingiesเป็น COLLATE Latin1_General_CS_ASซึ่งพิจารณาตัวพิมพ์เล็กและใหญ่โดยการรันสิ่งนี้บน SQL Server ของคุณ:
ALTER TABLE Thingies
ALTER COLUMN Name VARCHAR(25)
COLLATE Latin1_General_CS_AS
สำหรับข้อมูลเพิ่มเติมเกี่ยวกับSQL Server Collatesโปรดดูที่SQL SERVER Collate Case Sensitive SQL Query Search
ทางออกเดียวที่คุณสามารถใช้ได้กับฝั่งไคลเอ็นต์คือการใช้LINQ กับ Objectsเพื่อทำการเปรียบเทียบอีกแบบหนึ่งซึ่งดูเหมือนจะไม่สวยหรูมากนัก:
Thingies.Where(t => t.Name == "ThingamaBob")
.AsEnumerable()
.First(t => t.Name == "ThingamaBob");
คุณสามารถเพิ่มคำอธิบายประกอบ [CaseSensitive] สำหรับ EF6 + Code-first
เพิ่มชั้นเรียนนี้
[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());
}
}
แก้ไข DbContext ของคุณเพิ่ม
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Add(new AttributeToColumnAnnotationConvention<CaseSensitiveAttribute, bool>(
"CaseSensitive",
(property, attributes) => attributes.Single().IsEnabled));
base.OnModelCreating(modelBuilder);
}
แล้วทำ
Add-Migration CaseSensitive
ปรับปรุงฐานข้อมูล
อ้างอิงจากบทความhttps://milinaudara.wordpress.com/2015/02/04/case-sensitive-search-using-entity-framework-with-custom-annotation/พร้อมการแก้ไขข้อบกพร่องบางอย่าง
WHERE
เงื่อนไขใน SQL Server ไม่คำนึงถึงขนาดตัวพิมพ์โดยค่าเริ่มต้น ทำให้มันเป็นกรณีที่สำคัญโดยการเปลี่ยน collations เริ่มต้นของคอลัมน์ ( SQL_Latin1_General_CP1_CI_AS
) SQL_Latin1_General_CP1_CS_AS
เพื่อ
วิธีที่เปราะบางในการทำเช่นนี้คือการใช้รหัส เพิ่มไฟล์การโยกย้ายใหม่จากนั้นเพิ่มสิ่งนี้ภายในUp
วิธีการ:
public override void Up()
{
Sql("ALTER TABLE Thingies ALTER COLUMN Name VARCHAR(MAX) COLLATE SQL_Latin1_General_CP1_CS_AS NOT NULL");
}
แต่
คุณสามารถสร้างคำอธิบายประกอบแบบกำหนดเองที่เรียกว่า "CaseSensitive" โดยใช้คุณสมบัติใหม่ของ EF6 และคุณสามารถตกแต่งคุณสมบัติของคุณได้ดังนี้:
[CaseSensitive]
public string Name { get; set; }
นี้โพสต์บล็อกอธิบายถึงวิธีการทำเช่นนั้น
คำตอบที่ได้รับจาก @Morteza Manavi ช่วยแก้ปัญหาได้ อย่างไรก็ตามสำหรับโซลูชันฝั่งไคลเอ็นต์วิธีที่ดีจะเป็นดังต่อไปนี้ (เพิ่มการตรวจสอบอีกครั้ง)
var firstCheck = Thingies.Where(t => t.Name == "ThingamaBob")
.FirstOrDefault();
var doubleCheck = (firstCheck?.Name == model.Name) ? Thingies : null;
ฉันชอบคำตอบของ Morteza และโดยปกติแล้วจะชอบแก้ไขที่ฝั่งเซิร์ฟเวอร์ สำหรับฝั่งไคลเอ็นต์ฉันมักใช้:
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
โดยทั่วไปก่อนอื่นให้ตรวจสอบว่ามีผู้ใช้ที่มีเกณฑ์ที่กำหนดหรือไม่จากนั้นตรวจสอบว่ารหัสผ่านเหมือนกันหรือไม่ ยืดเยื้อไปหน่อย แต่ฉันรู้สึกว่ามันง่ายกว่าที่จะอ่านเมื่ออาจมีเกณฑ์ทั้งหมดที่เกี่ยวข้อง
ทั้งสองอย่างไม่ได้ผลStringComparison.IgnoreCase
สำหรับฉัน แต่สิ่งนี้ทำ:
context.MyEntities.Where(p => p.Email.ToUpper().Equals(muser.Email.ToUpper()));
How can I achieve case sensitive comparison
ใช้ string.Equals
Thingies.First(t => string.Equals(t.Name, "ThingamaBob", StringComparison.CurrentCulture);
นอกจากนี้คุณไม่ต้องกังวลเกี่ยวกับค่าว่างและรับเฉพาะข้อมูลที่คุณต้องการกลับมา
ใช้ StringComparision.CurrentCultureIgnoreCase สำหรับ Case Insensitive
Thingies.First(t => string.Equals(t.Name, "ThingamaBob", StringComparison.CurrentCultureIgnoreCase);
ไม่แน่ใจเกี่ยวกับ EF4 แต่ EF5 รองรับสิ่งนี้:
Thingies
.First(t => t.Name.Equals(
"ThingamaBob",
System.StringComparison.InvariantCultureIgnoreCase)
StringComparison
มาสร้างความแตกต่างได้ ฉันเคยเห็นคนแนะนำเรื่องแบบนี้มามากพอแล้วคิดว่าปัญหาอยู่ที่ไหนสักแห่งในไฟล์ EDMX (db-first) แม้ว่าstackoverflow.com/questions/841226/…