2009-05-21 18 views
6

ado.net में DataReader पर Peek विधि प्रतीत नहीं होता है। मैं अपने पाठक के माध्यम से लूप से पहले कुछ एक-ऑफ प्रोसेसिंग करने में सक्षम होना चाहता हूं, और बाद में पुनरावृत्ति के कारण इसे छोड़ने के बिना पहली पंक्ति में डेटा को देखने में सक्षम होना अच्छा लगेगा। इसे निष्पादित करने का श्रेष्ठ तरीका क्या है?मैं डेटा रीडर पर एक पीक() फ़ंक्शन कैसे कार्यान्वित करूं?

मैं SqlDataReader का उपयोग कर रहा हूं, लेकिन अधिमानतः कार्यान्वयन जितना संभव हो उतना सामान्य होगा (यानी IDataReader या DbDataReader पर लागू करें)।

उत्तर

5

मैं जेसन के समाधान के लिए कुछ इसी तरह का सुझाव देते हैं, लेकिन एक आवरण है कि IDataReader बजाय लागू करता है का उपयोग करते हुए, तो:

sealed public class PeekDataReader : IDataReader 
{ 
    private IDataReader wrappedReader; 
    private bool wasPeeked; 
    private bool lastResult; 

    public PeekDataReader(IDataReader wrappedReader) 
    { 
     this.wrappedReader = wrappedReader; 
    } 

    public bool Peek() 
    { 
     // If the previous operation was a peek, do not move... 
     if (this.wasPeeked) 
      return this.lastResult; 

     // This is the first peek for the current position, so read and tag 
     bool result = Read(); 
     this.wasPeeked = true; 
     return result; 
    } 

    public bool Read() 
    { 
     // If last operation was a peek, do not actually read 
     if (this.wasPeeked) 
     { 
      this.wasPeeked = false; 
      return this.lastResult; 
     } 

     // Remember the result for any subsequent peeks 
     this.lastResult = this.wrappedReader.Read(); 
     return this.lastResult; 
    } 

    public bool NextResult() 
    { 
     this.wasPeeked = false; 
     return this.wrappedReader.NextResult(); 
    } 

    // Add pass-through operations for all other IDataReader methods 
    // that simply call on 'this.wrappedReader' 
} 

ध्यान दें कि यह सब अप्रभावित संपत्तियों के लिए काफी पास-थ्रू कोड का एक सा की आवश्यकता होती है, लेकिन लाभ यह है कि यह एक सामान्य अमूर्त है जो बाद के 'पढ़ने' ऑपरेशन पर आगे बढ़े बिना परिणाम सेट में किसी भी स्थिति पर 'चोटी' कर सकता है।

का उपयोग करें:

using (IDataReader reader = new PeekDataReader(/* actual reader */)) 
{ 
    if (reader.Peek()) 
    { 
     // perform some operations on the first row if it exists... 
    } 

    while (reader.Read()) 
    { 
     // re-use the first row, and then read the remainder... 
    } 
} 

नोट हालांकि यह है कि हर 'पीक()' कॉल वास्तव में अगले रिकॉर्ड पर आ जाएगा अगर पिछले ऑपरेशन भी एक 'पीक()' नहीं था। इस समरूपता को 'रीड()' ऑपरेशन के साथ रखते हुए एक सरल कार्यान्वयन और अधिक सुरुचिपूर्ण एपीआई प्रदान करता है।

+1

आपका उदाहरण काम नहीं करता है, क्योंकि 'IDataReader' इंटरफ़ेस में आपकी' .Peek' विधि नहीं है। आपको स्पष्ट रूप से उपयोग करने वाले स्कोप चर को 'PeekDataReader' के रूप में टाइप करना चाहिए या' var' का उपयोग करना चाहिए। – julealgon

3

आपको एक पीक() विधि की आवश्यकता नहीं है। आप Do Do loop के साथ जो कुछ भी चाहते हैं उसे पूरा कर सकते हैं।

तो बजाय

while(dr.read()) 
{ 
    ... do stuff 
} 

आप

dr.read(); 
... do stuff 

do 
{ 
    ... do stuff 
}while(dr.read()) 
+0

पीक() इस दृष्टिकोण की तुलना में काफी अधिक लचीला है क्योंकि इसे कई स्थानों पर, कई बार कई बार "डेटाटाइडर" पर कई बार किया जा सकता है, बिना किसी भी "पहली बार" परिणाम पास किए बिना। –

+1

डेटा रीडर मानों को पढ़ना इसे आगे नहीं बढ़ाता है, पढ़ें() विधि यह करता है। आप इसे आगे बढ़ने के बिना जितनी बार चाहें मूल्यों को पढ़ सकते हैं। मुझे यकीन नहीं है कि कैसे पीक() किसी भी मूल्य को जोड़ देगा। मैं तुम्हारी बात याद कर सकता हूं। ???? –

+0

यह काम करने योग्य है, लेकिन मैं मैन्युअल रूप से लिनक के माध्यम से पाठक का उपभोग करना चाहता था। –

4

आप एक राज्य मशीन है कि झांकना मोड बनाम नियमित मोड पटरियों बना सकते हैं। हो सकता है कि कुछ इस तरह (सिर्फ उन्हें सभी एक ही Peeker.cs बुलाया फ़ाइल या ऐसा ही कुछ में टॉस सकता है): overkill की

public sealed class Peeker 
{ 
    internal readonly PeekMode PEEKING; 
    internal readonly NormalMode NORMAL; 

    private ReadState _state; 

    public Peeker() 
    { 
     PEEKING = new PeekMode(this); 
     NORMAL = new NormalMode(this); 

     // Start with a normal mode 
     _state = NORMAL; 
    } 

    public object[] OnRead(IDataReader dr, bool peek) 
    { 
     return _state.OnRead(dr, peek); 
    } 

    internal void SetState(ReadState state) 
    { 
     _state = state; 
    } 
} 

internal abstract class ReadState 
{ 
    protected Peeker _peeker; 

    protected ReadState(Peeker p) 
    { 
     _peeker = p; 
    } 

    public abstract object[] OnRead(IDataReader dr, bool peek);   
} 

internal class PeekMode : ReadState 
{ 
    public PeekMode(Peeker p) 
     : base(p) 
    { 
    } 

    public override object[] OnRead(IDataReader dr, bool peek) 
    { 
     object[] datarow = new object[dr.FieldCount]; 

     if (peek) 
     {     
      dr.GetValues(datarow);     
     } 
     else 
     { 
      if (dr.Read()) 
      { 
       dr.GetValues(datarow); 
       _peeker.SetState(_peeker.NORMAL); 
      } 
     } 

     return datarow; 
    } 
} 

internal class NormalMode : ReadState 
{ 
    public NormalMode(Peeker p) 
     : base(p) 
    { 
    } 

    public override object[] OnRead(IDataReader dr, bool peek) 
    { 
     object[] datarow = new object[dr.FieldCount]; 

     if (peek) 
     { 
      if (dr.Read()) 
      { 
       dr.GetValues(datarow); 
       _peeker.SetState(_peeker.PEEKING); 
      } 
     } 
     else 
     { 
      if (dr.Read()) 
      { 
       dr.GetValues(datarow); 
      } 
     } 

     return datarow; 
    } 
} 

तरह है, लेकिन ओह अच्छी तरह से।

आप बस अनुसरण करना होगा इसका इस्तेमाल करने के लिए:

Peeker p = new Peeker(); 
. 
. 
. 
SomeDataReaderType dr = SomeCommandType.ExecuteReader(); 
. 
. 
. 
// To peek 
object[] myDataRow = p.OnRead(dr, true); 

// or not to peek 
object[] myDataRow = p.OnRead(dr, false); 

तो फिर आप अपने पंक्ति के साथ क्या करने की जरूरत है। ऑब्जेक्ट सरणी का उपयोग करने से बेहतर तरीका हो सकता है, लेकिन आपको बिंदु मिल जाता है।

शुभकामनाएं!

+0

यह उतना ही कम है जितना मैं जा रहा था। ऐसा लगता है कि मुझे एक रैपर वर्ग की आवश्यकता होगी ताकि मैं राज्य की जानकारी रख सकूं। मुझे यकीन नहीं है कि यह परेशानी के लायक है, हालांकि। –

+0

निर्भर करता है कि यह कितना महत्वपूर्ण है। ऐसा करने में बहुत अधिक कोड नहीं लगेगा, लेकिन इसमें थोड़ा सा काम होगा (3 छोटी कक्षाएं संभवतः)। –

+0

ठीक है कि 4 छोटे वर्ग = = –

संबंधित मुद्दे