SqlDataReader ऑब्जेक्ट में स्तंभ नाम के लिए जाँच करें


212

मैं यह देखने के लिए कैसे जांचता हूं कि क्या कॉलम में मौजूद है SqlDataReader वस्तु ? मेरे डेटा एक्सेस लेयर में, मैंने एक विधि बनाई है जो एक ही ऑब्जेक्ट को कई संग्रहीत प्रक्रियाओं के कॉल के लिए बनाता है। संग्रहीत प्रक्रियाओं में से एक में एक अतिरिक्त कॉलम है जो अन्य संग्रहीत प्रक्रियाओं द्वारा उपयोग नहीं किया जाता है। मैं हर परिदृश्य के लिए समायोजित करने के लिए विधि को संशोधित करना चाहता हूं।

मेरा आवेदन C # में लिखा गया है।

जवाबों:


332
public static class DataRecordExtensions
{
    public static bool HasColumn(this IDataRecord dr, string columnName)
    {
        for (int i=0; i < dr.FieldCount; i++)
        {
            if (dr.GetName(i).Equals(columnName, StringComparison.InvariantCultureIgnoreCase))
                return true;
        }
        return false;
    }
}

Exceptionनियंत्रण तर्क के लिए s का उपयोग करना जैसे कुछ अन्य उत्तरों में बुरा व्यवहार माना जाता है और प्रदर्शन लागत होती है। यह # फेंके गए अपवादों के प्रोफाइलर को झूठी सकारात्मकता भी भेजता है और भगवान किसी को भी अपने डिबगर को फेंकने वाले अपवादों को तोड़ने में मदद करते हैं।

GetSchemaTable () भी कई उत्तरों में एक और सुझाव है। यह किसी क्षेत्र की मौजूदगी के लिए जाँच का एक पूर्वनिर्मित तरीका नहीं होगा क्योंकि यह सभी संस्करणों में लागू नहीं है (यह सार है और डॉटनेटकोर के कुछ संस्करणों में NotSupportedException फेंकता है)। GetSchemaTable प्रदर्शन को भी समझदार है क्योंकि यदि आप स्रोत की जांच करते हैं तो यह एक बहुत भारी शुल्क कार्य है ।

यदि आप इसे बहुत उपयोग करते हैं, तो खेतों के माध्यम से लूपिंग एक छोटे प्रदर्शन को प्रभावित कर सकता है और आप परिणामों पर विचार करना चाहते हैं।


क्या होगा अगर एक उपनाम उपयोग किया जाता है? नाम तुलना विफल हो जाएगी।
मर्फीब्रॉ 2

यह बहस योग्य है कि अपवाद प्रवाह का उपयोग करना बुरा अभ्यास है। यह एक बार बुरा माना गया था क्योंकि यह अन्य ऑपरेटरों के लिए महंगा है, लेकिन एक जुड़े आवेदन में नगण्य है। स्कीट ने 2006 में स्टैक की गहराई के आधार पर एमएस के प्रति 40-118 अपवादों को मापा। stackoverflow.com/a/891230/852208 । परीक्षण के बिना आगे, यह संभव है कि यह कोड वास्तव में धीमा है क्योंकि यह औसत मामला सभी कॉलमों के आधे हिस्से की जांच कर रहा है (हालांकि अभी भी एक डीबी कनेक्टेड ऐप में तुच्छ है)। मैं इस उत्तर को केवल मध्य पैराग्राफ में शामिल करूँगा क्योंकि अन्य दो राय हैं।
b_levitt

3
@b_levitt यह विवादास्पद नहीं है, यह बकवास कोड है और आपको नियंत्रण प्रवाह के अपवादों पर भरोसा नहीं करना चाहिए
चाड अनुदान

मेरे द्वारा बताए गए दो वाक्यों की तरह, यह अभी तक एक अन्य राय है जो विशुद्ध रूप से कम्प्यूटेशनल अनुप्रयोग में प्रदर्शन से परे किसी भी तर्क के साथ समर्थित नहीं है। मैं आपको सभी अपवादों पर विराम लगाने के लिए अपना डिबगर सेट करने और बस अपने कोड को अक्षम करने का साहस करता हूं और आप देखेंगे कि फ्रेमवर्क और अन्य लाइब्रेरी पहले से ही ऐसा कर रहे हैं। आपकी सलाह के साथ समस्या यह है कि यह डेवलपर्स को कोड वापस करने के लिए धक्का देता है जो सबसे अधिक सहमत एक अवर पैटर्न हैं: stackoverflow.com/questions/99683/… । इस तरह की कार्यप्रणाली "सफलता के गड्ढे" परीक्षण को विफल करती है।
b_levitt

एक कोड परिप्रेक्ष्य से, आपका उत्तर एक मान्य है। लेकिन आपकी राय इसे कोशिश / पकड़ के साथ एक बेहतर जवाब के रूप में वजन करने की कोशिश कर रही है (जो कि उपनाम भी संभालती है) यहां से बाहर है।
b_levitt

66

इस बूलियन फ़ंक्शन का उपयोग करना बेहतर है:

r.GetSchemaTable().Columns.Contains(field)

एक कॉल - कोई अपवाद नहीं। यह आंतरिक रूप से अपवादों को फेंक सकता है, लेकिन मुझे ऐसा नहीं लगता।

नोट: नीचे दी गई टिप्पणियों में, हमने यह पता लगा लिया है ... सही कोड वास्तव में यह है:

public static bool HasColumn(DbDataReader Reader, string ColumnName) { 
    foreach (DataRow row in Reader.GetSchemaTable().Rows) { 
        if (row["ColumnName"].ToString() == ColumnName) 
            return true; 
    } //Still here? Column not found. 
    return false; 
}

5
@ चमेली: मैंने भी जल्दी ही बोल दिया! आपका कोड स्कीमा तालिका में एक स्तंभ के लिए जाँच करता है, न कि आपका परिणाम सेट करता है। आपको प्रत्येक पंक्ति के "ColumnName" फ़ील्ड के मान के लिए "फ़ील्ड" ("फ़ील्ड" मान स्तंभ नाम है) की तुलना करने की आवश्यकता है। जब आप इसे पाएं तो टूट जाएं, यदि आप नहीं करते हैं तो झूठे वापस आ जाएंगे
स्टीव जे

4
@Steve J: जब GetSchemaTable में कोई परिणाम नहीं होगा तो परिणाम क्या होगा?
याहु

1
किसी और को भ्रमित करने के लिए, यह काम नहीं करता है। स्कीमा तालिका से ColumnName पंक्ति को पुनः प्राप्त करने और इसका उपयोग करने के बारे में नीचे दिया गया उत्तर देखें।
जेसन जैक्सन

3
हाँ, यह काम नहीं करता है। इतनी बार किसने उखाड़ा ??? अगर यह जवाब यहाँ नहीं होता तो यह बाद में मुझे बहुत डिबगिंग का समय बचा लेता!
c00000fd

1
@ चमेली वे दोनों काम करते हैं? ज़रुरी नहीं। कृपया अपने उत्तर के पहले भाग को हटा दें। मैंने खुद किया होगा, लेकिन आपकी अंतिम टिप्पणी के लिए!
नवफाल

33

मुझे लगता है कि आपका सबसे अच्छा दांव आपके DataReader के सामने GetOrdinal ("columnName") को कॉल करना है , और कॉलम मौजूद नहीं होने की स्थिति में IndexOutOfRangeException को पकड़ना है।

वास्तव में, चलो एक विस्तार विधि बनाते हैं:

public static bool HasColumn(this IDataRecord r, string columnName)
{
    try
    {
        return r.GetOrdinal(columnName) >= 0;
    }
    catch (IndexOutOfRangeException)
    {
        return false;
    }
}

संपादित करें

ठीक है, यह पोस्ट हाल ही में कुछ डाउन-वोटों को कम करने के लिए शुरू हो रही है, और मैं इसे हटा नहीं सकता क्योंकि यह स्वीकृत उत्तर है, इसलिए मैं इसे अपडेट करने जा रहा हूं और (मुझे उम्मीद है) अपवाद हैंडलिंग के उपयोग को सही ठहराने की कोशिश करेगा बहाव को काबू करें।

इसे प्राप्त करने का दूसरा तरीका, जैसा कि चाड ग्रांट द्वारा पोस्ट किया गया है, DataReader में प्रत्येक फ़ील्ड के माध्यम से लूप करना है और उस फ़ील्ड नाम के लिए केस-असंवेदनशील तुलना करें जिसे आप खोज रहे हैं। यह वास्तव में अच्छी तरह से काम करेगा, और सच्चाई से शायद ऊपर मेरे तरीके से बेहतर प्रदर्शन करेगा। निश्चित रूप से मैं लूप के अंदर की विधि का उपयोग कभी नहीं करूंगा जहां प्रदर्शन एक मुद्दा था।

मैं एक स्थिति के बारे में सोच सकता हूं जिसमें कोशिश / गेटऑर्डिनल / कैच विधि काम करेगी जहां लूप नहीं होता है। हालाँकि, यह अभी पूरी तरह से काल्पनिक स्थिति है, इसलिए यह बहुत ही भयावह औचित्य है। भले ही, मेरे साथ सहन करें और देखें कि आप क्या सोचते हैं।

एक डेटाबेस की कल्पना करें जो आपको एक तालिका के भीतर "उपनाम" कॉलम की अनुमति देता है। कल्पना कीजिए कि मैं "EmployeeName" नामक एक कॉलम के साथ एक तालिका को परिभाषित कर सकता हूं, लेकिन इसे "EmpName" का उपनाम भी दे सकता है, और किसी भी नाम के लिए चयन करने से उस कॉलम में डेटा वापस आ जाएगा। मेरे साथ इतनी दूर?

अब कल्पना कीजिए कि उस डेटाबेस के लिए एक ADO.NET प्रदाता है, और उन्होंने इसके लिए एक IDataReader कार्यान्वयन को कोडित किया है जो स्तंभ उपनामों को ध्यान में रखता है।

अब, dr.GetName(i)(के रूप में चाड के जवाब में प्रयुक्त) केवल एक ही स्ट्रिंग लौट सकते हैं, तो यह केवल वापस जाने के लिए है एक एक स्तंभ पर "अन्य नामों" की। हालाँकि, आपके GetOrdinal("EmpName")द्वारा खोजे जा रहे नाम के लिए प्रत्येक कॉलम के उपनाम की जांच करने के लिए इस प्रदाता के आंतरिक कार्यान्वयन का उपयोग कर सकते हैं।

इस काल्पनिक "अलियासड कॉलम" स्थिति में, कोशिश / गेटऑर्डिनल / कैच विधि यह सुनिश्चित करने का एकमात्र तरीका होगा कि आप परिणाम में कॉलम के नाम की हर भिन्नता के लिए जाँच कर रहे हैं।

कमजोर? ज़रूर। लेकिन एक विचार के लायक है। ईमानदारी से मैं IDataRecord पर एक "आधिकारिक" HasColumn विधि के बजाय बहुत कुछ करूँगा।


15
नियंत्रण तर्क के लिए अपवाद का उपयोग कर? नहीं नहीं नहीं
चाड ग्रांट

28
एक छोटी सी बात है जो सभी को नजरअंदाज करती है जब मैं मूल रूप से इस प्रश्न को पोस्ट करता हूं ... मैंने 12/8/08 को प्रश्न पूछा और मैट ने अपना उत्तर 12/17/08 को पोस्ट किया। सभी ने नियंत्रण तर्क के लिए एक अपवाद को पकड़ने के बारे में विचार किया, लेकिन 5/1/09 तक कोई ठोस वैकल्पिक समाधान नहीं दिया। यही कारण है कि यह मूल रूप से उत्तर के रूप में चिह्नित किया गया था। मैं आज भी इस समाधान का उपयोग कर रहा हूं।
माइकल नॉकिर्नर्न

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

5
+1। मैं एक व्यापक डिजाइन नियम के रूप में "कंट्रोल लॉजिक के लिए अपवाद का उपयोग नहीं करता" ठीक है। इसका मतलब यह नहीं है "हर कीमत पर इससे बचें"। उत्तर बहुत अच्छी तरह से प्रलेखित वर्कअराउंड है, और जैसा कि @Nick कहता है, प्रदर्शन हिट (यदि कोई हो ..) केवल तब होता है जब कॉलम मौजूद नहीं होता है।
लैरी

2
अपवादों को नियंत्रण तर्क के रूप में उपयोग करने से मेरे अनुभव में अधिक बोझिलता आती है। आपको "कॉमन लैंग्वेज रनटाइम एक्सेप्शन" पर "थ्रॉर्न" को अनटिक करना होगा और फिर जब आपको वास्तविक अपवाद मिलेगा तो यह हैंडलर में कहीं भी टूट सकता है और उस लाइन पर नहीं जिसमें समस्या है।
cdd

30

एक पंक्ति में, अपने DataReader पुनर्प्राप्ति के बाद इसका उपयोग करें:

var fieldNames = Enumerable.Range(0, dr.FieldCount).Select(i => dr.GetName(i)).ToArray();

फिर,

if (fieldNames.Contains("myField"))
{
    var myFieldValue = dr["myField"];
    ...

संपादित करें

बहुत अधिक कुशल एक-लाइनर जिसे स्कीमा लोड करने की आवश्यकता नहीं है:

var exists = Enumerable.Range(0, dr.FieldCount).Any(i => string.Equals(dr.GetName(i), fieldName, StringComparison.OrdinalIgnoreCase));

आप फ़ील्ड नामों को एक से अधिक बार स्कैन कर रहे हैं / किसी सरणी के साथ स्कैन करने के लिए अन्य सरणी आवंटित कर रहे हैं, यह उच्च ट्रैफ़िक कोड में बहुत कम प्रदर्शन करने वाला होगा।
चाड ग्रांट

@ChadGrant, यही कारण है कि Linq एक लाइनर बहुत अधिक कुशल है क्योंकि यह केवल एक पुनरावृत्ति करता है।
लैरी

18

यहाँ जैस्मीन के विचार के लिए एक नमूना काम कर रहा है:

var cols = r.GetSchemaTable().Rows.Cast<DataRow>().Select
    (row => row["ColumnName"] as string).ToList(); 

if (cols.Contains("the column name"))
{

}

1
केवल तभी यदि आप इसके चारों ओर एक कोशिश / पकड़
लपेटते हैं

आप इस विचार को सरल बना सकते हैं: Reader.GetSchemaTable ()। कॉलम में सुधार करें ("myFiled")
Lev Z

केवल एक कॉलम नाम खोजने के लिए GetSchemaTable () का उपयोग अत्यधिक (आवंटन वार) है। स्रोत की जाँच करें github.com/microsoft/referencesource/blob/…
चाड ग्रांट

12

यह मेरे लिए काम करता है:

bool hasColumnName = reader.GetSchemaTable().AsEnumerable().Any(c => c["ColumnName"] == "YOUR_COLUMN_NAME");

केवल एक कॉलम नाम खोजने के लिए GetSchemaTable () का उपयोग अत्यधिक (आवंटन वार) है। और इसे डॉटनेट कोर के सभी संस्करणों में लागू नहीं किया गया है। स्रोत की जाँच करें github.com/microsoft/referencesource/blob/…
चाड अनुदान

10

निम्नलिखित सरल और मेरे लिए काम किया है:

 bool hasMyColumn = (reader.GetSchemaTable().Select("ColumnName = 'MyColumnName'").Count() == 1);

केवल एक कॉलम नाम खोजने के लिए GetSchemaTable () का उपयोग अत्यधिक (आवंटन वार) है। स्रोत github.com/microsoft/referencesource/blob/…
चाड ग्रांट

8

यदि आप प्रश्न को पढ़ते हैं, तो माइकल ने DataReader के बारे में पूछा, न कि DataRecord के लोगों से। अपनी वस्तुओं को सही करवाओ।

r.GetSchemaTable().Columns.Contains(field)DataRecord का उपयोग करना काम करता है, लेकिन यह BS कॉलम लौटाता है (नीचे स्क्रीनशॉट देखें)

यह देखने के लिए कि क्या डेटा स्तंभ मौजूद है और किसी DataReader में डेटा मौजूद है, निम्नलिखित एक्सटेंशन का उपयोग करें:

public static class DataReaderExtensions
{
    /// <summary>
    /// Checks if a column's value is DBNull
    /// </summary>
    /// <param name="dataReader">The data reader</param>
    /// <param name="columnName">The column name</param>
    /// <returns>A bool indicating if the column's value is DBNull</returns>
    public static bool IsDBNull(this IDataReader dataReader, string columnName)
    {
        return dataReader[columnName] == DBNull.Value;
    }

    /// <summary>
    /// Checks if a column exists in a data reader
    /// </summary>
    /// <param name="dataReader">The data reader</param>
    /// <param name="columnName">The column name</param>
    /// <returns>A bool indicating the column exists</returns>
    public static bool ContainsColumn(this IDataReader dataReader, string columnName)
    {
        /// See: http://stackoverflow.com/questions/373230/check-for-column-name-in-a-sqldatareader-object/7248381#7248381
        try
        {
            return dataReader.GetOrdinal(columnName) >= 0;
        }
        catch (IndexOutOfRangeException)
        {
            return false;
        }
    }
}

उपयोग:

    public static bool CanCreate(SqlDataReader dataReader)
    {
        return dataReader.ContainsColumn("RoleTemplateId") 
            && !dataReader.IsDBNull("RoleTemplateId");
    }

r.GetSchemaTable().ColumnsDataReader पर कॉल करना BS कॉलम लौटाता है:

एक DataReader में GetSchemeTable को कॉल करना


मतों के उत्तर के तहत टिप्पणियां देखें
nawfal

आपका क्या मतलब द्वारा करते DataRecord काम करता है , लेकिन यह बी एस कॉलम रिटर्न ? आपका मतलब है कि यह चलता है (और गलत परिणाम देता है)?
नवफाल

2
"अपनी वस्तुओं को सही पाओ।" - लेकिन IDataReaderलागू करता है IDataRecord। वे एक ही वस्तु के अलग-अलग इंटरफेस हैं - जैसे ICollection<T>और IEnumerable<T>अलग-अलग इंटरफेस हैं List<T>IDataReaderअगले रिकॉर्ड को आगे बढ़ाने की अनुमति देता है, जबकि IDataRecordवर्तमान रिकॉर्ड से पढ़ने की अनुमति देता है। इस उत्तर में जिन विधियों का उपयोग किया जा रहा है वे सभी IDataRecordइंटरफ़ेस से आती हैं । क्यों के रूप में पैरामीटर घोषित करने के लिए बेहतर है की व्याख्या के लिए stackoverflow.com/a/1357743/221708 देखें IDataRecord
डैनियल शिलिंग

दिखाने के लिए क्यों r.GetSchemaTable().Columnsइस सवाल का एक बिल्कुल गलत जवाब है।
डैनियल शिलिंग

GetName () को IDataRecord इंटरफ़ेस से IDataReader में विरासत में मिला है। आधार इंटरफ़ेस को लक्षित करना सही कोड है।
चाड ग्रांट

7

मैंने विज़ुअल बेसिक उपयोगकर्ताओं के लिए लिखा है:

Protected Function HasColumnAndValue(ByRef reader As IDataReader, ByVal columnName As String) As Boolean
    For i As Integer = 0 To reader.FieldCount - 1
        If reader.GetName(i).Equals(columnName) Then
            Return Not IsDBNull(reader(columnName))
        End If
    Next

    Return False
End Function

मुझे लगता है कि यह अधिक शक्तिशाली है और उपयोग है:

If HasColumnAndValue(reader, "ID_USER") Then
    Me.UserID = reader.GetDecimal(reader.GetOrdinal("ID_USER")).ToString()
End If

4

यहाँ स्वीकृत उत्तर का एक लाइनर लाइनक संस्करण है:

Enumerable.Range(0, reader.FieldCount).Any(i => reader.GetName(i) == "COLUMN_NAME_GOES_HERE")

मामला संवेदनशील तुलना ... क्यों?
चाड ग्रांट

4

यहाँ जैस्मीन से एक लाइन में समाधान ... (एक और, सरल सरल!):

reader.GetSchemaTable().Select("ColumnName='MyCol'").Length > 0;

केवल एक कॉलम नाम खोजने के लिए GetSchemaTable () का उपयोग अत्यधिक (आवंटन वार) है। स्रोत की जाँच करें github.com/microsoft/referencesource/blob/…
चाड ग्रांट

@ChadGrant संभावित। मुझे लगता है कि किसी को संदर्भ के आधार पर बुद्धिमानी से चुनना होगा और आवृत्ति का उपयोग करना आवश्यक है ...
Spaark

3
Hashtable ht = new Hashtable();
    Hashtable CreateColumnHash(SqlDataReader dr)
    {
        ht = new Hashtable();
        for (int i = 0; i < dr.FieldCount; i++)
        {
            ht.Add(dr.GetName(i), dr.GetName(i));
        }
        return ht;
    }

    bool ValidateColumn(string ColumnName)
    {
        return ht.Contains(ColumnName);
    }

3

TLDR:

प्रदर्शन और खराब अभ्यास के दावों के साथ बहुत सारे उत्तर, इसलिए मैं यहां स्पष्ट करता हूं।

अपवादित मार्ग अधिक संख्या में लौटे स्तंभों के लिए तेज़ है, लूप मार्ग स्तंभों की कम संख्या के लिए तेज़ है, और क्रॉसओवर बिंदु लगभग 11 कॉलम है। ग्राफ़ और परीक्षण कोड देखने के लिए नीचे स्क्रॉल करें।

पूर्ण उत्तर:

शीर्ष के कुछ उत्तर के लिए कोड काम करता है, लेकिन तर्क में अपवाद से निपटने की स्वीकृति के आधार पर "बेहतर" उत्तर के लिए यहां एक अंतर्निहित बहस है और यह संबंधित प्रदर्शन है।

यह स्पष्ट करने के लिए कि मुझे विश्वास नहीं है कि कैटचिंग अपवादों के बारे में बहुत मार्गदर्शन है। Microsoft के पास थ्रॉविंग अपवादों के बारे में कुछ मार्गदर्शन है। वहां वे राज्य करते हैं:

यदि संभव हो तो नियंत्रण के सामान्य प्रवाह के अपवादों का उपयोग न करें।

पहला नोट "यदि संभव हो तो" की उदारता है। अधिक महत्वपूर्ण बात, विवरण इस संदर्भ देता है:

framework designers should design APIs so users can write code that does not throw exceptions

इसका मतलब यह है कि यदि आप एक एपीआई लिख रहे हैं जो किसी अन्य व्यक्ति द्वारा उपभोग किया जा सकता है, तो उन्हें बिना किसी प्रयास या पकड़ के अपवाद को नेविगेट करने की क्षमता दें। उदाहरण के लिए, अपने अपवाद-फेंकने वाले पार्स विधि के साथ एक TryParse प्रदान करें। हालांकि यह कहीं नहीं कहता है कि आपको अपवाद नहीं पकड़ना चाहिए।

इसके अलावा, जैसा कि एक अन्य उपयोगकर्ता बताते हैं, कैच ने हमेशा प्रकार से फ़िल्टरिंग की अनुमति दी है और हाल ही में जब क्लॉज के माध्यम से आगे फ़िल्टरिंग की अनुमति देते हैं । यह भाषा सुविधाओं की बर्बादी की तरह लगता है अगर हम उनका उपयोग करने वाले नहीं हैं।

यह कहा जा सकता है कि एक फेंके गए अपवाद के लिए कुछ लागत है, और एक भारी लूप में MAY प्रभाव प्रदर्शन की लागत है। हालांकि, यह भी कहा जा सकता है कि "कनेक्टेड एप्लिकेशन" में एक अपवाद की लागत नगण्य होने वाली है। वास्तविक लागत की एक दशक पहले जांच की गई थी: https://stackoverflow.com/a/891230/852208 दूसरे शब्दों में, एक डेटाबेस के कनेक्शन और क्वेरी की लागत एक फेंके गए अपवाद को बौना करने की संभावना है।

वह सब एक तरफ, मैं यह निर्धारित करना चाहता था कि वास्तव में कौन सी विधि तेज है। जैसा कि अपेक्षित था, कोई ठोस जवाब नहीं है।

कोई भी कोड जो स्तंभों पर लूप करता है, वह स्तंभों की संख्या के रूप में धीमा हो जाता है। यह भी कहा जा सकता है कि अपवादों पर भरोसा करने वाला कोई भी कोड उस दर के आधार पर धीमा हो जाएगा जिसमें क्वेरी नहीं मिल रही है।

चाड ग्रांट और मैट हैमिल्टन दोनों के जवाबों को लेते हुए, मैंने दोनों विधियों को 20 कॉलम तक और 50% त्रुटि दर तक चलाया (ओपी ने संकेत दिया कि वह इस दो परीक्षण का उपयोग विभिन्न प्रॉप्स के बीच कर रहे थे, इसलिए मैंने दो के रूप में कुछ मान लिया) ।

यहाँ परिणाम हैं, LinqPad के साथ साजिश रची: परिणाम - श्रृंखला 1 लूप है, 2 अपवाद है

यहां के ज़िगज़ैग प्रत्येक कॉलम की गिनती में दोष दर (कॉलम नहीं मिला) हैं।

संकरा परिणाम सेट पर, लूपिंग एक अच्छा विकल्प है। हालाँकि, GetOrdinal / Exception विधि स्तंभों की संख्या के प्रति लगभग संवेदनशील नहीं है और लगभग 11 स्तंभों से लूपिंग विधि को बेहतर बनाने के लिए शुरू होता है।

कहा कि मेरे पास वास्तव में एक वरीयता प्रदर्शन बुद्धिमान नहीं है क्योंकि 11 कॉलम उचित लगते हैं क्योंकि एक पूरे आवेदन पर औसतन कॉलम की संख्या वापस आती है। या तो मामले में हम यहाँ एक मिलीसेकंड के अंशों के बारे में बात कर रहे हैं।

हालाँकि, एक कोड सादगी पहलू, और अन्य समर्थन से, मैं शायद गेटऑर्डिनल मार्ग के साथ जाऊँगा।

यहाँ linqpad रूप में परीक्षण किया गया है। अपने तरीके से प्रजनन करने के लिए स्वतंत्र महसूस करें:

void Main()
{
    var loopResults = new List<Results>();
    var exceptionResults = new List<Results>();
    var totalRuns = 10000;
    for (var colCount = 1; colCount < 20; colCount++)
    {
        using (var conn = new SqlConnection(@"Data Source=(localdb)\MSSQLLocalDb;Initial Catalog=master;Integrated Security=True;"))
        {
            conn.Open();

            //create a dummy table where we can control the total columns
            var columns = String.Join(",",
                (new int[colCount]).Select((item, i) => $"'{i}' as col{i}")
            );
            var sql = $"select {columns} into #dummyTable";
            var cmd = new SqlCommand(sql,conn);
            cmd.ExecuteNonQuery();

            var cmd2 = new SqlCommand("select * from #dummyTable", conn);

            var reader = cmd2.ExecuteReader();
            reader.Read();

            Func<Func<IDataRecord, String, Boolean>, List<Results>> test = funcToTest =>
            {
                var results = new List<Results>();
                Random r = new Random();
                for (var faultRate = 0.1; faultRate <= 0.5; faultRate += 0.1)
                {
                    Stopwatch stopwatch = new Stopwatch();
                    stopwatch.Start();
                    var faultCount=0;
                    for (var testRun = 0; testRun < totalRuns; testRun++)
                    {
                        if (r.NextDouble() <= faultRate)
                        {
                            faultCount++;
                            if(funcToTest(reader, "colDNE"))
                                throw new ApplicationException("Should have thrown false");
                        }
                        else
                        {
                            for (var col = 0; col < colCount; col++)
                            {
                                if(!funcToTest(reader, $"col{col}"))
                                    throw new ApplicationException("Should have thrown true");
                            }
                        }
                    }
                    stopwatch.Stop();
                    results.Add(new UserQuery.Results{
                        ColumnCount = colCount, 
                        TargetNotFoundRate = faultRate,
                        NotFoundRate = faultCount * 1.0f / totalRuns, 
                        TotalTime=stopwatch.Elapsed
                    });
                }
                return results;
            };
            loopResults.AddRange(test(HasColumnLoop));

            exceptionResults.AddRange(test(HasColumnException));

        }

    }
    "Loop".Dump();
    loopResults.Dump();

    "Exception".Dump();
    exceptionResults.Dump();

    var combinedResults = loopResults.Join(exceptionResults,l => l.ResultKey, e=> e.ResultKey, (l, e) => new{ResultKey = l.ResultKey, LoopResult=l.TotalTime, ExceptionResult=e.TotalTime});
    combinedResults.Dump();
    combinedResults
        .Chart(r => r.ResultKey, r => r.LoopResult.Milliseconds * 1.0 / totalRuns, LINQPad.Util.SeriesType.Line)
        .AddYSeries(r => r.ExceptionResult.Milliseconds * 1.0 / totalRuns, LINQPad.Util.SeriesType.Line)
        .Dump();
}
public static bool HasColumnLoop(IDataRecord dr, string columnName)
{
    for (int i = 0; i < dr.FieldCount; i++)
    {
        if (dr.GetName(i).Equals(columnName, StringComparison.InvariantCultureIgnoreCase))
            return true;
    }
    return false;
}

public static bool HasColumnException(IDataRecord r, string columnName)
{
    try
    {
        return r.GetOrdinal(columnName) >= 0;
    }
    catch (IndexOutOfRangeException)
    {
        return false;
    }
}

public class Results
{
    public double NotFoundRate { get; set; }
    public double TargetNotFoundRate { get; set; }
    public int ColumnCount { get; set; }
    public double ResultKey {get => ColumnCount + TargetNotFoundRate;}
    public TimeSpan TotalTime { get; set; }


}

1
आप स्पष्ट रूप से अपवादों के साथ अजीब तरह का जुनून रखते हैं। प्रदर्शन के लिए एक स्थिर लुकअप में कॉलम लोकेशन को कैश करने और पूर्णांक लुकअप का उपयोग करने के लिए एक बेहतर तरीका होगा
चाड ग्रांट

अपवादों को नियंत्रण प्रवाह के रूप में उपयोग करने के साथ एक और मुद्दा यह है कि वे प्रोफाइलर में # अपवादों के रूप में दिखाते हैं जब आपके सुझाए गए कोड में वे जानबूझकर होते हैं ... अपवाद नहीं। अपवादों को तोड़ने के लिए अपने डिबगर की स्थापना का उल्लेख नहीं करना चाहिए। अनिवार्य रूप से त्रुटियों को रिपोर्ट करने वाली त्रुटियां नहीं हैं। आपको ऐसा नहीं करना चाहिए।
चाड ग्रांट

1
अंत में / सेकंड, और फ़िल्टर / सेकंड के लिए काउंटर भी हैं। क्या वे भी बुरे हैं? मैं इसे एक संभावित चेतावनी कहूंगा- पहला वास्तविक जो आपने प्रदान किया है। काउंटर सिर्फ जानकारी है। जब तक वे एक प्रदर्शन के मुद्दे के अनुरूप नहीं हैं, तब तक उनका कोई मतलब नहीं है - और इस मामले में मैंने पहले ही बिंदु दिखाया है जहां अपवादों में बेहतर प्रदर्शन होता है। मैंने यह भी संकेत दिया है कि ढांचे और पुस्तकालयों में पहले से ही बहुत सारे अपवाद हैं। मुझे अभी 60 एक्स / एस फेंकने वाले दृश्य स्टूडियो का एक उदाहरण मिला है। अपवाद तब तक त्रुटियां नहीं हैं जब तक कि वे अनकैप्ड न हों।
b_levitt

महान विश्लेषण। मैंने अपने नए उत्तर में इसके परिणामों का उपयोग किया।
yazanpro

1

यह कोड उन समस्याओं को ठीक करता है जो लेविटिकन ने अपने कोड के साथ की थी: (से अनुकूलित: [1]: http://msdn.microsoft.com/en-us/library/system.data.datatablereader.getschematable.aspx )

public List<string> GetColumnNames(SqlDataReader r)
{
    List<string> ColumnNames = new List<string>();
    DataTable schemaTable = r.GetSchemaTable();
    DataRow row = schemaTable.Rows[0];
    foreach (DataColumn col in schemaTable.Columns)
    {
        if (col.ColumnName == "ColumnName") 
        { 
            ColumnNames.Add(row[col.Ordinal].ToString()); 
            break; 
        }
    }
    return ColumnNames;
}

उन सभी बेकार कॉलम नामों को प्राप्त करने का कारण और आपकी तालिका से कॉलम का नाम नहीं है ... ऐसा इसलिए है क्योंकि आपके स्कीमा कॉलम का नाम मिल रहा है (अर्थात स्कीमा तालिका के कॉलम नाम)

नोट: यह केवल पहले कॉलम का नाम लौटाने के लिए लगता है ...

संपादित करें: सभी कॉलमों का नाम वापस करने वाला सही कोड, लेकिन आप इसे करने के लिए SqlDataReader का उपयोग नहीं कर सकते

public List<string> ExecuteColumnNamesReader(string command, List<SqlParameter> Params)
{
    List<string> ColumnNames = new List<string>();
    SqlDataAdapter da = new SqlDataAdapter();
    string connection = ""; // your sql connection string
    SqlCommand sqlComm = new SqlCommand(command, connection);
    foreach (SqlParameter p in Params) { sqlComm.Parameters.Add(p); }
    da.SelectCommand = sqlComm;
    DataTable dt = new DataTable();
    da.Fill(dt);
    DataRow row = dt.Rows[0];
    for (int ordinal = 0; ordinal < dt.Columns.Count; ordinal++)
    {
        string column_name = dt.Columns[ordinal].ColumnName;
        ColumnNames.Add(column_name);
    }
    return ColumnNames; // you can then call .Contains("name") on the returned collection
}

या एक लाइन में return r.GetSchemaTable().Rows.Cast<DataRow>().Select(x => (string)x["ColumnName"]).ToList();:)
nawfal

केवल एक कॉलम नाम खोजने के लिए GetSchemaTable () का उपयोग अत्यधिक (आवंटन वार) है। स्रोत की जाँच करें github.com/microsoft/referencesource/blob/…
चाड ग्रांट

1

अपने कोड को मजबूत और साफ रखने के लिए, इस तरह से एकल एक्सटेंशन फ़ंक्शन का उपयोग करें:

    Public Module Extensions

        <Extension()>
        Public Function HasColumn(r As SqlDataReader, columnName As String) As Boolean

            Return If(String.IsNullOrEmpty(columnName) OrElse r.FieldCount = 0, False, Enumerable.Range(0, r.FieldCount).Select(Function(i) r.GetName(i)).Contains(columnName, StringComparer.OrdinalIgnoreCase))

        End Function

    End Module

0

न तो मैं किया था GetSchemaTable, काम करने के लिए जब तक मैंने पाया इस तरह से

मूल रूप से मैं यह करता हूं:

Dim myView As DataView = dr.GetSchemaTable().DefaultView
myView.RowFilter = "ColumnName = 'ColumnToBeChecked'"

If myView.Count > 0 AndAlso dr.GetOrdinal("ColumnToBeChecked") <> -1 Then
  obj.ColumnToBeChecked = ColumnFromDb(dr, "ColumnToBeChecked")
End If

0
public static bool DataViewColumnExists(DataView dv, string columnName)
{
    return DataTableColumnExists(dv.Table, columnName);
}

public static bool DataTableColumnExists(DataTable dt, string columnName)
{
    string DebugTrace = "Utils::DataTableColumnExists(" + dt.ToString() + ")";
    try
    {
        return dt.Columns.Contains(columnName);
    }
    catch (Exception ex)
    {
        throw new MyExceptionHandler(ex, DebugTrace);
    }
}

Columns.Contains केस-असंवेदनशील btw है।


इसमें शामिल नहीं () अपवाद नहीं हैं, यह कोड व्यर्थ है। आप केवल शून्य सूचक अपवादों को पकड़ रहे होंगे।
चाड ग्रांट

0

आपकी विशेष स्थिति में (सभी प्रक्रियाओं में 1 को छोड़कर एक ही कॉलम होता है जिसमें अतिरिक्त 1 कॉलम होता है), पाठक की जांच करना बेहतर और तेज़ होगा। उनके बीच भेद करने के लिए फील्डकाउंट संपत्ति।

const int NormalColCount=.....
if(reader.FieldCount > NormalColCount)
{
// Do something special
}

मुझे पता है कि यह एक पुरानी पोस्ट है लेकिन मैंने उसी स्थिति में अन्य की मदद करने का जवाब देने का फैसला किया। आप (प्रदर्शन कारण के लिए) इस घोल को घोल बनाने वाले घोल में मिला सकते हैं।


कृपया उस समाधान को नाम दें जिसका आप उल्लेख कर रहे हैं। किन दो घोलों को मिलाना चाहिए?
पाब्लो जोमेर

0

मेरे डेटा एक्सेस क्लास को बैकवर्ड कम्पेटिबल होना चाहिए, इसलिए मैं एक रिलीज़ में एक कॉलम एक्सेस करने का प्रयास कर सकता हूँ जहाँ यह अभी तक डेटाबेस में मौजूद नहीं है। हमारे पास कुछ बड़े डेटा सेट लौटाए जा रहे हैं, इसलिए मैं एक विस्तार विधि का एक बड़ा प्रशंसक नहीं हूं जिसमें प्रत्येक संपत्ति के लिए डेटारीडर कॉलम संग्रह को पुनरावृत्त करना है।

मेरे पास एक उपयोगिता वर्ग है जो स्तंभों की एक निजी सूची बनाता है और फिर एक सामान्य विधि है जो स्तंभ नाम और आउटपुट पैरामीटर प्रकार के आधार पर एक मूल्य को हल करने का प्रयास करता है।

private List<string> _lstString;

public void GetValueByParameter<T>(IDataReader dr, string parameterName, out T returnValue)
{
    returnValue = default(T);

    if (!_lstString.Contains(parameterName))
    {
        Logger.Instance.LogVerbose(this, "missing parameter: " + parameterName);
        return;
    }

    try
    {
        if (dr[parameterName] != null && [parameterName] != DBNull.Value)
            returnValue = (T)dr[parameterName];
    }
    catch (Exception ex)
    {
        Logger.Instance.LogException(this, ex);
    }
}

/// <summary>
/// Reset the global list of columns to reflect the fields in the IDataReader
/// </summary>
/// <param name="dr">The IDataReader being acted upon</param>
/// <param name="NextResult">Advances IDataReader to next result</param>
public void ResetSchemaTable(IDataReader dr, bool nextResult)
{
    if (nextResult)
        dr.NextResult();

    _lstString = new List<string>();

    using (DataTable dataTableSchema = dr.GetSchemaTable())
    {
        if (dataTableSchema != null)
        {
            foreach (DataRow row in dataTableSchema.Rows)
            {
                _lstString.Add(row[dataTableSchema.Columns["ColumnName"]].ToString());
            }
        }
    }
}

फिर मैं बस अपने कोड को कॉल कर सकता हूं

using (var dr = ExecuteReader(databaseCommand))
{
    int? outInt;
    string outString;

    Utility.ResetSchemaTable(dr, false);        
    while (dr.Read())
    {
        Utility.GetValueByParameter(dr, "SomeColumn", out outInt);
        if (outInt.HasValue) myIntField = outInt.Value;
    }

    Utility.ResetSchemaTable(dr, true);
    while (dr.Read())
    {
        Utility.GetValueByParameter(dr, "AnotherColumn", out outString);
        if (!string.IsNullOrEmpty(outString)) myIntField = outString;
    }
}

0

संपूर्ण समस्या की कुंजी यहां है :

if (-1 == index) {
    throw ADP.IndexOutOfRange(fieldName);
}

यदि संदर्भित तीन पंक्तियों (वर्तमान में 72, 73 और 74 लाइनें) को बाहर निकाल दिया जाता है, तो आप यह -1निर्धारित करने के लिए आसानी से जांच कर सकते हैं कि क्या कॉलम मौजूद नहीं है।

मूल प्रदर्शन को सुनिश्चित करते हुए इसके आसपास का एकमात्र तरीका Reflectionनिम्नलिखित की तरह एक आधारित कार्यान्वयन का उपयोग करना है :

usings:

using System;
using System.Data;
using System.Reflection;
using System.Data.SqlClient;
using System.Linq;
using System.Web.Compilation; // I'm not sure what the .NET Core equivalent to BuildManager.cs

परावर्तन आधारित विस्तार विधि:

/// Gets the column ordinal, given the name of the column.
/// </summary>
/// <param name="reader"></param>
/// <param name="name">The name of the column.</param>
/// <returns> The zero-based column ordinal. -1 if the column does not exist.</returns>
public static int GetOrdinalSoft(this SqlDataReader reader, string name)
{
    try
    {
        // Note that "Statistics" will not be accounted for in this implemenation
        // If you have SqlConnection.StatisticsEnabled set to true (the default is false), you probably don't want to use this method
        // All of the following logic is inspired by the actual implementation of the framework:
        // https://referencesource.microsoft.com/#System.Data/fx/src/data/System/Data/SqlClient/SqlDataReader.cs,d66096b6f57cac74
        if (name == null)
            throw new ArgumentNullException("fieldName");

        Type sqlDataReaderType = typeof(SqlDataReader);
        object fieldNameLookup = sqlDataReaderType.GetField("_fieldNameLookup", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(reader);
        Type fieldNameLookupType;
        if (fieldNameLookup == null)
        {
            MethodInfo checkMetaDataIsReady = sqlDataReaderType.GetRuntimeMethods().First(x => x.Name == "CheckMetaDataIsReady" && x.GetParameters().Length == 0);
            checkMetaDataIsReady.Invoke(reader, null);
            fieldNameLookupType = BuildManager.GetType("System.Data.ProviderBase.FieldNameLookup", true, false);
            ConstructorInfo ctor = fieldNameLookupType.GetConstructor(new[] { typeof(SqlDataReader), typeof(int) });
            fieldNameLookup = ctor.Invoke(new object[] { reader, sqlDataReaderType.GetField("_defaultLCID", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(reader) });
        }
        else
            fieldNameLookupType = fieldNameLookup.GetType();

        MethodInfo indexOf = fieldNameLookupType.GetMethod("IndexOf", BindingFlags.Public | BindingFlags.Instance, null, new Type[] { typeof(string) }, null);

        return (int)indexOf.Invoke(fieldNameLookup, new object[] { name });
    }
    catch
    {
        // .NET Implemenation might have changed, revert back to the classic solution.
        if (reader.FieldCount > 11) // Performance observation by b_levitt
        {
            try
            {
                return reader.GetOrdinal(name);
            }
            catch
            {
                return -1;
            }
        }
        else
        {
            var exists = Enumerable.Range(0, reader.FieldCount).Any(i => string.Equals(reader.GetName(i), name, StringComparison.OrdinalIgnoreCase));
            if (exists)
                return reader.GetOrdinal(name);
            else
                return -1;
        }
    }
}


-1

कैसा रहेगा

if (dr.GetSchemaTable().Columns.Contains("accounttype"))
   do something
else
   do something

यह शायद एक लूप में उतना कुशल नहीं होगा


देखें Levitikon का जवाब बात यह है कि जिस तरह का देखने के लिए dr.GetSchemaTable().Columnsयह तुम्हारे लिए क्या देख रहे हैं नहीं है - शामिल हैं।
डैनियल शिलिंग

-1

यद्यपि सार्वजनिक रूप से उजागर नहीं किया गया है, लेकिन आंतरिक वर्ग में एक विधि मौजूद है System.Data.ProviderBase.FieldNameLookupजो SqlDataReaderनिर्भर करती है।

इसे एक्सेस करने और मूल प्रदर्शन प्राप्त करने के लिए, आपको रनटाइम पर एक विधि बनाने के लिए ILGenerator का उपयोग करना होगा। निम्न कोड आपको कक्षा int IndexOf(string fieldName)में सीधे पहुंच प्रदान करेगा System.Data.ProviderBase.FieldNameLookupऔर साथ ही साथ पुस्तक को भी रखेगा, SqlDataReader.GetOrdinal()ताकि कोई साइड इफेक्ट न हो। उत्पन्न कोड में मौजूदा SqlDataReader.GetOrdinal()को दिखाया गया है सिवाय इसके कि वह FieldNameLookup.IndexOf()इसके बजाय कॉल करता है FieldNameLookup.GetOrdinal()GetOrdinal()विधि करने के लिए कॉल IndexOf()समारोह और अगर एक अपवाद फेंकता -1दिया जाता है, तो हम उस व्यवहार बाईपास।

using System;
using System.Data;
using System.Data.SqlClient;
using System.Reflection;
using System.Reflection.Emit;

public static class SqlDataReaderExtensions {

   private delegate int IndexOfDelegate(SqlDataReader reader, string name);
   private static IndexOfDelegate IndexOf;

   public static int GetColumnIndex(this SqlDataReader reader, string name) {
      return name == null ? -1 : IndexOf(reader, name);
   }

   public static bool ContainsColumn(this SqlDataReader reader, string name) {
      return name != null && IndexOf(reader, name) >= 0;
   }

   static SqlDataReaderExtensions() {
      Type typeSqlDataReader = typeof(SqlDataReader);
      Type typeSqlStatistics = typeSqlDataReader.Assembly.GetType("System.Data.SqlClient.SqlStatistics", true);
      Type typeFieldNameLookup = typeSqlDataReader.Assembly.GetType("System.Data.ProviderBase.FieldNameLookup", true);

      BindingFlags staticflags = BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.IgnoreCase | BindingFlags.Static;
      BindingFlags instflags = BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.IgnoreCase | BindingFlags.Instance;

      DynamicMethod dynmethod = new DynamicMethod("SqlDataReader_IndexOf", typeof(int), new Type[2]{ typeSqlDataReader, typeof(string) }, true);
      ILGenerator gen = dynmethod.GetILGenerator();
      gen.DeclareLocal(typeSqlStatistics);
      gen.DeclareLocal(typeof(int));

      // SqlStatistics statistics = (SqlStatistics) null;
      gen.Emit(OpCodes.Ldnull);
      gen.Emit(OpCodes.Stloc_0);
      // try {
      gen.BeginExceptionBlock();
      //    statistics = SqlStatistics.StartTimer(this.Statistics);
      gen.Emit(OpCodes.Ldarg_0); //this
      gen.Emit(OpCodes.Call, typeSqlDataReader.GetProperty("Statistics", instflags | BindingFlags.GetProperty, null, typeSqlStatistics, Type.EmptyTypes, null).GetMethod);
      gen.Emit(OpCodes.Call, typeSqlStatistics.GetMethod("StartTimer", staticflags | BindingFlags.InvokeMethod, null, new Type[] { typeSqlStatistics }, null));
      gen.Emit(OpCodes.Stloc_0); //statistics
      //    if(this._fieldNameLookup == null) {
      Label branchTarget = gen.DefineLabel();
      gen.Emit(OpCodes.Ldarg_0); //this
      gen.Emit(OpCodes.Ldfld, typeSqlDataReader.GetField("_fieldNameLookup", instflags | BindingFlags.GetField));
      gen.Emit(OpCodes.Brtrue_S, branchTarget);
      //       this.CheckMetaDataIsReady();
      gen.Emit(OpCodes.Ldarg_0); //this
      gen.Emit(OpCodes.Call, typeSqlDataReader.GetMethod("CheckMetaDataIsReady", instflags | BindingFlags.InvokeMethod, null, Type.EmptyTypes, null));
      //       this._fieldNameLookup = new FieldNameLookup((IDataRecord)this, this._defaultLCID);
      gen.Emit(OpCodes.Ldarg_0); //this
      gen.Emit(OpCodes.Ldarg_0); //this
      gen.Emit(OpCodes.Ldarg_0); //this
      gen.Emit(OpCodes.Ldfld, typeSqlDataReader.GetField("_defaultLCID", instflags | BindingFlags.GetField));
      gen.Emit(OpCodes.Newobj, typeFieldNameLookup.GetConstructor(instflags, null, new Type[] { typeof(IDataReader), typeof(int) }, null));
      gen.Emit(OpCodes.Stfld, typeSqlDataReader.GetField("_fieldNameLookup", instflags | BindingFlags.SetField));
      //    }
      gen.MarkLabel(branchTarget);
      gen.Emit(OpCodes.Ldarg_0); //this
      gen.Emit(OpCodes.Ldfld, typeSqlDataReader.GetField("_fieldNameLookup", instflags | BindingFlags.GetField));
      gen.Emit(OpCodes.Ldarg_1); //name
      gen.Emit(OpCodes.Call, typeFieldNameLookup.GetMethod("IndexOf", instflags | BindingFlags.InvokeMethod, null, new Type[] { typeof(string) }, null));
      gen.Emit(OpCodes.Stloc_1); //int output
      Label leaveProtectedRegion = gen.DefineLabel();
      gen.Emit(OpCodes.Leave_S, leaveProtectedRegion);
      // } finally {
      gen.BeginFaultBlock();
      //    SqlStatistics.StopTimer(statistics);
      gen.Emit(OpCodes.Ldloc_0); //statistics
      gen.Emit(OpCodes.Call, typeSqlStatistics.GetMethod("StopTimer", staticflags | BindingFlags.InvokeMethod, null, new Type[] { typeSqlStatistics }, null));
      // }
      gen.EndExceptionBlock();
      gen.MarkLabel(leaveProtectedRegion);
      gen.Emit(OpCodes.Ldloc_1);
      gen.Emit(OpCodes.Ret);

      IndexOf = (IndexOfDelegate)dynmethod.CreateDelegate(typeof(IndexOfDelegate));
   }

}

1
आंतरिक कोड लगभग सटीक वही काम करता है जो मेरा जवाब इस अजीब प्रतिबिंब / प्रतिनिधि की आवश्यकता के बिना कर रहा है। यह प्रति ऑब्जेक्ट लुकअप को कैशिंग कर रहा है जो वास्तविक दुनिया में फायदेमंद नहीं होगा क्योंकि आप ऑर्डिनल्स को कैश करना चाहते हैं जब पहली बार क्वेरी को चलाया जाता है और ऐप के जीवनकाल में उस कैश का उपयोग करते हैं, हर क्वेरी पर एक नया कैश नहीं बनाते हैं।
चाड ग्रांट

-1

यह मेरे लिए काम करते हैं

public static class DataRecordExtensions
{
        public static bool HasColumn(IDataReader dataReader, string columnName)
        {
            dataReader.GetSchemaTable().DefaultView.RowFilter = $"ColumnName= '{columnName}'";
            return (dataReader.GetSchemaTable().DefaultView.Count > 0);
        }
}

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.