SQLDataReader অবজেক্টে কলামের নাম পরীক্ষা করুন


212

কোনও SqlDataReaderবস্তুতে একটি কলাম রয়েছে কিনা তা আমি কীভাবে চেক করব ? আমার ডেটা অ্যাক্সেস লেয়ারে, আমি একটি পদ্ধতি তৈরি করেছি যা একাধিক সঞ্চিত পদ্ধতি কলগুলির জন্য একই অবজেক্ট তৈরি করে। সঞ্চিত পদ্ধতির একটিতে একটি অতিরিক্ত কলাম রয়েছে যা অন্যান্য সঞ্চিত পদ্ধতি ব্যবহার করে না। প্রতিটি দৃশ্যের জন্য আমি পদ্ধতিটি সংশোধন করতে চাই।

আমার আবেদন সি # তে লেখা আছে is

উত্তর:


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কিছু অন্যান্য উত্তরের মতো নিয়ন্ত্রণ যুক্তির জন্য গুলি ব্যবহার করা খারাপ অভ্যাস হিসাবে বিবেচিত হয় এবং এর কার্য সম্পাদনের জন্য ব্যয় হয়। এটি # টি ব্যতিক্রম নিক্ষেপকারীদের প্রোফাইলের কাছে মিথ্যা ইতিবাচক প্রেরণ করে এবং anyoneশ্বর যে কোনও ব্যক্তিকে নিক্ষেপ করা ব্যতিক্রমগুলি ভাঙতে তাদের ডিবাগার সেট করতে সহায়তা করে।

গেটস্কেমেটেবল () হ'ল অনেক উত্তরের আরও একটি পরামর্শ। ক্ষেত্রের অস্তিত্বের জন্য এটি যাচাই বাছাই করার উপায় নয় কারণ এটি সমস্ত সংস্করণে প্রয়োগ করা হয়নি (এটি বিমূর্ত এবং ডটনেটকরের কয়েকটি সংস্করণে নোটসম্পোর্টড এক্সপশন নিক্ষেপ করে)। GetSchemaTable এছাড়াও Overkill কর্মক্ষমতা জ্ঞানী যেমন একটি প্রশংসনীয় ভারী দায়িত্ব ফাংশন যদি তুমি উৎস খুঁজে বার করো

ক্ষেত্রগুলির মধ্য দিয়ে লুপিংয়ে একটি ছোট পারফরম্যান্স হিট হতে পারে যদি আপনি এটি ব্যবহার করেন এবং ফলাফলগুলি ক্যাশে করার বিষয়ে বিবেচনা করতে পারেন।


যদি কোনও উপনাম ব্যবহার করা হয় তবে কী হবে? নাম তুলনা ব্যর্থ হবে।
মার্ফিব্রো 2

এটি বিতর্কযোগ্য যে ব্যতিক্রম প্রবাহটি ব্যবহার করা খারাপ অভ্যাস। এটি একবার খারাপ বলে বিবেচিত হয়েছিল কারণ এটি অন্যান্য অপারেটরদের কাছে তুলনামূলকভাবে ব্যয়বহুল, তবে কোনও সংযুক্ত অ্যাপ্লিকেশনটিতে নগন্য। স্কিট স্ট্যাক গভীরতার উপর নির্ভর করে 2006 সালে সব পথ ফিরে MS প্রতি 40-118 ব্যতিক্রম মাপা stackoverflow.com/a/891230/852208 । আরও পরীক্ষা না করেই সম্ভব, এই কোডটি সমস্ত কলামের অর্ধেক ক্ষেত্রে (এখনও একটি ডিবি সংযুক্ত অ্যাপে তুচ্ছ) যদিও এটির গড় কেসটি চেক করার সাথে প্রকৃতপক্ষে ধীর হয়। আমি এই উত্তরটি সম্পাদনা করব কেবলমাত্র মাঝের অনুচ্ছেদটি অন্তর্ভুক্ত করার জন্য কারণ অন্য দুটি মতামত।
b_levitt

3
@ বি_উইলিট এটি বিতর্কযোগ্য নয়, এটি ক্রেপ কোড এবং আপনারা নিয়ন্ত্রণ প্রবাহের ব্যতিক্রমগুলির উপর নির্ভর করবেন না
চাদ গ্রান্ট

আমি যে দুটি বাক্য দেখিয়েছি, তার মতোই এটি আবারও একটি মতামত যা খাঁটি গণনা প্রয়োগে পারফরম্যান্সের বাইরে কোনও যুক্তি সহকারে সমর্থিত নয়। আমি আপনাকে সাহস দিচ্ছি যে আপনার ডিবাগারটি সমস্ত ব্যতিক্রমগুলি ভাঙতে এবং কেবলমাত্র আমার কোডটি অক্ষম করুন এবং আপনি দেখতে পাবেন যে এমনকি ফ্রেমওয়ার্ক এবং অন্যান্য গ্রন্থাগারগুলি ইতিমধ্যে এটি কীভাবে করছে advice আপনার পরামর্শের সাথে সমস্যাটি হ'ল এটি বিকাশকারীদের কোডগুলি ফিরিয়ে দেওয়ার দিকে ধাক্কা দেয় যা সর্বাধিক সম্মত হ'ল নিকৃষ্ট প্যাটার্ন: স্ট্যাকওভারফ্লো . com / প্রশ্নস / 68৯68৮৩/২ । এই জাতীয় পদ্ধতি "সাফল্যের গর্ত" পরীক্ষায় ব্যর্থ হয়।
বি_লিট

একটি কোড দৃষ্টিকোণ থেকে, আপনার উত্তর একটি বৈধ উত্তর। তবে আপনার মতামতটির সাথে উত্তরের উত্তর হিসাবে চেষ্টা করার / ক্যাচ দিয়ে উত্তোলন করার চেষ্টা করা (যা এ্যালাইজগুলিও পরিচালনা করে) এখানে অযোগ্য।
বি_লিট

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
@ জেসমিন: আমি খুব তাড়াতাড়ি কথা বলেছি! আপনার কোডটি আপনার ফলাফল সেট নয়, স্কিমা সারণীতে একটি কলামের জন্য পরীক্ষা করে। আপনাকে প্রতিটি ক্ষেত্রের "কলামনাম" ক্ষেত্রের মানের সাথে "ফিল্ড" ("ক্ষেত্রটি" কলামের নাম মনে করে) তুলনা করতে হবে। আপনি এটি পেলে বিরতি, মিথ্যা ফিরে না আপনি যদি না।
স্টিভ জে

4
@ স্টিভ জে: ফলাফলসেটে কখন getSchemaTable এ একটি কলাম থাকবে না?
ইয়াহু দোয়া করুন 16 ই

1
বিভ্রান্ত অন্য কারও কাছে, এটি কাজ করে না। স্কিমা টেবিল থেকে কলামোনাম সারিটি পুনরুদ্ধার এবং এটি ব্যবহার সম্পর্কে নীচের উত্তরটি দেখুন।
জেসন জ্যাকসন

3
হ্যাঁ, এটি কাজ করে না। কে এতবার উজ্জীবিত করেছে ??? যদি এই উত্তরটি এখানে না পাওয়া যায় তবে পরে এটি আমাকে অনেক ডিবাগ করার সময় বাঁচাতে পারত!
c00000fd

1
@ জুঁই তারা দুজনেই কি কাজ করে? আসলে তা না. দয়া করে আপনার উত্তরের প্রথম অংশটি সরিয়ে দিন। আমি নিজেই করতাম, তবে আপনার শেষ মন্তব্যের জন্য!
নওফাল

33

আমি মনে করি আপনার সেরা বাজিটি হ'ল আপনার ডেটা রিডারকে সামনের দিকে গেটআর্ডিনাল ("কলামনাম") কল করা এবং কলামটি উপস্থিত না থাকলে ইনডেক্সআউটঅফরেঞ্জএক্সপেশন ধরা।

আসলে, আসুন একটি এক্সটেনশন পদ্ধতি তৈরি করুন:

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

সম্পাদন করা

ঠিক আছে, এই পোস্টটি ইদানীং কয়েকটি নিচে ভোট সংগ্রহ করতে শুরু করেছে, এবং আমি এটি মুছে ফেলতে পারি না কারণ এটি গ্রহণযোগ্য উত্তর, তাই আমি এটি আপডেট করব এবং (আশা করি) ব্যতিক্রম হ্যান্ডলিংয়ের ব্যবহারকে ন্যায়সঙ্গত করার চেষ্টা করব নিয়ন্ত্রণ প্রবাহ.

চাদ গ্রান্ট দ্বারা পোস্ট করা হিসাবে এটি অর্জনের অন্য উপায়টি হ'ল ডেটা রিডারের প্রতিটি ক্ষেত্রটি লুপ করা এবং আপনি যে ক্ষেত্রের নামটি সন্ধান করছেন তার ক্ষেত্রে কেস-সংবেদনশীল তুলনা করা। এটি সত্যই ভাল কাজ করবে এবং সত্যই সম্ভবত আমার উপরের পদ্ধতির চেয়ে আরও ভাল সম্পাদন করবে। অবশ্যই আমি উপরের পদ্ধতিটি কখনই লুপের ভিতরে ব্যবহার করব না যেখানে পারফরম্যান্স একটি সমস্যা ছিল।

আমি এমন একটি পরিস্থিতির কথা ভাবতে পারি যেখানে লুপটি না করে যেখানে চেষ্টা / গেটঅর্ডিনাল / ক্যাচ পদ্ধতি কাজ করবে। এটি এখনই একটি সম্পূর্ণ অনুমানমূলক পরিস্থিতি তাই এটি খুব ক্ষুদ্র ন্যায়সঙ্গত সমর্থনযোগ্যতা। নির্বিশেষে, আমার সাথে সহ্য করুন এবং আপনি কী মনে করেন দেখুন।

এমন একটি ডেটাবেস কল্পনা করুন যা আপনাকে কোনও সারণির মধ্যে "উলাম" কলাম করতে দেয়। কল্পনা করুন যে আমি "কর্মচারী নাম" নামে একটি কলাম দিয়ে একটি সারণী সংজ্ঞায়িত করতে পারি তবে এটিকে "এমপনেম" এর একটি উপাধি দিতে পারি এবং উভয় নামের জন্য একটি নির্বাচন করা করলে সেই কলামের ডেটা ফিরে আসবে। এতদিন আমার সাথে?

এখন কল্পনা করুন যে সেই ডাটাবেসের জন্য একটি ADO.NET সরবরাহকারী রয়েছে এবং তারা এটির জন্য একটি IDataReader বাস্তবায়ন কোড আপ করেছে যা কলামের উপনামগুলি অ্যাকাউন্টে নেয়।

এখন, dr.GetName(i)(চাদের উত্তরে ব্যবহৃত হিসাবে) কেবল একটি একক স্ট্রিংই ফিরে আসতে পারে, সুতরাং এটি একটি কলামে কেবলমাত্র একটি "এলিয়াস" দিতে হবে। তবে, GetOrdinal("EmpName")আপনি যে নামটি সন্ধান করছেন তার জন্য প্রতিটি কলামের উপন্যাসটি পরীক্ষা করতে এই সরবরাহকারীর ক্ষেত্রগুলির অভ্যন্তরীণ বাস্তবায়ন ব্যবহার করতে পারে।

এই হাইপোটিক্যাল "এলিয়াসেড কলাম" পরিস্থিতিতে, চেষ্টা / গেটঅর্ডিনাল / ক্যাচ পদ্ধতি হ'ল এটি নিশ্চিত হওয়ার একমাত্র উপায় হবে যে আপনি ফলাফলের মধ্যে একটি কলামের নামের প্রতিটি পরিবর্তনের জন্য পরীক্ষা করছেন।

ঠুনকো? অবশ্যই। কিন্তু একটি চিন্তা মূল্য। সত্যই আমি আইডাটা রেকর্ডে বরং "অফিসিয়াল" হাসকলম পদ্ধতিটি চাই।


15
নিয়ন্ত্রণ যুক্তি জন্য ব্যতিক্রম ব্যবহার করছেন? না নো
চাদ গ্রান্ট

28
আমি এই প্রশ্নটি মূলত পোস্ট করার সময় একটি ছোট বিষয় রয়েছে যা আমি প্রত্যক্ষ করি ... আমি 12/8/08 এ প্রশ্নটি জিজ্ঞাসা করি এবং ম্যাট তার উত্তর 12/17/08 পোস্ট করেছিলেন। প্রত্যেকে নিয়ন্ত্রণ যুক্তির ব্যতিক্রম ধরা সম্পর্কে দুর্গন্ধ সৃষ্টি করেছিল তবে 5/1/09 অবধি কোনও কঠিন বিকল্প সমাধান সরবরাহ করেনি। এজন্য এটি মূলত উত্তর হিসাবে চিহ্নিত হয়েছিল। আমি আজও এই সমাধানটি ব্যবহার করছি।
মাইকেল কনিকনার্ন

19
কলামটি না থাকলে কেবল এতেই পারফরম্যান্স হিট হবে। বর্ণিত অন্যান্য পদ্ধতিগুলির প্রতি একক সময় একটি পারফরম্যান্স হিট এবং আরও বড় পারফরম্যান্স হিট হবে। নিয়ন্ত্রণের প্রবাহের ক্ষেত্রে ব্যতিক্রম হ্যান্ডলিংটি এড়ানো সাধারণভাবে খারাপ অভ্যাস হলেও, এই সমাধানটি আপনার ক্ষেত্রে কার্যকর হয় কিনা তা বিবেচনা না করে প্রথমে উড়িয়ে দেওয়া উচিত নয়।
নিক হ্যারিসন

5
+1 টি। আমি একটি বিস্তৃত নকশা বিধি হিসাবে "নিয়ন্ত্রণ যুক্তির জন্য ব্যতিক্রম ব্যবহার করবেন না" ঠিক আছে ok এর অর্থ এই নয় যে "একে একে একে এড়ানো"। উত্তরটি খুব ভালভাবে নথিভুক্ত কাজ, এবং @ নিক যেমন বলেছেন, পারফরম্যান্স হিট (যদি থাকে ..) তখনই ঘটে যখন কলামটি বিদ্যমান নেই।
ল্যারি

2
ব্যতিক্রমকে নিয়ন্ত্রণ যুক্তি হিসাবে ব্যবহার করা আমার অভিজ্ঞতাতে ডিবাগিংকে আরও জটিল করে তোলে। আপনাকে "প্রচলিত ভাষা রানটাইম ব্যতিক্রমগুলি" তে "ছুঁড়ে" ফেলে দিতে হবে এবং তারপরে আপনি যখন সত্যিকারের ব্যতিক্রম পান তখন এটি কোনও হ্যান্ডলারের মধ্যে ভেঙে যেতে পারে এবং সমস্যাটির লাইনে নয়।
সিড করুন

30

এক লাইনে, আপনার ডেটা রিডার পুনরুদ্ধারের পরে এটি ব্যবহার করুন:

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

আপনি একাধিকবার ক্ষেত্রের নামগুলি গণনা করছেন / একটি কন্টেন্ট সহ স্ক্যান করতে অন্য অ্যারে বরাদ্দ করছেন, এটি উচ্চ ট্র্যাফিক কোডে আরও কম পারফর্মেন্ট হবে।
চাদ গ্রান্ট

@ চ্যাডগ্রান্ট অবশ্যই, এই কারণেই লিনক ওয়ান লাইনার আরও কার্যকর কারণ এটি কেবল একটি পুনরাবৃত্তি করে।
ল্যারি

18

জেসমিনের ধারণার জন্য এখানে একটি কার্যকারী নমুনা রয়েছে:

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

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

}

1
আপনি যদি তার চারপাশে কোনও চেষ্টা / ক্যাপচার করেন তবে
ডোনাল্ড R রেকর্ড

Reader.GetSchemaTable () Columns.Contains ( "myFiled"): আপনার সাথে এই ধারণা প্রক্রিয়া সহজ করতে পারেন।
লেভ জেড

গেটস্কেমা টেবিল () ব্যবহার করা কেবলমাত্র একটি কলামের নাম সন্ধানের জন্য অতিরিক্ত (বরাদ্দ বুদ্ধিমান) is উত্স github.com
চাদ গ্রান্ট

12

এটি আমার পক্ষে কাজ করে:

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

গেটস্কেমা টেবিল () ব্যবহার করা কেবলমাত্র একটি কলামের নাম সন্ধানের জন্য অতিরিক্ত (বরাদ্দ বুদ্ধিমান) is এবং এটি ডটনেট কোরের সমস্ত সংস্করণে প্রয়োগ করা হয়নি। উত্স github.com
চাদ গ্রান্ট

10

নিম্নলিখিতটি আমার পক্ষে সহজ এবং কাজ করেছে:

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

গেটস্কেমা টেবিল () ব্যবহার করা কেবলমাত্র একটি কলামের নাম সন্ধানের জন্য অতিরিক্ত (বরাদ্দ বুদ্ধিমান) is উত্স github.com
চাদ গ্রান্ট

8

আপনি যদি প্রশ্নটি পড়ে থাকেন, মাইকেল ডেটা রিকার্ড ভাবেন না, ডেটা রিডার সম্পর্কে জিজ্ঞাসা করেছিলেন। আপনার জিনিস সঠিকভাবে পান।

r.GetSchemaTable().Columns.Contains(field)ডেটা রেকর্ডে একটি ব্যবহার করা কাজ করে তবে এটি বিএস কলামগুলি ফেরত দেয় (নীচের স্ক্রিনশটটি দেখুন))

কোনও ডেটা কলামে কোনও ডেটা রিডারে ডেটা রয়েছে এবং তা দেখার জন্য, নিম্নলিখিত এক্সটেনশনগুলি ব্যবহার করুন:

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().Columnsডেটা রিডারকে কল করা BS কলামগুলি রিটার্ন করে:

ডেটা রিডারে গেটসেমিটেবল কল করা হচ্ছে



ডেটা রেকর্ড বলতে কী বোঝায় কাজ করে তবে এটি বিএস কলামগুলি ফেরত দেয় ? আপনি বোঝাতে চান এটি চলে (এবং ভুল ফলাফল দেয়)?
নওফাল

2
"আপনার জিনিসগুলি ঠিক পান" - কিন্তু IDataReaderপ্রয়োগ IDataRecord। এগুলি একই বস্তুর বিভিন্ন ইন্টারফেস - ঠিক যেমন ICollection<T>এবং IEnumerable<T>এর বিভিন্ন ইন্টারফেস List<T>IDataReaderপরবর্তী রেকর্ডে অগ্রসর হওয়ার অনুমতি দেয়, যখন IDataRecordবর্তমান রেকর্ড থেকে পড়ার অনুমতি দেয়। এই উত্তরে যে পদ্ধতিগুলি ব্যবহার করা হচ্ছে সেগুলি সমস্ত IDataRecordইন্টারফেস থেকে আসে । প্যারামিটারটিকে কেন ঘোষণার চেয়ে পছন্দীয় তা ব্যাখ্যা করার জন্য stackoverflow.com/a/1357743/221708 দেখুন IDataRecord
ড্যানিয়েল শিলিং

কেন r.GetSchemaTable().Columnsএই প্রশ্নের একেবারে ভুল উত্তর তা দেখানোর জন্য আপভোট করুন ।
ড্যানিয়েল শিলিং

গেটনাম () 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

এখানে এক লাইনে জুঁই থেকে সমাধান ... (আরও একটি সহজ!):

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

গেটস্কেমা টেবিল () ব্যবহার করা কেবলমাত্র একটি কলামের নাম সন্ধানের জন্য অতিরিক্ত (বরাদ্দ বুদ্ধিমান) is উত্স github.com
চাদ গ্রান্ট

পছন্দ করুন আমার ধারণা, প্রসঙ্গ এবং ফ্রিকোয়েন্সি এর উপর নির্ভর করে যে এটি ব্যবহার করা প্রয়োজন তার উপর নির্ভর করে একজনকে বিজ্ঞতার সাথে বেছে নিতে হবে ...
স্পার্ক

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 টি কলামের কাছাকাছি। একটি গ্রাফ এবং পরীক্ষার কোডটি দেখতে নীচে স্ক্রোল করুন।

পুরো উত্তর:

শীর্ষস্থানীয় কয়েকটি উত্তরের কোড কাজ করে, তবে যুক্তিতে ব্যতিক্রম হ্যান্ডলিংয়ের গ্রহণযোগ্যতার উপর ভিত্তি করে "আরও ভাল" উত্তরের জন্য এখানে অন্তর্নিহিত বিতর্ক রয়েছে এবং এটি সম্পর্কিত পারফরম্যান্স।

এটিকে পরিষ্কার করতে, আমি বিশ্বাস করি না ক্যাচিং ব্যতিক্রম সম্পর্কিত অনেক গাইডেন্স আছে। মাইক্রোসফ্টের থ্রোং ব্যতিক্রম সম্পর্কিত কিছু গাইডেন্স রয়েছে । সেখানে তারা বলে:

সম্ভব হলে নিয়ন্ত্রণের স্বাভাবিক প্রবাহের জন্য ব্যতিক্রম ব্যবহার করবেন না।

প্রথম নোটটি হ'ল "যদি সম্ভব হয়" এর লেন্সি। আরও গুরুত্বপূর্ণ, বর্ণনাটি এই প্রসঙ্গে দেয়:

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

এর অর্থ হ'ল আপনি যদি এমন একটি এপিআই লিখছেন যা অন্য কারও দ্বারা গ্রাস করা হতে পারে তবে চেষ্টা / ধরা ছাড়াই একটি ব্যতিক্রম নেভিগেট করার ক্ষমতা দিন। উদাহরণস্বরূপ, আপনার ব্যতিক্রম-ছোঁড়া পার্স পদ্ধতি সহ একটি ট্রিপ পার্স সরবরাহ করুন। এটি কোথাও বলছে না যদিও আপনার কোনও ব্যতিক্রম ধরা উচিত নয়।

তদ্ব্যতীত, অন্য একজন ব্যবহারকারী উল্লেখ করেছেন, ক্যাচগুলি সর্বদা টাইপ অনুসারে ফিল্টারিংয়ের অনুমতি দেয় এবং কিছুটা সাম্প্রতিক সময়ে যখন ক্লজটির মাধ্যমে আরও ফিল্টারিংয়ের অনুমতি দেয় । এটি ভাষা বৈশিষ্ট্যগুলির অপব্যয়ের মতো মনে হয় যদি আমরা সেগুলি ব্যবহার না করে।

এটি বলা যেতে পারে যে একটি নিক্ষিপ্ত ব্যতিক্রমের জন্য কিছু ব্যয় রয়েছে এবং এটি একটি ভারী লুপের জন্য প্রভাব ফেলতে পারে প্রভাবিত। তবে এটিও বলা যেতে পারে যে একটি "সংযুক্ত অ্যাপ্লিকেশন" এ ব্যতিক্রমের ব্যয়টি নগণ্য হতে চলেছে। প্রকৃত ব্যয় এক দশক আগে তদন্ত করা হয়েছিল: https://stackoverflow.com/a/891230/852208 অন্য কথায়, একটি ডাটাবেসের সংযোগ এবং ক্যোয়ারির ব্যয় একটি ছোঁড়া ব্যতিক্রমের বামন হতে পারে।

সব কিছু বাদ দিয়ে, আমি নির্ধারণ করতে চেয়েছিলাম কোন পদ্ধতিটি সত্যই দ্রুততর। যেমনটি প্রত্যাশা করা হয়েছে তেমন কোনও ठोस উত্তর নেই।

যে কোনও কোড কলামগুলির উপরে লুপ করে সেগুলি কলামের সংখ্যা বিদ্যমান থাকায় ধীর হয়ে যায়। এটিও বলা যেতে পারে যে ব্যতিক্রমগুলির উপর নির্ভর করে যে কোনও কোড কোয়েরিটি ব্যর্থ হওয়ার হারের উপর নির্ভর করে ধীর হয়ে যাবে।

চ্যাড গ্রান্ট এবং ম্যাট হ্যামিল্টন উভয়ের উত্তর গ্রহণ করে, আমি 20 টি কলাম এবং 50% ত্রুটি হার পর্যন্ত দুটি পদ্ধতি চালিয়েছি (ওপি ইঙ্গিত করেছে যে তিনি এই দুটি পরীক্ষা বিভিন্ন প্রকল্পের মধ্যে ব্যবহার করছেন, তাই আমি ধরে নিলাম দু'জন হিসাবে) ।

লিনকপ্যাডের মাধ্যমে প্লট করা ফলাফলগুলি এখানে: ফলাফল - সিরিজ 1 লুপ, 2 ব্যতিক্রম

এখানে জিগজাগগুলি প্রতিটি কলাম গণনার মধ্যে ত্রুটি হার (কলাম পাওয়া যায় নি)।

সংকীর্ণ ফলাফল সেট ওভার, লুপিং একটি ভাল পছন্দ। তবে, গেটঅর্ডিনাল / ব্যাতিক্রম পদ্ধতিটি কলামগুলির সংখ্যার তুলনায় প্রায় সংবেদনশীল নয় এবং প্রায় 11 টি কলামের লুপিং পদ্ধতিটিকে ছাড়িয়ে যেতে শুরু করে।

এটি বলেছে যে আমার কাছে 11 টি কলাম যুক্তিযুক্ত বলে মনে হচ্ছে কারণ পুরো অ্যাপ্লিকেশনটিতে গড় সংখ্যক কলাম ফিরে এসেছে। উভয় ক্ষেত্রেই আমরা এখানে মিলিসেকেন্ডের ভগ্নাংশের কথা বলছি।

তবে একটি কোড সরলতার দিক এবং উপাধি সমর্থন থেকে আমি সম্ভবত গেটআর্ডিনাল রুট দিয়ে যেতে চাই।

লিনকপ্যাড আকারে পরীক্ষাটি এখানে। আপনার নিজস্ব পদ্ধতিতে পুনরায় পোস্ট করতে নির্দ্বিধায়:

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

দুর্দান্ত বিশ্লেষণ। আমি এর ফলাফলগুলি আমার নতুন উত্তরে ব্যবহার করেছি।
ইয়াজানপ্রো

1

এই কোড যে সমস্ত কারণে Levitikon তাদের কোড সঙ্গে ছিল সংশোধন: (থেকে অভিযোজিত: [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();:)
নওফাল

গেটস্কেমা টেবিল () ব্যবহার করা কেবলমাত্র একটি কলামের নাম সন্ধানের জন্য অতিরিক্ত (বরাদ্দ বুদ্ধিমান) is উত্স github.com
চাদ গ্রান্ট

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 কেস-সংবেদনশীল বিটিডাব্লু।


ধারণ করে () ব্যতিক্রম ছুঁড়ে না, এই কোডটি অর্থহীন। আপনি কেবল নাল পয়েন্টার ব্যতিক্রমগুলি ধরছেন।
চাদ গ্রান্ট

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

যদি রেফারেন্সড তিনটি লাইন (বর্তমানে lines২,, and এবং taken৪ লাইনগুলি) বের করা হয়, তবে -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

আপনি যদি কলামগুলির তালিকা চান এবং আপনি কোনও ব্যতিক্রম পেতে চান না, তবে আপনি আপনার ডেটা রিডারটিতে গেটস্কেমা টেবিল () কেও কল করতে পারেন ...


2
আছে: যেমন কিনা এই কাজের ধরনে কিছু বিতর্ক stackoverflow.com/questions/373230/...
bzlm

-1

কেমন

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

এটি সম্ভবত একটি লুপ হিসাবে দক্ষ হবে না


দেখুন Levitikon এর উত্তর জিনিস যে ধরনের দেখতে dr.GetSchemaTable().Columnsএটা আপনার জন্য খুঁজছেন তা নয় - ধারণ করে।
ড্যানিয়েল শিলিং

-1

যদিও কোন প্রকাশ্যে উন্মুক্ত পদ্ধতি আছে, একটি পদ্ধতি অভ্যন্তরীণ ক্লাসে কোন অস্তিত্ব নেই System.Data.ProviderBase.FieldNameLookup, যাSqlDataReader নির্ভর করে।

এটি অ্যাক্সেস করতে এবং নেটিভ পারফরম্যান্স পেতে, আপনাকে রানটাইম সময়ে একটি পদ্ধতি তৈরি করতে অবশ্যই আইএলজিনিটর ব্যবহার করতে হবে। নিম্নলিখিত কোড আপনি সরাসরি অ্যাক্সেস করার অনুমতি দেবে 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
অভ্যন্তরীণ কোডটি প্রায়শই ঠিক একই জিনিসটি করে আমার উত্তরটি করছে, এই অদ্ভুত প্রতিচ্ছবি / প্রতিনিধি প্রয়োজন ছাড়াই। এটি প্রতি বস্তুর উদাহরণ অনুসারে লুকিংয়ের ক্যাচিং করছে যা বাস্তব জগতে যেমন আপনি ক্যারিয়ারটি প্রথমবার চালু হয় তখন অধ্যাদেশগুলিকে ক্যাশে করতে চান এবং অ্যাপ্লিকেশনটির আজীবন সেই ক্যাশেটি ব্যবহার করতে চান, প্রতিটি ক্যোয়ারিতে নতুন ক্যাশে তৈরি না করে উপকারী হবে না beneficial
চাদ গ্রান্ট

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

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.