আমরা যদি ডেটারেডার সারিটি সরবরাহ করি এবং সমস্ত রেকর্ড না পড়ি তবে কী ডেটাবেস সংযোগটি বন্ধ হয়ে যাবে?


15

কিভাবে বুঝতে যদিও yieldশব্দ কাজ, আমি জুড়ে এসেছিল link1 এবং link2 Stackoverflow যা ব্যবহার অত্যাবশ্যক yield returnযখন DataReader উপর iterating এবং ভাল হিসাবে এটি আমার প্রয়োজন suits। তবে এটি আমাকে কী ঘটছে তা ভাবতে বাধ্য করে, যদি আমি yield returnনীচে প্রদর্শিত হিসাবে ব্যবহার করি এবং যদি আমি পুরো ডেটারিডার দিয়ে পুনরায় না ঘটাতে পারি তবে ডিবি সংযোগটি কি চিরকাল খোলা থাকবে?

IEnumerable<IDataRecord> GetRecords()
{
    SqlConnection myConnection = new SqlConnection(@"...");
    SqlCommand myCommand = new SqlCommand(@"...", myConnection);
    myCommand.CommandType = System.Data.CommandType.Text;
    myConnection.Open();
    myReader = myCommand.ExecuteReader(CommandBehavior.CloseConnection);
    try
       {               
          while (myReader.Read())
          {
            yield return myReader;          
          }
        }
    finally
        {
            myReader.Close();
        }
}


void AnotherMethod()
{
    foreach(var rec in GetRecords())
    {
       i++;
       System.Console.WriteLine(rec.GetString(1));
       if (i == 5)
         break;
  }
}

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

সম্পাদন করা বেনের উত্তরের উত্তর পরিবর্তন করেছে কারণ পদ্ধতি আহ্বানকারীদের পদ্ধতিটি সঠিকভাবে ব্যবহার করা আশা করা ভুল এবং ডিবি সংযোগের ক্ষেত্রে পদ্ধতিটি অকারণে একাধিকবার বলা হলেও এটি আরও ব্যয়বহুল হবে।

বিস্তারিত ব্যাখ্যার জন্য জাকব এবং বেনকে ধন্যবাদ।


আমি যা দেখছি তা থেকে আপনি সংযোগটি প্রথম স্থানে খুলছেন না
পাপারাজ্জো

@ ফ্রিসবি সম্পাদিত :)
গাওদেপ্রসাদ

উত্তর:


12

হ্যাঁ, আপনি যে সমস্যার বর্ণনা দিয়েছেন তার মুখোমুখি হবেন: যতক্ষণ না আপনি ফলাফলটি নিয়ে পুনরাবৃত্তি শেষ না করেন, আপনি সংযোগটি উন্মুক্ত রাখবেন। এর সাথে মোকাবিলা করার জন্য আমি দুটি সাধারণ পন্থা ভাবতে পারি:

ধাক্কা, টান না

বর্তমানে আপনি একটি ফিরিয়ে দিচ্ছেন IEnumerable<IDataRecord>, এমন একটি ডেটা স্ট্রাকচার যা থেকে আপনি টানতে পারেন। পরিবর্তে, আপনি আপনার পদ্ধতি সুইচ করতে পারে ধাক্কা তার ফলগুলি। সবচেয়ে সহজ উপায় Action<IDataRecord>হ'ল একটি পাস যা প্রতিটি পুনরাবৃত্তির জন্য বলা হয়:

void GetRecords(Action<IDataRecord> callback)
{
    // ...
      while (myReader.Read())
      {
        callback(myReader);
      }
}

নোট করুন যে আপনি আইটেমগুলির সংকলনের সাথে ডিল করছেন, IObservable/ IObserverতা কিছুটা যথাযথ ডেটা কাঠামো হতে পারে তবে আপনার এটি প্রয়োজন না হলে একটি সাধারণAction অনেক বেশি সোজা।

আগ্রহের সাথে মূল্যায়ন করুন

একটি বিকল্প হ'ল ফিরে আসার আগে পুনরাবৃত্তি সম্পূর্ণরূপে সম্পূর্ণ হয় তা নিশ্চিত করা।

আপনি কেবলমাত্র ফলাফলটি তালিকায় রেখে তারপরে ফিরে এসে সাধারণত এটি করতে পারেন, তবে এক্ষেত্রে প্রতিটি আইটেমের অতিরিক্ত জটিলতা পাঠকের সমান রেফারেন্স হিসাবে রয়েছে। সুতরাং পাঠকের কাছ থেকে আপনার প্রয়োজনীয় ফলাফলটি বের করতে আপনার কিছু দরকার:

IEnumerable<T> GetRecords<T>(Func<IDataRecord,T> extractor)
{
    // ...
     var result = new List<T>();
     try
     {
       while (myReader.Read())
       {
         result.Add(extractor(myReader));         
       }
     }
     finally
     {
         myReader.Close();
     }
     return result;
}

আপনি এজারিলি মূল্যায়ন নামটি ব্যবহার করেছেন। আমার এসকিউএলকম্যান্ডের ডেটাডার্ডার যদি একাধিক আউটপুট (মাইরেডার.নেক্সটআরসাল্ট () এর মতো) ফেরত দেয় এবং আমি তালিকার একটি তালিকা তৈরি করি তবে এখন এটি কি মেমরির ওভারহেড হবে? অথবা কলকারীর কাছে ডেটারেডার পাঠানো [আমি ব্যক্তিগতভাবে এটি পছন্দ করি না] অনেক কার্যকর হবে? [তবে সংযোগটি দীর্ঘ সময় খোলা থাকবে]। আমি এখানে যা স্পষ্টভাবে বিভ্রান্ত করছি তা হল তালিকার একটি তালিকা তৈরির চেয়ে সংযোগটি বেশি সময় খোলা রাখার ট্রেড অফের মধ্যে। আপনি নিরাপদে ধরে নিতে পারেন যে আমার ওয়েবপৃষ্ঠায় ডিবিতে সংযোগ স্থাপন করা প্রায় 500+ এর কাছাকাছি লোক থাকবে।
গাওদেপ্রসাদ

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

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

1
@ বার্নটোকোড প্রশ্নটি দেখুন: "আমি যদি নীচের মত দেখায় ফলন ফেরত ব্যবহার করি এবং যদি আমি সম্পূর্ণ ডেটা রিডার দিয়ে পুনরায় না ঘটাতে পারি তবে ডিবি সংযোগ চিরকাল খোলা থাকবে"? সমস্যাটি হ'ল আপনি একটি আইনুনামেবল ফিরিয়ে দেন এবং প্রত্যেক কলার যিনি এটি পরিচালনা করেন তাদের এই বিশেষ গোটচা সম্পর্কে সচেতন থাকতে হবে: "আপনি যদি আমার উপরে পুনরাবৃত্তিটি শেষ না করেন তবে আমি একটি সংযোগ খোলাম"। পুশ পদ্ধতিতে, আপনি সেই দায়িত্বটি কলার থেকে দূরে সরিয়ে রাখেন- তাদের কাছে আংশিক পুনরাবৃত্তি করার কোনও বিকল্প নেই। সময় নিয়ন্ত্রণ তাদের কাছে ফিরিয়ে দেওয়ার পরে, সংযোগটি বন্ধ হয়ে যায়।
বেন অ্যারনসন

1
এটি একটি দুর্দান্ত উত্তর। আমি পুশ পদ্ধতির পছন্দ করি কারণ আপনার যদি একটি বড় প্রশ্ন থাকে যে আপনি একটি পেজড ফ্যাশনে উপস্থাপন করছেন তবে আপনি অ্যাকশন <> এর চেয়ে ফানক <> এ পাস করে গতির জন্য আগের পাঠটি বাতিল করতে পারেন; এটি গেটআরকর্ডস ফাংশনটিও পেজিং করা থেকে পরিষ্কার মনে করে।
ওয়েলকাহোলিজম

10

আপনার finallyব্লক সর্বদা কার্যকর করা হবে।

আপনি যখন yield returnসংকলকটি ব্যবহার করবেন তখন একটি রাষ্ট্রীয় মেশিন বাস্তবায়নের জন্য একটি নতুন নেস্টেড শ্রেণি তৈরি করবে।

এই শ্রেণিতে finallyপৃথক পদ্ধতি হিসাবে ব্লকগুলি থেকে সমস্ত কোড থাকবে । এটি finallyরাষ্ট্রের উপর নির্ভর করে যেসব ব্লকগুলি কার্যকর করতে হবে তার উপর নজর রাখবে। সমস্ত প্রয়োজনীয় finallyব্লক Disposeপদ্ধতিতে কার্যকর করা হবে ।

সি # ভাষার বিবরণ অনুসারে foreach (V v in x) embedded-statementপ্রসারিত হয় expand

{
    E e = ((C)(x)).GetEnumerator();
    try
    {
        while (e.MoveNext())
        {
            V v = (V)(T)e.Current;
            embedded - statement
        }
    }
    finally {
         // Dispose e
    }
}

সুতরাং আপনি breakবা এর সাথে লুপটি প্রস্থান করলেও গণকের নিষ্পত্তি হবে return

পুনরাবৃত্তি বাস্তবায়ন সম্পর্কে আরও তথ্য পেতে আপনি জেন স্কিটির এই নিবন্ধটি পড়তে পারেন

সম্পাদন করা

এই জাতীয় পদ্ধতির সমস্যাটি হ'ল পদ্ধতিটি সঠিকভাবে ব্যবহার করতে আপনি আপনার ক্লাসের ক্লায়েন্টদের উপর নির্ভর করেন। তারা উদাহরণস্বরূপ সরাসরি গণক পেতে এবং whileএটি নিষ্পত্তি না করে একটি লুপের মাধ্যমে পুনরাবৃত্তি করতে পারে।

@ বেনআরনসন আপনাকে প্রস্তাবিত সমাধানগুলির একটি বিবেচনা করা উচিত।


1
এটি অত্যন্ত বিশ্বাসযোগ্য নয়। উদাহরণস্বরূপ: var records = GetRecords(); var first = records.First(); var count = records.Count()প্রকৃতপক্ষে সেই পদ্ধতিটি দু'বার সম্পাদন করবে এবং সংযোগ এবং পাঠককে প্রতিটি বার খোলার এবং বন্ধ করতে হবে। এটির উপর দু'বার আইট্রেট করা একই জিনিসটি করে। আপনি এটির উপরে পুনরাবৃত্তি করার আগে ফলাফলটি দীর্ঘকাল ধরে পাস করতে পারেন ইত্যাদি the পদ্ধতিতে স্বাক্ষরের কোনও কিছুই এই জাতীয় আচরণের বোঝায় না
বেন অ্যারোনসন

2
@ বেনআরনসন আমি আমার উত্তরে বর্তমান বাস্তবায়ন সম্পর্কে সুনির্দিষ্ট প্রশ্নের দিকে মনোনিবেশ করেছি। আপনি যদি পুরো সমস্যাটি দেখেন তবে আমি সম্মত হলাম যে আপনি নিজের উত্তরের পরামর্শ মত উপায়টি ব্যবহার করা আরও ভাল।
জাকুব লর্টজ

1
@ জাকুবল্টজ ফেয়ার যথেষ্ট
বেন

2
@ এসবেনসকভ পিডারসন সাধারণত যখন আপনি কিছু বোকামি-প্রমাণ করার চেষ্টা করেন, আপনি কিছু কার্যকারিতা হারাবেন। আপনার এটি ভারসাম্যপূর্ণ করা দরকার। এখানে আমরা আগ্রহের সাথে ফলাফলগুলি লোড করে খুব বেশি হারাতে পারি না। যাই হোক, আমার পক্ষে সবচেয়ে বড় সমস্যা নামকরণ। আমি যখন GetRecordsনামার পদ্ধতিটি দেখি তখন আমি IEnumerableএটি রেকর্ডগুলি মেমরিতে লোড করে রাখার প্রত্যাশা করি। অন্যদিকে, এটি যদি সম্পত্তি ছিল Records, আমি বরং এটি ডেটাবেসগুলিতে এক ধরণের বিমূর্ততা ধরে নেব।
জাকুব লর্টজ

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

5

নির্দিষ্ট yieldআচরণ নির্বিশেষে , আপনার কোডটিতে সম্পাদনের পথ রয়েছে যা আপনার সংস্থানগুলি সঠিকভাবে নিষ্পত্তি করবে না। যদি আপনার দ্বিতীয় লাইনের ব্যতিক্রম বা তৃতীয়টি ছুড়ে যায় তবে কী হবে? নাকি আপনার চতুর্থ? আপনার খুব জটিল চেষ্টা / শেষ চেইনের দরকার হবে, বা আপনি usingব্লকগুলি ব্যবহার করতে পারেন ।

IEnumerable<IDataRecord> GetRecords()
{
    using(var connection = new SqlConnection(@"..."))
    {
        connection.Open();

        using(var command = new SqlCommand(@"...", connection);
        {
            using(var reader = command.ExecuteReader())
            {
               while(reader.Read())
               {
                   // your code here.
                   yield return reader;
               }
            }
        }
    }
}

লোকেরা মন্তব্য করেছেন যে এটি স্বজ্ঞাত নয়, যে লোকেরা আপনার পদ্ধতিটি কল করে তারা হয়ত জানেন না যে ফলাফলকে দুবার গণনা করা পদ্ধতিটিকে দু'বার কল করবে। ভাল, শক্ত ভাগ্য। ভাষাটি এইভাবে কাজ করে। এটি সেই সংকেত যা IEnumerable<T>প্রেরণ করে। এটি ফিরে না আসার একটি কারণ List<T>বা আছে T[]। যে লোকেরা এগুলি জানে না তাদের শিক্ষার প্রয়োজন হয়, চারপাশে কাজ করা হয়নি।

ভিজ্যুয়াল স্টুডিওতে স্ট্যাটিক কোড বিশ্লেষণ নামে একটি বৈশিষ্ট্য রয়েছে। আপনার উত্সগুলি সঠিকভাবে নিষ্পত্তি হয়েছে কিনা তা জানতে আপনি এটি ব্যবহার করতে পারেন।


ভাষাটি পুনরাবৃত্তিকে IEnumerableসমস্ত ধরণের জিনিসগুলি করতে দেয়, যেমন সম্পূর্ণ সম্পর্কযুক্ত ব্যতিক্রম ছুঁড়ে দেওয়া বা 5 জিবি ফাইলকে ডিস্কে লেখার মতো। কেবলমাত্র ভাষাটির অনুমতি দেওয়ার অর্থ এই নয় যে এটি এমন কোনও IEnumerableপদ্ধতি থেকে ফিরে আসে যা গ্রহণযোগ্য that
বেন অ্যারনসন

1
একটি রিটার্নিং IEnumerable<T> হয় ইঙ্গিত এটি দুইবার enumerating দুটি কল স্থাপিত হবে। আপনি যদি একাধিকবার গণনা করেন তবে আপনি আপনার সরঞ্জামগুলিতে সহায়ক সতর্কতাও পাবেন। ব্যতিক্রম নিক্ষেপ সম্পর্কে বিন্দুটি রিটার্নের ধরণের নির্বিশেষে সমানভাবে বৈধ। যদি সেই পদ্ধতিটি কোনও ফেরত List<T>দেয় তবে এটি একই ব্যতিক্রম ছুঁড়ে ফেলবে।
নভে

আমি আপনার বক্তব্যটি বুঝতে পারি এবং কিছুটা হলেও আমি সম্মত হয়েছি- আপনি যদি এমন কোনও পদ্ধতি গ্রহণ করেন যা আপনাকে একটি IEnumerableতত্কালীন ইমপোর্টার দেয়। তবে আমি এটিও মনে করি যে পদ্ধতি লেখক হিসাবে আপনার স্বাক্ষরটি যা বোঝায় সেগুলি মেনে চলার দায়িত্ব আপনার রয়েছে। পদ্ধতিটি বলা হয় GetRecords, সুতরাং যখন এটি ফিরে আসে আপনি এটি প্রত্যাশা করতেন, ইয়াক জ্ঞান, রেকর্ডগুলি অর্জন করল । যদি এটি GiveMeSomethingICanPullRecordsFrom(বা আরও বাস্তববাদী GetRecordSourceবা অনুরূপ) বলা IEnumerableহত তবে একটি অলস আরও গ্রহণযোগ্য হবে।
বেন অ্যারনসন

@ বেনআরনসন আমি সম্মত হই যে উদাহরণস্বরূপ File, ReadLinesএবং ReadAllLinesসহজেই পৃথকভাবে বলা যেতে পারে এবং এটি একটি ভাল জিনিস। (যদিও এটি আরও কারণ যে কোনও পদ্ধতির ওভারলোড কেবল রিটার্ন টাইপের মাধ্যমে পৃথক হতে পারে না)। সম্ভবত রিডারকর্ডস এবং রিডএলরেকর্ডসও নামকরণের স্কিম হিসাবে এখানে ফিট করবে।
নভে

2

আপনি যা করেছেন তা ভুল বলে মনে হচ্ছে তবে ঠিকঠাক কাজ করবে।

আপনার আইনিউমেটর <> ব্যবহার করা উচিত , কারণ এটি আইডিস্পোজেবলের উত্তরাধিকার সূত্রে প্রাপ্ত

তবে আপনি ভবিষ্যদ্বাণী ব্যবহার করার কারণে, সংকলকটি ভবিষ্যতের জন্য একটি আইনিমুয়েটর <> জেনারেট করার জন্য একটি আইডিস্পোজেবল ব্যবহার করছে।

সত্যিকার অর্থে, ভবিষ্যদ্বাণীতে ইন্টারনালি অনেক কিছুই জড়িত।

পরীক্ষা করে দেখুন /programming/13459447/do-i-need-to-consider-disposing-of-any-ienumerablet-i-use

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