LINQ से एंटिटीज के मामले संवेदनशील तुलना करते हैं


115

यह LINQ एंटिटीज में केस-संवेदी तुलना नहीं है:

Thingies.First(t => t.Name == "ThingamaBob");

मैं LINQ से Entities तक केस की संवेदनशील तुलना कैसे कर सकता हूं?


@ रॉनी: क्या आप इसके बारे में निश्चित हैं? क्या आपका मतलब केस असंवेदनशील तुलना है?
माइकल पेट्रोत्ता

14
एकदम पक्का। नहीं, मेरा यह मतलब नहीं है।
रॉनी ओवरबी

12
नहीं, मेरे कंप्यूटर पर EF 4.0 w / SQL Server 2008 R2 चल रहा है, ऊपर मामला असंवेदनशील है। मुझे पता है कि बहुत सारी जगहें कहती हैं कि ईएफ डिफ़ॉल्ट रूप से संवेदनशील मामला है, लेकिन मैंने ऐसा अनुभव नहीं किया है।
tster

3
अंतर्निहित डेटाबेस पर निर्भर नहीं करेगा?
कोडीनिक्स ऑक्ट

1
@ कोमोडायनिक्स: यह एक अच्छा सवाल है! क्या Linq से EF एक DB क्वेरी के लिए लैम्ब्डा अभिव्यक्ति का अनुवाद करता है? मुझे जवाब नहीं पता।
Tergiver

जवाबों:


163

ऐसा इसलिए है क्योंकि आप LINQ To Entities का उपयोग कर रहे हैं जो अंततः आपके लैंबडा एक्सप्रेशन को SQL स्टेटमेंट में बदल देती है। इसका मतलब है कि केस सेंसिटिविटी आपके SQL सर्वर की दया पर है जो डिफ़ॉल्ट रूप से SQL_Latin1_General_CP1_CI_AS Collation है और यह केस सेंसिटिव नहीं है।

वास्तव में SQL सर्वर पर प्रस्तुत की गई उत्पन्न SQL क्वेरी को देखने के लिए ObjectQuery.ToTraceString का उपयोग करना रहस्य को प्रकट करता है:

string sqlQuery = ((ObjectQuery)context.Thingies
        .Where(t => t.Name == "ThingamaBob")).ToTraceString();

जब आप LINQ को Entities क्वेरी के लिए बनाते हैं , तो LINQ से एंटिटीज LINQ parser को क्वेरी को संसाधित करने के लिए लाभ देता है और इसे LINQ अभिव्यक्ति ट्री में परिवर्तित करता है। LINQ एक्सप्रेशन ट्री को तब Object Services API में पास किया जाता है, जो एक्सप्रेशन ट्री को कमांड ट्री में परिवर्तित करता है। फिर इसे स्टोर प्रदाता (जैसे SqlClient) को भेजा जाता है, जो कमांड ट्री को मूल डेटाबेस कमांड टेक्स्ट में बदल देता है। डेटा संग्रह पर निष्पादित हो क्वेरी और परिणाम कर रहे हैं materialized में इकाई ऑब्जेक्ट्स द्वारा वस्तु सेवाएं। मामले की संवेदनशीलता को ध्यान में रखने के लिए कोई तर्क नहीं दिया गया है। तो कोई बात नहीं जो भी आप अपने विधेय में डालते हैं, यह हमेशा आपके SQL सर्वर द्वारा उसी के समान माना जाएगा जब तक आप उस कॉलम के लिए अपने SQL सर्वर Collates को नहीं बदलते।

सर्वर साइड समाधान:

इसलिए, सबसे अच्छा समाधान का मिलान को बदलने के लिए किया जाएगा नाम में स्तंभ थिंगी मुक़ाबला करने के लिए तालिका Latin1_General_CS_AS जो मामले अपने एसक्यूएल सर्वर पर इस चलाकर प्रति संवेदनशील है:

ALTER TABLE Thingies
ALTER COLUMN Name VARCHAR(25)
COLLATE Latin1_General_CS_AS

SQL सर्वर Collates के बारे में अधिक जानकारी के लिए, SQL सर्वर कोलाज़ केस सेंसिटिव SQL क्वेरी खोज पर एक नज़र डालें

क्लाइंट-साइड समाधान:

एकमात्र समाधान जो आप ग्राहक पक्ष पर लागू कर सकते हैं, वह है LINQ का उपयोग करने के लिए ऑब्जेक्ट्स के लिए अभी तक एक और तुलना करना जो बहुत सुरुचिपूर्ण नहीं लगता है:

Thingies.Where(t => t.Name == "ThingamaBob")
        .AsEnumerable()
        .First(t => t.Name == "ThingamaBob");

मैं एंटिटी फ्रेमवर्क के साथ डेटाबेस स्कीमा उत्पन्न कर रहा हूं, इसलिए मेरे कॉलिंग कोड का उपयोग करने वाला समाधान सबसे अच्छा होगा। मुझे लगता है कि परिणाम वापस आने के बाद मैं एक जांच करूंगा। धन्यवाद।
रोनी ओवरबीज

कोई दिक्कत नहीं है। हां, यह सही है और मैंने अपना जवाब क्लाइंट साइड समाधान के साथ अपडेट किया है, हालांकि यह बहुत सुरुचिपूर्ण नहीं है और मैं अभी भी डेटा स्टोर समाधान का उपयोग करने की सलाह देता हूं।
मोर्टेज़ा मनवी

18
@eglasius यह पूरी तरह से सच नहीं है: यह सभी डेटा नहीं लाती है, यह केवल उस डेटा को प्राप्त करती है जो असंवेदनशील रूप से केस से मेल खाती है, और उसके बाद यह क्लाइंट केस पर फिर से संवेदनशील तरीके से फ़िल्टर हो जाता है। बेशक, यदि आप हजारों प्रविष्टियाँ करते हैं जो केस असंवेदनशील से मेल खाते हैं, लेकिन उनमें से केवल एक ही सही एक केस संवेदनशील है, तो यह बहुत अधिक उपरि है। लेकिन मुझे नहीं लगता कि वास्तविकता इस तरह के परिदृश्य पेश करेगी ... :)
अचम

1
@MassoodKhaari आपके द्वारा पोस्ट किया गया समाधान इसे केस असंवेदनशील बना देगा क्योंकि आप तुलना के दोनों पक्षों को कम कर रहे हैं। ओपी को एक केस संवेदनशील तुलना की जरूरत है।
जॉनी

1
"इसलिए, सबसे अच्छा समाधान यह होगा कि नाम कॉलम के कोलाज को लैटिन L1_General_CS_AS के COLLATE तालिका में बदल दिया जाए" - मुझे नहीं लगता कि यह सबसे अच्छा है। अधिकांश समय मुझे असंवेदनशील LIKE फिल्टर (.Contains ()) की आवश्यकता होती है, लेकिन कभी-कभी इसे संवेदनशील होना चाहिए। मैं आपके "क्लाइंट-साइड समाधान" की कोशिश करूंगा - यह मेरे उपयोग के मामले के लिए बहुत अधिक सुरुचिपूर्ण है जो मुझे लगता है (यह समझने में अच्छा होगा कि यह क्या करता है लेकिन आपके पास यह सब नहीं हो सकता है :))।
अविश्वसनीय जन

11

आप EF6 + कोड-प्रथम के लिए [CaseSensitive] एनोटेशन जोड़ सकते हैं

इस वर्ग को जोड़ें

[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);
    }

फिर करो

ऐड-माइग्रेशन केससेन्सिटिव

डेटाबेस अद्यतन करें

https://milinaudara.wordpress.com/2015/02/04/case-sensitive-search-using-entity-framework-with-custom-annotation/ पर लेख के आधार पर कुछ बग ठीक करें


11

WHERESQL सर्वर में स्थितियाँ डिफ़ॉल्ट रूप से असंवेदनशील होती हैं। कॉलम के डिफ़ॉल्ट कोलाज़ ( 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");
}

परंतु

आप नई EF6 सुविधाओं का उपयोग करके "CaseSensitive" नामक कस्टम एनोटेशन बना सकते हैं और आप अपने गुणों को इस तरह से सजा सकते हैं:

[CaseSensitive]
public string Name { get; set; }

यह ब्लॉग पोस्ट बताता है कि यह कैसे करना है।


उस लेख में एक बग है
RouR

3

@Morteza Manavi द्वारा दिया गया उत्तर समस्या को हल करता है। फिर भी, क्लाइंट-साइड समाधान के लिए , एक सुरुचिपूर्ण तरीका निम्नलिखित होगा (एक डबल चेक जोड़कर)।

var firstCheck = Thingies.Where(t => t.Name == "ThingamaBob")
    .FirstOrDefault();
var doubleCheck = (firstCheck?.Name == model.Name) ? Thingies : null;

-4

मुझे मोर्टेजा का उत्तर पसंद आया, और सामान्य रूप से सर्वर साइड पर ठीक करना पसंद करेंगे। क्लाइंट-साइड के लिए मैं आमतौर पर उपयोग करता हूं:

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

मूल रूप से, पहले यह जांचना कि यदि आवश्यक मानदंडों वाला कोई उपयोगकर्ता है, तो जांचें कि क्या पासवर्ड समान है। थोड़ा लंबा-घुमावदार, लेकिन मुझे लगता है कि यह पढ़ना आसान है जब मानदंडों का एक पूरा गुच्छा हो सकता है।


2
यह उत्तर बताता है कि आप अपने डेटाबेस में सादे पाठ के रूप में पासवर्ड संग्रहीत कर रहे हैं जो एक बड़ी सुरक्षा भेद्यता है।
जेसन कॉयन

2
@JasonCoyne जिस पासवर्ड से वह तुलना कर रहा है, वह पहले से ही हैशेड हो सकता है
पीटर मॉरिस

-4

न ही StringComparison.IgnoreCaseमेरे लिए काम किया। लेकिन यह किया:

context.MyEntities.Where(p => p.Email.ToUpper().Equals(muser.Email.ToUpper()));

2
यह पूछे जाने वाले प्रश्न के साथ मदद नहीं करेगा, जो है,How can I achieve case sensitive comparison
रेग एडिट

-4

स्ट्रिंग का उपयोग करें

Thingies.First(t => string.Equals(t.Name, "ThingamaBob", StringComparison.CurrentCulture);

इसके अलावा, आपको अशक्त के बारे में चिंता करने की ज़रूरत नहीं है और केवल वही जानकारी प्राप्त करें जो आप चाहते हैं।

केस असंवेदनशील के लिए StringComparision.CurrentCultureIgnoreCase का उपयोग करें।

Thingies.First(t => string.Equals(t.Name, "ThingamaBob", StringComparison.CurrentCultureIgnoreCase);

बराबर () SQL में परिवर्तित नहीं किया जा सकता ... यदि आप प्रयास करें और आवृत्ति विधि का उपयोग करते हैं, तो StringComparison पर ध्यान नहीं दिया जाता है।
LMK

क्या आपने इसका समाधान आजमाया है? मैं अपने अंत में EF के साथ ठीक काम करने की कोशिश की।
दर्शन जोशी

-6

EF4 के बारे में निश्चित नहीं है, लेकिन EF5 इसका समर्थन करता है:

Thingies
    .First(t => t.Name.Equals(
        "ThingamaBob",
        System.StringComparison.InvariantCultureIgnoreCase)

जिज्ञासु कि क्या sql उत्पन्न करता है।
रॉनी ओवरबी

मैंने EF5 के साथ यह जाँच की, यह बस SQL ​​में WHERE ... = ... उत्पन्न करता है। तो फिर, यह एसक्यूएल सर्वर की तरफ कॉलेशन सेटिंग्स पर निर्भर है।
अचिम

यहाँ तक कि DB में केस-सेंसिटिव कोलैबेशन के साथ भी मुझे यह या किसी अन्य StringComparisonएनम को फर्क नहीं पड़ा। मैंने देखा है कि काफी लोग इस तरह का सुझाव देते हुए सोचते हैं कि समस्या ईडीएमएक्स फाइल (डीबी-फर्स्ट) में कहीं होनी चाहिए, हालाँकि stackoverflow.com/questions/841226/…
drzaus
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.